Refine custom syntax.

This commit is contained in:
Stephen Chung 2020-07-11 15:09:17 +08:00
parent e49bfebac5
commit 2a8d63fd5f
9 changed files with 58 additions and 33 deletions

View File

@ -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

View File

@ -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<Dynamic, Box<EvalAltResult>>
```
@ -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<Dynamic, Box<EvalAltResult>> {
let var_name = inputs[0].get_variable_name().unwrap().to_string();

View File

@ -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.

View File

@ -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<Dynamic, Box<EvalAltResult>> {
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!(),

View File

@ -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")]

View File

@ -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<String>,
access: FnAccess,

View File

@ -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.

View File

@ -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<Dynamic, Box<EvalAltResult>>;
/// A general function trail object.
@ -71,7 +70,7 @@ impl Engine {
&mut State,
&Module,
&mut Option<&mut Dynamic>,
&[Expr],
&[Expression],
usize,
) -> Result<Dynamic, Box<EvalAltResult>>
+ SendSync

View File

@ -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<EvalAltResult>> {
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();