diff --git a/Cargo.toml b/Cargo.toml index 99da6522..6d48bc8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ num-traits = { version = "0.2.11", default-features = false } [features] #default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"] -default = ["internals"] +default = [] plugins = [] unchecked = [] # unchecked arithmetic sync = [] # restrict to only types that implement Send + Sync diff --git a/doc/src/engine/custom-syntax.md b/doc/src/engine/custom-syntax.md index 542efaa5..e0529841 100644 --- a/doc/src/engine/custom-syntax.md +++ b/doc/src/engine/custom-syntax.md @@ -1,5 +1,5 @@ -Extending Rhai with Custom Syntax -================================ +Extend Rhai with Custom Syntax +============================= {{#include ../links.md}} @@ -131,7 +131,7 @@ Fn( state: &mut State, lib: &Module, this_ptr: &mut Option<&mut Dynamic>, - inputs: &[Expr], + inputs: &[Expression], level: usize ) -> Result> ``` @@ -144,7 +144,7 @@ where: * `state : &mut State` - mutable reference to the current evaluation state; **do not touch**. * `lib : &Module` - reference to the current collection of script-defined functions. * `this_ptr : &mut Option<&mut Dynamic>` - mutable reference to the current binding of the `this` pointer; **do not touch**. -* `inputs : &[Expr]` - a list of input expression trees. +* `inputs : &[Expression]` - a list of input expression trees. * `level : usize` - the current function call level. There are a lot of parameters, most of which should not be touched or Bad Things Happen™. @@ -158,11 +158,11 @@ and statement blocks (`$block$) are provided. To access a particular argument, use the following patterns: -| Argument type | Pattern (`n` = slot in `inputs`) | Result type | Description | -| :-----------: | ---------------------------------------- | :---------: | ------------------ | -| `$ident$` | `inputs[n].get_variable_name().unwrap()` | `&str` | name of a variable | -| `$expr$` | `inputs.get(n).unwrap()` | `Expr` | an expression tree | -| `$block$` | `inputs.get(n).unwrap()` | `Expr` | an expression tree | +| Argument type | Pattern (`n` = slot in `inputs`) | Result type | Description | +| :-----------: | ---------------------------------------- | :----------: | ------------------ | +| `$ident$` | `inputs[n].get_variable_name().unwrap()` | `&str` | name of a variable | +| `$expr$` | `inputs.get(n).unwrap()` | `Expression` | an expression tree | +| `$block$` | `inputs.get(n).unwrap()` | `Expression` | an expression tree | ### Evaluate an Expression Tree @@ -213,7 +213,7 @@ fn implementation_func( state: &mut State, lib: &Module, this_ptr: &mut Option<&mut Dynamic>, - inputs: &[Expr], + inputs: &[Expression], level: usize ) -> Result> { let var_name = inputs[0].get_variable_name().unwrap().to_string(); diff --git a/doc/src/engine/dsl.md b/doc/src/engine/dsl.md index 5534f243..3585936b 100644 --- a/doc/src/engine/dsl.md +++ b/doc/src/engine/dsl.md @@ -76,9 +76,9 @@ For its evaluation, the callback function will receive the following list of par `exprs[0] = "sum"` - math operator `exprs[1] = "price"` - field name -`exprs[2] = Expr(table)` - data source +`exprs[2] = Expression(table)` - data source `exprs[3] = "row"` - loop variable name -`exprs[4] = Expr(row.wright > 50)` - expression +`exprs[4] = Expression(row.wright > 50)` - expression The other identified, such as `"select"`, `"from"`, as as as symbols `->` and `:` are parsed in the order defined within the custom syntax. diff --git a/src/engine.rs b/src/engine.rs index dfded485..0455c6f1 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -95,6 +95,36 @@ pub const MARKER_BLOCK: &str = "$block$"; #[cfg(feature = "internals")] pub const MARKER_IDENT: &str = "$ident$"; +#[cfg(feature = "internals")] +pub struct Expression<'a>(&'a Expr); + +#[cfg(feature = "internals")] +impl<'a> From<&'a Expr> for Expression<'a> { + fn from(expr: &'a Expr) -> Self { + Self(expr) + } +} + +#[cfg(feature = "internals")] +impl Expression<'_> { + /// If this expression is a variable name, return it. Otherwise `None`. + #[cfg(feature = "internals")] + pub fn get_variable_name(&self) -> Option<&str> { + match self.0 { + Expr::Variable(x) => Some((x.0).0.as_str()), + _ => None, + } + } + /// Get the expression. + pub(crate) fn expr(&self) -> &Expr { + &self.0 + } + /// Get the position of this expression. + pub fn position(&self) -> Position { + self.0.position() + } +} + /// A type specifying the method of chaining. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] enum ChainType { @@ -1691,10 +1721,10 @@ impl Engine { state: &mut State, lib: &Module, this_ptr: &mut Option<&mut Dynamic>, - expr: &Expr, + expr: &Expression, level: usize, ) -> Result> { - self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) + self.eval_expr(scope, mods, state, lib, this_ptr, expr.expr(), level) } /// Evaluate an expression @@ -2131,8 +2161,8 @@ impl Engine { #[cfg(feature = "internals")] Expr::Custom(x) => { let func = (x.0).1.as_ref(); - let exprs = (x.0).0.as_ref(); - func(self, scope, mods, state, lib, this_ptr, exprs, level) + let ep: StaticVec<_> = (x.0).0.iter().map(|e| e.into()).collect(); + func(self, scope, mods, state, lib, this_ptr, ep.as_ref(), level) } _ => unreachable!(), diff --git a/src/lib.rs b/src/lib.rs index 6e319260..a3edc8ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -169,7 +169,7 @@ pub use parser::{CustomExpr, Expr, ReturnType, ScriptFnDef, Stmt}; #[cfg(feature = "internals")] #[deprecated(note = "this type is volatile and may change")] -pub use engine::{Imports, State as EvalState}; +pub use engine::{Expression, Imports, State as EvalState}; #[cfg(feature = "internals")] #[deprecated(note = "this type is volatile and may change")] diff --git a/src/module.rs b/src/module.rs index 7181e4d7..94bd40a4 100644 --- a/src/module.rs +++ b/src/module.rs @@ -342,7 +342,11 @@ impl Module { /// 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. - pub(crate) fn set_fn( + /// + /// ## WARNING - Low Level API + /// + /// This function is very low level. + pub fn set_fn( &mut self, name: impl Into, access: FnAccess, diff --git a/src/parser.rs b/src/parser.rs index 4df5b799..55fbdabf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -908,14 +908,6 @@ impl Expr { _ => self, } } - - #[cfg(feature = "internals")] - pub fn get_variable_name(&self) -> Option<&str> { - match self { - Self::Variable(x) => Some((x.0).0.as_str()), - _ => None, - } - } } /// Consume a particular token, checking that it is the expected one. diff --git a/src/syntax.rs b/src/syntax.rs index 2fea999e..05ab5e0b 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -2,11 +2,10 @@ #![cfg(feature = "internals")] use crate::any::Dynamic; -use crate::engine::{Engine, Imports, State, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT}; +use crate::engine::{Engine, Expression, Imports, State, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT}; use crate::error::LexError; use crate::fn_native::{SendSync, Shared}; use crate::module::Module; -use crate::parser::Expr; use crate::result::EvalAltResult; use crate::scope::Scope; use crate::token::{is_valid_identifier, Token}; @@ -28,7 +27,7 @@ pub type FnCustomSyntaxEval = dyn Fn( &mut State, &Module, &mut Option<&mut Dynamic>, - &[Expr], + &[Expression], usize, ) -> Result>; /// A general function trail object. @@ -71,7 +70,7 @@ impl Engine { &mut State, &Module, &mut Option<&mut Dynamic>, - &[Expr], + &[Expression], usize, ) -> Result> + SendSync diff --git a/tests/syntax.rs b/tests/syntax.rs index 501c90b3..0fdf3c07 100644 --- a/tests/syntax.rs +++ b/tests/syntax.rs @@ -1,6 +1,6 @@ #![cfg(feature = "internals")] use rhai::{ - Dynamic, Engine, EvalAltResult, EvalState, Expr, Imports, LexError, Module, Scope, INT, + Dynamic, Engine, EvalAltResult, EvalState, Expression, Imports, LexError, Module, Scope, INT, }; #[test] @@ -24,7 +24,7 @@ fn test_custom_syntax() -> Result<(), Box> { state: &mut EvalState, lib: &Module, this_ptr: &mut Option<&mut Dynamic>, - inputs: &[Expr], + inputs: &[Expression], level: usize| { let var_name = inputs[0].get_variable_name().unwrap().to_string(); let stmt = inputs.get(1).unwrap();