1个不稳定版本
0.7.4 | 2024年5月30日 |
---|
#19 在 #solidity
487 每月下载量
用于 21 个crate(直接使用2个)
315KB
9K SLoC
linera-alloy-syn-solidity
syn
驱动的类似 TokenStream
的Solidity解析器。
解析的根元素是 File
,它包含一系列 Item
。 Item
还支持外部属性,如下所示。
⚠️ 进行中 ⚠️
设计
此解析器专门为Rust过程宏设计。它旨在模仿官方Solidity编译器(Solc)解析有效Solidity代码时的行为。这意味着所有由Solc v0.5.*[^1] 及以上版本认可的Solidity有效代码也将被 linera-alloy-syn-solidity
正确识别和解析。
然而,与官方Solidity编译器和语法规范相比,linera-alloy-syn-solidity
更为宽容和宽松。以下是一些在 linera-alloy-syn-solidity
中有效但在官方编译器中无效的代码模式示例
- 标识符是Rust标识符(
syn::Ident
),因此不能包含美元符号($
),但可以包含Unicode字符 - 尾随标点符号,如函数参数或枚举定义中的逗号(
,
) - 在某些上下文中的某些变量和函数属性,如接口中的
internal
函数或具有实现({ ... }
)的函数 - 项目定义中的参数存储位置,如在结构体或错误定义中的
uint256[] memory
- 元组类型
(T, U, ..)
在需要类型的地方是被允许的,并且可以可选地由tuple
关键字引导。这与ethers.js
的人类可读 ABI 相同。
这种宽容的行为是故意设计的,以方便在过程宏中使用,并减少解析器和 AST 中的代码复杂性。
[^1]: 较旧版本可能仍然可以成功解析,但这不能保证。
已知限制
此解析器仅限于有效的 Rust 令牌,这意味着某些 Solidity 构造不支持。以下是一些示例,但不仅限于这些:
- 标识符内的美元符号(
$
) - 单引号字符串
hex
和unicode
字符串字面量前缀。字面量前缀在 Rust 版本 2021 及以上中被保留。"\uXXXX"
Unicode 转义。Rust 使用"\u{XXXX}"
来表示 Unicode 代码点。- 无效的嵌套块注释。例如,
/*/*/
无法解析。
大多数情况下,您可以复制粘贴 Solidity 代码,并期望它在大多数情况下可以正确解析。您可以在 测试 目录中看到一些正确解析的 Solidity 代码示例(经过一些非常轻度的修改)。
示例
基本用法
use quote::quote;
use linera_alloy_syn_solidity::{Expr, File, Item, Lit, Stmt};
// Create a Solidity `TokenStream`
let tokens = quote! {
/// @name HelloWorld
/// @notice A hello world example in Solidity.
contract HelloWorld {
/// @notice Returns the string "Hello, World!".
function helloWorld() external pure returns (string memory) {
return "Hello, World!";
}
}
};
// Parse the tokens into a `File`
let ast: File = linera_alloy_syn_solidity::parse2(tokens)?;
let items: &[Item] = &ast.items;
let Some(Item::Contract(contract)) = items.first() else {
unreachable!()
};
assert_eq!(contract.name, "HelloWorld");
assert_eq!(contract.attrs.len(), 2); // doc comments
let body: &[Item] = &contract.body;
let Some(Item::Function(function)) = body.first() else {
unreachable!()
};
assert_eq!(function.attrs.len(), 1); // doc comment
assert_eq!(function.name.as_ref().unwrap(), "helloWorld");
assert!(function.parameters.is_empty()); // ()
assert_eq!(function.attributes.len(), 2); // external pure
assert!(function.returns.is_some());
let Some([Stmt::Return(ret)]) = function.body() else {
unreachable!()
};
let Some(Expr::Lit(Lit::Str(s))) = &ret.expr else {
unreachable!()
};
assert_eq!(s.value(), "Hello, World!");
# syn::Result::Ok(())
依赖项
~240–680KB
~16K SLoC