diff --git a/hornbeam_grammar/src/ast.rs b/hornbeam_grammar/src/ast.rs index 6e06b66..3f3269c 100644 --- a/hornbeam_grammar/src/ast.rs +++ b/hornbeam_grammar/src/ast.rs @@ -150,6 +150,14 @@ pub enum Expression { left: Box, right: Box, }, + LessThan { + left: Box, + right: Box, + }, + LessThanOrEquals { + left: Box, + right: Box, + }, // Other Operators ListAdd { diff --git a/hornbeam_grammar/src/hornbeam.pest b/hornbeam_grammar/src/hornbeam.pest index 40750e9..ee171c7 100644 --- a/hornbeam_grammar/src/hornbeam.pest +++ b/hornbeam_grammar/src/hornbeam.pest @@ -152,7 +152,7 @@ wshack = _{ (wsnc | (comment ~ &(ws* ~ Expr)))* } Expr = { prefix* ~ ws* ~ Term ~ ws* ~ postfix* ~ (ws* ~ infix ~ ws* ~ prefix* ~ ws* ~ Term ~ wshack ~ postfix*)* } // INFIX -infix = _{ add | sub | mul | div | pow | modulo | listAdd | equals | band | bor } +infix = _{ add | sub | mul | div | pow | modulo | listAdd | equals | notEquals | greaterThanOrEqual | lessThanOrEqual | greaterThan | lessThan | band | bor } add = { "+" } sub = { "-" } mul = { "*" } @@ -161,6 +161,11 @@ pow = { "^" } modulo = { "%" } listAdd = { "++" } equals = { "==" } +notEquals = { "!=" } +greaterThan = { ">" } +lessThan = { "<" } +greaterThanOrEqual = { ">=" } +lessThanOrEqual = { "<=" } // BUG: these should have forced whitespace at the start! // (lookbehind wouldn't be the worst feature in the world for a parser grammar!) diff --git a/hornbeam_grammar/src/parser.rs b/hornbeam_grammar/src/parser.rs index 63255a8..1e0f3b9 100644 --- a/hornbeam_grammar/src/parser.rs +++ b/hornbeam_grammar/src/parser.rs @@ -42,7 +42,12 @@ fn error(msg: &str, span: Span) -> PCError { lazy_static! { static ref PRATT_PARSER: PrattParser = PrattParser::new() .op(Op::infix(Rule::band, Assoc::Left) | Op::infix(Rule::bor, Assoc::Left)) - .op(Op::infix(Rule::equals, Assoc::Left)) + .op(Op::infix(Rule::equals, Assoc::Left) + | Op::infix(Rule::notEquals, Assoc::Left) + | Op::infix(Rule::lessThan, Assoc::Left) + | Op::infix(Rule::greaterThan, Assoc::Left) + | Op::infix(Rule::greaterThanOrEqual, Assoc::Left) + | Op::infix(Rule::lessThanOrEqual, Assoc::Left)) .op(Op::infix(Rule::add, Assoc::Left) | Op::infix(Rule::sub, Assoc::Left)) .op(Op::infix(Rule::mul, Assoc::Left) | Op::infix(Rule::div, Assoc::Left)) .op(Op::infix(Rule::pow, Assoc::Right)) @@ -294,6 +299,11 @@ impl HornbeamParser { Rule::mul => Expression::Mul { left: Box::new(lhs?), right: Box::new(rhs?) }, Rule::div => Expression::Div { left: Box::new(lhs?), right: Box::new(rhs?) }, Rule::equals => Expression::Equals { left: Box::new(lhs?), right: Box::new(rhs?) }, + Rule::notEquals => Expression::BNot { sub: Box::new(Expression::Equals { left: Box::new(lhs?), right: Box::new(rhs?) }) }, + Rule::lessThan => Expression::LessThan { left: Box::new(lhs?), right: Box::new(rhs?) }, + Rule::lessThanOrEqual => Expression::LessThanOrEquals { left: Box::new(lhs?), right: Box::new(rhs?) }, + Rule::greaterThan => Expression::BNot { sub: Box::new(Expression::LessThanOrEquals { left: Box::new(lhs?), right: Box::new(rhs?) }) }, + Rule::greaterThanOrEqual => Expression::BNot { sub: Box::new(Expression::LessThan { left: Box::new(lhs?), right: Box::new(rhs?) }) }, Rule::bor => Expression::BOr { left: Box::new(lhs?), right: Box::new(rhs?) }, Rule::band => Expression::BAnd { left: Box::new(lhs?), right: Box::new(rhs?) }, other => unimplemented!("unimp infix {other:?}!"), diff --git a/hornbeam_interpreter/src/engine.rs b/hornbeam_interpreter/src/engine.rs index e64f640..6b93e38 100644 --- a/hornbeam_interpreter/src/engine.rs +++ b/hornbeam_interpreter/src/engine.rs @@ -618,6 +618,34 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret }), } } + Expression::LessThan { left, right } => { + let lval = self.evaluate_expression(scope_idx, &left, loc)?; + let rval = self.evaluate_expression(scope_idx, &right, loc)?; + + match (lval, rval) { + (Value::Int(lint), Value::Int(rint)) => Ok(Value::Bool(lint < rint)), + (Value::Str(lstr), Value::Str(rstr)) => Ok(Value::Bool(lstr < rstr)), + (lother, rother) => Err(InterpreterError::TypeError { + context: "LessThan".to_string(), + conflict: format!("can't test {lother:?} < {rother:?}!"), + location: loc.clone(), + }), + } + } + Expression::LessThanOrEquals { left, right } => { + let lval = self.evaluate_expression(scope_idx, &left, loc)?; + let rval = self.evaluate_expression(scope_idx, &right, loc)?; + + match (lval, rval) { + (Value::Int(lint), Value::Int(rint)) => Ok(Value::Bool(lint <= rint)), + (Value::Str(lstr), Value::Str(rstr)) => Ok(Value::Bool(lstr <= rstr)), + (lother, rother) => Err(InterpreterError::TypeError { + context: "LessThanOrEquals".to_string(), + conflict: format!("can't test {lother:?} <= {rother:?}!"), + location: loc.clone(), + }), + } + } Expression::ListAdd { left, right } => { let lval = self.evaluate_expression(scope_idx, &left, loc)?; let rval = self.evaluate_expression(scope_idx, &right, loc)?;