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