From 4add90b2155ef066501b06dce8410c2777b878bd Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 27 Oct 2020 09:56:37 +0800 Subject: [PATCH] Change parser output to String. --- doc/src/engine/custom-syntax.md | 48 +++++++++++++++++---------------- doc/src/engine/var.md | 34 +++++++++++------------ doc/src/rust/register-raw.md | 35 ++++++++++++------------ src/syntax.rs | 10 +++---- 4 files changed, 63 insertions(+), 64 deletions(-) diff --git a/doc/src/engine/custom-syntax.md b/doc/src/engine/custom-syntax.md index 081b0bb6..61cfae84 100644 --- a/doc/src/engine/custom-syntax.md +++ b/doc/src/engine/custom-syntax.md @@ -116,16 +116,19 @@ The function signature of an implementation is: where: -* `context: &mut EvalContext` - mutable reference to the current evaluation _context_, exposing the following: - * `context.scope: &mut Scope` - mutable reference to the current [`Scope`]; variables can be added to/removed from it. - * `context.engine(): &Engine` - reference to the current [`Engine`]. - * `context.iter_namespaces(): impl Iterator` - iterator of the namespaces (as [modules]) containing all script-defined functions. - * `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any. - * `context.call_level(): usize` - the current nesting level of function calls. +| Parameter | Type | Description | +| ----------------------------- | :-----------------------------: | ------------------------------------------------------------------------------------- | +| `context` | `&mut EvalContext` | mutable reference to the current evaluation _context_ | +| - `context.scope` | `&mut Scope` | mutable reference to the current [`Scope`]; variables can be added to/removed from it | +| - `context.engine()` | `&Engine` | reference to the current [`Engine`] | +| - `context.iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | +| - `context.this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any | +| - `context.call_level()` | `usize` | the current nesting level of function calls | +| `inputs` | `&[Expression]` | a list of input expression trees | -* `inputs: &[Expression]` - a list of input expression trees. +### Return Value -* Return value - result of evaluating the custom syntax expression. +Return value is the result of evaluating the custom syntax expression. ### Access Arguments @@ -283,12 +286,12 @@ engine.register_custom_syntax_raw( "perform", |stream| match stream.len() { // perform ... - 1 => Ok(Some("$ident$".into())), + 1 => Ok(Some("$ident$".to_string())), // perform command ... 2 => match stream[1].as_str() { - "action" => Ok(Some("$expr$".into())), - "hello" => Ok(Some("world".into())), - "update" | "check" | "add" | "remove" => Ok(Some("$ident$".into())), + "action" => Ok(Some("$expr$".to_string())), + "hello" => Ok(Some("world".to_string())), + "update" | "check" | "add" | "remove" => Ok(Some("$ident$".to_string())), "cleanup" => Ok(None), cmd => Err(ParseError(Box::new(ParseErrorType::BadInput( format!("Improper command: {}", cmd))), @@ -320,21 +323,20 @@ engine.register_custom_syntax_raw( The custom syntax parser has the following signature: -> `Fn(stream: &[String]) -> Result, ParseError>` +> `Fn(stream: &[String]) -> Result, ParseError>` where: -* `stream: &[String]` - a slice of symbols that have been parsed so far, perhaps containing the following: - * `$expr$` - an expression - * `$block$` - a statement block +| Parameter | Type | Description | +| --------- | :---------: | -------------------------------------------------------------------------------------------------- | +| `stream` | `&[String]` | a slice of symbols that have been parsed so far, possibly containing `"$expr$"` and/or `"$block$"` | ### Return Value -The return value is `Result, ParseError>` where: +The return value is `Result, ParseError>` where: -* `Ok(None)` - parsing complete and there are no more symbols to match. - -* `Ok(Some(symbol))` - next symbol to match. - -* `Err(ParseError)` - error is reflected back to the [`Engine`]. - Normally this is `ParseErrorType::BadInput` to indicate that there is a syntax error, but it can be any error. +| Value | Description | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Ok(None)` | parsing complete and there are no more symbols to match | +| `Ok(Some(symbol))` | next symbol to match, which can also be `"$expr$"`, `"$ident$"` or `"$block$"` | +| `Err(ParseError)` | error that is reflected back to the [`Engine`].
Normally this is `ParseError(ParseErrorType::BadInput(message), Position::none())` to indicate that there is a syntax error, but it can be any `ParseError`. | diff --git a/doc/src/engine/var.md b/doc/src/engine/var.md index 85267783..dd661f8b 100644 --- a/doc/src/engine/var.md +++ b/doc/src/engine/var.md @@ -67,27 +67,23 @@ The function signature passed to `Engine::on_var` takes the following form: where: -* `name: &str` - variable name. - -* `index: usize` - an offset from the bottom of the current [`Scope`] that the variable is supposed to reside. - Offsets start from 1, with 1 meaning the last variable in the current [`Scope`]. Essentially the correct variable is at position `scope.len() - index`. - - If `index` is zero, then there is no pre-calculated offset position and a search through the current [`Scope`] must be performed. - -* `context: &EvalContext` - reference to the current evaluation _context_, which exposes the following fields: - * `context.scope: &Scope` - reference to the current [`Scope`] containing all variables up to the current evaluation position. - * `context.engine(): &Engine` - reference to the current [`Engine`]. - * `context.iter_namespaces(): impl Iterator` - iterator of the namespaces (as [modules]) containing all script-defined functions. - * `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any. - * `context.call_level(): usize` - the current nesting level of function calls. +| Parameter | Type | Description | +| ----------------------------- | :-----------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | `&str` | variable name | +| `index` | `usize` | an offset from the bottom of the current [`Scope`] that the variable is supposed to reside.
Offsets start from 1, with 1 meaning the last variable in the current [`Scope`]. Essentially the correct variable is at position `scope.len() - index`.
If `index` is zero, then there is no pre-calculated offset position and a search through the current [`Scope`] must be performed. | +| `context` | `&EvalContext` | reference to the current evaluation _context_ | +| - `context.scope` | `&Scope` | reference to the current [`Scope`] containing all variables up to the current evaluation position | +| - `context.engine()` | `&Engine` | reference to the current [`Engine`] | +| - `context.iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | +| - `context.this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any | +| - `context.call_level()` | `usize` | the current nesting level of function calls | ### Return Value The return value is `Result, Box>` where: -* `Ok(None)` - normal variable resolution process should continue, meaning to continue searching through the [`Scope`]. - -* `Ok(Some(Dynamic))` - wrapped [`Dynamic`] is taken as the value of the variable, which is treated as a constant. - -* `Err(Box)` - error is reflected back to the [`Engine`]. - Normally this is `EvalAltResult::ErrorVariableNotFound` to indicate that the variable does not exist, but it can be any error. +| Value | Description | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `Ok(None)` | normal variable resolution process should continue, i.e. continue searching through the [`Scope`] | +| `Ok(Some(Dynamic))` | value of the variable, treated as a constant | +| `Err(Box)` | error that is reflected back to the [`Engine`].
Normally this is `EvalAltResult::ErrorVariableNotFound(var_name, Position::none())` to indicate that the variable does not exist, but it can be any `EvalAltResult`. | diff --git a/doc/src/rust/register-raw.md b/doc/src/rust/register-raw.md index 694e6612..38f9b4b1 100644 --- a/doc/src/rust/register-raw.md +++ b/doc/src/rust/register-raw.md @@ -65,18 +65,17 @@ The function signature passed to `Engine::register_raw_fn` takes the following f where: -* `T: Clone` - return type of the function. +| Parameter | Type | Description | +| ----------------------------- | :-----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `T` | `impl Clone` | return type of the function | +| `context` | `NativeCallContext` | the current _native call context_ | +| - `context.engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. | +| - `context.iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | +| `args` | `&mut [&mut Dynamic]` | a slice containing `&mut` references to [`Dynamic`] values.
The slice is guaranteed to contain enough arguments _of the correct types_. | -* `context: NativeCallContext` - the current _native call context_, which exposes the following: +### Return value - * `context.engine(): &Engine` - the current [`Engine`], with all configurations and settings. - This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. - * `context.iter_namespaces(): impl Iterator` - iterator of the namespaces (as [modules]) containing all script-defined functions. - -* `args: &mut [&mut Dynamic]` - a slice containing `&mut` references to [`Dynamic`] values. - The slice is guaranteed to contain enough arguments _of the correct types_. - -* Return value - result of the function call. +The return value is the result of the function call. Remember, in Rhai, all arguments _except_ the _first_ one are always passed by _value_ (i.e. cloned). Therefore, it is unnecessary to ever mutate any argument except the first one, as all mutations @@ -118,16 +117,16 @@ let mut engine = Engine::new(); engine.register_raw_fn( "bar", &[ - std::any::TypeId::of::(), // parameter types + std::any::TypeId::of::(), // parameter types std::any::TypeId::of::(), std::any::TypeId::of::(), ], |context, args| { // 'args' is guaranteed to contain enough arguments of the correct types - let fp = std::mem::take(args[1]).cast::(); // 2nd argument - function pointer - let value = args[2].clone(); // 3rd argument - function argument - let this_ptr = args.get_mut(0).unwrap(); // 1st argument - this pointer + let fp = std::mem::take(args[1]).cast::(); // 2nd argument - function pointer + let value = args[2].clone(); // 3rd argument - function argument + let this_ptr = args.get_mut(0).unwrap(); // 1st argument - this pointer // Use 'FnPtr::call_dynamic' to call the function pointer. // Beware, private script-defined functions will not be found. @@ -135,13 +134,14 @@ engine.register_raw_fn( }, ); -let result = engine.eval::(r#" +let result = engine.eval::( + r#" fn foo(x) { this += x; } // script-defined function 'foo' let x = 41; // object x.bar(Fn("foo"), 1); // pass 'foo' as function pointer x -"#)?; + "#)?; ``` @@ -158,7 +158,8 @@ Shared values are implemented as `Rc>` (`Arc>` If the value is _not_ a shared value, or if running under [`no_closure`] where there is no [capturing][automatic currying], this API de-sugars to a simple `Dynamic::downcast_ref` and -`Dynamic::downcast_mut`. +`Dynamic::downcast_mut`. In other words, there is no locking and reference counting overhead +for the vast majority of non-shared values. If the value is a shared value, then it is first locked and the returned lock guard then allows access to the underlying value in the specified type. diff --git a/src/syntax.rs b/src/syntax.rs index 90305e44..83149911 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -27,11 +27,11 @@ pub type FnCustomSyntaxEval = /// A general expression parsing trait object. #[cfg(not(feature = "sync"))] -pub type FnCustomSyntaxParse = dyn Fn(&[String]) -> Result, ParseError>; +pub type FnCustomSyntaxParse = dyn Fn(&[String]) -> Result, ParseError>; /// A general expression parsing trait object. #[cfg(feature = "sync")] pub type FnCustomSyntaxParse = - dyn Fn(&[String]) -> Result, ParseError> + Send + Sync; + dyn Fn(&[String]) -> Result, ParseError> + Send + Sync; /// An expression sub-tree in an AST. #[derive(Debug, Clone, Hash)] @@ -107,7 +107,7 @@ impl Engine { ) -> Result<&mut Self, ParseError> { let keywords = keywords.as_ref(); - let mut segments: StaticVec = Default::default(); + let mut segments: StaticVec<_> = Default::default(); for s in keywords { let s = s.as_ref().trim(); @@ -161,7 +161,7 @@ impl Engine { } }; - segments.push(seg.into()); + segments.push(seg); } // If the syntax has no keywords, just ignore the registration @@ -204,7 +204,7 @@ impl Engine { pub fn register_custom_syntax_raw( &mut self, key: impl Into, - parse: impl Fn(&[String]) -> Result, ParseError> + SendSync + 'static, + parse: impl Fn(&[String]) -> Result, ParseError> + SendSync + 'static, new_vars: isize, func: impl Fn(&mut EvalContext, &[Expression]) -> Result> + SendSync