diff --git a/src/ast.rs b/src/ast.rs index 8c6e160b..9b1a0880 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -862,6 +862,8 @@ pub enum Expr { /// Used to hold either an Array or Map literal for quick cloning. /// All other primitive data types should use the appropriate variants for better speed. DynamicConstant(Box, Position), + /// Boolean constant. + BoolConstant(bool, Position), /// Integer constant. IntegerConstant(INT, Position), /// Floating-point constant. @@ -877,10 +879,6 @@ pub enum Expr { Array(Box>, Position), /// #{ name:expr, ... } Map(Box>, Position), - /// true - True(Position), - /// false - False(Position), /// () Unit(Position), /// Variable access - (optional index, optional modules, hash, variable name) @@ -932,8 +930,7 @@ impl Expr { x.clone(), Default::default(), )))), - Self::True(_) => true.into(), - Self::False(_) => false.into(), + Self::BoolConstant(x, _) => (*x).into(), Self::Unit(_) => ().into(), #[cfg(not(feature = "no_index"))] @@ -978,6 +975,7 @@ impl Expr { Self::FloatConstant(_, pos) => *pos, Self::DynamicConstant(_, pos) => *pos, + Self::BoolConstant(_, pos) => *pos, Self::IntegerConstant(_, pos) => *pos, Self::CharConstant(_, pos) => *pos, Self::StringConstant(_, pos) => *pos, @@ -991,7 +989,7 @@ impl Expr { Self::And(x, _) | Self::Or(x, _) | Self::In(x, _) => x.lhs.position(), - Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos, + Self::Unit(pos) => *pos, Self::Dot(x, _) | Self::Index(x, _) => x.lhs.position(), @@ -1009,6 +1007,7 @@ impl Expr { Self::FloatConstant(_, pos) => *pos = new_pos, Self::DynamicConstant(_, pos) => *pos = new_pos, + Self::BoolConstant(_, pos) => *pos = new_pos, Self::IntegerConstant(_, pos) => *pos = new_pos, Self::CharConstant(_, pos) => *pos = new_pos, Self::StringConstant(_, pos) => *pos = new_pos, @@ -1020,7 +1019,7 @@ impl Expr { Self::Stmt(_, pos) => *pos = new_pos, Self::FnCall(_, pos) => *pos = new_pos, Self::And(_, pos) | Self::Or(_, pos) | Self::In(_, pos) => *pos = new_pos, - Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos = new_pos, + Self::Unit(pos) => *pos = new_pos, Self::Dot(_, pos) | Self::Index(_, pos) => *pos = new_pos, Self::Custom(_, pos) => *pos = new_pos, } @@ -1066,12 +1065,11 @@ impl Expr { Self::FloatConstant(_, _) => true, Self::DynamicConstant(_, _) + | Self::BoolConstant(_, _) | Self::IntegerConstant(_, _) | Self::CharConstant(_, _) | Self::StringConstant(_, _) | Self::FnPointer(_, _) - | Self::True(_) - | Self::False(_) | Self::Unit(_) => true, // An array literal is constant if all items are constant @@ -1099,14 +1097,13 @@ impl Expr { Self::FloatConstant(_, _) => false, Self::DynamicConstant(_, _) + | Self::BoolConstant(_, _) | Self::IntegerConstant(_, _) | Self::CharConstant(_, _) | Self::FnPointer(_, _) | Self::In(_, _) | Self::And(_, _) | Self::Or(_, _) - | Self::True(_) - | Self::False(_) | Self::Unit(_) => false, Self::StringConstant(_, _) diff --git a/src/engine.rs b/src/engine.rs index 6ae87c9f..ac00db9a 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1815,8 +1815,7 @@ impl Engine { .into()) } - Expr::True(_) => Ok(true.into()), - Expr::False(_) => Ok(false.into()), + Expr::BoolConstant(x, _) => Ok((*x).into()), Expr::Unit(_) => Ok(Dynamic::UNIT), Expr::Custom(custom, _) => { diff --git a/src/optimize.rs b/src/optimize.rs index 01beb455..7dc2a1a9 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -282,12 +282,12 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { }, // if false { if_block } -> Noop - Stmt::If(Expr::False(pos), x, _) if x.1.is_none() => { + Stmt::If(Expr::BoolConstant(false, pos), x, _) if x.1.is_none() => { state.set_dirty(); *stmt = Stmt::Noop(*pos); } // if true { if_block } -> if_block - Stmt::If(Expr::True(_), x, _) if x.1.is_none() => { + Stmt::If(Expr::BoolConstant(true, _), x, _) if x.1.is_none() => { *stmt = mem::take(&mut x.0); optimize_stmt(stmt, state, true); } @@ -316,12 +316,12 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { optimize_stmt(&mut x.0, state, true); } // if false { if_block } else { else_block } -> else_block - Stmt::If(Expr::False(_), x, _) if x.1.is_some() => { + Stmt::If(Expr::BoolConstant(false, _), x, _) if x.1.is_some() => { *stmt = mem::take(x.1.as_mut().unwrap()); optimize_stmt(stmt, state, true); } // if true { if_block } else { else_block } -> if_block - Stmt::If(Expr::True(_), x, _) => { + Stmt::If(Expr::BoolConstant(true, _), x, _) => { *stmt = mem::take(&mut x.0); optimize_stmt(stmt, state, true); } @@ -375,12 +375,12 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { } // while false { block } -> Noop - Stmt::While(Expr::False(pos), _, _) => { + Stmt::While(Expr::BoolConstant(false, pos), _, _) => { state.set_dirty(); *stmt = Stmt::Noop(*pos) } // while true { block } -> loop { block } - Stmt::While(Expr::True(_), block, pos) => { + Stmt::While(Expr::BoolConstant(true, _), block, pos) => { optimize_stmt(block, state, false); *stmt = Stmt::Loop(Box::new(mem::take(block)), *pos) } @@ -576,32 +576,23 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { // "xxx" in "xxxxx" (Expr::StringConstant(a, pos), Expr::StringConstant(b, _)) => { state.set_dirty(); - *expr = if b.contains(a.as_str()) { Expr::True(*pos) } else { Expr::False(*pos) }; + *expr = Expr::BoolConstant( b.contains(a.as_str()), *pos); } // 'x' in "xxxxx" (Expr::CharConstant(a, pos), Expr::StringConstant(b, _)) => { state.set_dirty(); - *expr = if b.contains(*a) { Expr::True(*pos) } else { Expr::False(*pos) }; + *expr = Expr::BoolConstant(b.contains(*a), *pos); } // "xxx" in #{...} (Expr::StringConstant(a, pos), Expr::Map(b, _)) => { state.set_dirty(); - *expr = if b.iter().find(|(x, _)| x.name == *a).is_some() { - Expr::True(*pos) - } else { - Expr::False(*pos) - }; + *expr = Expr::BoolConstant(b.iter().find(|(x, _)| x.name == *a).is_some(), *pos); } // 'x' in #{...} (Expr::CharConstant(a, pos), Expr::Map(b, _)) => { state.set_dirty(); let ch = a.to_string(); - - *expr = if b.iter().find(|(x, _)| x.name == &ch).is_some() { - Expr::True(*pos) - } else { - Expr::False(*pos) - }; + *expr = Expr::BoolConstant(b.iter().find(|(x, _)| x.name == &ch).is_some(), *pos); } // lhs in rhs (lhs, rhs) => { optimize_expr(lhs, state); optimize_expr(rhs, state); } @@ -609,18 +600,18 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { // lhs && rhs Expr::And(x, _) => match (&mut x.lhs, &mut x.rhs) { // true && rhs -> rhs - (Expr::True(_), rhs) => { + (Expr::BoolConstant(true, _), rhs) => { state.set_dirty(); optimize_expr(rhs, state); *expr = mem::take(rhs); } // false && rhs -> false - (Expr::False(pos), _) => { + (Expr::BoolConstant(false, pos), _) => { state.set_dirty(); - *expr = Expr::False(*pos); + *expr = Expr::BoolConstant(false, *pos); } // lhs && true -> lhs - (lhs, Expr::True(_)) => { + (lhs, Expr::BoolConstant(true, _)) => { state.set_dirty(); optimize_expr(lhs, state); *expr = mem::take(lhs); @@ -631,18 +622,18 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { // lhs || rhs Expr::Or(ref mut x, _) => match (&mut x.lhs, &mut x.rhs) { // false || rhs -> rhs - (Expr::False(_), rhs) => { + (Expr::BoolConstant(false, _), rhs) => { state.set_dirty(); optimize_expr(rhs, state); *expr = mem::take(rhs); } // true || rhs -> true - (Expr::True(pos), _) => { + (Expr::BoolConstant(true, pos), _) => { state.set_dirty(); - *expr = Expr::True(*pos); + *expr = Expr::BoolConstant(true, *pos); } // lhs || false - (lhs, Expr::False(_)) => { + (lhs, Expr::BoolConstant(false, _)) => { state.set_dirty(); optimize_expr(lhs, state); *expr = mem::take(lhs); diff --git a/src/parser.rs b/src/parser.rs index 795993de..f0e4c69a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -464,8 +464,7 @@ fn parse_index_chain( | Expr::And(_, _) | Expr::Or(_, _) | Expr::In(_, _) - | Expr::True(_) - | Expr::False(_) + | Expr::BoolConstant(_, _) | Expr::Unit(_) => { return Err(PERR::MalformedIndexExpr( "Only arrays, object maps and strings can be indexed".into(), @@ -499,8 +498,7 @@ fn parse_index_chain( | Expr::And(_, _) | Expr::Or(_, _) | Expr::In(_, _) - | Expr::True(_) - | Expr::False(_) + | Expr::BoolConstant(_, _) | Expr::Unit(_) => { return Err(PERR::MalformedIndexExpr( "Only arrays, object maps and strings can be indexed".into(), @@ -541,7 +539,7 @@ fn parse_index_chain( .into_err(x.position())) } // lhs[true], lhs[false] - x @ Expr::True(_) | x @ Expr::False(_) => { + x @ Expr::BoolConstant(_, _) => { return Err(PERR::MalformedIndexExpr( "Array access expects integer index, not a boolean".into(), ) @@ -999,8 +997,8 @@ fn parse_primary( Token::LeftBracket => parse_array_literal(input, state, lib, settings.level_up())?, #[cfg(not(feature = "no_object"))] Token::MapStart => parse_map_literal(input, state, lib, settings.level_up())?, - Token::True => Expr::True(settings.pos), - Token::False => Expr::False(settings.pos), + Token::True => Expr::BoolConstant(true, settings.pos), + Token::False => Expr::BoolConstant(false, settings.pos), Token::LexError(err) => return Err(err.into_err(settings.pos)), _ => { @@ -1451,8 +1449,7 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result { return Err(PERR::MalformedInExpr( "'in' expression expects a string, array or object map".into(), @@ -1492,8 +1489,7 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result { + | (x @ Expr::BoolConstant(_, _), Expr::StringConstant(_, _)) => { return Err(PERR::MalformedInExpr( "'in' expression for a string expects a string, not a boolean".into(), ) @@ -1545,8 +1541,7 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result { + | (x @ Expr::BoolConstant(_, _), Expr::Map(_, _)) => { return Err(PERR::MalformedInExpr( "'in' expression for an object map expects a string, not a boolean".into(), ) @@ -2961,8 +2956,7 @@ pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option { Union::Int(value) => Some(Expr::IntegerConstant(value, pos)), Union::Char(value) => Some(Expr::CharConstant(value, pos)), Union::Str(value) => Some(Expr::StringConstant(value, pos)), - Union::Bool(true) => Some(Expr::True(pos)), - Union::Bool(false) => Some(Expr::False(pos)), + Union::Bool(value) => Some(Expr::BoolConstant(value, pos)), #[cfg(not(feature = "no_index"))] Union::Array(array) => { let items: Vec<_> = array