Rust语法树生成库tree-sitter-generate的使用,高效解析与生成编程语言语法树
Tree-sitter Generate
这个辅助crate实现了tree-sitter generate
命令的逻辑,可以用于外部工具从语法文件生成解析器。
安装
在项目目录中运行以下Cargo命令:
cargo add tree-sitter-generate
或者在Cargo.toml中添加以下行:
tree-sitter-generate = "0.25.8"
使用示例
下面是一个使用tree-sitter-generate生成语法解析器的完整示例:
use std::path::PathBuf;
use tree_sitter_generate::generate;
fn main() {
// 定义语法文件路径和输出目录
let grammar_path = PathBuf::from("path/to/your/grammar.js");
let output_dir = PathBuf::from("path/to/output/directory");
// 生成解析器
if let Err(e) = generate(&grammar_path, &output_dir) {
eprintln!("Failed to generate parser: {}", e);
std::process::exit(1);
}
println!("Parser generated successfully!");
}
详细说明
- 首先需要准备一个语法定义文件(通常命名为
grammar.js
) - 指定输出目录,生成的解析器代码将写入该目录
- 调用
generate
函数执行生成过程
生成的解析器包含以下文件:
parser.c
- 解析器实现tree_sitter/parser.h
- 解析器头文件binding.rs
- Rust绑定代码
注意事项
- 需要安装tree-sitter CLI工具
- 语法文件需要符合tree-sitter的语法规范
- 生成过程可能需要C编译器和其他构建依赖
完整示例
下面是一个更完整的示例,展示了如何在实际项目中生成和使用tree-sitter解析器:
use std::path::PathBuf;
use std::fs;
use tree_sitter_generate::generate;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 准备语法文件和输出路径
let grammar_path = PathBuf::from("examples/my-grammar.js");
let output_dir = PathBuf::from("src/generated");
// 2. 确保输出目录存在
fs::create_dir_all(&output_dir)?;
// 3. 生成解析器
generate(&grammar_path, &output_dir)?;
// 4. 打印成功信息
println!("解析器生成成功!输出目录: {}", output_dir.display());
// 5. 可以在项目中直接使用生成的解析器
// 通常需要将生成的binding.rs集成到项目中
Ok(())
}
注意事项
- 确保已安装tree-sitter CLI工具
- 语法文件需要符合tree-sitter的语法规范
- 生成过程需要C编译器和构建工具链
- 生成的Rust绑定代码可能需要手动集成到项目中
1 回复
Rust语法树生成库tree-sitter-generate的使用:高效解析与生成编程语言语法树
以下是内容中提供的完整示例:
基本使用方法示例
1. 定义语法规则 (grammar.js)
module.exports = grammar({
name: 'my_language',
rules: {
source_file: $ => repeat($.statement),
statement: $ => seq(
$.identifier,
'=',
$.expression,
';'
),
identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/,
expression: $ => choice(
$.number,
$.identifier,
$.binary_expression
),
binary_expression: $ => prec.left(seq(
$.expression,
choice('+', '-', '*', '/'),
$.expression
)),
number: $ => /\d+/
}
});
2. Rust中使用解析器
use tree_sitter::{Parser, Language};
extern "C" { fn tree_sitter_my_language() -> Language; }
fn main() {
let language = unsafe { tree_sitter_my_language() };
let mut parser = Parser::new();
parser.set_language(language).unwrap();
let code = "x = 42 + y;";
let tree = parser.parse(code, None).unwrap();
let root_node = tree.root_node();
let mut cursor = root_node.walk();
loop {
let node = cursor.node();
println!("{}: {}", node.kind(), node.utf8_text(code.as_bytes()).unwrap());
if !cursor.goto_first_child() {
break;
}
}
}
完整示例Demo:构建一个带变量支持的增强版计算器
use tree_sitter::{Parser, Language, Node};
use std::collections::HashMap;
// 声明外部语言函数
extern "C" { fn tree_sitter_calculator() -> Language; }
fn evaluate(
node: Node,
code: &str,
variables: &mut HashMap<String, i64>
) -> Result<i64, String> {
match node.kind() {
"number" => {
node.utf8_text(code.as_bytes())
.unwrap()
.parse()
.map_err(|_| "无效数字".to_string())
},
"identifier" => {
let var_name = node.utf8_text(code.as_bytes()).unwrap();
variables.get(var_name)
.copied()
.ok_or_else(|| format!("未定义变量: {}", var_name))
},
"binary_expression" => {
let left = evaluate(node.named_child(0).unwrap(), code, variables)?;
let right = evaluate(node.named_child(1).unwrap(), code, variables)?;
let op = node.child(1).unwrap().utf8_text(code.as_bytes()).unwrap();
match op {
"+" => Ok(left + right),
"-" => Ok(left - right),
"*" => Ok(left * right),
"/" => if right != 0 {
Ok(left / right)
} else {
Err("除以零错误".to_string())
},
_ => Err("未知操作符".to_string())
}
},
"assignment" => {
let var_node = node.named_child(0).unwrap();
let var_name = var_node.utf8_text(code.as_bytes()).unwrap();
let value = evaluate(node.named_child(1).unwrap(), code, variables)?;
variables.insert(var_name.to_string(), value);
Ok(value)
},
"program" => {
let mut result = 0;
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
if child.is_named() {
result = evaluate(child, code, variables)?;
}
}
Ok(result)
},
_ => Err(format!("未知节点类型: {}", node.kind()))
}
}
fn main() {
// 获取语言定义
let language = unsafe { tree_sitter_calculator() };
let mut parser = Parser::new();
parser.set_language(language).unwrap();
// 示例代码,支持变量和多个表达式
let code = r#"
a = 5;
b = 10;
a * b - 3;
"#;
// 解析代码
let tree = parser.parse(code, None).unwrap();
// 存储变量的哈希表
let mut variables = HashMap::new();
// 计算并输出结果
match evaluate(tree.root_node(), code, &mut variables) {
Ok(result) => println!("计算结果: {}", result),
Err(e) => eprintln!("错误: {}", e),
}
}
对应的语法规则 (grammar.js)
module.exports = grammar({
name: 'calculator',
rules: {
program: $ => repeat($._statement),
_statement: $ => choice(
$.assignment,
$.expression
),
assignment: $ => seq(
$.identifier,
'=',
$.expression,
';'
),
expression: $ => choice(
$.number,
$.identifier,
$.binary_expression,
prec.left(seq('(', $.expression, ')'))
),
binary_expression: $ => prec.left(seq(
$.expression,
choice('+', '-', '*', '/'),
$.expression
)),
identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/,
number: $ => /\d+/,
comment: $ => token(seq('//', /.*/))
}
});
这个增强版计算器示例演示了:
- 支持变量声明和赋值
- 处理多个表达式
- 完善的错误处理
- 使用哈希表存储变量状态
- 支持基本算术运算和括号优先级
要使用这个示例,你需要:
- 创建 grammar.js 文件并写入上述语法规则
- 运行
tree-sitter generate
生成解析器 - 将 Rust 代码保存为 main.rs 并运行