diff --git a/CHANGELOG.md b/CHANGELOG.md index c22224b1..9a8444ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Bug fixes * Expressions such as `(v[0].func()).prop` now parse correctly. * Shadowed variable exports are now handled correctly. * Shadowed constant definitions are now optimized correctly when propagated (e.g. `const X = 1; const X = 1 + 1 + 1; X` now evaluates to 3 instead of 0). +* Identifiers and comma's in the middle of custom syntax now register correctly. New features ------------ diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index 762b5dcc..5f52d94c 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -232,11 +232,9 @@ impl Engine { } let token = Token::lookup_symbol_from_syntax(s).or_else(|| { - if is_reserved_keyword_or_symbol(s).0 { - Some(Token::Reserved(Box::new(s.into()))) - } else { - None - } + is_reserved_keyword_or_symbol(s) + .0 + .then(|| Token::Reserved(Box::new(s.into()))) }); let seg = match s { @@ -256,6 +254,9 @@ impl Engine { #[cfg(not(feature = "no_float"))] CUSTOM_SYNTAX_MARKER_FLOAT if !segments.is_empty() => s.into(), + // Identifier not in first position + _ if !segments.is_empty() && is_valid_identifier(s) => s.into(), + // Keyword/symbol not in first position _ if !segments.is_empty() && token.is_some() => { // Make it a custom keyword/symbol if it is disabled or reserved @@ -277,10 +278,7 @@ impl Engine { { return Err(LexError::ImproperSymbol( s.to_string(), - format!( - "Improper symbol for custom syntax at position #{}: '{s}'", - segments.len() + 1, - ), + format!("Improper symbol for custom syntax at position #0: '{s}'"), ) .into_err(Position::NONE)); } diff --git a/tests/custom_syntax.rs b/tests/custom_syntax.rs index 85072baf..ede70784 100644 --- a/tests/custom_syntax.rs +++ b/tests/custom_syntax.rs @@ -251,6 +251,65 @@ fn test_custom_syntax() -> Result<(), Box> { Ok(()) } +#[test] +fn test_custom_syntax_scope() -> Result<(), Box> { + let mut engine = Engine::new(); + + engine.register_custom_syntax( + [ + "with", "offset", "(", "$expr$", ",", "$expr$", ")", "$block$", + ], + true, + |context, inputs| { + let x = context + .eval_expression_tree(&inputs[0])? + .as_int() + .map_err(|typ| { + Box::new(EvalAltResult::ErrorMismatchDataType( + "integer".to_string(), + typ.to_string(), + inputs[0].position(), + )) + })?; + + let y = context + .eval_expression_tree(&inputs[1])? + .as_int() + .map_err(|typ| { + Box::new(EvalAltResult::ErrorMismatchDataType( + "integer".to_string(), + typ.to_string(), + inputs[1].position(), + )) + })?; + + let orig_len = context.scope().len(); + + context.scope_mut().push_constant("x", x); + context.scope_mut().push_constant("y", y); + + let result = context.eval_expression_tree(&inputs[2]); + + context.scope_mut().rewind(orig_len); + + result + }, + )?; + + assert_eq!( + engine.eval::( + " + let y = 1; + let x = 0; + with offset(44, 2) { x - y } + " + )?, + 42 + ); + + Ok(()) +} + #[test] fn test_custom_syntax_matrix() -> Result<(), Box> { let mut engine = Engine::new();