Cesar Rodas 10 mesiacov pred
rodič
commit
696bf760f7

+ 17 - 2
utxo/src/filter_expr/expr.pest

@@ -14,10 +14,25 @@ not_expr     = { (^"NOT" | "!") ~ logical_term }
 comparison   = { sum ~ (comp_op ~ sum)? }
 sum          = { product ~ (add_op ~ product)* }
 product      = { factor ~ (mul_op ~ factor)* }
-factor       = { number | variable | "(" ~ expr ~ ")" }
+factor       = { number | string | variable | "(" ~ expr ~ ")" }
 comp_op      = { "=" | "!=" | "<" | "<=" | ">" | ">=" }
 add_op       = { "+" | "-" }
 mul_op       = { "*" | "/" }
+
+// string
+string = ${ quote ~ inner_str ~ quote }
+quote = { "\"" }
+inner_str = @{ (!("\"" | "\\") ~ ANY)* ~ (escape ~ inner_str)? }
+escape = @{ "\\" ~ ("\"" | "\\" | "r" | "n" | "t" | "0" | "'" | code ) }
+code = @{ "x" ~ hex_digit{2} }
+hex_digit = @{ '0'..'9' | 'a'..'f' | 'A'..'F' }
+
+
+// variable
 variable     = ${ "$" ~ ident ~ (^"." ~ ident)* }
-ident        = @{ASCII_ALPHANUMERIC+}
+ident        = @{  ("_" | alpha) ~ ("_" | alpha_num)* }
+alpha        = _{ 'a'..'z' | 'A'..'Z' }
+alpha_num    = _{ alpha | '0'..'9' }
+
+// number
 number       = @{ "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }

+ 63 - 2
utxo/src/filter_expr/parser.rs

@@ -1,7 +1,7 @@
 use std::str::FromStr;
 
 // src/main.rs
-use pest::{Parser, Span};
+use pest::{error::Error, Parser, Span};
 use pest_derive::Parser;
 
 #[derive(Parser)]
@@ -73,6 +73,7 @@ enum Expr {
         right: Box<Expr>,
     },
     Variable(Vec<String>),
+    String(String),
     Ident(String),
     Number(i128),
 }
@@ -84,6 +85,54 @@ pub struct Query {
     order_by_clause: Option<(Expr, Order)>,
 }
 
+/// Borrowed from https://github.com/pest-parser/pest/blob/master/meta/src/parser.rs#L687C2-L741C2
+fn unescape(string: &str) -> Option<String> {
+    let mut result = String::new();
+    let mut chars = string.chars();
+
+    loop {
+        match chars.next() {
+            Some('\\') => match chars.next()? {
+                '"' => result.push('"'),
+                '\\' => result.push('\\'),
+                'r' => result.push('\r'),
+                'n' => result.push('\n'),
+                't' => result.push('\t'),
+                '0' => result.push('\0'),
+                '\'' => result.push('\''),
+                'x' => {
+                    let string: String = chars.clone().take(2).collect();
+                    if string.len() != 2 {
+                        return None;
+                    }
+                    for _ in 0..string.len() {
+                        chars.next()?;
+                    }
+                    let value = u8::from_str_radix(&string, 16).ok()?;
+                    result.push(char::from(value));
+                }
+                'u' => {
+                    if chars.next()? != '{' {
+                        return None;
+                    }
+                    let string: String = chars.clone().take_while(|c| *c != '}').collect();
+                    if string.len() < 2 || 6 < string.len() {
+                        return None;
+                    }
+                    for _ in 0..string.len() + 1 {
+                        chars.next()?;
+                    }
+                    let value = u32::from_str_radix(&string, 16).ok()?;
+                    result.push(char::from_u32(value)?);
+                }
+                _ => return None,
+            },
+            Some(c) => result.push(c),
+            None => return Some(result),
+        };
+    }
+}
+
 fn parse_expr(pair: pest::iterators::Pair<Rule>) -> Expr {
     match pair.as_rule() {
         Rule::logical_expr
@@ -117,6 +166,18 @@ fn parse_expr(pair: pest::iterators::Pair<Rule>) -> Expr {
 
             last_expr.unwrap()
         }
+        Rule::string => {
+            let mut inner = pair.into_inner();
+            let _ = inner.next();
+
+            Expr::String(
+                inner
+                    .next()
+                    .map(|x| unescape(x.as_str()))
+                    .flatten()
+                    .expect("invalid escape"),
+            )
+        }
         Rule::not_expr => {
             let mut inner = pair.into_inner();
             Expr::Not(Box::new(parse_expr(inner.next().unwrap())))
@@ -138,7 +199,7 @@ fn parse_expr(pair: pest::iterators::Pair<Rule>) -> Expr {
 }
 
 pub fn parse_query(query: &str) -> Query {
-    let pairs = QueryParser::parse(Rule::query, query).unwrap();
+    let pairs = QueryParser::parse(Rule::query, query).expect("parsing");
 
     let mut where_clause = None;
     let mut limit_clause = None;

+ 2 - 3
utxo/src/filter_expr/program.rs

@@ -43,10 +43,9 @@ mod test {
             r#"
             WHERE
                 $foo = 3
-                AND $bar
+                AND $bar = "bar"
                 AND $foo = 1 + 2 + 3 +  ((1+ 2-3*4-5) * $bar.tx.lol)
-            LIMIT 10
-            ORDER BY $foo DESC
+            ORDER BY $bar DESC
         "#,
         );
     }