26个版本 (6个重大更新)
新 0.8.0 | 2024年8月21日 |
---|---|
0.7.7 | 2024年7月8日 |
0.7.6 | 2024年6月10日 |
0.7.0 | 2024年3月30日 |
0.3.1 | 2023年7月30日 |
#1 in 魔法豆
每月下载量 250,638
在 115 个crate中使用 (4个直接使用)
315KB
9K SLoC
syn-solidity
syn
驱动的用于类似 TokenStream
的 Solidity 解析器。
解析的根元素是 File
,其中包含一个 Item
列表。 Item
也支持外部属性,如下所示。
设计
此解析器专门为Rust过程宏设计。它的目的是在解析有效的Solidity代码时模仿官方Solidity编译器(Solc)的行为。这意味着所有由Solc v0.5.*[^1]及更高版本识别的有效Solidity代码也将被 syn-solidity
正确识别和解析。
然而,与官方Solidity编译器和语法规范相比,syn-solidity
更加宽容和宽松。以下是一些在 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 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 = 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(())
依赖项
~230–670KB
~16K SLoC