From ea38185cac845f27ff54f3edf3f0eaddaa3d97a5 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 29 Jul 2022 09:42:30 +0800 Subject: [PATCH 1/5] Add ParseError:err_type and ParseError::position. --- CHANGELOG.md | 1 + codegen/tests/test_modules.rs | 30 +++++++++++++------------- codegen/tests/test_nested.rs | 40 +++++++++++++++++------------------ src/types/parse_error.rs | 15 +++++++++++++ tests/arrays.rs | 21 ++++++++++-------- tests/assignments.rs | 33 +++++++++++++++++++++-------- tests/custom_syntax.rs | 11 ++++++---- tests/data_size.rs | 8 +++---- tests/eval.rs | 4 ++-- tests/fn_ptr.rs | 10 ++++----- tests/functions.rs | 6 ++++-- tests/internal_fn.rs | 10 ++++----- tests/looping.rs | 4 ++-- tests/maps.rs | 20 +++++++++--------- tests/mismatched_op.rs | 3 ++- tests/stack.rs | 12 ++++++----- tests/switch.rs | 13 ++++++------ tests/tokens.rs | 8 +++---- tests/var_scope.rs | 2 +- 19 files changed, 147 insertions(+), 104 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6db362aa..3063db23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Enhancements * `Iterator` type for functions metadata is simplified to `Iterator`. * `Scope::remove` is added to remove a variable from a `Scope`, returning its value. * The code base is cleaner by running it through Clippy. +* `ParseError::err_type` and `ParseError::position` are added for convenience. Version 1.8.0 diff --git a/codegen/tests/test_modules.rs b/codegen/tests/test_modules.rs index 98764d7e..cc9406f5 100644 --- a/codegen/tests/test_modules.rs +++ b/codegen/tests/test_modules.rs @@ -323,21 +323,21 @@ fn export_by_prefix_test() -> Result<(), Box> { assert_eq!(&output_array[3].as_int().unwrap(), &42); assert!(matches!(*engine.eval::( - r#" - let ex = 41.0; - let fx = Math::Advanced::foo_add_float2(ex, 1.0); - fx - "#).unwrap_err(), + " + let ex = 41.0; + let fx = Math::Advanced::foo_add_float2(ex, 1.0); + fx + ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) if s == "Math::Advanced::foo_add_float2 (f64, f64)" && p == rhai::Position::new(3, 34))); assert!(matches!(*engine.eval::( - r#" - let ex = 41.0; - let fx = Math::Advanced::bar_m(ex, 1.0); - fx - "#).unwrap_err(), + " + let ex = 41.0; + let fx = Math::Advanced::bar_m(ex, 1.0); + fx + ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) if s == "Math::Advanced::bar_m (f64, f64)" && p == rhai::Position::new(3, 34))); @@ -405,11 +405,11 @@ fn export_all_test() -> Result<(), Box> { assert_eq!(&output_array[3].as_int().unwrap(), &42); assert!(matches!(*engine.eval::( - r#" - let ex = 41; - let fx = Math::Advanced::foo_p(ex, 1); - fx - "#).unwrap_err(), + " + let ex = 41; + let fx = Math::Advanced::foo_p(ex, 1); + fx + ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) if s == "Math::Advanced::foo_p (i64, i64)" && p == rhai::Position::new(3, 34))); diff --git a/codegen/tests/test_nested.rs b/codegen/tests/test_nested.rs index ede543c1..077672b4 100644 --- a/codegen/tests/test_nested.rs +++ b/codegen/tests/test_nested.rs @@ -143,41 +143,41 @@ fn export_nested_by_prefix_test() -> Result<(), Box> { assert_eq!(&output_array[3].as_int().unwrap(), &42); assert!(matches!(*engine.eval::( - r#" - let ex = 41.0; - let fx = Math::Advanced::foo_third_adders::add_float(ex, 1.0); - fx - "#).unwrap_err(), + " + let ex = 41.0; + let fx = Math::Advanced::foo_third_adders::add_float(ex, 1.0); + fx + ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) if s == "Math::Advanced::foo_third_adders::add_float (f64, f64)" && p == rhai::Position::new(3, 52))); assert!(matches!(*engine.eval::( - r#" - let ex = 41; - let fx = Math::Advanced::foo_third_adders::add_int(ex, 1); - fx - "#).unwrap_err(), + " + let ex = 41; + let fx = Math::Advanced::foo_third_adders::add_int(ex, 1); + fx + ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) if s == "Math::Advanced::foo_third_adders::add_int (i64, i64)" && p == rhai::Position::new(3, 52))); assert!(matches!(*engine.eval::( - r#" - let ex = 41; - let fx = Math::Advanced::bar_fourth_adders::add_int(ex, 1); - fx - "#).unwrap_err(), + " + let ex = 41; + let fx = Math::Advanced::bar_fourth_adders::add_int(ex, 1); + fx + ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) if s == "Math::Advanced::bar_fourth_adders::add_int (i64, i64)" && p == rhai::Position::new(3, 53))); assert!(matches!(*engine.eval::( - r#" - let ex = 41.0; - let fx = Math::Advanced::bar_fourth_adders::add_float(ex, 1.0); - fx - "#).unwrap_err(), + " + let ex = 41.0; + let fx = Math::Advanced::bar_fourth_adders::add_float(ex, 1.0); + fx + ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) if s == "Math::Advanced::bar_fourth_adders::add_float (f64, f64)" && p == rhai::Position::new(3, 53))); diff --git a/src/types/parse_error.rs b/src/types/parse_error.rs index 4278ec5c..b1cbf12a 100644 --- a/src/types/parse_error.rs +++ b/src/types/parse_error.rs @@ -299,6 +299,21 @@ impl fmt::Display for ParseError { } } +impl ParseError { + /// Get the [type][ParseErrorType] of this parse error. + #[inline(always)] + #[must_use] + pub fn err_type(&self) -> &ParseErrorType { + &self.0 + } + /// Get the [position][Position] of this parse error. + #[inline(always)] + #[must_use] + pub fn position(&self) -> Position { + self.1 + } +} + impl From for RhaiError { #[inline(always)] fn from(err: ParseErrorType) -> Self { diff --git a/tests/arrays.rs b/tests/arrays.rs index aaea491a..d29d062b 100644 --- a/tests/arrays.rs +++ b/tests/arrays.rs @@ -179,40 +179,43 @@ fn test_array_index_types() -> Result<(), Box> { engine.compile("[1, 2, 3][0]['x']")?; assert!(matches!( - *engine + engine .compile("[1, 2, 3]['x']") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); #[cfg(not(feature = "no_float"))] assert!(matches!( - *engine + engine .compile("[1, 2, 3][123.456]") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); assert!(matches!( - *engine.compile("[1, 2, 3][()]").expect_err("should error").0, + engine + .compile("[1, 2, 3][()]") + .expect_err("should error") + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); assert!(matches!( - *engine + engine .compile(r#"[1, 2, 3]["hello"]"#) .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); assert!(matches!( - *engine + engine .compile("[1, 2, 3][true && false]") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); diff --git a/tests/assignments.rs b/tests/assignments.rs index 03df4be8..1be3901b 100644 --- a/tests/assignments.rs +++ b/tests/assignments.rs @@ -21,40 +21,55 @@ fn test_assignments_bad_lhs() -> Result<(), Box> { let engine = Engine::new(); assert_eq!( - *engine.compile("(x+y) = 42;").expect_err("should error").0, + *engine + .compile("(x+y) = 42;") + .expect_err("should error") + .err_type(), ParseErrorType::AssignmentToInvalidLHS("".to_string()) ); assert_eq!( - *engine.compile("foo(x) = 42;").expect_err("should error").0, + *engine + .compile("foo(x) = 42;") + .expect_err("should error") + .err_type(), ParseErrorType::AssignmentToInvalidLHS("".to_string()) ); assert_eq!( - *engine.compile("true = 42;").expect_err("should error").0, + *engine + .compile("true = 42;") + .expect_err("should error") + .err_type(), ParseErrorType::AssignmentToConstant("".to_string()) ); assert_eq!( - *engine.compile("123 = 42;").expect_err("should error").0, + *engine + .compile("123 = 42;") + .expect_err("should error") + .err_type(), ParseErrorType::AssignmentToConstant("".to_string()) ); #[cfg(not(feature = "no_object"))] { assert_eq!( - *engine.compile("x.foo() = 42;").expect_err("should error").0, + *engine + .compile("x.foo() = 42;") + .expect_err("should error") + .err_type(), ParseErrorType::AssignmentToInvalidLHS("".to_string()) ); assert_eq!( *engine .compile("x.foo().x.y = 42;") .expect_err("should error") - .0, + .err_type(), ParseErrorType::AssignmentToInvalidLHS("".to_string()) ); assert_eq!( *engine .compile("x.y.z.foo() = 42;") .expect_err("should error") - .0, + .err_type(), ParseErrorType::AssignmentToInvalidLHS("".to_string()) ); #[cfg(not(feature = "no_index"))] @@ -62,7 +77,7 @@ fn test_assignments_bad_lhs() -> Result<(), Box> { *engine .compile("x.foo()[0] = 42;") .expect_err("should error") - .0, + .err_type(), ParseErrorType::AssignmentToInvalidLHS("".to_string()) ); #[cfg(not(feature = "no_index"))] @@ -70,7 +85,7 @@ fn test_assignments_bad_lhs() -> Result<(), Box> { *engine .compile("x[y].z.foo() = 42;") .expect_err("should error") - .0, + .err_type(), ParseErrorType::AssignmentToInvalidLHS("".to_string()) ); } diff --git a/tests/custom_syntax.rs b/tests/custom_syntax.rs index a770acc6..5d4cb113 100644 --- a/tests/custom_syntax.rs +++ b/tests/custom_syntax.rs @@ -13,11 +13,11 @@ fn test_custom_syntax() -> Result<(), Box> { // Disable 'while' and make sure it still works with custom syntax engine.disable_symbol("while"); assert!(matches!( - *engine.compile("while false {}").expect_err("should error").0, + engine.compile("while false {}").expect_err("should error").err_type(), ParseErrorType::Reserved(err) if err == "while" )); assert!(matches!( - *engine.compile("let while = 0").expect_err("should error").0, + engine.compile("let while = 0").expect_err("should error").err_type(), ParseErrorType::Reserved(err) if err == "while" )); @@ -157,7 +157,7 @@ fn test_custom_syntax() -> Result<(), Box> { *engine .register_custom_syntax(&["!"], false, |_, _| Ok(Dynamic::UNIT)) .expect_err("should error") - .0, + .err_type(), ParseErrorType::BadInput(LexError::ImproperSymbol( "!".to_string(), "Improper symbol for custom syntax at position #1: '!'".to_string() @@ -261,7 +261,10 @@ fn test_custom_syntax_raw() -> Result<(), Box> { ); assert_eq!(engine.eval::("(hello kitty) + foo")?, 1041); assert_eq!( - *engine.compile("hello hey").expect_err("should error").0, + *engine + .compile("hello hey") + .expect_err("should error") + .err_type(), ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string(), "".to_string())) ); diff --git a/tests/data_size.rs b/tests/data_size.rs index e584678e..d6636a3f 100644 --- a/tests/data_size.rs +++ b/tests/data_size.rs @@ -16,7 +16,7 @@ fn test_max_string_size() -> Result<(), Box> { *engine .compile(r#"let x = "hello, world!";"#) .expect_err("should error") - .0, + .err_type(), ParseErrorType::LiteralTooLarge("Length of string literal".to_string(), 10) ); @@ -24,7 +24,7 @@ fn test_max_string_size() -> Result<(), Box> { *engine .compile(r#"let x = "朝に紅顔、暮に白骨";"#) .expect_err("should error") - .0, + .err_type(), ParseErrorType::LiteralTooLarge("Length of string literal".to_string(), 10) ); @@ -84,7 +84,7 @@ fn test_max_array_size() -> Result<(), Box> { *engine .compile("let x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];") .expect_err("should error") - .0, + .err_type(), ParseErrorType::LiteralTooLarge("Size of array literal".to_string(), 10) ); @@ -266,7 +266,7 @@ fn test_max_map_size() -> Result<(), Box> { "let x = #{a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9,j:10,k:11,l:12,m:13,n:14,o:15};" ) .expect_err("should error") - .0, + .err_type(), ParseErrorType::LiteralTooLarge( "Number of properties in object map literal".to_string(), 10 diff --git a/tests/eval.rs b/tests/eval.rs index e57c6371..a7b834f9 100644 --- a/tests/eval.rs +++ b/tests/eval.rs @@ -167,10 +167,10 @@ fn test_eval_disabled() -> Result<(), Box> { engine.disable_symbol("eval"); assert!(matches!( - *engine + engine .compile(r#"eval("40 + 2")"#) .expect_err("should error") - .0, + .err_type(), ParseErrorType::BadInput(LexError::ImproperSymbol(err, ..)) if err == "eval" )); diff --git a/tests/fn_ptr.rs b/tests/fn_ptr.rs index 0944ea58..b7174efa 100644 --- a/tests/fn_ptr.rs +++ b/tests/fn_ptr.rs @@ -65,12 +65,12 @@ fn test_fn_ptr() -> Result<(), Box> { *engine .eval::( r#" - fn foo(x) { this += x; } + fn foo(x) { this += x; } - let f = Fn("foo"); - call(f, 2); - x - "# + let f = Fn("foo"); + call(f, 2); + x + "# ) .expect_err("should error"), EvalAltResult::ErrorInFunctionCall(fn_name, _, err, ..) diff --git a/tests/functions.rs b/tests/functions.rs index fb392350..dddb835a 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -84,7 +84,8 @@ fn test_functions_global_module() -> Result<(), Box> { 42 ); - assert!(matches!(*engine.run(" + assert!(matches!(*engine.run( + " fn foo() { global::ANSWER } { @@ -104,7 +105,8 @@ fn test_functions_global_module() -> Result<(), Box> { ); #[cfg(not(feature = "no_closure"))] - assert!(matches!(*engine.run(" + assert!(matches!(*engine.run( + " do_stuff(|| { const LOCAL_VALUE = 42; global::LOCAL_VALUE diff --git a/tests/internal_fn.rs b/tests/internal_fn.rs index 72808e96..ddd8ff76 100644 --- a/tests/internal_fn.rs +++ b/tests/internal_fn.rs @@ -110,7 +110,7 @@ fn test_internal_fn_overloading() -> Result<(), Box> { " ) .expect_err("should error") - .0, + .err_type(), ParseErrorType::FnDuplicatedDefinition("abc".to_string(), 1) ); @@ -125,8 +125,8 @@ fn test_internal_fn_params() -> Result<(), Box> { assert_eq!( *engine .compile("fn hello(x, x) { x }") - .expect_err("should be error") - .0, + .expect_err("should error") + .err_type(), ParseErrorType::FnDuplicatedParam("hello".to_string(), "x".to_string()) ); @@ -236,7 +236,7 @@ fn test_internal_fn_bang() -> Result<(), Box> { #[cfg(not(feature = "no_object"))] assert!(matches!( - *engine + engine .compile( " fn foo() { this += x; } @@ -248,7 +248,7 @@ fn test_internal_fn_bang() -> Result<(), Box> { " ) .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedCapture(..) )); diff --git a/tests/looping.rs b/tests/looping.rs index 8b99e1bd..925d15dc 100644 --- a/tests/looping.rs +++ b/tests/looping.rs @@ -30,7 +30,7 @@ fn test_loop() -> Result<(), Box> { *engine .compile("let x = 0; break;") .expect_err("should error") - .0, + .err_type(), ParseErrorType::LoopBreak ); @@ -38,7 +38,7 @@ fn test_loop() -> Result<(), Box> { *engine .compile("let x = 0; if x > 0 { continue; }") .expect_err("should error") - .0, + .err_type(), ParseErrorType::LoopBreak ); diff --git a/tests/maps.rs b/tests/maps.rs index 6c3a53d0..3cb414db 100644 --- a/tests/maps.rs +++ b/tests/maps.rs @@ -132,43 +132,43 @@ fn test_map_index_types() -> Result<(), Box> { engine.compile(r#"#{a:1, b:2, c:3}["a"]['x']"#)?; assert!(matches!( - *engine + engine .compile("#{a:1, b:2, c:3}['x']") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); assert!(matches!( - *engine + engine .compile("#{a:1, b:2, c:3}[1]") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); #[cfg(not(feature = "no_float"))] assert!(matches!( - *engine + engine .compile("#{a:1, b:2, c:3}[123.456]") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); assert!(matches!( - *engine + engine .compile("#{a:1, b:2, c:3}[()]") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); assert!(matches!( - *engine + engine .compile("#{a:1, b:2, c:3}[true && false]") .expect_err("should error") - .0, + .err_type(), ParseErrorType::MalformedIndexExpr(..) )); diff --git a/tests/mismatched_op.rs b/tests/mismatched_op.rs index 1b1f7d5e..a117f215 100644 --- a/tests/mismatched_op.rs +++ b/tests/mismatched_op.rs @@ -30,7 +30,8 @@ fn test_mismatched_op_custom_type() -> Result<(), Box> { .register_type_with_name::("TestStruct") .register_fn("new_ts", TestStruct::new); - assert!(matches!(*engine.eval::(" + assert!(matches!(*engine.eval::( + " let x = new_ts(); let y = new_ts(); x == y diff --git a/tests/stack.rs b/tests/stack.rs index c10b4133..849c321b 100644 --- a/tests/stack.rs +++ b/tests/stack.rs @@ -40,9 +40,11 @@ fn test_stack_overflow_parsing() -> Result<(), Box> { let mut engine = Engine::new(); assert_eq!( - *engine.compile(" - let a = (1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) - ").expect_err("should error").0, + *engine.compile( + " + let a = (1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + " + ).expect_err("should error").0, ParseErrorType::ExprTooDeep ); @@ -69,7 +71,7 @@ fn test_stack_overflow_parsing() -> Result<(), Box> { " ) .expect_err("should error") - .0, + .err_type(), ParseErrorType::ExprTooDeep ); @@ -111,7 +113,7 @@ fn test_stack_overflow_parsing() -> Result<(), Box> { " ) .expect_err("should error") - .0, + .err_type(), ParseErrorType::ExprTooDeep ); diff --git a/tests/switch.rs b/tests/switch.rs index edcc4546..8008ccf2 100644 --- a/tests/switch.rs +++ b/tests/switch.rs @@ -115,10 +115,10 @@ fn test_switch_errors() -> Result<(), Box> { let engine = Engine::new(); assert!(matches!( - *engine + engine .compile("switch x { _ => 123, 1 => 42 }") .expect_err("should error") - .0, + .err_type(), ParseErrorType::WrongSwitchDefaultCase )); @@ -179,10 +179,10 @@ fn test_switch_condition() -> Result<(), Box> { ); assert!(matches!( - *engine + engine .compile("switch x { 1 => 123, _ if true => 42 }") .expect_err("should error") - .0, + .err_type(), ParseErrorType::WrongSwitchCaseCondition )); @@ -274,8 +274,9 @@ fn test_switch_ranges() -> Result<(), Box> { 'x' ); assert!(matches!( - *engine.compile("switch x { 10..20 => (), 20..=42 => 'a', 25..45 => 'z', 42 => 'x', 30..100 => true }") - .expect_err("should error").0, + engine.compile( + "switch x { 10..20 => (), 20..=42 => 'a', 25..45 => 'z', 42 => 'x', 30..100 => true }" + ).expect_err("should error").err_type(), ParseErrorType::WrongSwitchIntegerCase )); assert_eq!( diff --git a/tests/tokens.rs b/tests/tokens.rs index 1b9cb71a..f6fac1aa 100644 --- a/tests/tokens.rs +++ b/tests/tokens.rs @@ -7,10 +7,10 @@ fn test_tokens_disabled() { engine.disable_symbol("if"); // disable the 'if' keyword assert!(matches!( - *engine + engine .compile("let x = if true { 42 } else { 0 };") .expect_err("should error") - .0, + .err_type(), ParseErrorType::Reserved(err) if err == "if" )); @@ -20,12 +20,12 @@ fn test_tokens_disabled() { *engine .compile("let x = 40 + 2; x += 1;") .expect_err("should error") - .0, + .err_type(), ParseErrorType::UnknownOperator("+=".to_string()) ); assert!(matches!( - *engine.compile("let x = += 0;").expect_err("should error").0, + engine.compile("let x = += 0;").expect_err("should error").err_type(), ParseErrorType::Reserved(err) if err == "+=" )); } diff --git a/tests/var_scope.rs b/tests/var_scope.rs index fdf256d3..73701746 100644 --- a/tests/var_scope.rs +++ b/tests/var_scope.rs @@ -233,7 +233,7 @@ fn test_var_def_filter() -> Result<(), Box> { ); assert!(matches!( - *engine.compile("let x = 42;").expect_err("should error").0, + engine.compile("let x = 42;").expect_err("should error").err_type(), ParseErrorType::ForbiddenVariable(s) if s == "x" )); assert!(matches!( From fc976172e761db42e8102ba4dd63258e8198a673 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 29 Jul 2022 09:43:40 +0800 Subject: [PATCH 2/5] Fix bug with capturing undefined variable. --- CHANGELOG.md | 1 + src/eval/stmt.rs | 6 +++--- tests/closures.rs | 22 ++++++++++++++++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3063db23..10d05cbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Bug fixes * `switch` cases with conditions that evaluate to constant `()` no longer optimize to `false` (should raise a type error during runtime). * Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings. +* Capturing an unknown variable in a closure no longer panics. New features ------------ diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 9154a92e..bb7ac905 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -1016,7 +1016,7 @@ impl Engine { // Share statement #[cfg(not(feature = "no_closure"))] - Stmt::Share(name, ..) => { + Stmt::Share(name, pos) => { if let Some((index, ..)) = scope.get_index(name) { let val = scope.get_mut_by_index(index); @@ -1024,10 +1024,10 @@ impl Engine { // Replace the variable with a shared value. *val = std::mem::take(val).into_shared(); } + Ok(Dynamic::UNIT) } else { - unreachable!("variable {} not found for sharing", name); + Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into()) } - Ok(Dynamic::UNIT) } _ => unreachable!("statement cannot be evaluated: {:?}", stmt), diff --git a/tests/closures.rs b/tests/closures.rs index f7c1b291..392e8e94 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -42,21 +42,35 @@ fn test_fn_ptr_curry_call() -> Result<(), Box> { #[cfg(not(feature = "no_object"))] fn test_closures() -> Result<(), Box> { let mut engine = Engine::new(); + let mut scope = Scope::new(); + + scope.push("x", 42 as INT); assert!(matches!( - *engine - .compile_expression("let f = |x| {};") + engine + .compile_expression("|x| {}") .expect_err("should error") - .0, + .err_type(), ParseErrorType::BadInput(..) )); + assert_eq!( + engine.eval_with_scope::( + &mut scope, + " + let f = || { x }; + f.call() + ", + )?, + 42 + ); + assert_eq!( engine.eval::( " let foo = #{ x: 42 }; let f = || { this.x }; - foo.call(f) + foo.call(f) ", )?, 42 From 1073a7bd54df43885d7d005147c74b036885ab90 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 29 Jul 2022 10:49:03 +0800 Subject: [PATCH 3/5] Fix bug in constant interpolated string. --- CHANGELOG.md | 1 + src/ast/expr.rs | 16 +++++++++++++++- src/optimizer.rs | 8 ++++---- tests/string.rs | 2 ++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10d05cbd..2eb7b1e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Bug fixes * `switch` cases with conditions that evaluate to constant `()` no longer optimize to `false` (should raise a type error during runtime). * Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings. * Capturing an unknown variable in a closure no longer panics. +* Fixes panic in interpolated strings with constant expressions. New features ------------ diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 4d6a4b69..193324fa 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -5,12 +5,16 @@ use crate::engine::{KEYWORD_FN_PTR, OP_EXCLUSIVE_RANGE, OP_INCLUSIVE_RANGE}; use crate::func::hashing::ALT_ZERO_HASH; use crate::tokenizer::Token; use crate::types::dynamic::Union; -use crate::{calc_fn_hash, Dynamic, FnPtr, Identifier, ImmutableString, Position, StaticVec, INT}; +use crate::{ + calc_fn_hash, Dynamic, FnPtr, Identifier, ImmutableString, Position, SmartString, StaticVec, + INT, +}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ collections::BTreeMap, fmt, + fmt::Write, hash::Hash, iter::once, num::{NonZeroU8, NonZeroUsize}, @@ -576,6 +580,16 @@ impl Expr { })) } + // Interpolated string + Self::InterpolatedString(x, ..) if self.is_constant() => { + let mut s = SmartString::new_const(); + for segment in x.iter() { + let v = segment.get_literal_value().unwrap(); + write!(&mut s, "{}", v).unwrap(); + } + s.into() + } + // Fn Self::FnCall(ref x, ..) if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR => diff --git a/src/optimizer.rs b/src/optimizer.rs index 590e760d..4f561f65 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -12,7 +12,7 @@ use crate::tokenizer::{Span, Token}; use crate::types::dynamic::AccessMode; use crate::{ calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, Identifier, - Position, Scope, StaticVec, AST, INT, + Position, Scope, StaticVec, AST, INT, ImmutableString, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -1052,10 +1052,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { state.set_dirty(); *expr = Expr::StringConstant(state.engine.const_empty_string(), *pos); } - // `...` - Expr::InterpolatedString(x, ..) if x.len() == 1 && matches!(x[0], Expr::StringConstant(..)) => { + // `... ${const} ...` + Expr::InterpolatedString(..) if expr.is_constant() => { state.set_dirty(); - *expr = mem::take(&mut x[0]); + *expr = Expr::StringConstant(expr.get_literal_value().unwrap().cast::(), expr.position()); } // `... ${ ... } ...` Expr::InterpolatedString(x, ..) => { diff --git a/tests/string.rs b/tests/string.rs index c569b880..3bbed302 100644 --- a/tests/string.rs +++ b/tests/string.rs @@ -334,6 +334,8 @@ fn test_string_split() -> Result<(), Box> { fn test_string_interpolated() -> Result<(), Box> { let engine = Engine::new(); + assert_eq!(engine.eval::("`${}`")?, ""); + assert_eq!( engine.eval::( " From 7afcad24d6ff2adb1abac20258550ba5da30ca34 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 29 Jul 2022 11:01:00 +0800 Subject: [PATCH 4/5] Fix tests. --- codegen/tests/test_modules.rs | 111 +++++++++++++++++----------------- codegen/tests/test_nested.rs | 41 +++++++------ 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/codegen/tests/test_modules.rs b/codegen/tests/test_modules.rs index cc9406f5..a4657871 100644 --- a/codegen/tests/test_modules.rs +++ b/codegen/tests/test_modules.rs @@ -64,10 +64,11 @@ fn one_fn_and_const_module_test() -> Result<(), Box> { assert_eq!( engine.eval::( - r#" - let m = Math::Advanced::MYSTIC_NUMBER; - let x = Math::Advanced::euclidean_distance(0.0, 1.0, 0.0, m); - x"# + " + let m = Math::Advanced::MYSTIC_NUMBER; + let x = Math::Advanced::euclidean_distance(0.0, 1.0, 0.0, m); + x + " )?, 41.0 ); @@ -146,12 +147,13 @@ fn mut_opaque_ref_test() -> Result<(), Box> { assert_eq!( engine.eval::( r#" - let success = "it worked"; - let message1 = Host::Msg::new_message(true, success); - let ok1 = Host::Msg::write_out_message(message1); - let message2 = Host::Msg::new_os_message(true, 0); - let ok2 = Host::Msg::write_out_message(message2); - ok1 && ok2"# + let success = "it worked"; + let message1 = Host::Msg::new_message(true, success); + let ok1 = Host::Msg::write_out_message(message1); + let message2 = Host::Msg::new_os_message(true, 0); + let ok2 = Host::Msg::write_out_message(message2); + ok1 && ok2 + "# )?, true ); @@ -184,13 +186,13 @@ fn duplicate_fn_rename_test() -> Result<(), Box> { engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( - r#" - let fx = get_mystic_number(); - let fy = Math::Advanced::add(fx, 1.0); - let ix = 42; - let iy = Math::Advanced::add(ix, 1); - [fy, iy] - "#, + " + let fx = get_mystic_number(); + let fy = Math::Advanced::add(fx, 1.0); + let ix = 42; + let iy = Math::Advanced::add(ix, 1); + [fy, iy] + ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &43.0); assert_eq!(&output_array[1].as_int().unwrap(), &43); @@ -235,21 +237,21 @@ fn multiple_fn_rename_test() -> Result<(), Box> { engine.register_global_module(m.into()); let output_array = engine.eval::( - r#" - let fx = get_mystic_number(); - let fy1 = add(fx, 1.0); - let fy2 = add_together(fx, 1.0); - let fy3 = fx + 1.0; - let p1 = fx.prop; - let p2 = prop(fx); - let idx1 = fx[1]; - let idx2 = idx(fx, 1); - let ix = 42; - let iy1 = add(ix, 1); - let iy2 = add_together(ix, 1); - let iy3 = ix + 1; - [fy1, fy2, fy3, iy1, iy2, iy3, p1, p2, idx1, idx2] - "#, + " + let fx = get_mystic_number(); + let fy1 = add(fx, 1.0); + let fy2 = add_together(fx, 1.0); + let fy3 = fx + 1.0; + let p1 = fx.prop; + let p2 = prop(fx); + let idx1 = fx[1]; + let idx2 = idx(fx, 1); + let ix = 42; + let iy1 = add(ix, 1); + let iy2 = add_together(ix, 1); + let iy3 = ix + 1; + [fy1, fy2, fy3, iy1, iy2, iy3, p1, p2, idx1, idx2] + ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &44.0); assert_eq!(&output_array[1].as_float().unwrap(), &44.0); @@ -307,15 +309,15 @@ fn export_by_prefix_test() -> Result<(), Box> { engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( - r#" - let ex = 41.0; - let fx = Math::Advanced::foo_add_f(ex, 1.0); - let gx = Math::Advanced::foo_m(41.0, 1.0); - let ei = 41; - let fi = Math::Advanced::bar_add_i(ei, 1); - let gi = Math::Advanced::foo_n(41, 1); - [fx, gx, fi, gi] - "#, + " + let ex = 41.0; + let fx = Math::Advanced::foo_add_f(ex, 1.0); + let gx = Math::Advanced::foo_m(41.0, 1.0); + let ei = 41; + let fi = Math::Advanced::bar_add_i(ei, 1); + let gi = Math::Advanced::foo_n(41, 1); + [fx, gx, fi, gi] + ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &42.0); assert_eq!(&output_array[1].as_float().unwrap(), &42.0); @@ -329,8 +331,7 @@ fn export_by_prefix_test() -> Result<(), Box> { fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) - if s == "Math::Advanced::foo_add_float2 (f64, f64)" - && p == rhai::Position::new(3, 34))); + if s == "Math::Advanced::foo_add_float2 (f64, f64)")); assert!(matches!(*engine.eval::( " @@ -339,8 +340,7 @@ fn export_by_prefix_test() -> Result<(), Box> { fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) - if s == "Math::Advanced::bar_m (f64, f64)" - && p == rhai::Position::new(3, 34))); + if s == "Math::Advanced::bar_m (f64, f64)")); Ok(()) } @@ -389,15 +389,15 @@ fn export_all_test() -> Result<(), Box> { engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( - r#" - let ex = 41.0; - let fx = Math::Advanced::foo_add_f(ex, 1.0); - let gx = Math::Advanced::foo_m(41.0, 1.0); - let ei = 41; - let fi = Math::Advanced::foo_add_i(ei, 1); - let gi = Math::Advanced::foo_n(41, 1); - [fx, gx, fi, gi] - "#, + " + let ex = 41.0; + let fx = Math::Advanced::foo_add_f(ex, 1.0); + let gx = Math::Advanced::foo_m(41.0, 1.0); + let ei = 41; + let fi = Math::Advanced::foo_add_i(ei, 1); + let gi = Math::Advanced::foo_n(41, 1); + [fx, gx, fi, gi] + ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &42.0); assert_eq!(&output_array[1].as_float().unwrap(), &42.0); @@ -411,8 +411,7 @@ fn export_all_test() -> Result<(), Box> { fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) - if s == "Math::Advanced::foo_p (i64, i64)" - && p == rhai::Position::new(3, 34))); + if s == "Math::Advanced::foo_p (i64, i64)")); Ok(()) } diff --git a/codegen/tests/test_nested.rs b/codegen/tests/test_nested.rs index 077672b4..9a7ff676 100644 --- a/codegen/tests/test_nested.rs +++ b/codegen/tests/test_nested.rs @@ -52,7 +52,12 @@ fn one_fn_sub_module_nested_attr_test() -> Result<(), Box> { engine.register_static_module("Math::Advanced", m.into()); assert_eq!( - engine.eval::(r#"let m = Math::Advanced::constants::get_mystic_number(); m"#)?, + engine.eval::( + " + let m = Math::Advanced::constants::get_mystic_number(); + m + " + )?, 42.0 ); Ok(()) @@ -121,21 +126,21 @@ fn export_nested_by_prefix_test() -> Result<(), Box> { engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( - r#" - let ex = 41.0; - let fx = Math::Advanced::foo_first_adders::add_float(ex, 1.0); + " + let ex = 41.0; + let fx = Math::Advanced::foo_first_adders::add_float(ex, 1.0); - let ei = 41; - let fi = Math::Advanced::foo_first_adders::add_int(ei, 1); + let ei = 41; + let fi = Math::Advanced::foo_first_adders::add_int(ei, 1); - let gx = 41.0; - let hx = Math::Advanced::foo_second_adders::add_float(gx, 1.0); + let gx = 41.0; + let hx = Math::Advanced::foo_second_adders::add_float(gx, 1.0); - let gi = 41; - let hi = Math::Advanced::foo_second_adders::add_int(gi, 1); + let gi = 41; + let hi = Math::Advanced::foo_second_adders::add_int(gi, 1); - [fx, hx, fi, hi] - "#, + [fx, hx, fi, hi] + ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &42.0); assert_eq!(&output_array[1].as_float().unwrap(), &42.0); @@ -149,8 +154,7 @@ fn export_nested_by_prefix_test() -> Result<(), Box> { fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) - if s == "Math::Advanced::foo_third_adders::add_float (f64, f64)" - && p == rhai::Position::new(3, 52))); + if s == "Math::Advanced::foo_third_adders::add_float (f64, f64)")); assert!(matches!(*engine.eval::( " @@ -159,8 +163,7 @@ fn export_nested_by_prefix_test() -> Result<(), Box> { fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) - if s == "Math::Advanced::foo_third_adders::add_int (i64, i64)" - && p == rhai::Position::new(3, 52))); + if s == "Math::Advanced::foo_third_adders::add_int (i64, i64)")); assert!(matches!(*engine.eval::( " @@ -169,8 +172,7 @@ fn export_nested_by_prefix_test() -> Result<(), Box> { fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) - if s == "Math::Advanced::bar_fourth_adders::add_int (i64, i64)" - && p == rhai::Position::new(3, 53))); + if s == "Math::Advanced::bar_fourth_adders::add_int (i64, i64)")); assert!(matches!(*engine.eval::( " @@ -179,8 +181,7 @@ fn export_nested_by_prefix_test() -> Result<(), Box> { fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, p) - if s == "Math::Advanced::bar_fourth_adders::add_float (f64, f64)" - && p == rhai::Position::new(3, 53))); + if s == "Math::Advanced::bar_fourth_adders::add_float (f64, f64)")); Ok(()) } From 52edded8417b5cd3261fc12b470b0a8511f97a45 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 29 Jul 2022 11:10:20 +0800 Subject: [PATCH 5/5] Fix formatting. --- src/optimizer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/optimizer.rs b/src/optimizer.rs index 4f561f65..81264050 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -12,7 +12,7 @@ use crate::tokenizer::{Span, Token}; use crate::types::dynamic::AccessMode; use crate::{ calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, Identifier, - Position, Scope, StaticVec, AST, INT, ImmutableString, + ImmutableString, Position, Scope, StaticVec, AST, INT, }; #[cfg(feature = "no_std")] use std::prelude::v1::*;