infix evaluation

main
Ziyang Hu 2 years ago
parent f220bf13c7
commit fcfff45123

@ -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<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!()
}
@ -48,7 +123,7 @@ fn parse_int(s: &str, radix: u32) -> i64 {
}
#[inline]
fn parse_quoted_string(pairs: Pairs<Rule>) -> String {
fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
let mut ret = String::new();
for pair in pairs {
let s = pair.as_str();
@ -63,18 +138,21 @@ fn parse_quoted_string(pairs: Pairs<Rule>) -> 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<Rule>) -> String {
fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
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<Rule>) -> 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<Rule>) -> Expr {
fn parse_expr_primary(pair: Pair<Rule>) -> Result<Expr> {
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::<i64>().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::<f64>().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::<i64>()?))),
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::<f64>()?))),
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<Rule>) -> Expr {
}
}
fn parse_expr(pair: Pair<Rule>) -> Expr {
PREC_CLIMBER.climb(iter::once(pair), parse_expr_primary, parse_expr_infix)
fn parse_expr(pair: Pair<Rule>) -> Result<Expr> {
PREC_CLIMBER.climb(pair.into_inner(), parse_expr_primary, parse_expr_infix)
}
pub fn parse_expr_from_str(inp: &str) -> Result<Expr> {
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());
}
}
Loading…
Cancel
Save