diff --git a/src/parser.rs b/src/parser.rs index 67807e87..fc9e8966 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -14,7 +14,7 @@ use crate::tokenizer::{ is_keyword_function, is_valid_function_name, is_valid_identifier, Token, TokenStream, TokenizerControl, }; -use crate::types::dynamic::AccessMode; +use crate::types::dynamic::{AccessMode, Union}; use crate::types::StringsInterner; use crate::{ calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ExclusiveRange, FnArgsVec, @@ -1243,8 +1243,19 @@ impl Engine { continue; } - if value.is_int() && !ranges.is_empty() { - return Err(PERR::WrongSwitchIntegerCase.into_err(expr.start_position())); + if !ranges.is_empty() { + let forbidden = match value { + Dynamic(Union::Int(..)) => true, + #[cfg(not(feature = "no_float"))] + Dynamic(Union::Float(..)) => true, + #[cfg(feature = "decimal")] + Dynamic(Union::Decimal(..)) => true, + _ => false, + }; + + if forbidden { + return Err(PERR::WrongSwitchIntegerCase.into_err(expr.start_position())); + } } let hasher = &mut get_hasher(); diff --git a/src/types/parse_error.rs b/src/types/parse_error.rs index 19156ef8..e6062d5d 100644 --- a/src/types/parse_error.rs +++ b/src/types/parse_error.rs @@ -105,7 +105,7 @@ pub enum ParseErrorType { DuplicatedSwitchCase, /// A variable name is duplicated. Wrapped value is the variable name. DuplicatedVariable(String), - /// An integer case of a `switch` statement is in an appropriate place. + /// A numeric case of a `switch` statement is in an appropriate place. WrongSwitchIntegerCase, /// The default case of a `switch` statement is in an appropriate place. WrongSwitchDefaultCase, @@ -236,7 +236,7 @@ impl fmt::Display for ParseErrorType { Self::Reserved(s) if is_valid_identifier(s.as_str()) => write!(f, "'{s}' is a reserved keyword"), Self::Reserved(s) => write!(f, "'{s}' is a reserved symbol"), Self::UnexpectedEOF => f.write_str("Script is incomplete"), - Self::WrongSwitchIntegerCase => f.write_str("Integer switch case cannot follow a range case"), + Self::WrongSwitchIntegerCase => f.write_str("Numeric switch case cannot follow a range case"), Self::WrongSwitchDefaultCase => f.write_str("Default switch case must be the last"), Self::WrongSwitchCaseCondition => f.write_str("This switch case cannot have a condition"), Self::PropertyExpected => f.write_str("Expecting name of a property"), diff --git a/tests/switch.rs b/tests/switch.rs index 0de962f7..f37dacc0 100644 --- a/tests/switch.rs +++ b/tests/switch.rs @@ -10,9 +10,7 @@ fn test_switch() -> Result<(), Box> { engine.eval::("switch 2 { 1 => (), 2 => 'a', 42 => true }")?, 'a' ); - engine - .run("switch 3 { 1 => (), 2 => 'a', 42 => true }") - .unwrap(); + engine.run("switch 3 { 1 => (), 2 => 'a', 42 => true }")?; assert_eq!( engine.eval::("switch 3 { 1 => (), 2 => 'a', 42 => true, _ => 123 }")?, 123 @@ -31,15 +29,13 @@ fn test_switch() -> Result<(), Box> { )?, 'a' ); - assert!(engine - .eval_with_scope::(&mut scope, "switch x { 1 => (), 2 => 'a', 42 => true }") - .unwrap()); - assert!(engine - .eval_with_scope::(&mut scope, "switch x { 1 => (), 2 => 'a', _ => true }") - .unwrap()); - let _: () = engine - .eval_with_scope::<()>(&mut scope, "switch x { 1 => 123, 2 => 'a' }") - .unwrap(); + assert!( + engine.eval_with_scope::(&mut scope, "switch x { 1 => (), 2 => 'a', 42 => true }")? + ); + assert!( + engine.eval_with_scope::(&mut scope, "switch x { 1 => (), 2 => 'a', _ => true }")? + ); + let _: () = engine.eval_with_scope::<()>(&mut scope, "switch x { 1 => 123, 2 => 'a' }")?; assert_eq!( engine.eval_with_scope::( @@ -276,6 +272,13 @@ fn test_switch_ranges() -> Result<(), Box> { ).expect_err("should error").err_type(), ParseErrorType::WrongSwitchIntegerCase )); + #[cfg(not(feature = "no_float"))] + assert!(matches!( + engine.compile( + "switch x { 10..20 => (), 20..=42 => 'a', 25..45 => 'z', 42.0 => 'x', 30..100 => true }" + ).expect_err("should error").err_type(), + ParseErrorType::WrongSwitchIntegerCase + )); assert_eq!( engine.eval_with_scope::( &mut scope,