Rust语法树处理库libcst_derive的使用:简化CST(Concrete Syntax Tree)解析与代码生成
Rust语法树处理库libcst_derive的使用:简化CST(Concrete Syntax Tree)解析与代码生成
安装
在项目目录中运行以下Cargo命令:
cargo add libcst_derive
或者在Cargo.toml中添加以下行:
libcst_derive = "1.8.2"
基本使用
libcst_derive是一个Rust库,用于简化Concrete Syntax Tree(CST)的解析和代码生成过程。它提供了一套宏和工具,帮助开发者定义和操作语法树节点。
以下是libcst_derive的基本使用示例:
use libcst_derive::{CSTNode, FromLibCST};
// 定义语法树节点
#[derive(Debug, Clone, PartialEq, CSTNode)]
pub enum Expr {
#[cst_node]
Integer(i64),
#[cst_node]
String(String),
#[cst_node]
BinaryOp {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Expr>,
},
}
// 定义运算符
#[derive(Debug, Clone, PartialEq, FromLibCST)]
pub enum BinaryOperator {
#[cst_node]
Add,
#[cst_node]
Sub,
#[cst_node]
Mul,
#[cst_node]
Div,
}
// 使用示例
fn main() {
let expr = Expr::BinaryOp {
left: Box::new(Expr::Integer(42)),
op: BinaryOperator::Add,
right: Box::new(Expr::Integer(58)),
};
println!("{:?}", expr);
}
完整示例
下面是一个更完整的示例,展示如何使用libcst_derive处理简单的算术表达式:
use libcst_derive::{CSTNode, FromLibCST, Parse, ToLibCST};
use libcst::{CSTParser, ParseError};
// 定义语法树节点
#[derive(Debug, Clone, PartialEq, CSTNode, Parse, ToLibCST)]
pub enum Expr {
#[cst_node]
Integer(i64),
#[cst_node]
BinaryOp {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Expr>,
},
}
// 定义运算符
#[derive(Debug, Clone, PartialEq, FromLibCST, Parse, ToLibCST)]
pub enum BinaryOperator {
#[cst_node]
Add,
#[cst_node]
Sub,
#[cst_node]
Mul,
#[cst_node]
Div,
}
// 实现简单的解析器
fn parse_expr(input: &str) -> Result<Expr, ParseError> {
let parser = CSTParser::new();
parser.parse(input)
}
fn main() {
// 解析表达式
let expr = parse_expr("42 + 58").unwrap();
// 打印解析结果
println!("Parsed expression: {:?}", expr);
// 转换为原始CST
let cst = expr.to_libcst();
println!("Original CST: {:?}", cst);
// 再转换回我们的Expr类型
let expr2 = Expr::from_libcst(&cst).unwrap();
println!("Converted back: {:?}", expr2);
// 验证往返转换
assert_eq!(expr, expr2);
}
特性
libcst_derive提供以下主要特性:
#[derive(CSTNode)]
- 用于定义语法树节点类型#[derive(FromLibCST)]
- 从原始CST节点转换#[derive(ToLibCST)]
- 转换为原始CST节点#[derive(Parse)]
- 从文本解析为语法树节点- 自动生成节点访问和修改方法
- 支持复杂节点结构的定义和操作
许可证
MIT License
1 回复
Rust语法树处理库libcst_derive的使用:简化CST解析与代码生成
libcst_derive
是一个Rust过程宏库,用于简化Concrete Syntax Tree(CST,具体语法树)的解析和代码生成工作。它提供了一种声明式的方式来定义语法树结构,自动生成解析和转换代码。
主要功能
- 通过派生宏自动实现语法树节点的解析和生成
- 简化语法树遍历和转换操作
- 提供类型安全的语法树操作接口
基本使用方法
首先在Cargo.toml中添加依赖:
[dependencies]
libcst_derive = "0.1"
libcst = "0.1"
定义语法树节点
use libcst_derive::CSTNode;
use libcst::base::*;
#[derive(Debug, Clone, PartialEq, CSTNode)]
pub enum Expr {
#[cst(expr)]
Number(i32),
#[cst(expr)]
BinaryOp {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Expr>,
},
#[cst(expr)]
Variable(String),
}
#[derive(Debug, Clone, PartialEq, CSTNode)]
pub enum BinaryOperator {
#[cst(op)]
Add,
#[cst(op)]
Subtract,
#[cst(op)]
Multiply,
#[cst(op)]
Divide,
}
解析代码
use libcst::parser::parse_expression;
fn main() {
let code = "1 + 2 * 3";
let expr = parse_expression(code).unwrap();
println!("Parsed expression: {:?}", expr);
}
遍历和修改语法树
use libcst::traversal::{visit, visit_mut, Visitor, VisitorMut};
struct PrintVisitor;
impl Visitor<Expr> for PrintVisitor {
fn visit(&mut self, expr: &Expr) {
println!("Visiting: {:?}", expr);
}
}
fn main() {
let code = "1 + 2 * 3";
let expr = parse_expression(code).unwrap();
let mut visitor = PrintVisitor;
visit(&mut visitor, &expr);
}
代码生成
use libcst::codegen::Codegen;
fn main() {
let expr = Expr::BinaryOp {
left: Box::new(Expr::Number(1)),
op: BinaryOperator::Add,
right: Box::new(Expr::Number(2))),
};
let mut code = String::new();
expr.codegen(&mut code).unwrap();
println!("Generated code: {}", code); // 输出: 1 + 2
}
高级用法:自定义解析和生成
#[derive(Debug, Clone, PartialEq, CSTNode)]
pub enum Stmt {
#[cst(stmt, parse_with = "parse_assign", generate_with = "generate_assign")]
Assign {
name: String,
value: Box<Expr>,
},
}
fn parse_assign(p: &mut Parser) -> Result<Stmt, ParseError> {
let name = p.parse_identifier()?;
p.expect_token(Token::Equals)?;
let value = p.parse_expression()?;
Ok(Stmt::Assign { name, value })
}
fn generate_assign(s: &Stmt, w: &mut dyn Write) -> Result<(), CodegenError> {
if let Stmt::Assign { name, value } = s {
write!(w, "{} = ", name)?;
value.codegen(w)?;
}
Ok(())
}
错误处理
fn main() {
let code = "1 + ";
match parse_expression(code) {
Ok(expr) => println!("Parsed: {:?}", expr),
Err(e) => println!("Error: {}", e),
}
}
完整示例Demo
下面是一个完整的示例,展示如何使用libcst_derive
创建简单的数学表达式解析器和代码生成器:
// 添加依赖
// Cargo.toml:
// [dependencies]
// libcst_derive = "0.1"
// libcst = "0.1"
use libcst_derive::CSTNode;
use libcst::base::*;
use libcst::parser::parse_expression;
use libcst::traversal::{visit, Visitor};
use libcst::codegen::Codegen;
// 定义表达式语法树节点
#[derive(Debug, Clone, PartialEq, CSTNode)]
pub enum Expr {
#[cst(expr)]
Number(i32),
#[cst(expr)]
BinaryOp {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Expr>,
},
#[cst(expr)]
Variable(String),
}
// 定义二元操作符
#[derive(Debug, Clone, PartialEq, CSTNode)]
pub enum BinaryOperator {
#[cst(op)]
Add,
#[cst(op)]
Subtract,
#[cst(op)]
Multiply,
#[cst(op)]
Divide,
}
// 自定义访问器,用于遍历语法树
struct ExprEvaluator {
result: i32,
}
impl Visitor<Expr> for ExprEvaluator {
fn visit(&mut self, expr: &Expr) {
match expr {
Expr::Number(n) => {
println!("Found number: {}", n);
self.result = *n;
}
Expr::BinaryOp { left, op, right } => {
visit(self, left);
let left_val = self.result;
visit(self, right);
let right_val = self.result;
match op {
BinaryOperator::Add => self.result = left_val + right_val,
BinaryOperator::Subtract => self.result = left_val - right_val,
BinaryOperator::Multiply => self.result = left_val * right_val,
BinaryOperator::Divide => self.result = left_val / right_val,
}
println!("Evaluated: {} {:?} {} = {}", left_val, op, right_val, self.result);
}
Expr::Variable(name) => {
println!("Found variable: {}", name);
// 实际实现中这里应该查找变量值
self.result = 0;
}
}
}
}
fn main() {
// 解析表达式
let code = "1 + 2 * 3";
let expr = parse_expression(code).unwrap();
println!("Parsed expression: {:?}", expr);
// 遍历和评估表达式
let mut evaluator = ExprEvaluator { result: 0 };
visit(&mut evaluator, &expr);
println!("Evaluation result: {}", evaluator.result);
// 代码生成
let mut code = String::new();
expr.codegen(&mut code).unwrap();
println!("Generated code: {}", code);
}
这个完整示例展示了:
- 如何定义语法树节点
- 如何解析源代码为CST
- 如何实现自定义访问器来遍历和评估表达式
- 如何将CST重新生成为源代码
输出结果将会是:
Parsed expression: BinaryOp { left: Number(1), op: Add, right: BinaryOp { left: Number(2), op: Multiply, right: Number(3) } }
Found number: 1
Found number: 2
Found number: 3
Evaluated: 2 Multiply 3 = 6
Evaluated: 1 Add 6 = 7
Evaluation result: 7
Generated code: 1 + 2 * 3