3个版本
| 新 0.1.2 | 2024年8月16日 |
|---|---|
| 0.1.1 | 2024年2月10日 |
| 0.1.0 | 2024年2月10日 |
#994 in 解析器实现
每月150次下载
67KB
2K SLoC
fexpr 
用Rust重写Go fexpr
fexpr是一个过滤器查询语言解析器,它生成易于工作的AST结构,以便您可以从用户输入安全地创建SQL、Elasticsearch等查询。
换句话说,将字符串"id > 1"转换为结构体[{&& {{identifier id} > {number 1}}}]。
支持括号和各种条件表达式运算符(见语法)。
示例用法
cargo add fexpr
fn main() {
let result = fexpr::parse("id=123 && status='active'");
if let Ok(result) = result {
println!("{}", result)
}
}
// Output:
// [{&& {{identifier id} = {number 123}}} {&& {{identifier status} = {text active}}}]
注意,每个解析的表达式语句都包含一个连接/并集运算符(
&&或||),以便可以在小段上消耗结果,而无需依赖于分组/嵌套上下文。
语法
fexpr语法类似于SQL的WHERE表达式语法。它识别几种标记类型(标识符、数字、引号文本、表达式运算符、空格等)。
您可以在
scanner.rs中找到所有支持的标记。
运算符
=等于运算符(例如a=b)!=不等于运算符(例如a!=b)>大于运算符(例如a>b)>=大于或等于运算符(例如a>=b)<小于或等于运算符(例如:a<b)<=小于或等于运算符(例如:a<=b)~类似/包含运算符(例如:a~b)!~非 类似/包含运算符(例如:a!~b)?=数组/任意等于运算符(例如:a?=b)?!=数组/任意不等于运算符(例如:a?!=b)?>数组/任意大于运算符(例如:a?>b)?>=数组/任意大于等于运算符(例如:a?>=b)?<数组/任意小于运算符(例如:a?<b)?<=数组/任意小于等于运算符(例如:a?<=b)?~数组/任意 类似/包含运算符(例如:a?~b)?!~数组/任意 非 类似/包含运算符(例如:a?!~b)&&AND 连接运算符(例如:a=b && c=d)||OR 连接运算符(例如:a=b || c=d)()括号(例如:(a=1 && b=2) || (a=3 && b=4))
数字
数字标记可以是任何整数或小数。
示例:123,10.50,-14。
标识符
标识符标记是以下字符开头的字面量:字母、_、@ 或 #,并且可以包含任意数量的字母、数字、.(通常用作分隔符)或 :(通常用作修饰符)字符。
示例: id、a.b.c、field123、@request.method、author.name:length。
引文文本
文本标记是任何被 ' 或 " 引号包裹的字面量。
示例: 'Lorem ipsum dolor 123!'、"escaped \"word\""、"mixed 'quotes' are fine"。
注释
注释标记是任何以 // 开头的单行文本字面量。与空白符类似,注释会被 fexpr::parse() 忽略。
示例: // test。
仅使用扫描器
标记化器(又称 fexpr::Scanner)可以在没有解析器状态机的情况下使用,这样您就可以编写自己的自定义标记处理程序。
use std::io::BufReader;
fn main() {
let s = fexpr::Scanner::new(BufReader::new("id > 123".as_bytes()));
if let Ok(mut s) = s {
loop {
let t = s.scan();
if let Err(_) = t {
break;
}
if let Ok(t) = t {
if matches!(t, fexpr::Token::Eof(_)) {
break;
}
println!("{t}")
}
}
}
}
// Output:
// {identifier id}
// {whitespace }
// {sign >}
// {whitespace }
// {number 123}
依赖项
~2.1–3MB
~53K SLoC