From 2be757fda02e0243202b14db58a949089f7178bf Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 21 Nov 2020 13:05:57 +0800 Subject: [PATCH 01/12] Make shadowing variables in custom syntax work. --- RELEASES.md | 5 +++++ src/parser.rs | 37 +++++++++++++++++++++++++++++++------ tests/syntax.rs | 21 +++++++++++++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 4d5f3028..1f0a1fed 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,11 @@ It also allows exposing selected module functions (usually methods) to the globa This is very convenient when encapsulating the API of a custom Rust type into a module while having methods and iterators registered on the custom type work normally. +Bug fixes +--------- + +* Custom syntax that introduces a shadowing variable now works properly. + Breaking changes ---------------- diff --git a/src/parser.rs b/src/parser.rs index aea543c8..2a7a4684 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -46,6 +46,8 @@ struct ParseState<'e> { strings: HashMap, /// Encapsulates a local stack with variable names to simulate an actual runtime scope. stack: Vec<(ImmutableString, ScopeEntryType)>, + /// Size of the local variables stack upon entry of the current block scope. + entry_stack_len: usize, /// Tracks a list of external variables (variables that are not explicitly declared in the scope). #[cfg(not(feature = "no_closure"))] externals: HashMap, @@ -92,6 +94,7 @@ impl<'e> ParseState<'e> { allow_capture: true, strings: HashMap::with_capacity(64), stack: Vec::with_capacity(16), + entry_stack_len: 0, #[cfg(not(feature = "no_module"))] modules: Default::default(), } @@ -103,15 +106,26 @@ impl<'e> ParseState<'e> { /// /// The return value is the offset to be deducted from `Stack::len`, /// i.e. the top element of the `ParseState` is offset 1. + /// /// Return `None` when the variable name is not found in the `stack`. #[inline] fn access_var(&mut self, name: &str, _pos: Position) -> Option { + let mut barrier = false; + let index = self .stack .iter() .rev() .enumerate() - .find(|(_, (n, _))| *n == name) + .find(|(_, (n, _))| { + if n.is_empty() { + // Do not go beyond empty variable names + barrier = true; + false + } else { + *n == name + } + }) .and_then(|(i, _)| NonZeroUsize::new(i + 1)); #[cfg(not(feature = "no_closure"))] @@ -123,7 +137,11 @@ impl<'e> ParseState<'e> { self.allow_capture = true } - index + if barrier { + None + } else { + index + } } /// Find a module by name in the `ParseState`, searching in reverse. @@ -1781,6 +1799,9 @@ fn parse_custom_syntax( // Adjust the variables stack match syntax.scope_delta { delta if delta > 0 => { + // Add enough empty variable names to the stack. + // Empty variable names act as a barrier so earlier variables will not be matched. + // Variable searches stop at the first empty variable name. state.stack.resize( state.stack.len() + delta as usize, ("".into(), ScopeEntryType::Normal), @@ -2284,7 +2305,9 @@ fn parse_block( settings.ensure_level_within_max_limit(state.max_expr_depth)?; let mut statements = Vec::with_capacity(8); - let prev_stack_len = state.stack.len(); + + let prev_entry_stack_len = state.entry_stack_len; + state.entry_stack_len = state.stack.len(); #[cfg(not(feature = "no_module"))] let prev_mods_len = state.modules.len(); @@ -2328,7 +2351,8 @@ fn parse_block( } } - state.stack.truncate(prev_stack_len); + state.stack.truncate(state.entry_stack_len); + state.entry_stack_len = prev_entry_stack_len; #[cfg(not(feature = "no_module"))] state.modules.truncate(prev_mods_len); @@ -2372,10 +2396,11 @@ fn parse_stmt( settings.ensure_level_within_max_limit(state.max_expr_depth)?; match token { - // Semicolon - empty statement + // ; - empty statement Token::SemiColon => Ok(Some(Stmt::Noop(settings.pos))), - Token::LeftBrace => parse_block(input, state, lib, settings.level_up()).map(Some), + // { - statements block + Token::LeftBrace => Ok(Some(parse_block(input, state, lib, settings.level_up())?)), // fn ... #[cfg(not(feature = "no_function"))] diff --git a/tests/syntax.rs b/tests/syntax.rs index 225feec4..819931e6 100644 --- a/tests/syntax.rs +++ b/tests/syntax.rs @@ -52,6 +52,16 @@ fn test_custom_syntax() -> Result<(), Box> { }, )?; + assert_eq!( + engine.eval::( + r" + let x = 0; + exec |x| -> { x += 1 } while x < 42; + x + " + )?, + 42 + ); assert_eq!( engine.eval::( r" @@ -96,8 +106,10 @@ fn test_custom_syntax_raw() -> Result<(), Box> { }, _ => unreachable!(), }, - 0, - |_, inputs| { + 1, + |context, inputs| { + context.scope.push("foo", 999 as INT); + Ok(match inputs[0].get_variable_name().unwrap() { "world" => 123 as INT, "kitty" => 42 as INT, @@ -109,6 +121,11 @@ fn test_custom_syntax_raw() -> Result<(), Box> { assert_eq!(engine.eval::("hello world")?, 123); assert_eq!(engine.eval::("hello kitty")?, 42); + assert_eq!( + engine.eval::("let foo = 0; (hello kitty) + foo")?, + 1041 + ); + assert_eq!(engine.eval::("(hello kitty) + foo")?, 1041); assert_eq!( *engine.compile("hello hey").expect_err("should error").0, ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string())) From 6c07d5fd735617686ce68107e044dfa3cb591946 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 21 Nov 2020 14:46:05 +0800 Subject: [PATCH 02/12] Fix constant example. --- doc/src/language/constants.md | 19 ++++++++++++------- tests/constants.rs | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/doc/src/language/constants.md b/doc/src/language/constants.md index da2a13be..52124d21 100644 --- a/doc/src/language/constants.md +++ b/doc/src/language/constants.md @@ -34,23 +34,28 @@ It is very useful to have a constant value hold a [custom type], which essential as a [_singleton_](../patterns/singleton.md). ```rust -use rhai::{Engine, Scope}; +use rhai::{Engine, Scope, RegisterFn}; +#[derive(Debug, Clone)] struct TestStruct(i64); // custom type -let engine = Engine::new() +let mut engine = Engine::new(); + +engine .register_type_with_name::("TestStruct") // register custom type - .register_get_set("value", - |obj: &mut TestStruct| obj.0, // property getter - |obj: &mut TestStruct, value: i64| obj.0 = value // property setter + .register_get("value", |obj: &mut TestStruct| obj.0), // property getter + .register_fn("update_value", + |obj: &mut TestStruct, value: i64| obj.0 = value // mutating method ); let mut scope = Scope::new(); // create custom scope scope.push_constant("MY_NUMBER", TestStruct(123_i64)); // add constant variable -engine.consume_with_scope(&mut scope, r" - MY_NUMBER.value = 42; // constant objects can be modified +// Beware: constant objects can still be modified via a method call! +engine.consume_with_scope(&mut scope, +r" + MY_NUMBER.update_value(42); print(MY_NUMBER.value); // prints 42 ")?; ``` diff --git a/tests/constants.rs b/tests/constants.rs index 2f516a1b..090abfaa 100644 --- a/tests/constants.rs +++ b/tests/constants.rs @@ -1,4 +1,4 @@ -use rhai::{Engine, EvalAltResult, ParseErrorType, Scope, INT}; +use rhai::{Engine, EvalAltResult, ParseErrorType, RegisterFn, Scope, INT}; #[test] fn test_constant() -> Result<(), Box> { @@ -62,3 +62,36 @@ fn test_var_is_def() -> Result<(), Box> { Ok(()) } + +#[cfg(not(feature = "no_object"))] +#[test] +fn test_constant_mut() -> Result<(), Box> { + #[derive(Debug, Clone)] + struct TestStruct(INT); // custom type + + let mut engine = Engine::new(); + + engine + .register_type_with_name::("TestStruct") + .register_get("value", |obj: &mut TestStruct| obj.0) + .register_fn("update_value", |obj: &mut TestStruct, value: INT| { + obj.0 = value + }); + + let mut scope = Scope::new(); + + scope.push_constant("MY_NUMBER", TestStruct(123)); + + assert_eq!( + engine.eval_with_scope::( + &mut scope, + r" + MY_NUMBER.update_value(42); + MY_NUMBER.value + ", + )?, + 42 + ); + + Ok(()) +} From 0046fe7e7380b122090f51903cab33bc1c849003 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 21 Nov 2020 15:08:18 +0800 Subject: [PATCH 03/12] Prefer Engine::disable_symbol to disable eval. --- RELEASES.md | 1 + doc/src/language/eval.md | 25 +++++------------- doc/src/rust/packages/builtin.md | 1 - src/packages/eval.rs | 14 ---------- src/packages/mod.rs | 2 -- src/parse_error.rs | 9 ++++--- src/parser.rs | 44 +++++++++++++++++--------------- src/syntax.rs | 26 +++++++++++-------- src/token.rs | 30 ++++++++++++---------- tests/eval.rs | 28 ++++++++++++++++++-- 10 files changed, 96 insertions(+), 84 deletions(-) delete mode 100644 src/packages/eval.rs diff --git a/RELEASES.md b/RELEASES.md index 1f0a1fed..bae0c5ef 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -20,6 +20,7 @@ Breaking changes * `Module::set_fn`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`. * `unless` is now a reserved keyword. +* `EvalPackage` is removed in favor of `Engine::disable_symbol`. New features ------------ diff --git a/doc/src/language/eval.md b/doc/src/language/eval.md index fec9569a..0b9eb8b0 100644 --- a/doc/src/language/eval.md +++ b/doc/src/language/eval.md @@ -60,7 +60,13 @@ print(x); -------------- For those who subscribe to the (very sensible) motto of ["`eval` is evil"](http://linterrors.com/js/eval-is-evil), -disable `eval` by overloading it, probably with something that throws. +disable `eval` using [`Engine::disable_symbol`][disable keywords and operators]: + +```rust +engine.disable_symbol("eval"); // disable usage of 'eval' +``` + +`eval` can also be disabled by overloading it, probably with something that throws: ```rust fn eval(script) { throw "eval is evil! I refuse to run " + script } @@ -75,20 +81,3 @@ engine.register_result_fn("eval", |script: String| -> Result<(), Box Result> { - Err("eval is evil!".into()) - } -} diff --git a/src/packages/mod.rs b/src/packages/mod.rs index ede3da61..a4c443ed 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -6,7 +6,6 @@ use crate::{Module, Shared, StaticVec}; pub(crate) mod arithmetic; mod array_basic; -mod eval; mod fn_basic; mod iter_basic; mod logic; @@ -21,7 +20,6 @@ mod time_basic; pub use arithmetic::ArithmeticPackage; #[cfg(not(feature = "no_index"))] pub use array_basic::BasicArrayPackage; -pub use eval::EvalPackage; pub use fn_basic::BasicFnPackage; pub use iter_basic::BasicIteratorPackage; pub use logic::LogicPackage; diff --git a/src/parse_error.rs b/src/parse_error.rs index 9b851818..010864cf 100644 --- a/src/parse_error.rs +++ b/src/parse_error.rs @@ -32,7 +32,7 @@ pub enum LexError { /// An identifier is in an invalid format. MalformedIdentifier(String), /// Bad symbol encountered when tokenizing the script text. - ImproperSymbol(String), + ImproperSymbol(String, String), } impl Error for LexError {} @@ -47,7 +47,10 @@ impl fmt::Display for LexError { Self::MalformedIdentifier(s) => write!(f, "{}: '{}'", self.desc(), s), Self::UnterminatedString => f.write_str(self.desc()), Self::StringTooLong(max) => write!(f, "{} ({})", self.desc(), max), - Self::ImproperSymbol(s) => f.write_str(s), + Self::ImproperSymbol(s, d) if d.is_empty() => { + write!(f, "Invalid symbol encountered: '{}'", s) + } + Self::ImproperSymbol(_, d) => f.write_str(d), } } } @@ -62,7 +65,7 @@ impl LexError { Self::MalformedNumber(_) => "Invalid number", Self::MalformedChar(_) => "Invalid character", Self::MalformedIdentifier(_) => "Variable name is not proper", - Self::ImproperSymbol(_) => "Invalid symbol encountered", + Self::ImproperSymbol(_, _) => "Invalid symbol encountered", } } /// Convert a `&LexError` into a [`ParseError`]. diff --git a/src/parser.rs b/src/parser.rs index 2a7a4684..10ebf146 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -995,11 +995,8 @@ fn parse_primary( // Access to `this` as a variable is OK Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => { if !settings.is_function_scope { - return Err(PERR::BadInput(LexError::ImproperSymbol(format!( - "'{}' can only be used in functions", - s - ))) - .into_err(settings.pos)); + let msg = format!("'{}' can only be used in functions", s); + return Err(PERR::BadInput(LexError::ImproperSymbol(s, msg)).into_err(settings.pos)); } else { let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos); Expr::Variable(Box::new((None, None, 0, var_name_def))) @@ -1045,6 +1042,7 @@ fn parse_primary( LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos) } else { PERR::BadInput(LexError::ImproperSymbol( + "!".to_string(), "'!' cannot be used to call module functions".to_string(), )) .into_err(token_pos) @@ -1333,6 +1331,7 @@ fn make_assignment_stmt<'a>( } // ??? && ??? = rhs, ??? || ??? = rhs Expr::And(_, _) | Expr::Or(_, _) => Err(PERR::BadInput(LexError::ImproperSymbol( + "=".to_string(), "Possibly a typo of '=='?".to_string(), )) .into_err(pos)), @@ -1438,10 +1437,13 @@ fn make_dot_expr( && [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL] .contains(&x.name.as_ref()) => { - return Err(PERR::BadInput(LexError::ImproperSymbol(format!( - "'{}' should not be called in method style. Try {}(...);", - x.name, x.name - ))) + return Err(PERR::BadInput(LexError::ImproperSymbol( + x.name.to_string(), + format!( + "'{}' should not be called in method style. Try {}(...);", + x.name, x.name + ), + )) .into_err(pos)); } // lhs.func!(...) @@ -1932,20 +1934,22 @@ fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> { match input.peek().unwrap() { (Token::Equals, pos) => Err(PERR::BadInput(LexError::ImproperSymbol( + "=".to_string(), "Possibly a typo of '=='?".to_string(), )) .into_err(*pos)), - (Token::PlusAssign, pos) - | (Token::MinusAssign, pos) - | (Token::MultiplyAssign, pos) - | (Token::DivideAssign, pos) - | (Token::LeftShiftAssign, pos) - | (Token::RightShiftAssign, pos) - | (Token::ModuloAssign, pos) - | (Token::PowerOfAssign, pos) - | (Token::AndAssign, pos) - | (Token::OrAssign, pos) - | (Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol( + (token @ Token::PlusAssign, pos) + | (token @ Token::MinusAssign, pos) + | (token @ Token::MultiplyAssign, pos) + | (token @ Token::DivideAssign, pos) + | (token @ Token::LeftShiftAssign, pos) + | (token @ Token::RightShiftAssign, pos) + | (token @ Token::ModuloAssign, pos) + | (token @ Token::PowerOfAssign, pos) + | (token @ Token::AndAssign, pos) + | (token @ Token::OrAssign, pos) + | (token @ Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol( + token.syntax().to_string(), "Expecting a boolean expression, not an assignment".to_string(), )) .into_err(*pos)), diff --git a/src/syntax.rs b/src/syntax.rs index e3e6f1ca..695822e9 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -137,11 +137,14 @@ impl Engine { .map(|v| v.is_keyword() || v.is_reserved()) .unwrap_or(false) => { - return Err(LexError::ImproperSymbol(format!( - "Improper symbol for custom syntax at position #{}: '{}'", - segments.len() + 1, - s - )) + return Err(LexError::ImproperSymbol( + s.to_string(), + format!( + "Improper symbol for custom syntax at position #{}: '{}'", + segments.len() + 1, + s + ), + ) .into_err(Position::NONE) .into()); } @@ -154,11 +157,14 @@ impl Engine { } // Anything else is an error _ => { - return Err(LexError::ImproperSymbol(format!( - "Improper symbol for custom syntax at position #{}: '{}'", - segments.len() + 1, - s - )) + return Err(LexError::ImproperSymbol( + s.to_string(), + format!( + "Improper symbol for custom syntax at position #{}: '{}'", + segments.len() + 1, + s + ), + ) .into_err(Position::NONE) .into()); } diff --git a/src/token.rs b/src/token.rs index c36a5651..cd54059d 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1658,39 +1658,41 @@ impl<'a> Iterator for TokenIterator<'a, '_> { Some((Token::Reserved(s), pos)) => Some((match (s.as_str(), self.engine.custom_keywords.contains_key(&s)) { - ("===", false) => Token::LexError(LERR::ImproperSymbol( + ("===", false) => Token::LexError(LERR::ImproperSymbol(s, "'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(), )), - ("!==", false) => Token::LexError(LERR::ImproperSymbol( + ("!==", false) => Token::LexError(LERR::ImproperSymbol(s, "'!==' is not a valid operator. This is not JavaScript! Should it be '!='?".to_string(), )), - ("->", false) => Token::LexError(LERR::ImproperSymbol( + ("->", false) => Token::LexError(LERR::ImproperSymbol(s, "'->' is not a valid symbol. This is not C or C++!".to_string())), - ("<-", false) => Token::LexError(LERR::ImproperSymbol( + ("<-", false) => Token::LexError(LERR::ImproperSymbol(s, "'<-' is not a valid symbol. This is not Go! Should it be '<='?".to_string(), )), - (":=", false) => Token::LexError(LERR::ImproperSymbol( + (":=", false) => Token::LexError(LERR::ImproperSymbol(s, "':=' is not a valid assignment operator. This is not Go! Should it be simply '='?".to_string(), )), - ("::<", false) => Token::LexError(LERR::ImproperSymbol( + ("::<", false) => Token::LexError(LERR::ImproperSymbol(s, "'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(), )), - ("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol( + ("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol(s, "'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(), )), - ("#", false) => Token::LexError(LERR::ImproperSymbol( + ("#", false) => Token::LexError(LERR::ImproperSymbol(s, "'#' is not a valid symbol. Should it be '#{'?".to_string(), )), // Reserved keyword/operator that is custom. (_, true) => Token::Custom(s), // Reserved operator that is not custom. - (token, false) if !is_valid_identifier(token.chars()) => Token::LexError(LERR::ImproperSymbol( - format!("'{}' is a reserved symbol", token) - )), + (token, false) if !is_valid_identifier(token.chars()) => { + let msg = format!("'{}' is a reserved symbol", token); + Token::LexError(LERR::ImproperSymbol(s, msg)) + }, // Reserved keyword that is not custom and disabled. - (token, false) if self.engine.disabled_symbols.contains(token) => Token::LexError(LERR::ImproperSymbol( - format!("reserved symbol '{}' is disabled", token) - )), + (token, false) if self.engine.disabled_symbols.contains(token) => { + let msg = format!("reserved symbol '{}' is disabled", token); + Token::LexError(LERR::ImproperSymbol(s, msg)) + }, // Reserved keyword/operator that is not custom. (_, false) => Token::Reserved(s), }, pos)), diff --git a/tests/eval.rs b/tests/eval.rs index 7732bd25..568a5e5b 100644 --- a/tests/eval.rs +++ b/tests/eval.rs @@ -1,4 +1,4 @@ -use rhai::{Engine, EvalAltResult, Scope, INT}; +use rhai::{Engine, EvalAltResult, LexError, ParseErrorType, RegisterFn, Scope, INT}; #[test] fn test_eval() -> Result<(), Box> { @@ -98,10 +98,34 @@ fn test_eval_override() -> Result<(), Box> { fn eval(x) { x } // reflect the script back eval("40 + 2") - "# + "# )?, "40 + 2" ); + let mut engine = Engine::new(); + + // Reflect the script back + engine.register_fn("eval", |script: &str| script.to_string()); + + assert_eq!(engine.eval::(r#"eval("40 + 2")"#)?, "40 + 2"); + + Ok(()) +} + +#[test] +fn test_eval_disabled() -> Result<(), Box> { + let mut engine = Engine::new(); + + engine.disable_symbol("eval"); + + assert!(matches!( + *engine + .compile(r#"eval("40 + 2")"#) + .expect_err("should error") + .0, + ParseErrorType::BadInput(LexError::ImproperSymbol(err, _)) if err == "eval" + )); + Ok(()) } From eb4636f219a05bc590f9eed844363f47a252d37f Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 21 Nov 2020 15:15:14 +0800 Subject: [PATCH 04/12] Fix LexError::ImproperSymbol. --- src/serde_impl/de.rs | 2 +- tests/syntax.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/serde_impl/de.rs b/src/serde_impl/de.rs index b4e6786c..6d7fcfed 100644 --- a/src/serde_impl/de.rs +++ b/src/serde_impl/de.rs @@ -120,7 +120,7 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>( impl Error for Box { fn custom(err: T) -> Self { EvalAltResult::ErrorParsing( - ParseErrorType::BadInput(LexError::ImproperSymbol(err.to_string())), + ParseErrorType::BadInput(LexError::ImproperSymbol("".to_string(), err.to_string())), Position::NONE, ) .into() diff --git a/tests/syntax.rs b/tests/syntax.rs index 819931e6..526ebf92 100644 --- a/tests/syntax.rs +++ b/tests/syntax.rs @@ -79,6 +79,7 @@ fn test_custom_syntax() -> Result<(), Box> { .expect_err("should error") .0, ParseErrorType::BadInput(LexError::ImproperSymbol( + "!".to_string(), "Improper symbol for custom syntax at position #1: '!'".to_string() )) ); @@ -100,6 +101,7 @@ fn test_custom_syntax_raw() -> Result<(), Box> { s => Err(ParseError( Box::new(ParseErrorType::BadInput(LexError::ImproperSymbol( s.to_string(), + "".to_string(), ))), Position::NONE, )), @@ -128,7 +130,7 @@ 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, - ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string())) + ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string(), "".to_string())) ); Ok(()) From 97368da76244ac0efb94cd3641d14016035669e3 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 21 Nov 2020 15:44:17 +0800 Subject: [PATCH 05/12] Reserve begin/end. --- RELEASES.md | 2 +- doc/src/SUMMARY.md | 2 +- doc/src/appendix/keywords.md | 2 ++ doc/src/language/eval.md | 2 +- doc/src/language/keywords.md | 33 +++++++++++++++++---------------- doc/src/language/statements.md | 6 ++++-- src/token.rs | 13 ++++++------- 7 files changed, 32 insertions(+), 28 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index bae0c5ef..6fa1e36b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -19,7 +19,7 @@ Breaking changes ---------------- * `Module::set_fn`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`. -* `unless` is now a reserved keyword. +* `begin`, `end`, `unless` are now reserved keywords. * `EvalPackage` is removed in favor of `Engine::disable_symbol`. New features diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 73332147..e6a4da84 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -97,7 +97,7 @@ The Rhai Scripting Language 19. [Modules](language/modules/index.md) 1. [Export Variables, Functions and Sub-Modules](language/modules/export.md) 2. [Import Modules](language/modules/import.md) - 20. [Eval Statement](language/eval.md) + 20. [Eval Function](language/eval.md) 6. [Safety and Protection](safety/index.md) 1. [Checked Arithmetic](safety/checked.md) 2. [Sand-Boxing](safety/sandbox.md) diff --git a/doc/src/appendix/keywords.md b/doc/src/appendix/keywords.md index 0e542dcf..b11e8421 100644 --- a/doc/src/appendix/keywords.md +++ b/doc/src/appendix/keywords.md @@ -49,6 +49,8 @@ Reserved Keywords | --------- | --------------------- | | `var` | variable declaration | | `static` | variable declaration | +| `begin` | block scope | +| `end` | block scope | | `shared` | share value | | `each` | looping | | `then` | control flow | diff --git a/doc/src/language/eval.md b/doc/src/language/eval.md index 0b9eb8b0..7e9bdd4d 100644 --- a/doc/src/language/eval.md +++ b/doc/src/language/eval.md @@ -1,4 +1,4 @@ -`eval` Statement +`eval` Function =============== {{#include ../links.md}} diff --git a/doc/src/language/keywords.md b/doc/src/language/keywords.md index c7cd5f3a..53f3ca65 100644 --- a/doc/src/language/keywords.md +++ b/doc/src/language/keywords.md @@ -5,21 +5,22 @@ Keywords The following are reserved keywords in Rhai: -| Active keywords | Reserved keywords | Usage | Inactive under feature | -| ------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: | -| `true`, `false` | | boolean constants | | -| `let`, `const` | `var`, `static` | variable declarations | | -| `is_shared` | | shared values | [`no_closure`] | -| `if`, `else` | `then`, `goto`, `exit` | control flow | | -| | `switch`, `match`, `case` | matching | | -| `while`, `loop`, `for`, `in`, `continue`, `break` | `do`, `each` | looping | | -| `fn`, `private` | `public`, `new` | functions | [`no_function`] | -| `return` | | return values | | -| `throw`, `try`, `catch` | | throw/catch exceptions | | -| `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] | -| `Fn`, `call`, `curry` | | function pointers | | -| | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | | -| `type_of`, `print`, `debug`, `eval` | | special functions | | -| | `default`, `void`, `null`, `nil` | special values | | +| Active keywords | Reserved keywords | Usage | Inactive under feature | +| ---------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: | +| `true`, `false` | | constants | | +| `let`, `const` | `var`, `static` | variables | | +| | `begin`, `end` | block scopes | | +| `is_shared` | | shared values | [`no_closure`] | +| `if`, `else` | `then`, `unless`, `goto`, `exit` | control flow | | +| `switch` | `match`, `case` | switching and matching | | +| `do`, `while`, `loop`, `until`, `for`, `in`, `continue`, `break` | `each` | looping | | +| `fn`, `private` | `public`, `new` | functions | [`no_function`] | +| `return` | | return values | | +| `throw`, `try`, `catch` | | throw/catch exceptions | | +| `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] | +| `Fn`, `call`, `curry` | | function pointers | | +| | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | | +| `type_of`, `print`, `debug`, `eval` | | special functions | | +| | `default`, `void`, `null`, `nil` | special values | | Keywords cannot become the name of a [function] or [variable], even when they are disabled. diff --git a/doc/src/language/statements.md b/doc/src/language/statements.md index 450011c2..a4fad876 100644 --- a/doc/src/language/statements.md +++ b/doc/src/language/statements.md @@ -9,7 +9,7 @@ Terminated by '`;`' Statements are terminated by semicolons '`;`' and they are mandatory, except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted. -Semicolons can also be omitted if the statement contains a block itself +Semicolons can also be omitted if the statement ends with a block itself (e.g. the `if`, `while`, `for` and `loop` statements). ```rust @@ -35,6 +35,8 @@ Statement Expression A statement can be used anywhere where an expression is expected. These are called, for lack of a more creative name, "statement expressions." -The _last_ statement of a statement block is _always_ the block's return value when used as a statement. +The _last_ statement of a statement block is _always_ the block's return value when used as a statement, +_regardless_ of whether it is terminated by a semicolon or not. This is different from Rust where, +if the last statement is terminated by a semicolon, the block's return value is taken to be `()`. If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`]. diff --git a/src/token.rs b/src/token.rs index cd54059d..6cea048f 100644 --- a/src/token.rs +++ b/src/token.rs @@ -532,11 +532,10 @@ impl Token { "import" | "export" | "as" => Reserved(syntax.into()), "===" | "!==" | "->" | "<-" | ":=" | "::<" | "(*" | "*)" | "#" | "public" | "new" - | "use" | "module" | "package" | "var" | "static" | "shared" | "with" | "each" - | "then" | "goto" | "unless" | "exit" | "match" | "case" | "default" | "void" - | "null" | "nil" | "spawn" | "thread" | "go" | "sync" | "async" | "await" | "yield" => { - Reserved(syntax.into()) - } + | "use" | "module" | "package" | "var" | "static" | "begin" | "end" | "shared" + | "with" | "each" | "then" | "goto" | "unless" | "exit" | "match" | "case" + | "default" | "void" | "null" | "nil" | "spawn" | "thread" | "go" | "sync" + | "async" | "await" | "yield" => Reserved(syntax.into()), KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR @@ -1670,12 +1669,12 @@ impl<'a> Iterator for TokenIterator<'a, '_> { "'<-' is not a valid symbol. This is not Go! Should it be '<='?".to_string(), )), (":=", false) => Token::LexError(LERR::ImproperSymbol(s, - "':=' is not a valid assignment operator. This is not Go! Should it be simply '='?".to_string(), + "':=' is not a valid assignment operator. This is not Go or Pascal! Should it be simply '='?".to_string(), )), ("::<", false) => Token::LexError(LERR::ImproperSymbol(s, "'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(), )), - ("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol(s, + ("(*", false) | ("*)", false) | ("begin", false) | ("end", false) => Token::LexError(LERR::ImproperSymbol(s, "'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(), )), ("#", false) => Token::LexError(LERR::ImproperSymbol(s, From 254fd16e62bfdb50d4a0ff11aa6f83fa49c5853c Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 21 Nov 2020 17:39:43 +0800 Subject: [PATCH 06/12] Fix type sizes test. --- src/ast.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 5e71db1e..93e049a2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1154,8 +1154,8 @@ mod tests { assert_eq!(size_of::(), 32); assert_eq!(size_of::>(), 32); assert_eq!(size_of::(), 72); - assert_eq!(size_of::(), 32); + assert_eq!(size_of::(), 56); assert_eq!(size_of::(), 16); - assert_eq!(size_of::(), 64); + assert_eq!(size_of::(), 72); } } From e5c9ca23b55d0cccea4c0af06aed9a4241b66256 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 21 Nov 2020 22:18:32 +0800 Subject: [PATCH 07/12] Build index when creating a module. --- RELEASES.md | 1 + codegen/src/rhai_module.rs | 1 + codegen/src/test/module.rs | 43 ++++++++++++++++++++++++++++ doc/src/rust/modules/imp-resolver.md | 2 +- src/module/mod.rs | 27 ++++------------- src/module/resolvers/file.rs | 4 +-- src/packages/mod.rs | 1 + 7 files changed, 54 insertions(+), 25 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 6fa1e36b..700a792f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -19,6 +19,7 @@ Breaking changes ---------------- * `Module::set_fn`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`. +* `Module::get_sub_module_mut` is removed. * `begin`, `end`, `unless` are now reserved keywords. * `EvalPackage` is removed in favor of `Engine::disable_symbol`. diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 76d7648a..0d8cd0ba 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -162,6 +162,7 @@ pub(crate) fn generate_body( pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 56d3290c..7e0f7eb0 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -257,6 +257,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -291,6 +292,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -352,6 +354,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -413,6 +416,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -485,6 +489,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -577,6 +582,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -642,6 +648,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -714,6 +721,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -745,6 +753,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -778,6 +787,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -813,6 +823,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -848,6 +859,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -889,6 +901,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -945,6 +958,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -979,6 +993,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1041,6 +1056,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1103,6 +1119,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1168,6 +1185,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1209,6 +1227,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1253,6 +1272,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1294,6 +1314,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1337,6 +1358,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1399,6 +1421,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1463,6 +1486,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1528,6 +1552,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1597,6 +1622,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1663,6 +1689,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1733,6 +1760,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1802,6 +1830,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1874,6 +1903,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1888,6 +1918,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1928,6 +1959,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1944,6 +1976,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -1958,6 +1991,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2024,6 +2058,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2040,6 +2075,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2054,6 +2090,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2077,6 +2114,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2091,6 +2129,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2116,6 +2155,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2132,6 +2172,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2146,6 +2187,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] @@ -2167,6 +2209,7 @@ mod generate_tests { pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); + m.build_index(); m } #[allow(unused_mut)] diff --git a/doc/src/rust/modules/imp-resolver.md b/doc/src/rust/modules/imp-resolver.md index ff6b04d3..32a4361e 100644 --- a/doc/src/rust/modules/imp-resolver.md +++ b/doc/src/rust/modules/imp-resolver.md @@ -50,7 +50,7 @@ impl ModuleResolver for MyModuleResolver { // Return EvalAltResult::ErrorInModule upon loading error EvalAltResult::ErrorInModule(path.into(), Box::new(err), pos).into() )?; - my_module.build_index(); // index it + my_module.build_index(); // index it Rc::new(my_module) // make it shared } else { // Return EvalAltResult::ErrorModuleNotFound if the path is invalid diff --git a/src/module/mod.rs b/src/module/mod.rs index 4e548e14..6b2dc51c 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -2,9 +2,7 @@ use crate::ast::{FnAccess, IdentX}; use crate::dynamic::Variant; -use crate::fn_native::{ - shared_make_mut, shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync, -}; +use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync}; use crate::fn_register::by_value as cast_arg; use crate::stdlib::{ any::TypeId, @@ -399,23 +397,6 @@ impl Module { self.modules.get(name).map(|m| m.as_ref()) } - /// Get a mutable reference to a sub-module. - /// - /// # Example - /// - /// ``` - /// use rhai::Module; - /// - /// let mut module = Module::new(); - /// let sub_module = Module::new(); - /// module.set_sub_module("question", sub_module); - /// assert!(module.get_sub_module_mut("question").is_some()); - /// ``` - #[inline(always)] - pub fn get_sub_module_mut(&mut self, name: &str) -> Option<&mut Module> { - self.modules.get_mut(name).map(shared_make_mut) - } - /// Set a sub-module into the module. /// /// If there is an existing sub-module of the same name, it is replaced. @@ -1537,6 +1518,8 @@ impl Module { }); } + module.build_index(); + Ok(module) } @@ -1545,7 +1528,7 @@ impl Module { /// /// If the module is already indexed, this method has no effect. #[cfg(not(feature = "no_module"))] - pub fn build_index(&mut self) { + pub fn build_index(&mut self) -> &mut Self { // Collect a particular module. fn index_module<'a>( module: &'a Module, @@ -1645,6 +1628,8 @@ impl Module { self.all_type_iterators = type_iterators; self.indexed = true; } + + self } /// Does a type iterator exist in the entire module tree? diff --git a/src/module/resolvers/file.rs b/src/module/resolvers/file.rs index 17423536..c8146b3c 100644 --- a/src/module/resolvers/file.rs +++ b/src/module/resolvers/file.rs @@ -159,12 +159,10 @@ impl ModuleResolver for FileModuleResolver { _ => Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos)), })?; - let mut m = Module::eval_ast_as_new(scope, &ast, engine).map_err(|err| { + let m = Module::eval_ast_as_new(scope, &ast, engine).map_err(|err| { Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos)) })?; - m.build_index(); - module = Some(m.into()); module_ref = module.clone(); }; diff --git a/src/packages/mod.rs b/src/packages/mod.rs index a4c443ed..e9731ec2 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -131,6 +131,7 @@ macro_rules! def_package { pub fn new() -> Self { let mut module = $root::Module::new_with_capacity(1024); ::init(&mut module); + module.build_index(); Self(module.into()) } } From 739dce72e3d48f745dbcada03f7cff29a09b803b Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 22 Nov 2020 15:41:55 +0800 Subject: [PATCH 08/12] Move if_def_fn into CorePackage. --- doc/src/language/functions.md | 2 +- src/engine.rs | 2 -- src/fn_call.rs | 57 +++++++---------------------------- src/fn_native.rs | 4 +-- src/optimize.rs | 15 +++------ src/packages/pkg_core.rs | 27 ++++++++++++++++- src/packages/string_basic.rs | 4 +-- 7 files changed, 47 insertions(+), 64 deletions(-) diff --git a/doc/src/language/functions.md b/doc/src/language/functions.md index 362dc057..acb3e33c 100644 --- a/doc/src/language/functions.md +++ b/doc/src/language/functions.md @@ -104,7 +104,7 @@ This is similar to Rust and many other modern languages, such as JavaScript's `f `is_def_fn` ----------- -Use `is_def_fn` to detect if a function is defined (and therefore callable), based on its name +Use `is_def_fn` to detect if a Rhai function is defined (and therefore callable), based on its name and the number of parameters. ```rust diff --git a/src/engine.rs b/src/engine.rs index ac747dfb..647050a8 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -178,9 +178,7 @@ pub const KEYWORD_FN_PTR_CURRY: &str = "curry"; #[cfg(not(feature = "no_closure"))] pub const KEYWORD_IS_SHARED: &str = "is_shared"; pub const KEYWORD_IS_DEF_VAR: &str = "is_def_var"; -pub const KEYWORD_IS_DEF_FN: &str = "is_def_fn"; pub const KEYWORD_THIS: &str = "this"; -pub const FN_TO_STRING: &str = "to_string"; #[cfg(not(feature = "no_object"))] pub const FN_GET: &str = "get$"; #[cfg(not(feature = "no_object"))] diff --git a/src/fn_call.rs b/src/fn_call.rs index bbf40192..1c629bf2 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,8 +3,7 @@ use crate::ast::{Expr, Stmt}; use crate::engine::{ search_imports, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, - KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, - KEYWORD_PRINT, KEYWORD_TYPE_OF, + KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF, }; use crate::fn_native::FnCallArgs; use crate::module::NamespaceRef; @@ -419,7 +418,7 @@ impl Engine { #[inline] pub(crate) fn has_override_by_name_and_arguments( &self, - mods: &Imports, + mods: Option<&Imports>, lib: &[&Module], fn_name: &str, arg_types: impl AsRef<[TypeId]>, @@ -436,7 +435,7 @@ impl Engine { #[inline(always)] pub(crate) fn has_override( &self, - mods: &Imports, + mods: Option<&Imports>, lib: &[&Module], hash_fn: u64, hash_script: u64, @@ -454,8 +453,7 @@ impl Engine { || self.packages.contains_fn(hash_script) || self.packages.contains_fn(hash_fn) // Then check imported modules - || mods.contains_fn(hash_script) - || mods.contains_fn(hash_fn) + || mods.map(|m| m.contains_fn(hash_script) || m.contains_fn(hash_fn)).unwrap_or(false) } /// Perform an actual function call, native Rust or scripted, taking care of special functions. @@ -494,7 +492,7 @@ impl Engine { // type_of KEYWORD_TYPE_OF if args.len() == 1 - && !self.has_override(mods, lib, hash_fn, hash_script, pub_only) => + && !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) => { Ok(( self.map_type_name(args[0].type_name()).to_string().into(), @@ -506,7 +504,7 @@ impl Engine { // by a function pointer so it isn't caught at parse time. KEYWORD_FN_PTR | KEYWORD_EVAL if args.len() == 1 - && !self.has_override(mods, lib, hash_fn, hash_script, pub_only) => + && !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) => { EvalAltResult::ErrorRuntime( format!( @@ -521,7 +519,7 @@ impl Engine { // Script-like function found #[cfg(not(feature = "no_function"))] - _ if self.has_override(mods, lib, 0, hash_script, pub_only) => { + _ if self.has_override(Some(mods), lib, 0, hash_script, pub_only) => { // Get function let func = lib .iter() @@ -856,7 +854,7 @@ impl Engine { let hash_fn = calc_native_fn_hash(empty(), fn_name, once(TypeId::of::())); - if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) { + if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) { // Fn - only in function call style return self .eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)? @@ -912,7 +910,7 @@ impl Engine { if name == KEYWORD_FN_PTR_CALL && args_expr.len() >= 1 - && !self.has_override(mods, lib, 0, hash_script, pub_only) + && !self.has_override(Some(mods), lib, 0, hash_script, pub_only) { let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; @@ -942,7 +940,7 @@ impl Engine { if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 { let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::())); - if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) { + if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) { let var_name = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; let var_name = var_name.as_str().map_err(|err| { @@ -952,44 +950,11 @@ impl Engine { } } - // Handle is_def_fn() - if name == KEYWORD_IS_DEF_FN && args_expr.len() == 2 { - let hash_fn = calc_native_fn_hash( - empty(), - name, - [TypeId::of::(), TypeId::of::()] - .iter() - .cloned(), - ); - - if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) { - let fn_name = - self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; - let num_params = - self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[1], level)?; - - let fn_name = fn_name.as_str().map_err(|err| { - self.make_type_mismatch_err::(err, args_expr[0].position()) - })?; - let num_params = num_params.as_int().map_err(|err| { - self.make_type_mismatch_err::(err, args_expr[1].position()) - })?; - - return Ok(if num_params < 0 { - false - } else { - let hash = calc_script_fn_hash(empty(), fn_name, num_params as usize); - lib.iter().any(|&m| m.contains_fn(hash, false)) - } - .into()); - } - } - // Handle eval() if name == KEYWORD_EVAL && args_expr.len() == 1 { let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::())); - if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) { + if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) { // eval - only in function call style let prev_len = scope.len(); let script = diff --git a/src/fn_native.rs b/src/fn_native.rs index c29464f9..e605df82 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -49,8 +49,8 @@ pub type Locked = crate::stdlib::sync::RwLock; #[derive(Debug, Copy, Clone)] pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> { engine: &'e Engine, - mods: Option<&'a Imports>, - lib: &'m [&'pm Module], + pub(crate) mods: Option<&'a Imports>, + pub(crate) lib: &'m [&'pm Module], } impl<'e, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'a Imports, &'m M)> diff --git a/src/optimize.rs b/src/optimize.rs index 51fe2d2a..19ee51ce 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -1,10 +1,7 @@ //! Module implementing the AST optimizer. use crate::ast::{Expr, ScriptFnDef, Stmt}; -use crate::engine::{ - KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, - KEYWORD_TYPE_OF, -}; +use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF}; use crate::fn_call::run_builtin_binary_op; use crate::parser::map_dynamic_to_expr; use crate::stdlib::{ @@ -467,11 +464,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { fn optimize_expr(expr: &mut Expr, state: &mut State) { // These keywords are handled specially const DONT_EVAL_KEYWORDS: &[&str] = &[ - KEYWORD_PRINT, // side effects - KEYWORD_DEBUG, // side effects - KEYWORD_EVAL, // arbitrary scripts - KEYWORD_IS_DEF_FN, // functions collection is volatile - KEYWORD_IS_DEF_VAR, // variables scope is volatile + KEYWORD_PRINT, // side effects + KEYWORD_DEBUG, // side effects + KEYWORD_EVAL, // arbitrary scripts ]; match expr { @@ -650,7 +645,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect(); // Search for overloaded operators (can override built-in). - if !state.engine.has_override_by_name_and_arguments(&state.engine.global_sub_modules, state.lib, x.name.as_ref(), arg_types.as_ref(), false) { + if !state.engine.has_override_by_name_and_arguments(Some(&state.engine.global_sub_modules), state.lib, x.name.as_ref(), arg_types.as_ref(), false) { if let Some(result) = run_builtin_binary_op(x.name.as_ref(), &arg_values[0], &arg_values[1]) .ok().flatten() .and_then(|result| map_dynamic_to_expr(result, *pos)) diff --git a/src/packages/pkg_core.rs b/src/packages/pkg_core.rs index 284c5997..8335c126 100644 --- a/src/packages/pkg_core.rs +++ b/src/packages/pkg_core.rs @@ -4,9 +4,34 @@ use super::iter_basic::BasicIteratorPackage; use super::logic::LogicPackage; use super::string_basic::BasicStringPackage; -use crate::def_package; +use crate::fn_native::{CallableFunction, FnCallArgs}; +use crate::stdlib::{any::TypeId, iter::empty}; +use crate::{ + calc_script_fn_hash, def_package, FnAccess, FnNamespace, ImmutableString, NativeCallContext, + INT, +}; def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, { + #[cfg(not(feature = "no_function"))] + { + let f = |ctx: NativeCallContext, args: &mut FnCallArgs| { + let num_params = args[1].clone().cast::(); + let fn_name = args[0].as_str().unwrap(); + + Ok(if num_params < 0 { + false.into() + } else { + let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize); + ctx.engine().has_override(ctx.mods, ctx.lib, 0, hash_script, true).into() + }) + }; + + lib.set_fn("is_def_fn", FnNamespace::Global, FnAccess::Public, + Some(&["fn_name: &str", "num_params: INT"]), + &[TypeId::of::(), TypeId::of::()], + CallableFunction::from_method(Box::new(f))); + } + ArithmeticPackage::init(lib); LogicPackage::init(lib); BasicStringPackage::init(lib); diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 2db28c7a..80686547 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case)] -use crate::engine::{FN_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT}; +use crate::engine::{KEYWORD_DEBUG, KEYWORD_PRINT}; use crate::plugin::*; use crate::stdlib::{ fmt::{Debug, Display}, @@ -32,7 +32,7 @@ macro_rules! gen_functions { macro_rules! reg_print_functions { ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $( - set_exported_fn!($mod_name, FN_TO_STRING, $root::$arg_type::to_string_func); + set_exported_fn!($mod_name, "to_string", $root::$arg_type::to_string_func); set_exported_fn!($mod_name, KEYWORD_PRINT, $root::$arg_type::to_string_func); )* } } From 07fe132e1a0dfafa4d8940be2d6f10597f4d6c4f Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 22 Nov 2020 17:21:34 +0800 Subject: [PATCH 09/12] Add gen_fn_siguatures API. --- RELEASES.md | 16 ++- codegen/src/function.rs | 39 +++++-- codegen/src/lib.rs | 2 + codegen/src/rhai_module.rs | 24 +++-- codegen/src/test/function.rs | 45 ++++++++ codegen/src/test/module.rs | 193 +++++++++++++++++++++++++++++------ doc/src/appendix/keywords.md | 3 - examples/repl.rs | 13 +++ src/ast.rs | 2 +- src/engine.rs | 11 +- src/engine_api.rs | 25 ++++- src/fn_register.rs | 4 +- src/module/mod.rs | 65 +++++++++++- src/packages/iter_basic.rs | 12 ++- src/packages/mod.rs | 9 ++ src/plugin.rs | 3 + src/token.rs | 17 +-- 17 files changed, 400 insertions(+), 83 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 700a792f..3dcca24e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,9 @@ It also allows exposing selected module functions (usually methods) to the globa This is very convenient when encapsulating the API of a custom Rust type into a module while having methods and iterators registered on the custom type work normally. +A new `gen_fn_signatures` API enables enumerating the registered functions of an `Engine` for documentation purposes. +It also prepares the way for a future reflection API. + Bug fixes --------- @@ -19,6 +22,7 @@ Breaking changes ---------------- * `Module::set_fn`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`. +* `Module::set_fn` takes a further parameter with a list of parameter names and types, if any. * `Module::get_sub_module_mut` is removed. * `begin`, `end`, `unless` are now reserved keywords. * `EvalPackage` is removed in favor of `Engine::disable_symbol`. @@ -26,13 +30,15 @@ Breaking changes New features ------------ -* `switch` statement. -* `do ... while` and `do ... until` statement. -* `Engine::register_module` to register a module as a sub-module in the global namespace. -* `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace. +* New `switch` statement. +* New `do ... while` and `do ... until` statements. +* New `Engine::gen_fn_signatures`, `Module::gen_fn_signatures` and `PackagesCollection::gen_fn_signatures` to generate a list of signatures for functions registered. +* New `Engine::register_module` to register a module as a sub-module in the global namespace. +* New `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace. * `Module::set_fn_XXX_mut` can expose a module function to the global namespace. This is convenient when registering an API for a custom type. * `Module::set_getter_fn`, `Module::set_setter_fn`, `Module::set_indexer_get_fn`, `Module::set_indexer_set_fn` all expose the function to the global namespace by default. This is convenient when registering an API for a custom type. -* `#[rhai_fn(global)]` and `#[rhai_fn(internal)]` attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type. +* New `Module::update_fn_param_names` to update a module function's parameter names and types. +* New `#[rhai_fn(global)]` and `#[rhai_fn(internal)]` attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type. Enhancements ------------ diff --git a/codegen/src/function.rs b/codegen/src/function.rs index f1d18fcd..5f976fd9 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -12,7 +12,7 @@ use std::format; use std::borrow::Cow; -use quote::{quote, quote_spanned}; +use quote::{quote, quote_spanned, ToTokens}; use syn::{ parse::{Parse, ParseStream, Parser}, spanned::Spanned, @@ -83,6 +83,10 @@ pub(crate) fn flatten_type_groups(ty: &syn::Type) -> &syn::Type { } } +pub(crate) fn print_type(ty: &syn::Type) -> String { + ty.to_token_stream().to_string().replace("& ", "&") +} + #[derive(Debug, Default)] pub(crate) struct ExportedFnParams { pub name: Option>, @@ -576,6 +580,7 @@ impl ExportedFn { syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span()); let impl_block = self.generate_impl("Token"); let callable_block = self.generate_callable("Token"); + let input_names_block = self.generate_input_names("Token"); let input_types_block = self.generate_input_types("Token"); let dyn_result_fn_block = self.generate_dynamic_fn(); quote! { @@ -585,6 +590,7 @@ impl ExportedFn { struct Token(); #impl_block #callable_block + #input_names_block #input_types_block #dyn_result_fn_block } @@ -655,6 +661,19 @@ impl ExportedFn { } } + pub fn generate_input_names(&self, on_type_name: &str) -> proc_macro2::TokenStream { + let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span()); + let input_names_fn_name: syn::Ident = syn::Ident::new( + format!("{}_input_names", on_type_name.to_lowercase()).as_str(), + self.name().span(), + ); + quote! { + pub fn #input_names_fn_name() -> Box<[&'static str]> { + #token_name().input_names() + } + } + } + pub fn generate_input_types(&self, on_type_name: &str) -> proc_macro2::TokenStream { let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span()); let input_types_fn_name: syn::Ident = syn::Ident::new( @@ -680,6 +699,7 @@ impl ExportedFn { let mut unpack_stmts: Vec = Vec::new(); let mut unpack_exprs: Vec = Vec::new(); + let mut input_type_names: Vec = Vec::new(); let mut input_type_exprs: Vec = Vec::new(); let skip_first_arg; @@ -693,8 +713,9 @@ impl ExportedFn { let first_arg = self.arg_list().next().unwrap(); let var = syn::Ident::new("arg0", proc_macro2::Span::call_site()); match first_arg { - syn::FnArg::Typed(pattern) => { - let arg_type = match flatten_type_groups(pattern.ty.as_ref()) { + syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => { + let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty)); + let arg_type = match flatten_type_groups(ty.as_ref()) { syn::Type::Reference(syn::TypeReference { ref elem, .. }) => elem.as_ref(), p => p, }; @@ -706,6 +727,7 @@ impl ExportedFn { }) .unwrap(), ); + input_type_names.push(arg_name); input_type_exprs.push( syn::parse2::(quote_spanned!( arg_type.span()=> TypeId::of::<#arg_type>() @@ -731,9 +753,10 @@ impl ExportedFn { let is_string; let is_ref; match arg { - syn::FnArg::Typed(pattern) => { - let arg_type = pattern.ty.as_ref(); - let downcast_span = match flatten_type_groups(pattern.ty.as_ref()) { + syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => { + let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty)); + let arg_type = ty.as_ref(); + let downcast_span = match flatten_type_groups(arg_type) { syn::Type::Reference(syn::TypeReference { mutability: None, ref elem, @@ -767,6 +790,7 @@ impl ExportedFn { }) .unwrap(), ); + input_type_names.push(arg_name); if !is_string { input_type_exprs.push( syn::parse2::(quote_spanned!( @@ -837,6 +861,9 @@ impl ExportedFn { fn is_method_call(&self) -> bool { #is_method_call } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(#type_name()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec![#(#input_type_names),*].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![#(#input_type_exprs),*].into_boxed_slice() } diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 065a9461..38ee893a 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -340,6 +340,7 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream let gen_mod_path = crate::register::generated_module_path(&rust_modpath); let tokens = quote! { #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, + Some(#gen_mod_path::token_input_names().as_ref()), #gen_mod_path::token_input_types().as_ref(), #gen_mod_path::token_callable()); }; @@ -381,6 +382,7 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke let gen_mod_path = crate::register::generated_module_path(&rust_modpath); let tokens = quote! { #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, + Some(#gen_mod_path::token_input_names().as_ref()), #gen_mod_path::token_input_types().as_ref(), #gen_mod_path::token_callable()); }; diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 0d8cd0ba..129089b0 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -3,8 +3,9 @@ use std::collections::HashMap; use quote::{quote, ToTokens}; use crate::attrs::ExportScope; -use crate::function::flatten_type_groups; -use crate::function::{ExportedFn, FnNamespaceAccess, FnSpecialAccess}; +use crate::function::{ + flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, +}; use crate::module::Module; pub(crate) type ExportedConst = (String, Box, syn::Expr); @@ -82,6 +83,16 @@ pub(crate) fn generate_body( let reg_names = function.exported_names(); let mut namespace = FnNamespaceAccess::Internal; + let fn_input_names: Vec = function + .arg_list() + .map(|fnarg| match fnarg { + syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"), + syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => { + format!("{}: {}", pat.to_token_stream(), print_type(ty)) + } + }) + .collect(); + let fn_input_types: Vec = function .arg_list() .map(|fnarg| match fnarg { @@ -117,6 +128,7 @@ pub(crate) fn generate_body( }, t => t.clone(), }; + syn::parse2::(quote! { core::any::TypeId::of::<#arg_type>()}) .unwrap() @@ -138,7 +150,8 @@ pub(crate) fn generate_body( ); set_fn_stmts.push( syn::parse2::(quote! { - m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, &[#(#fn_input_types),*], + m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, + Some(&[#(#fn_input_names),*]), &[#(#fn_input_types),*], #fn_token_name().into()); }) .unwrap(), @@ -151,6 +164,7 @@ pub(crate) fn generate_body( }); gen_fn_tokens.push(function.generate_impl(&fn_token_name.to_string())); gen_fn_tokens.push(function.generate_callable(&fn_token_name.to_string())); + gen_fn_tokens.push(function.generate_input_names(&fn_token_name.to_string())); gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string())); } @@ -195,9 +209,7 @@ pub(crate) fn check_rename_collisions(fns: &Vec) -> Result<(), syn:: .fold(name.to_string(), |mut argstr, fnarg| { let type_string: String = match fnarg { syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"), - syn::FnArg::Typed(syn::PatType { ref ty, .. }) => { - ty.as_ref().to_token_stream().to_string() - } + syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty), }; argstr.push('.'); argstr.push_str(&type_string); diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 3cfdbf7b..c0e74229 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -286,6 +286,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { false } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(Token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec![].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } @@ -293,6 +296,9 @@ mod generate_tests { pub fn token_callable() -> CallableFunction { Token().into() } + pub fn token_input_names() -> Box<[&'static str]> { + Token().input_names() + } pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } @@ -328,6 +334,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { false } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(Token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: usize"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -335,6 +344,9 @@ mod generate_tests { pub fn token_callable() -> CallableFunction { Token().into() } + pub fn token_input_names() -> Box<[&'static str]> { + Token().input_names() + } pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } @@ -370,6 +382,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { false } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(Token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: usize"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -377,6 +392,9 @@ mod generate_tests { pub fn token_callable() -> CallableFunction { Token().into() } + pub fn token_input_names() -> Box<[&'static str]> { + Token().input_names() + } pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } @@ -414,6 +432,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { false } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(Token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec![].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } @@ -421,6 +442,9 @@ mod generate_tests { pub fn token_callable() -> CallableFunction { Token().into() } + pub fn token_input_names() -> Box<[&'static str]> { + Token().input_names() + } pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } @@ -452,6 +476,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { false } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(MyType()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: usize"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -485,6 +512,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { false } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(Token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: usize", "y: usize"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() @@ -493,6 +523,9 @@ mod generate_tests { pub fn token_callable() -> CallableFunction { Token().into() } + pub fn token_input_names() -> Box<[&'static str]> { + Token().input_names() + } pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } @@ -529,6 +562,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { true } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(Token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut usize", "y: usize"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() @@ -537,6 +573,9 @@ mod generate_tests { pub fn token_callable() -> CallableFunction { Token().into() } + pub fn token_input_names() -> Box<[&'static str]> { + Token().input_names() + } pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } @@ -573,6 +612,9 @@ mod generate_tests { fn is_method_call(&self) -> bool { false } fn is_variadic(&self) -> bool { false } fn clone_boxed(&self) -> Box { Box::new(Token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["message: &str"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -580,6 +622,9 @@ mod generate_tests { pub fn token_callable() -> CallableFunction { Token().into() } + pub fn token_input_names() -> Box<[&'static str]> { + Token().input_names() + } pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 7e0f7eb0..8afdf134 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -297,7 +297,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, &[], + m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[], get_mystic_number_token().into()); if flatten {} else {} } @@ -315,6 +315,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(get_mystic_number_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec![].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } @@ -322,6 +325,9 @@ mod generate_tests { pub fn get_mystic_number_token_callable() -> CallableFunction { get_mystic_number_token().into() } + pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> { + get_mystic_number_token().input_names() + } pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { get_mystic_number_token().input_types() } @@ -359,7 +365,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::()], add_one_to_token().into()); if flatten {} else {} } @@ -378,6 +384,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(add_one_to_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -385,6 +394,9 @@ mod generate_tests { pub fn add_one_to_token_callable() -> CallableFunction { add_one_to_token().into() } + pub fn add_one_to_token_input_names() -> Box<[&'static str]> { + add_one_to_token().input_names() + } pub fn add_one_to_token_input_types() -> Box<[TypeId]> { add_one_to_token().input_types() } @@ -421,7 +433,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::()], add_one_to_token().into()); if flatten {} else {} } @@ -440,6 +452,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(add_one_to_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -447,6 +462,9 @@ mod generate_tests { pub fn add_one_to_token_callable() -> CallableFunction { add_one_to_token().into() } + pub fn add_one_to_token_input_names() -> Box<[&'static str]> { + add_one_to_token().input_names() + } pub fn add_one_to_token_input_types() -> Box<[TypeId]> { add_one_to_token().input_types() } @@ -494,10 +512,10 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::()], add_one_to_token().into()); - m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], add_n_to_token().into()); if flatten {} else {} } @@ -516,6 +534,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(add_one_to_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -523,6 +544,9 @@ mod generate_tests { pub fn add_one_to_token_callable() -> CallableFunction { add_one_to_token().into() } + pub fn add_one_to_token_input_names() -> Box<[&'static str]> { + add_one_to_token().input_names() + } pub fn add_one_to_token_input_types() -> Box<[TypeId]> { add_one_to_token().input_types() } @@ -543,6 +567,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(add_n_to_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "y: INT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() @@ -551,6 +578,9 @@ mod generate_tests { pub fn add_n_to_token_callable() -> CallableFunction { add_n_to_token().into() } + pub fn add_n_to_token_input_names() -> Box<[&'static str]> { + add_n_to_token().input_names() + } pub fn add_n_to_token_input_types() -> Box<[TypeId]> { add_n_to_token().input_types() } @@ -587,8 +617,8 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], add_together_token().into()); if flatten {} else {} } @@ -608,6 +638,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(add_together_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "y: INT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() @@ -616,6 +649,9 @@ mod generate_tests { pub fn add_together_token_callable() -> CallableFunction { add_together_token().into() } + pub fn add_together_token_input_names() -> Box<[&'static str]> { + add_together_token().input_names() + } pub fn add_together_token_input_types() -> Box<[TypeId]> { add_together_token().input_types() } @@ -653,14 +689,14 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("add", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], add_together_token().into()); - m.set_fn("+", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("+", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], add_together_token().into()); - m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], add_together_token().into()); if flatten {} else {} } @@ -680,6 +716,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(add_together_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "y: INT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() @@ -688,6 +727,9 @@ mod generate_tests { pub fn add_together_token_callable() -> CallableFunction { add_together_token().into() } + pub fn add_together_token_input_names() -> Box<[&'static str]> { + add_together_token().input_names() + } pub fn add_together_token_input_types() -> Box<[TypeId]> { add_together_token().input_types() } @@ -906,7 +948,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, &[], + m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[], get_mystic_number_token().into()); if flatten {} else {} } @@ -924,6 +966,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(get_mystic_number_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec![].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } @@ -931,6 +976,9 @@ mod generate_tests { pub fn get_mystic_number_token_callable() -> CallableFunction { get_mystic_number_token().into() } + pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> { + get_mystic_number_token().input_names() + } pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { get_mystic_number_token().input_types() } @@ -999,7 +1047,7 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::()], + Some(&["x: &str"]), &[core::any::TypeId::of::()], print_out_to_token().into()); if flatten {} else {} } @@ -1018,6 +1066,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(print_out_to_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &str"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -1025,6 +1076,9 @@ mod generate_tests { pub fn print_out_to_token_callable() -> CallableFunction { print_out_to_token().into() } + pub fn print_out_to_token_input_names() -> Box<[&'static str]> { + print_out_to_token().input_names() + } pub fn print_out_to_token_input_types() -> Box<[TypeId]> { print_out_to_token().input_types() } @@ -1062,7 +1116,7 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::()], + Some(&["x: String"]), &[core::any::TypeId::of::()], print_out_to_token().into()); if flatten {} else {} } @@ -1081,6 +1135,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(print_out_to_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: String"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -1088,6 +1145,9 @@ mod generate_tests { pub fn print_out_to_token_callable() -> CallableFunction { print_out_to_token().into() } + pub fn print_out_to_token_input_names() -> Box<[&'static str]> { + print_out_to_token().input_names() + } pub fn print_out_to_token_input_types() -> Box<[TypeId]> { print_out_to_token().input_types() } @@ -1125,7 +1185,7 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::()], + Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::()], increment_token().into()); if flatten {} else {} } @@ -1144,6 +1204,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(increment_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -1151,6 +1214,9 @@ mod generate_tests { pub fn increment_token_callable() -> CallableFunction { increment_token().into() } + pub fn increment_token_input_names() -> Box<[&'static str]> { + increment_token().input_names() + } pub fn increment_token_input_types() -> Box<[TypeId]> { increment_token().input_types() } @@ -1191,7 +1257,7 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::()], + Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::()], increment_token().into()); if flatten {} else {} } @@ -1210,6 +1276,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(increment_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -1217,6 +1286,9 @@ mod generate_tests { pub fn increment_token_callable() -> CallableFunction { increment_token().into() } + pub fn increment_token_input_names() -> Box<[&'static str]> { + increment_token().input_names() + } pub fn increment_token_input_types() -> Box<[TypeId]> { increment_token().input_types() } @@ -1278,7 +1350,7 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::()], + Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::()], increment_token().into()); if flatten {} else {} } @@ -1297,6 +1369,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(increment_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -1304,6 +1379,9 @@ mod generate_tests { pub fn increment_token_callable() -> CallableFunction { increment_token().into() } + pub fn increment_token_input_names() -> Box<[&'static str]> { + increment_token().input_names() + } pub fn increment_token_input_types() -> Box<[TypeId]> { increment_token().input_types() } @@ -1363,7 +1441,7 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} } @@ -1382,6 +1460,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(int_foo_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -1389,6 +1470,9 @@ mod generate_tests { pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } + pub fn int_foo_token_input_names() -> Box<[&'static str]> { + int_foo_token().input_names() + } pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } @@ -1426,9 +1510,9 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::()], int_foo_token().into()); - m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} } @@ -1447,6 +1531,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(int_foo_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } @@ -1454,6 +1541,9 @@ mod generate_tests { pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } + pub fn int_foo_token_input_names() -> Box<[&'static str]> { + int_foo_token().input_names() + } pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } @@ -1491,9 +1581,8 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} } @@ -1513,6 +1602,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(int_foo_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64", "y: u64"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } @@ -1520,6 +1612,9 @@ mod generate_tests { pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } + pub fn int_foo_token_input_names() -> Box<[&'static str]> { + int_foo_token().input_names() + } pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } @@ -1557,13 +1652,11 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], int_foo_token().into()); - m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, - &[core::any::TypeId::of::(), - core::any::TypeId::of::()], + m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} } @@ -1583,6 +1676,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(int_foo_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64", "y: u64"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } @@ -1590,6 +1686,9 @@ mod generate_tests { pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } + pub fn int_foo_token_input_names() -> Box<[&'static str]> { + int_foo_token().input_names() + } pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } @@ -1628,6 +1727,7 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public, + Some(&["x: &mut MyCollection", "i: u64"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], get_by_index_token().into()); @@ -1649,6 +1749,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(get_by_index_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() @@ -1657,6 +1760,9 @@ mod generate_tests { pub fn get_by_index_token_callable() -> CallableFunction { get_by_index_token().into() } + pub fn get_by_index_token_input_names() -> Box<[&'static str]> { + get_by_index_token().input_names() + } pub fn get_by_index_token_input_types() -> Box<[TypeId]> { get_by_index_token().input_types() } @@ -1695,10 +1801,12 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("get", FnNamespace::Internal, FnAccess::Public, + Some(&["x: &mut MyCollection", "i: u64"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], get_by_index_token().into()); m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public, + Some(&["x: &mut MyCollection", "i: u64"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], get_by_index_token().into()); @@ -1720,6 +1828,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(get_by_index_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() @@ -1728,6 +1839,9 @@ mod generate_tests { pub fn get_by_index_token_callable() -> CallableFunction { get_by_index_token().into() } + pub fn get_by_index_token_input_names() -> Box<[&'static str]> { + get_by_index_token().input_names() + } pub fn get_by_index_token_input_types() -> Box<[TypeId]> { get_by_index_token().input_types() } @@ -1766,6 +1880,7 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public, + Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]), &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], @@ -1789,6 +1904,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(set_by_index_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::(), @@ -1798,6 +1916,9 @@ mod generate_tests { pub fn set_by_index_token_callable() -> CallableFunction { set_by_index_token().into() } + pub fn set_by_index_token_input_names() -> Box<[&'static str]> { + set_by_index_token().input_names() + } pub fn set_by_index_token_input_types() -> Box<[TypeId]> { set_by_index_token().input_types() } @@ -1836,11 +1957,13 @@ mod generate_tests { #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn("set", FnNamespace::Internal, FnAccess::Public, + Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]), &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], set_by_index_token().into()); m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public, + Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]), &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], @@ -1864,6 +1987,9 @@ mod generate_tests { fn clone_boxed(&self) -> Box { Box::new(set_by_index_token()) } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice() + } fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::(), @@ -1873,6 +1999,9 @@ mod generate_tests { pub fn set_by_index_token_callable() -> CallableFunction { set_by_index_token().into() } + pub fn set_by_index_token_input_names() -> Box<[&'static str]> { + set_by_index_token().input_names() + } pub fn set_by_index_token_input_types() -> Box<[TypeId]> { set_by_index_token().input_types() } diff --git a/doc/src/appendix/keywords.md b/doc/src/appendix/keywords.md index b11e8421..2866cb5d 100644 --- a/doc/src/appendix/keywords.md +++ b/doc/src/appendix/keywords.md @@ -9,8 +9,6 @@ Keywords List | `false` | boolean false literal | | no | | | `let` | variable declaration | | no | | | `const` | constant declaration | | no | | -| `is_def_var` | is a variable declared? | | yes | yes | -| `is_shared` | is a value shared? | [`no_closure`] | yes | no | | `if` | if statement | | no | | | `else` | else block of if statement | | no | | | `switch` | matching | | no | | @@ -35,7 +33,6 @@ Keywords List | `call` | call a [function pointer] | | yes | no | | `curry` | curry a [function pointer] | | yes | no | | `this` | reference to base object for method call | [`no_function`] | no | | -| `is_def_fn` | is a scripted function defined? | [`no_function`] | yes | yes | | `type_of` | get type name of value | | yes | yes | | `print` | print value | | yes | yes | | `debug` | print value in debug format | | yes | yes | diff --git a/examples/repl.rs b/examples/repl.rs index bd0691ef..24be5392 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -42,6 +42,7 @@ fn print_help() { println!("help => print this help"); println!("quit, exit => quit"); println!("scope => print all variables in the scope"); + println!("functions => print all functions defined"); println!("ast => print the last AST"); println!("astu => print the last raw, un-optimized AST"); println!(r"end a line with '\' to continue to the next line."); @@ -133,6 +134,18 @@ fn main() { println!("{:#?}\n", &ast); continue; } + "functions" => { + // print a list of all registered functions + engine + .gen_fn_signatures(false) + .into_iter() + .for_each(|f| println!("{}", f)); + main_ast + .iter_functions() + .for_each(|(_, _, _, _, f)| println!("{}", f)); + println!(); + continue; + } _ => (), } diff --git a/src/ast.rs b/src/ast.rs index 93e049a2..e89fa446 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -100,7 +100,7 @@ impl fmt::Display for ScriptFnDef { .iter() .map(|s| s.as_str()) .collect::>() - .join(",") + .join(", ") ) } } diff --git a/src/engine.rs b/src/engine.rs index 647050a8..1a8afa66 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -95,24 +95,25 @@ impl Imports { self.0.as_mut().unwrap().truncate(size); } } - /// Get an iterator to this stack of imported modules. + /// Get an iterator to this stack of imported modules in reverse order. #[allow(dead_code)] pub fn iter(&self) -> impl Iterator)> { self.0.iter().flat_map(|lib| { lib.iter() + .rev() .map(|(name, module)| (name.as_str(), module.clone())) }) } - /// Get an iterator to this stack of imported modules. + /// Get an iterator to this stack of imported modules in reverse order. #[allow(dead_code)] pub(crate) fn iter_raw<'a>( &'a self, ) -> impl Iterator)> + 'a { - self.0.iter().flat_map(|lib| lib.iter().cloned()) + self.0.iter().flat_map(|lib| lib.iter().rev().cloned()) } - /// Get a consuming iterator to this stack of imported modules. + /// Get a consuming iterator to this stack of imported modules in reverse order. pub fn into_iter(self) -> impl Iterator)> { - self.0.into_iter().flat_map(|lib| lib.into_iter()) + self.0.into_iter().flat_map(|lib| lib.into_iter().rev()) } /// Add a stream of imported modules. pub fn extend(&mut self, stream: impl Iterator)>) { diff --git a/src/engine_api.rs b/src/engine_api.rs index f005071e..0d7023f6 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -1515,7 +1515,7 @@ impl Engine { .into() }); } - /// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments + /// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments /// and optionally a value for binding to the `this` pointer. /// /// ## WARNING @@ -1578,7 +1578,7 @@ impl Engine { self.call_fn_dynamic_raw(scope, &[lib.as_ref()], name, &mut this_ptr, args.as_mut()) } - /// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments. + /// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments. /// /// ## WARNING /// @@ -1646,6 +1646,27 @@ impl Engine { let stmt = crate::stdlib::mem::take(ast.statements_mut()); crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level) } + /// Generate a list of all registered functions. + /// + /// The ordering is: + /// 1) Functions registered into the global namespace + /// 2) Functions in registered sub-modules + /// 3) Functions in packages + pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec { + let mut signatures: Vec<_> = Default::default(); + + signatures.extend(self.global_namespace.gen_fn_signatures()); + + self.global_sub_modules.iter().for_each(|(name, m)| { + signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f))) + }); + + if include_packages { + signatures.extend(self.packages.gen_fn_signatures()); + } + + signatures + } /// Provide a callback that will be invoked before each variable access. /// /// ## Return Value of Callback diff --git a/src/fn_register.rs b/src/fn_register.rs index afc87194..3a6db5f8 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -187,7 +187,7 @@ macro_rules! def_register { { #[inline] fn register_fn(&mut self, name: &str, f: FN) -> &mut Self { - self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, + self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None, &[$(map_type_id::<$par>()),*], CallableFunction::$abi(make_func!(f : map_dynamic ; $($par => $let => $clone => $arg),*)) ); @@ -202,7 +202,7 @@ macro_rules! def_register { { #[inline] fn register_result_fn(&mut self, name: &str, f: FN) -> &mut Self { - self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, + self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None, &[$(map_type_id::<$par>()),*], CallableFunction::$abi(make_func!(f : map_result ; $($par => $let => $clone => $arg),*)) ); diff --git a/src/module/mod.rs b/src/module/mod.rs index 6b2dc51c..924f383f 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -79,7 +79,31 @@ pub struct FuncInfo { /// Number of parameters. pub params: usize, /// Parameter types (if applicable). - pub types: Option>, + pub param_types: Option>, + /// Parameter names (if available). + pub param_names: Option>, +} + +impl FuncInfo { + /// Generate a signature of the function. + pub fn gen_signature(&self) -> String { + let mut sig = format!("{}(", self.name); + + if let Some(ref names) = self.param_names { + let params: Vec<_> = names.iter().map(ImmutableString::to_string).collect(); + sig.push_str(¶ms.join(", ")); + } else { + for x in 0..self.params { + sig.push_str("_"); + if x < self.params - 1 { + sig.push_str(", "); + } + } + } + + sig.push_str(")"); + sig + } } /// A module which may contain variables, sub-modules, external Rust functions, @@ -230,6 +254,14 @@ impl Module { self.indexed } + /// Generate signatures for all the functions in the module. + pub fn gen_fn_signatures<'a>(&'a self) -> impl Iterator + 'a { + self.functions + .values() + .filter(|FuncInfo { access, .. }| !access.is_private()) + .map(FuncInfo::gen_signature) + } + /// Does a variable exist in the module? /// /// # Example @@ -329,7 +361,8 @@ impl Module { namespace: FnNamespace::Internal, access: fn_def.access, params: num_params, - types: None, + param_types: None, + param_names: Some(fn_def.params.clone()), func: fn_def.into(), }, ); @@ -450,6 +483,17 @@ impl Module { } } + /// Update the parameter names and types in a registered function. + /// + /// The [`u64`] hash is calculated either by the function [`crate::calc_native_fn_hash`] or + /// the function [`crate::calc_script_fn_hash`]. + pub fn update_fn_param_names(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self { + if let Some(f) = self.functions.get_mut(&hash_fn) { + f.param_names = Some(arg_names.iter().map(|&n| n.into()).collect()); + } + self + } + /// Set a Rust function into the module, returning a hash key. /// /// If there is an existing Rust function of the same hash, it is replaced. @@ -462,6 +506,7 @@ impl Module { name: impl Into, namespace: FnNamespace, access: FnAccess, + arg_names: Option<&[&str]>, arg_types: &[TypeId], func: CallableFunction, ) -> u64 { @@ -488,7 +533,8 @@ impl Module { namespace, access, params: params.len(), - types: Some(params), + param_types: Some(params), + param_names: arg_names.map(|p| p.iter().map(|&v| v.into()).collect()), func: func.into(), }, ); @@ -576,6 +622,7 @@ impl Module { name, namespace, access, + None, arg_types, CallableFunction::from_method(Box::new(f)), ) @@ -606,6 +653,7 @@ impl Module { name, FnNamespace::Internal, FnAccess::Public, + None, &arg_types, CallableFunction::from_pure(Box::new(f)), ) @@ -638,6 +686,7 @@ impl Module { name, FnNamespace::Internal, FnAccess::Public, + None, &arg_types, CallableFunction::from_pure(Box::new(f)), ) @@ -673,6 +722,7 @@ impl Module { name, namespace, FnAccess::Public, + None, &arg_types, CallableFunction::from_method(Box::new(f)), ) @@ -738,6 +788,7 @@ impl Module { name, FnNamespace::Internal, FnAccess::Public, + None, &arg_types, CallableFunction::from_pure(Box::new(f)), ) @@ -780,6 +831,7 @@ impl Module { name, namespace, FnAccess::Public, + None, &arg_types, CallableFunction::from_method(Box::new(f)), ) @@ -900,6 +952,7 @@ impl Module { name, FnNamespace::Internal, FnAccess::Public, + None, &arg_types, CallableFunction::from_pure(Box::new(f)), ) @@ -948,6 +1001,7 @@ impl Module { name, namespace, FnAccess::Public, + None, &arg_types, CallableFunction::from_method(Box::new(f)), ) @@ -1008,6 +1062,7 @@ impl Module { crate::engine::FN_IDX_SET, FnNamespace::Internal, FnAccess::Public, + None, &arg_types, CallableFunction::from_method(Box::new(f)), ) @@ -1100,6 +1155,7 @@ impl Module { name, FnNamespace::Internal, FnAccess::Public, + None, &arg_types, CallableFunction::from_pure(Box::new(f)), ) @@ -1155,6 +1211,7 @@ impl Module { name, namespace, FnAccess::Public, + None, &arg_types, CallableFunction::from_method(Box::new(f)), ) @@ -1569,7 +1626,7 @@ impl Module { name, namespace, params, - types, + param_types: types, func, .. }, diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index c336707f..97ff0f59 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -48,7 +48,8 @@ macro_rules! reg_range { ($lib:expr, $x:expr, $( $y:ty ),*) => ( $( $lib.set_iterator::>(); - $lib.set_fn_2($x, get_range::<$y>); + let hash = $lib.set_fn_2($x, get_range::<$y>); + $lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y))]); )* ) } @@ -59,14 +60,16 @@ macro_rules! reg_step { ($lib:expr, $x:expr, $( $y:ty ),*) => ( $( $lib.set_iterator::>(); - $lib.set_fn_3($x, get_step_range::<$y>); + let hash = $lib.set_fn_3($x, get_step_range::<$y>); + $lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), concat!("step: ", stringify!($y))]); )* ) } def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { lib.set_iterator::>(); - lib.set_fn_2("range", get_range::); + let hash = lib.set_fn_2("range", get_range::); + lib.update_fn_param_names(hash, &["from: INT", "to: INT"]); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] @@ -79,7 +82,8 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { } lib.set_iterator::>(); - lib.set_fn_3("range", get_step_range::); + let hash = lib.set_fn_3("range", get_step_range::); + lib.update_fn_param_names(hash, &["from: INT", "to: INT", "step: INT"]); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] diff --git a/src/packages/mod.rs b/src/packages/mod.rs index e9731ec2..3b6669c7 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -87,6 +87,15 @@ impl PackagesCollection { .as_ref() .and_then(|x| x.iter().find_map(|p| p.get_iter(id))) } + /// Get an iterator over all the packages in the [`PackagesCollection`]. + pub(crate) fn iter(&self) -> impl Iterator { + self.0.iter().flat_map(|p| p.iter()) + } + + /// Generate signatures for all the functions in the [`PackagesCollection`]. + pub fn gen_fn_signatures<'a>(&'a self) -> impl Iterator + 'a { + self.iter().flat_map(|m| m.gen_fn_signatures()) + } } /// Macro that makes it easy to define a _package_ (which is basically a shared module) diff --git a/src/plugin.rs b/src/plugin.rs index 66783bbd..91385628 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -33,6 +33,9 @@ pub trait PluginFunction { /// Convert a plugin function into a boxed trait object. fn clone_boxed(&self) -> Box; + /// Return a boxed slice of the names of the function's parameters. + fn input_names(&self) -> Box<[&'static str]>; + /// Return a boxed slice of type ID's of the function's parameters. fn input_types(&self) -> Box<[TypeId]>; } diff --git a/src/token.rs b/src/token.rs index 6cea048f..aad19ef2 100644 --- a/src/token.rs +++ b/src/token.rs @@ -2,7 +2,7 @@ use crate::engine::{ KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, - KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF, + KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF, }; use crate::stdlib::{ borrow::Cow, @@ -538,11 +538,7 @@ impl Token { | "async" | "await" | "yield" => Reserved(syntax.into()), KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR - | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR - | KEYWORD_IS_DEF_FN | KEYWORD_THIS => Reserved(syntax.into()), - - #[cfg(not(feature = "no_closure"))] - crate::engine::KEYWORD_IS_SHARED => Reserved(syntax.into()), + | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_THIS => Reserved(syntax.into()), _ => return None, }) @@ -1513,12 +1509,8 @@ fn get_identifier( #[inline(always)] pub fn is_keyword_function(name: &str) -> bool { match name { - #[cfg(not(feature = "no_closure"))] - crate::engine::KEYWORD_IS_SHARED => true, KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR - | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR | KEYWORD_IS_DEF_FN => { - true - } + | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY => true, _ => false, } } @@ -1528,8 +1520,7 @@ pub fn is_keyword_function(name: &str) -> bool { #[inline(always)] pub fn can_override_keyword(name: &str) -> bool { match name { - KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR - | KEYWORD_IS_DEF_VAR | KEYWORD_IS_DEF_FN => true, + KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR => true, _ => false, } } From 9edd494000ba6580e7a363404217570a079d1a38 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 22 Nov 2020 17:32:10 +0800 Subject: [PATCH 10/12] Fix builds. --- examples/repl.rs | 3 +++ src/module/mod.rs | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/repl.rs b/examples/repl.rs index 24be5392..d5ca863f 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -140,9 +140,12 @@ fn main() { .gen_fn_signatures(false) .into_iter() .for_each(|f| println!("{}", f)); + + #[cfg(not(feature = "no_functions"))] main_ast .iter_functions() .for_each(|(_, _, _, _, f)| println!("{}", f)); + println!(); continue; } diff --git a/src/module/mod.rs b/src/module/mod.rs index 924f383f..c4d5147b 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1584,7 +1584,6 @@ impl Module { /// variables and functions as one flattened namespace. /// /// If the module is already indexed, this method has no effect. - #[cfg(not(feature = "no_module"))] pub fn build_index(&mut self) -> &mut Self { // Collect a particular module. fn index_module<'a>( From d3f38941268bc1d36e542328d6e22dadf464cc18 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 22 Nov 2020 17:35:33 +0800 Subject: [PATCH 11/12] Fix typo. --- examples/repl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/repl.rs b/examples/repl.rs index d5ca863f..fe7c4bc5 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -141,7 +141,7 @@ fn main() { .into_iter() .for_each(|f| println!("{}", f)); - #[cfg(not(feature = "no_functions"))] + #[cfg(not(feature = "no_function"))] main_ast .iter_functions() .for_each(|(_, _, _, _, f)| println!("{}", f)); From 6222f14fcb7db40034524da11d6a3f0851f268d5 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 22 Nov 2020 17:49:00 +0800 Subject: [PATCH 12/12] Fix no-std build. --- src/engine_api.rs | 2 ++ src/packages/mod.rs | 2 +- src/packages/pkg_core.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine_api.rs b/src/engine_api.rs index 0d7023f6..b801a33c 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -7,8 +7,10 @@ use crate::optimize::OptimizationLevel; use crate::stdlib::{ any::{type_name, TypeId}, boxed::Box, + format, hash::{Hash, Hasher}, string::String, + vec::Vec, }; use crate::utils::get_hasher; use crate::{ diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 3b6669c7..bc764554 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -1,7 +1,7 @@ //! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages. use crate::fn_native::{CallableFunction, IteratorFn}; -use crate::stdlib::any::TypeId; +use crate::stdlib::{any::TypeId, string::String}; use crate::{Module, Shared, StaticVec}; pub(crate) mod arithmetic; diff --git a/src/packages/pkg_core.rs b/src/packages/pkg_core.rs index 8335c126..7480fdd1 100644 --- a/src/packages/pkg_core.rs +++ b/src/packages/pkg_core.rs @@ -5,7 +5,7 @@ use super::logic::LogicPackage; use super::string_basic::BasicStringPackage; use crate::fn_native::{CallableFunction, FnCallArgs}; -use crate::stdlib::{any::TypeId, iter::empty}; +use crate::stdlib::{any::TypeId, boxed::Box, iter::empty}; use crate::{ calc_script_fn_hash, def_package, FnAccess, FnNamespace, ImmutableString, NativeCallContext, INT,