|
@@ -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;
|