diff --git a/src/ast.rs b/src/ast.rs index c3e64015..eb71f5fa 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,4 +1,3 @@ -use std::iter; use pest::iterators::{Pair, Pairs}; use pest::Parser as PestParser; use pest::prec_climber::{Assoc, PrecClimber, Operator}; @@ -38,7 +37,83 @@ pub enum Expr<'a> { Const(Value<'a>), } -fn parse_expr_infix<'a>(_lhs: Expr<'a>, _op: Pair, _rhs: Expr<'a>) -> Expr<'a> { +fn parse_expr_infix<'a>(lhs: Result>, op: Pair, rhs: Result>) -> Result> { + 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!() } @@ -48,7 +123,7 @@ fn parse_int(s: &str, radix: u32) -> i64 { } #[inline] -fn parse_quoted_string(pairs: Pairs) -> String { +fn parse_quoted_string(pairs: Pairs) -> Result { let mut ret = String::new(); for pair in pairs { let s = pair.as_str(); @@ -63,18 +138,21 @@ fn parse_quoted_string(pairs: Pairs) -> String { r"\t" => ret.push('\t'), s if s.starts_with(r"\u") => { let code = parse_int(s, 16) as u32; - let ch = char::from_u32(code).unwrap_or('\u{FFFD}'); - ret.push(ch); + let ch = char::from_u32(code); + match ch { + Some(c) => ret.push(c), + None => panic!() + } } s => ret.push_str(s) } } - ret + Ok(ret) } #[inline] -fn parse_s_quoted_string(pairs: Pairs) -> String { +fn parse_s_quoted_string(pairs: Pairs) -> Result { let mut ret = String::new(); for pair in pairs { let s = pair.as_str(); @@ -89,29 +167,32 @@ fn parse_s_quoted_string(pairs: Pairs) -> String { r"\t" => ret.push('\t'), s if s.starts_with(r"\u") => { let code = parse_int(s, 16) as u32; - let ch = char::from_u32(code).unwrap_or('\u{FFFD}'); - ret.push(ch); + let ch = char::from_u32(code); + match ch { + Some(c) => ret.push(c), + None => panic!() + } } s => ret.push_str(s) } } - ret + Ok(ret) } -fn parse_expr_primary(pair: Pair) -> Expr { +fn parse_expr_primary(pair: Pair) -> Result { match pair.as_rule() { Rule::expr => 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::().unwrap())), - Rule::hex_pos_int => Const(Value::Int(parse_int(pair.as_str(), 16))), - Rule::octo_pos_int => Const(Value::Int(parse_int(pair.as_str(), 8))), - Rule::bin_pos_int => Const(Value::Int(parse_int(pair.as_str(), 2))), - Rule::dot_float | Rule::sci_float => Const(Value::Float(pair.as_str().replace('_', "").parse::().unwrap())), - Rule::null => Const(Value::Null), - Rule::boolean => 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::s_quoted_string => Const(Value::OwnString(Box::new(parse_s_quoted_string(pair.into_inner().next().unwrap().into_inner())))), + Rule::pos_int => Ok(Const(Value::Int(pair.as_str().replace('_', "").parse::()?))), + Rule::hex_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 16)))), + Rule::octo_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 8)))), + Rule::bin_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 2)))), + Rule::dot_float | Rule::sci_float => Ok(Const(Value::Float(pair.as_str().replace('_', "").parse::()?))), + Rule::null => Ok(Const(Value::Null)), + Rule::boolean => Ok(Const(Value::Bool(pair.as_str() == "true"))), + Rule::quoted_string => Ok(Const(Value::OwnString(Box::new(parse_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); unimplemented!() @@ -119,13 +200,13 @@ fn parse_expr_primary(pair: Pair) -> Expr { } } -fn parse_expr(pair: Pair) -> Expr { - PREC_CLIMBER.climb(iter::once(pair), parse_expr_primary, parse_expr_infix) +fn parse_expr(pair: Pair) -> Result { + PREC_CLIMBER.climb(pair.into_inner(), parse_expr_primary, parse_expr_infix) } pub fn parse_expr_from_str(inp: &str) -> Result { let expr_tree = Parser::parse(Rule::expr, inp)?.next().unwrap(); - Ok(parse_expr(expr_tree)) + parse_expr(expr_tree) } #[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(r##""x""##))); } + + #[test] + fn operators() { + println!("{:#?}", parse_expr_from_str("1/10+2+3*4").unwrap()); + } } \ No newline at end of file