Rust源代码解析库solar-parse的使用,solar-parse提供高效语法分析和AST操作功能

solar-parse

Solidity 和 Yul 的词法分析器(lexer)和解析器(parser)。

这两个实现都是从 Rust 编译器中的 rustc_lexerrustc_parse 修改而来,以适应 Rust 和 Solidity/Yul 之间的差异。

安装

在项目目录中运行以下 Cargo 命令:

cargo add solar-parse

或者在 Cargo.toml 中添加以下行:

solar-parse = "0.1.5"

示例使用

以下是一个使用 solar-parse 解析 Solidity 代码的完整示例:

use solar_parse::solidity;
use std::fs;

fn main() {
    // 读取 Solidity 文件
    let solidity_code = fs::read_to_string("example.sol").expect("无法读取文件");
    
    // 解析 Solidity 代码
    let parse_result = solidity::parse(&solidity_code);
    
    match parse_result {
        Ok(ast) => {
            // 成功解析,可以操作 AST
            println!("成功解析 Solidity 代码");
            println!("AST 节点数量: {}", ast.nodes.len());
            
            // 遍历 AST 节点
            for node in ast.nodes {
                println!("节点类型: {:?}", node.kind);
                // 这里可以添加更多的 AST 处理逻辑
            }
        }
        Err(e) => {
            // 解析失败
            println!("解析错误: {:?}", e);
        }
    }
}

完整示例代码

以下是一个更完整的示例,展示如何解析 Solidity 合约并分析其结构:

use solar_parse::solidity;
use std::{fs, path::Path};

// 定义一个分析 Solidity 合约的函数
fn analyze_contract(file_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    // 检查文件是否存在
    if !Path::new(file_path).exists() {
        return Err(format!("文件 {} 不存在", file_path).into());
    }

    // 读取 Solidity 文件内容
    let source_code = fs::read_to_string(file_path)?;
    
    // 解析 Solidity 代码
    let ast = solidity::parse(&source_code)?;
    
    println!("合约分析结果:");
    println!("总节点数: {}", ast.nodes.len());
    println!("--------------------------------");
    
    // 遍历并分类节点
    let mut contract_count = 0;
    let mut function_count = 0;
    let mut variable_count = 0;
    
    for node in ast.nodes {
        match node.kind {
            solidity::NodeKind::ContractDefinition => {
                contract_count += 1;
                println!("发现合约定义: {:?}", node);
            }
            solidity::NodeKind::FunctionDefinition => {
                function_count += 1;
                println!("发现函数定义: {:?}", node);
            }
            solidity::NodeKind::VariableDeclaration => {
                variable_count += 1;
                println!("发现变量声明: {:?}", node);
            }
            _ => {
                // 其他类型的节点
            }
        }
    }
    
    println!("--------------------------------");
    println!("统计:");
    println!("合约数量: {}", contract_count);
    println!("函数数量: {}", function_count);
    println!("变量数量: {}", variable_count);
    
    Ok(())
}

fn main() {
    let file_path = "contract.sol";
    
    match analyze_contract(file_path) {
        Ok(_) => println!("分析完成"),
        Err(e) => println!("分析出错: {}", e),
    }
}

功能

solar-parse 提供以下主要功能:

  1. 高效语法分析:基于 Rust 编译器的解析器实现,提供高性能的代码解析能力
  2. AST 操作:解析后生成抽象语法树(AST),可以方便地进行代码分析和转换
  3. 支持 Solidity 和 Yul:专门针对这两种智能合约语言进行了优化
  4. 错误处理:提供详细的解析错误信息

技术细节

该库是从 Rust 编译器的 rustc_lexerrustc_parse 模块修改而来,保留了 Rust 编译器的高效特性,同时针对 Solidity 和 Yul 语言的特点进行了专门调整。


1 回复

Rust源代码解析库solar-parse使用指南

概述

solar-parse是一个高效的Rust源代码解析库,提供语法分析和抽象语法树(AST)操作功能。它专为需要处理Rust代码的工具(如linter、格式化工具、代码生成器等)设计,具有高性能和易用性的特点。

主要特性

  • 完整的Rust语法解析支持
  • 高效的解析性能
  • 易于遍历和操作的AST结构
  • 源代码位置信息保留
  • 错误恢复能力

安装

在Cargo.toml中添加依赖:

[dependencies]
solar-parse = "0.4"

基本使用方法

解析Rust代码

use solar_parse::{parse_source, SyntaxTree};

fn main() {
    let code = r#"
        fn main() {
            println!("Hello, world!");
        }
    "#;
    
    let syntax_tree = parse_source(code).expect("Failed to parse code");
    
    // 输出整个语法树
    println!("{:#?}", syntax_tree);
}

遍历AST节点

use solar_parse::{parse_source, visit::Visitor, SyntaxKind};

struct MyVisitor;

impl Visitor for MyVisitor {
    fn visit_node(&mut self, node: &solar_parse::SyntaxNode) {
        if node.kind() == SyntaxKind::FnDef {
            println!("Found function definition at {:?}", node.text_range());
        }
    }
}

