|
|
@ -1,4 +1,3 @@
|
|
|
|
use std::iter;
|
|
|
|
|
|
|
|
use pest::iterators::{Pair, Pairs};
|
|
|
|
use pest::iterators::{Pair, Pairs};
|
|
|
|
use pest::Parser as PestParser;
|
|
|
|
use pest::Parser as PestParser;
|
|
|
|
use pest::prec_climber::{Assoc, PrecClimber, Operator};
|
|
|
|
use pest::prec_climber::{Assoc, PrecClimber, Operator};
|
|
|
@ -38,7 +37,83 @@ pub enum Expr<'a> {
|
|
|
|
Const(Value<'a>),
|
|
|
|
Const(Value<'a>),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_expr_infix<'a>(_lhs: Expr<'a>, _op: Pair<Rule>, _rhs: Expr<'a>) -> Expr<'a> {
|
|
|
|
fn parse_expr_infix<'a>(lhs: Result<Expr<'a>>, op: Pair<Rule>, rhs: Result<Expr<'a>>) -> Result<Expr<'a>> {
|
|
|
|
|
|
|
|
let lhs = lhs?;
|
|
|
|
|
|
|
|
let rhs = rhs?;
|
|
|
|
|
|
|
|
if let (Const(a), Const(b)) = (lhs, rhs) {
|
|
|
|
|
|
|
|
match op.as_rule() {
|
|
|
|
|
|
|
|
Rule::op_add => {
|
|
|
|
|
|
|
|
match (a, b) {
|
|
|
|
|
|
|
|
(Value::Null, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Int(va + vb))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va + vb as f64))),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 + vb))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va + vb))),
|
|
|
|
|
|
|
|
(Value::OwnString(va), Value::OwnString(vb)) => return Ok(Const(Value::OwnString(Box::new(*va + &*vb)))),
|
|
|
|
|
|
|
|
(Value::OwnString(va), Value::RefString(vb)) => return Ok(Const(Value::OwnString(Box::new(*va + &*vb)))),
|
|
|
|
|
|
|
|
(Value::RefString(va), Value::OwnString(vb)) => return Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))),
|
|
|
|
|
|
|
|
(Value::RefString(va), Value::RefString(vb)) => return Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))),
|
|
|
|
|
|
|
|
_ => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Rule::op_sub => {
|
|
|
|
|
|
|
|
match (a, b) {
|
|
|
|
|
|
|
|
(Value::Null, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Int(va - vb))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va - vb as f64))),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 - vb))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va - vb))),
|
|
|
|
|
|
|
|
_ => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Rule::op_mul => {
|
|
|
|
|
|
|
|
match (a, b) {
|
|
|
|
|
|
|
|
(Value::Null, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Int(va * vb))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va * vb as f64))),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 * vb))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va * vb))),
|
|
|
|
|
|
|
|
_ => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Rule::op_div => {
|
|
|
|
|
|
|
|
match (a, b) {
|
|
|
|
|
|
|
|
(Value::Null, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Float(va as f64 / vb as f64))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va / vb as f64))),
|
|
|
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 / vb))),
|
|
|
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va / vb))),
|
|
|
|
|
|
|
|
_ => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Rule::op_eq => return Ok(Const(Value::Bool(a == b))),
|
|
|
|
|
|
|
|
Rule::op_ne => return Ok(Const(Value::Bool(a != b))),
|
|
|
|
|
|
|
|
Rule::op_or => {
|
|
|
|
|
|
|
|
match (a, b) {
|
|
|
|
|
|
|
|
(Value::Null, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Null, Value::Bool(b)) => return Ok(Const(Value::Bool(b))),
|
|
|
|
|
|
|
|
(Value::Bool(b), Value::Null) => return Ok(Const(Value::Bool(b))),
|
|
|
|
|
|
|
|
(Value::Bool(a), Value::Bool(b)) => return Ok(Const(Value::Bool(a || b))),
|
|
|
|
|
|
|
|
_ => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
Rule::op_and => {
|
|
|
|
|
|
|
|
match (a, b) {
|
|
|
|
|
|
|
|
(Value::Null, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Null, Value::Bool(_)) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Bool(_), Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
|
|
|
(Value::Bool(a), Value::Bool(b)) => return Ok(Const(Value::Bool(a && b))),
|
|
|
|
|
|
|
|
_ => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
Rule::op_coalesce => return Ok(if a == Value::Null { Const(b) } else { Const(a) }),
|
|
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
unimplemented!()
|
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -48,7 +123,7 @@ fn parse_int(s: &str, radix: u32) -> i64 {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
fn parse_quoted_string(pairs: Pairs<Rule>) -> String {
|
|
|
|
fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
let mut ret = String::new();
|
|
|
|
let mut ret = String::new();
|
|
|
|
for pair in pairs {
|
|
|
|
for pair in pairs {
|
|
|
|
let s = pair.as_str();
|
|
|
|
let s = pair.as_str();
|
|
|
@ -63,18 +138,21 @@ fn parse_quoted_string(pairs: Pairs<Rule>) -> String {
|
|
|
|
r"\t" => ret.push('\t'),
|
|
|
|
r"\t" => ret.push('\t'),
|
|
|
|
s if s.starts_with(r"\u") => {
|
|
|
|
s if s.starts_with(r"\u") => {
|
|
|
|
let code = parse_int(s, 16) as u32;
|
|
|
|
let code = parse_int(s, 16) as u32;
|
|
|
|
let ch = char::from_u32(code).unwrap_or('\u{FFFD}');
|
|
|
|
let ch = char::from_u32(code);
|
|
|
|
ret.push(ch);
|
|
|
|
match ch {
|
|
|
|
|
|
|
|
Some(c) => ret.push(c),
|
|
|
|
|
|
|
|
None => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s => ret.push_str(s)
|
|
|
|
s => ret.push_str(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret
|
|
|
|
Ok(ret)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
fn parse_s_quoted_string(pairs: Pairs<Rule>) -> String {
|
|
|
|
fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
let mut ret = String::new();
|
|
|
|
let mut ret = String::new();
|
|
|
|
for pair in pairs {
|
|
|
|
for pair in pairs {
|
|
|
|
let s = pair.as_str();
|
|
|
|
let s = pair.as_str();
|
|
|
@ -89,29 +167,32 @@ fn parse_s_quoted_string(pairs: Pairs<Rule>) -> String {
|
|
|
|
r"\t" => ret.push('\t'),
|
|
|
|
r"\t" => ret.push('\t'),
|
|
|
|
s if s.starts_with(r"\u") => {
|
|
|
|
s if s.starts_with(r"\u") => {
|
|
|
|
let code = parse_int(s, 16) as u32;
|
|
|
|
let code = parse_int(s, 16) as u32;
|
|
|
|
let ch = char::from_u32(code).unwrap_or('\u{FFFD}');
|
|
|
|
let ch = char::from_u32(code);
|
|
|
|
ret.push(ch);
|
|
|
|
match ch {
|
|
|
|
|
|
|
|
Some(c) => ret.push(c),
|
|
|
|
|
|
|
|
None => panic!()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s => ret.push_str(s)
|
|
|
|
s => ret.push_str(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret
|
|
|
|
Ok(ret)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_expr_primary(pair: Pair<Rule>) -> Expr {
|
|
|
|
fn parse_expr_primary(pair: Pair<Rule>) -> Result<Expr> {
|
|
|
|
match pair.as_rule() {
|
|
|
|
match pair.as_rule() {
|
|
|
|
Rule::expr => parse_expr_primary(pair.into_inner().next().unwrap()),
|
|
|
|
Rule::expr => parse_expr_primary(pair.into_inner().next().unwrap()),
|
|
|
|
Rule::term => parse_expr_primary(pair.into_inner().next().unwrap()),
|
|
|
|
Rule::term => parse_expr_primary(pair.into_inner().next().unwrap()),
|
|
|
|
|
|
|
|
|
|
|
|
Rule::pos_int => Const(Value::Int(pair.as_str().replace('_', "").parse::<i64>().unwrap())),
|
|
|
|
Rule::pos_int => Ok(Const(Value::Int(pair.as_str().replace('_', "").parse::<i64>()?))),
|
|
|
|
Rule::hex_pos_int => Const(Value::Int(parse_int(pair.as_str(), 16))),
|
|
|
|
Rule::hex_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 16)))),
|
|
|
|
Rule::octo_pos_int => Const(Value::Int(parse_int(pair.as_str(), 8))),
|
|
|
|
Rule::octo_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 8)))),
|
|
|
|
Rule::bin_pos_int => Const(Value::Int(parse_int(pair.as_str(), 2))),
|
|
|
|
Rule::bin_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 2)))),
|
|
|
|
Rule::dot_float | Rule::sci_float => Const(Value::Float(pair.as_str().replace('_', "").parse::<f64>().unwrap())),
|
|
|
|
Rule::dot_float | Rule::sci_float => Ok(Const(Value::Float(pair.as_str().replace('_', "").parse::<f64>()?))),
|
|
|
|
Rule::null => Const(Value::Null),
|
|
|
|
Rule::null => Ok(Const(Value::Null)),
|
|
|
|
Rule::boolean => Const(Value::Bool(pair.as_str() == "true")),
|
|
|
|
Rule::boolean => Ok(Const(Value::Bool(pair.as_str() == "true"))),
|
|
|
|
Rule::quoted_string => Const(Value::OwnString(Box::new(parse_quoted_string(pair.into_inner().next().unwrap().into_inner())))),
|
|
|
|
Rule::quoted_string => Ok(Const(Value::OwnString(Box::new(parse_quoted_string(pair.into_inner().next().unwrap().into_inner())?)))),
|
|
|
|
Rule::s_quoted_string => Const(Value::OwnString(Box::new(parse_s_quoted_string(pair.into_inner().next().unwrap().into_inner())))),
|
|
|
|
Rule::s_quoted_string => Ok(Const(Value::OwnString(Box::new(parse_s_quoted_string(pair.into_inner().next().unwrap().into_inner())?)))),
|
|
|
|
_ => {
|
|
|
|
_ => {
|
|
|
|
println!("{:#?}", pair);
|
|
|
|
println!("{:#?}", pair);
|
|
|
|
unimplemented!()
|
|
|
|
unimplemented!()
|
|
|
@ -119,13 +200,13 @@ fn parse_expr_primary(pair: Pair<Rule>) -> Expr {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_expr(pair: Pair<Rule>) -> Expr {
|
|
|
|
fn parse_expr(pair: Pair<Rule>) -> Result<Expr> {
|
|
|
|
PREC_CLIMBER.climb(iter::once(pair), parse_expr_primary, parse_expr_infix)
|
|
|
|
PREC_CLIMBER.climb(pair.into_inner(), parse_expr_primary, parse_expr_infix)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn parse_expr_from_str(inp: &str) -> Result<Expr> {
|
|
|
|
pub fn parse_expr_from_str(inp: &str) -> Result<Expr> {
|
|
|
|
let expr_tree = Parser::parse(Rule::expr, inp)?.next().unwrap();
|
|
|
|
let expr_tree = Parser::parse(Rule::expr, inp)?.next().unwrap();
|
|
|
|
Ok(parse_expr(expr_tree))
|
|
|
|
parse_expr(expr_tree)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
#[cfg(test)]
|
|
|
@ -153,4 +234,9 @@ mod tests {
|
|
|
|
assert_eq!(parse_expr_from_str(r#""x'""#).unwrap(), Const(Value::RefString("x'")));
|
|
|
|
assert_eq!(parse_expr_from_str(r#""x'""#).unwrap(), Const(Value::RefString("x'")));
|
|
|
|
assert_eq!(parse_expr_from_str(r#"'"x"'"#).unwrap(), Const(Value::RefString(r##""x""##)));
|
|
|
|
assert_eq!(parse_expr_from_str(r#"'"x"'"#).unwrap(), Const(Value::RefString(r##""x""##)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn operators() {
|
|
|
|
|
|
|
|
println!("{:#?}", parse_expr_from_str("1/10+2+3*4").unwrap());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|