fn main() {
    let code = r#"
        fn foo() {}
        fn bar() {}
    "#;
    
    let syntax_tree = parse_source(code).unwrap();
    let mut visitor = MyVisitor;
    syntax_tree.walk(&mut visitor);
}

修改AST

use solar_parse::{parse_source, edit::SyntaxRewriter};

fn main() {
    let code = "fn foo() { let x = 1; }";
    let syntax_tree = parse_source(code).unwrap();
    
    let mut rewriter = SyntaxRewriter::default();
    rewriter.set_rewrite_fn(SyntaxKind::IntLiteral, |node| {
        if node.text() == "1" {
            Some("42".to_string())
        } else {
            None
        }
    });
    
    let new_tree = rewriter.rewrite(&syntax_tree);
    println!("Modified code: {}", new_tree.to_string());
}
// 输出: fn foo() { let x = 42; }

高级用法

错误处理

use solar_parse::{parse_source, ParseError};

fn main() {
    let code = "fn foo() {"; // 不完整的代码
    
    match parse_source(code) {
        Ok(tree) => println!("Parsed successfully"),
        Err(ParseError::IncompleteInput) => eprintln!("Error: Incomplete input"),
        Err(e) => eprintln!("Parse error: {}", e),
    }
}

提取特定语法结构

use solar_parse::{parse_source, SyntaxKind};

fn extract_function_names(code: &str) -> Vec<String> {
    let syntax_tree = parse_source(code).unwrap();
    let mut names = Vec::new();
    
    for node in syntax_tree.descendants() {
        if node.kind() == SyntaxKind::FnDef {
            if let Some(name_node) = node.children().find(|n| n.kind() == SyntaxKind::Ident) {
                names.push(name_node.text().to_string());
            }
        }
    }
    
    names
}

fn main() {
    let code = r#"
        fn foo() {}
        fn bar() {}
    "#;
    
    let names = extract_function_names(code);
    println!("Function names: {:?}", names); // 输出: ["foo", "bar"]
}

性能提示

  1. 对于大型代码库,考虑增量解析
  2. 重用Parser实例来解析多个文件
  3. 只遍历你需要的AST部分

完整示例

以下是一个结合了多个功能的完整示例,展示如何使用solar-parse进行代码解析、遍历、修改和分析:

use solar_parse::{
    parse_source, 
    visit::Visitor, 
    SyntaxKind,
    edit::SyntaxRewriter
};

// 自定义访问器,用于统计函数和变量
struct StatsVisitor {
    function_count: usize,
    variable_count: usize,
}

impl Visitor for StatsVisitor {
    fn visit_node(&mut self, node: &solar_parse::SyntaxNode) {
        match node.kind() {
            SyntaxKind::FnDef => {
                self.function_count += 1;
                println!("Found function: {:?}", node.text_range());
            }
            SyntaxKind::LetStmt => {
                self.variable_count += 1;
                println!("Found variable declaration: {:?}", node.text_range());
            }
            _ => {}
        }
    }
}

fn main() {
    // 示例Rust代码
    let code = r#"
        fn main() {
            let x = 1;
            let y = 2;
            
            fn helper() {
                let z = 3;
            }
        }
    "#;
    
    // 1. 解析代码
    let syntax_tree = parse_source(code).expect("Failed to parse code");
    
    // 2. 使用访问器遍历AST
    let mut visitor = StatsVisitor {
        function_count: 0,
        variable_count: 0,
    };
    syntax_tree.walk(&mut visitor);
    
    println!("Total functions: {}", visitor.function_count);
    println!("Total variables: {}", visitor.variable_count);
    
    // 3. 修改AST - 将所有数字字面量乘以2
    let mut rewriter = SyntaxRewriter::default();
    rewriter.set_rewrite_fn(SyntaxKind::IntLiteral, |node| {
        if let Ok(value) = node.text().parse::<i32>() {
            Some((value * 2).to_string())
        } else {
            None
        }
    });
    
    let modified_tree = rewriter.rewrite(&syntax_tree);
    println!("Modified code:\n{}", modified_tree.to_string());
    
    // 4. 提取函数名
    let function_names = syntax_tree.descendants()
        .filter(|n| n.kind() == SyntaxKind::FnDef)
        .filter_map(|n| {
            n.children()
                .find(|n| n.kind() == SyntaxKind::Ident)
                .map(|n| n.text().to_string())
        })
        .collect::<Vec<_>>();
    
    println!("Function names: {:?}", function_names);
}

这个完整示例展示了:

  1. 使用parse_source解析Rust代码
  2. 实现自定义访问器Visitor来统计函数和变量数量
  3. 使用SyntaxRewriter修改AST节点
  4. 遍历AST提取特定信息(函数名)

输出结果将显示:

  • 找到的函数和变量数量
  • 修改后的代码(所有数字乘以2)
  • 提取的函数名列表

solar-parse为Rust代码分析提供了强大的基础,适用于构建各种开发工具和静态分析器。

回到顶部