Add no_custom_syntax.
This commit is contained in:
parent
b6528bd51d
commit
b4dbc7619a
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@ -27,6 +27,7 @@ jobs:
|
|||||||
- "--features no_float,serde,metadata,internals,debugging"
|
- "--features no_float,serde,metadata,internals,debugging"
|
||||||
- "--features f32_float,serde,metadata,internals,debugging"
|
- "--features f32_float,serde,metadata,internals,debugging"
|
||||||
- "--features decimal,serde,metadata,internals,debugging"
|
- "--features decimal,serde,metadata,internals,debugging"
|
||||||
|
- "--features no_custom_syntax,serde,metadata,internals,debugging"
|
||||||
- "--features no_float,decimal"
|
- "--features no_float,decimal"
|
||||||
- "--tests --features only_i32,serde,metadata,internals,debugging"
|
- "--tests --features only_i32,serde,metadata,internals,debugging"
|
||||||
- "--features only_i64,serde,metadata,internals,debugging"
|
- "--features only_i64,serde,metadata,internals,debugging"
|
||||||
@ -36,8 +37,8 @@ jobs:
|
|||||||
- "--features no_module,serde,metadata,internals,debugging"
|
- "--features no_module,serde,metadata,internals,debugging"
|
||||||
- "--features no_closure,serde,metadata,internals,debugging"
|
- "--features no_closure,serde,metadata,internals,debugging"
|
||||||
- "--features unicode-xid-ident,serde,metadata,internals,debugging"
|
- "--features unicode-xid-ident,serde,metadata,internals,debugging"
|
||||||
- "--features sync,no_function,no_float,no_position,no_optimize,no_module,no_closure,metadata,serde,unchecked,debugging"
|
- "--features sync,no_function,no_float,no_position,no_optimize,no_module,no_closure,no_custom_syntax,metadata,serde,unchecked,debugging"
|
||||||
- "--features no_function,no_float,no_position,no_index,no_object,no_optimize,no_module,no_closure,unchecked"
|
- "--features no_function,no_float,no_position,no_index,no_object,no_optimize,no_module,no_closure,no_custom_syntax,unchecked"
|
||||||
toolchain: [stable]
|
toolchain: [stable]
|
||||||
experimental: [false]
|
experimental: [false]
|
||||||
include:
|
include:
|
||||||
|
@ -4,6 +4,11 @@ Rhai Release Notes
|
|||||||
Version 1.9.0
|
Version 1.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
New features
|
||||||
|
------------
|
||||||
|
|
||||||
|
* A new feature, `no_custom_syntax`, is added to remove custom syntax support from Rhai for applications that do not require it (which should be most).
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ no_object = [] # no custom objects
|
|||||||
no_function = ["no_closure"] # no script-defined functions (meaning no closures)
|
no_function = ["no_closure"] # no script-defined functions (meaning no closures)
|
||||||
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
||||||
no_module = [] # no modules
|
no_module = [] # no modules
|
||||||
|
no_custom_syntax = [] # no custom syntax or custom operators
|
||||||
unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers.
|
unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers.
|
||||||
metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
|
metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
|
||||||
internals = [] # expose internal data structures
|
internals = [] # expose internal data structures
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
//! Module implementing custom syntax for [`Engine`].
|
//! Module implementing custom syntax for [`Engine`].
|
||||||
|
#![cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
|
||||||
use crate::ast::Expr;
|
use crate::ast::Expr;
|
||||||
use crate::func::SendSync;
|
use crate::func::SendSync;
|
||||||
@ -153,6 +154,8 @@ pub struct CustomSyntax {
|
|||||||
impl Engine {
|
impl Engine {
|
||||||
/// Register a custom syntax with the [`Engine`].
|
/// Register a custom syntax with the [`Engine`].
|
||||||
///
|
///
|
||||||
|
/// Not available under `no_custom_syntax`.
|
||||||
|
///
|
||||||
/// * `symbols` holds a slice of strings that define the custom syntax.
|
/// * `symbols` holds a slice of strings that define the custom syntax.
|
||||||
/// * `scope_may_be_changed` specifies variables _may_ be added/removed by this custom syntax.
|
/// * `scope_may_be_changed` specifies variables _may_ be added/removed by this custom syntax.
|
||||||
/// * `func` is the implementation function.
|
/// * `func` is the implementation function.
|
||||||
@ -296,6 +299,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
/// Register a custom syntax with the [`Engine`].
|
/// Register a custom syntax with the [`Engine`].
|
||||||
///
|
///
|
||||||
|
/// Not available under `no_custom_syntax`.
|
||||||
|
///
|
||||||
/// # WARNING - Low Level API
|
/// # WARNING - Low Level API
|
||||||
///
|
///
|
||||||
/// This function is very low level.
|
/// This function is very low level.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Module containing all deprecated API that will be removed in the next major version.
|
//! Module containing all deprecated API that will be removed in the next major version.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Engine, EvalAltResult, Expression, FnPtr, ImmutableString, NativeCallContext,
|
Dynamic, Engine, EvalAltResult, FnPtr, ImmutableString, NativeCallContext, Position,
|
||||||
Position, RhaiResult, RhaiResultOf, Scope, AST,
|
RhaiResult, RhaiResultOf, Scope, AST,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -312,7 +312,8 @@ impl FnPtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression<'_> {
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
impl crate::Expression<'_> {
|
||||||
/// If this expression is a variable name, return it. Otherwise [`None`].
|
/// If this expression is a variable name, return it. Otherwise [`None`].
|
||||||
///
|
///
|
||||||
/// # Deprecated
|
/// # Deprecated
|
||||||
|
@ -28,10 +28,11 @@ pub mod custom_syntax;
|
|||||||
|
|
||||||
pub mod deprecated;
|
pub mod deprecated;
|
||||||
|
|
||||||
use crate::engine::Precedence;
|
|
||||||
use crate::tokenizer::Token;
|
|
||||||
use crate::{Dynamic, Engine, Identifier};
|
use crate::{Dynamic, Engine, Identifier};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
use crate::{engine::Precedence, tokenizer::Token};
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -121,6 +122,8 @@ impl Engine {
|
|||||||
|
|
||||||
/// Register a custom operator with a precedence into the language.
|
/// Register a custom operator with a precedence into the language.
|
||||||
///
|
///
|
||||||
|
/// Not available under `no_custom_syntax`.
|
||||||
|
///
|
||||||
/// The operator can be a valid identifier, a reserved symbol, a disabled operator or a disabled keyword.
|
/// The operator can be a valid identifier, a reserved symbol, a disabled operator or a disabled keyword.
|
||||||
///
|
///
|
||||||
/// The precedence cannot be zero.
|
/// The precedence cannot be zero.
|
||||||
@ -147,6 +150,7 @@ impl Engine {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
pub fn register_custom_operator(
|
pub fn register_custom_operator(
|
||||||
&mut self,
|
&mut self,
|
||||||
keyword: impl AsRef<str>,
|
keyword: impl AsRef<str>,
|
||||||
@ -161,8 +165,11 @@ impl Engine {
|
|||||||
let keyword = keyword.as_ref();
|
let keyword = keyword.as_ref();
|
||||||
|
|
||||||
match Token::lookup_from_syntax(keyword) {
|
match Token::lookup_from_syntax(keyword) {
|
||||||
// Standard identifiers, reserved keywords and custom keywords are OK
|
// Standard identifiers and reserved keywords are OK
|
||||||
None | Some(Token::Reserved(..)) | Some(Token::Custom(..)) => (),
|
None | Some(Token::Reserved(..)) => (),
|
||||||
|
// custom keywords are OK
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
Some(Token::Custom(..)) => (),
|
||||||
// Active standard keywords cannot be made custom
|
// Active standard keywords cannot be made custom
|
||||||
// Disabled keywords are OK
|
// Disabled keywords are OK
|
||||||
Some(token) if token.is_standard_keyword() => {
|
Some(token) if token.is_standard_keyword() => {
|
||||||
|
@ -48,6 +48,9 @@ impl From<(Expr, Expr)> for BinaryExpr {
|
|||||||
|
|
||||||
/// _(internals)_ A custom syntax expression.
|
/// _(internals)_ A custom syntax expression.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// Not available under `no_custom_syntax`.
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct CustomExpr {
|
pub struct CustomExpr {
|
||||||
/// List of keywords.
|
/// List of keywords.
|
||||||
@ -61,6 +64,7 @@ pub struct CustomExpr {
|
|||||||
pub self_terminated: bool,
|
pub self_terminated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
impl CustomExpr {
|
impl CustomExpr {
|
||||||
/// Is this custom syntax self-terminated (i.e. no need for a semicolon terminator)?
|
/// Is this custom syntax self-terminated (i.e. no need for a semicolon terminator)?
|
||||||
///
|
///
|
||||||
@ -421,6 +425,7 @@ pub enum Expr {
|
|||||||
/// lhs `??` rhs
|
/// lhs `??` rhs
|
||||||
Coalesce(Box<BinaryExpr>, Position),
|
Coalesce(Box<BinaryExpr>, Position),
|
||||||
/// Custom syntax
|
/// Custom syntax
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Custom(Box<CustomExpr>, Position),
|
Custom(Box<CustomExpr>, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,6 +535,7 @@ impl fmt::Debug for Expr {
|
|||||||
.field("rhs", &x.rhs)
|
.field("rhs", &x.rhs)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(),
|
Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
@ -703,10 +709,12 @@ impl Expr {
|
|||||||
| Self::Coalesce(.., pos)
|
| Self::Coalesce(.., pos)
|
||||||
| Self::Index(.., pos)
|
| Self::Index(.., pos)
|
||||||
| Self::Dot(.., pos)
|
| Self::Dot(.., pos)
|
||||||
| Self::Custom(.., pos)
|
|
||||||
| Self::InterpolatedString(.., pos)
|
| Self::InterpolatedString(.., pos)
|
||||||
| Self::Property(.., pos) => *pos,
|
| Self::Property(.., pos) => *pos,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
Self::Custom(.., pos) => *pos,
|
||||||
|
|
||||||
Self::FnCall(x, ..) | Self::MethodCall(x, ..) => x.pos,
|
Self::FnCall(x, ..) | Self::MethodCall(x, ..) => x.pos,
|
||||||
|
|
||||||
Self::Stmt(x) => x.position(),
|
Self::Stmt(x) => x.position(),
|
||||||
@ -761,10 +769,12 @@ impl Expr {
|
|||||||
| Self::Variable(.., pos)
|
| Self::Variable(.., pos)
|
||||||
| Self::FnCall(.., pos)
|
| Self::FnCall(.., pos)
|
||||||
| Self::MethodCall(.., pos)
|
| Self::MethodCall(.., pos)
|
||||||
| Self::Custom(.., pos)
|
|
||||||
| Self::InterpolatedString(.., pos)
|
| Self::InterpolatedString(.., pos)
|
||||||
| Self::Property(.., pos) => *pos = new_pos,
|
| Self::Property(.., pos) => *pos = new_pos,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
Self::Custom(.., pos) => *pos = new_pos,
|
||||||
|
|
||||||
Self::Stmt(x) => x.set_position(new_pos, Position::NONE),
|
Self::Stmt(x) => x.set_position(new_pos, Position::NONE),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,8 +863,10 @@ impl Expr {
|
|||||||
| Self::Dot(..)
|
| Self::Dot(..)
|
||||||
| Self::Index(..)
|
| Self::Index(..)
|
||||||
| Self::Array(..)
|
| Self::Array(..)
|
||||||
| Self::Map(..)
|
| Self::Map(..) => false,
|
||||||
| Self::Custom(..) => false,
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
Self::Custom(..) => false,
|
||||||
|
|
||||||
Self::Variable(..) => match token {
|
Self::Variable(..) => match token {
|
||||||
Token::LeftParen => true,
|
Token::LeftParen => true,
|
||||||
@ -925,6 +937,7 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Self::Custom(x, ..) => {
|
Self::Custom(x, ..) => {
|
||||||
for e in &x.inputs {
|
for e in &x.inputs {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
|
@ -9,7 +9,9 @@ pub mod script_fn;
|
|||||||
pub mod stmt;
|
pub mod stmt;
|
||||||
|
|
||||||
pub use ast::{ASTNode, AST};
|
pub use ast::{ASTNode, AST};
|
||||||
pub use expr::{BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes};
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
pub use expr::CustomExpr;
|
||||||
|
pub use expr::{BinaryExpr, Expr, FnCallExpr, FnCallHashes};
|
||||||
pub use flags::{ASTFlags, FnAccess};
|
pub use flags::{ASTFlags, FnAccess};
|
||||||
pub use ident::Ident;
|
pub use ident::Ident;
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
@ -713,6 +713,7 @@ impl Stmt {
|
|||||||
Self::Noop(..) => false,
|
Self::Noop(..) => false,
|
||||||
|
|
||||||
Self::Expr(e) => match &**e {
|
Self::Expr(e) => match &**e {
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Expr::Custom(x, ..) if x.is_self_terminated() => true,
|
Expr::Custom(x, ..) if x.is_self_terminated() => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! Main module defining the script evaluation [`Engine`].
|
//! Main module defining the script evaluation [`Engine`].
|
||||||
|
|
||||||
use crate::api::custom_syntax::CustomSyntax;
|
|
||||||
use crate::api::options::LangOptions;
|
use crate::api::options::LangOptions;
|
||||||
use crate::func::native::{
|
use crate::func::native::{
|
||||||
OnDebugCallback, OnDefVarCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback,
|
OnDebugCallback, OnDefVarCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback,
|
||||||
@ -111,9 +110,11 @@ pub struct Engine {
|
|||||||
/// A set of symbols to disable.
|
/// A set of symbols to disable.
|
||||||
pub(crate) disabled_symbols: BTreeSet<Identifier>,
|
pub(crate) disabled_symbols: BTreeSet<Identifier>,
|
||||||
/// A map containing custom keywords and precedence to recognize.
|
/// A map containing custom keywords and precedence to recognize.
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
pub(crate) custom_keywords: BTreeMap<Identifier, Option<Precedence>>,
|
pub(crate) custom_keywords: BTreeMap<Identifier, Option<Precedence>>,
|
||||||
/// Custom syntax.
|
/// Custom syntax.
|
||||||
pub(crate) custom_syntax: BTreeMap<Identifier, CustomSyntax>,
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
pub(crate) custom_syntax: BTreeMap<Identifier, crate::api::custom_syntax::CustomSyntax>,
|
||||||
/// Callback closure for filtering variable definition.
|
/// Callback closure for filtering variable definition.
|
||||||
pub(crate) def_var_filter: Option<Box<OnDefVarCallback>>,
|
pub(crate) def_var_filter: Option<Box<OnDefVarCallback>>,
|
||||||
/// Callback closure for resolving variable access.
|
/// Callback closure for resolving variable access.
|
||||||
@ -160,17 +161,19 @@ impl fmt::Debug for Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
f.field("global_sub_modules", &self.global_sub_modules);
|
f.field("global_sub_modules", &self.global_sub_modules);
|
||||||
|
|
||||||
f.field("disabled_symbols", &self.disabled_symbols)
|
f.field("disabled_symbols", &self.disabled_symbols);
|
||||||
.field("custom_keywords", &self.custom_keywords)
|
|
||||||
.field(
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
f.field("custom_keywords", &self.custom_keywords).field(
|
||||||
"custom_syntax",
|
"custom_syntax",
|
||||||
&self
|
&self
|
||||||
.custom_syntax
|
.custom_syntax
|
||||||
.keys()
|
.keys()
|
||||||
.map(|s| s.as_str())
|
.map(|s| s.as_str())
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
)
|
);
|
||||||
.field("def_var_filter", &self.def_var_filter.is_some())
|
|
||||||
|
f.field("def_var_filter", &self.def_var_filter.is_some())
|
||||||
.field("resolve_var", &self.resolve_var.is_some())
|
.field("resolve_var", &self.resolve_var.is_some())
|
||||||
.field("token_mapper", &self.token_mapper.is_some());
|
.field("token_mapper", &self.token_mapper.is_some());
|
||||||
|
|
||||||
@ -268,7 +271,9 @@ impl Engine {
|
|||||||
|
|
||||||
empty_string: ImmutableString::new(),
|
empty_string: ImmutableString::new(),
|
||||||
disabled_symbols: BTreeSet::new(),
|
disabled_symbols: BTreeSet::new(),
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
custom_keywords: BTreeMap::new(),
|
custom_keywords: BTreeMap::new(),
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
custom_syntax: BTreeMap::new(),
|
custom_syntax: BTreeMap::new(),
|
||||||
|
|
||||||
def_var_filter: None,
|
def_var_filter: None,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
//! Evaluation context.
|
//! Evaluation context.
|
||||||
|
|
||||||
use super::{Caches, GlobalRuntimeState};
|
use super::{Caches, GlobalRuntimeState};
|
||||||
use crate::{Dynamic, Engine, Expression, Module, RhaiResult, Scope};
|
use crate::{Dynamic, Engine, Module, Scope};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
/// Context of a script evaluation process.
|
/// Context of a script evaluation process.
|
||||||
#[derive(Debug)]
|
#[allow(dead_code)]
|
||||||
pub struct EvalContext<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> {
|
pub struct EvalContext<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> {
|
||||||
/// The current [`Engine`].
|
/// The current [`Engine`].
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
@ -142,13 +142,14 @@ impl<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> EvalContext<'a, 's, 'ps, 'g, 'pg, '
|
|||||||
self.level
|
self.level
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an [expression tree][Expression] within this [evaluation context][`EvalContext`].
|
/// Evaluate an [expression tree][crate::Expression] within this [evaluation context][`EvalContext`].
|
||||||
///
|
///
|
||||||
/// # WARNING - Low Level API
|
/// # WARNING - Low Level API
|
||||||
///
|
///
|
||||||
/// This function is very low level. It evaluates an expression from an [`AST`][crate::AST].
|
/// This function is very low level. It evaluates an expression from an [`AST`][crate::AST].
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn eval_expression_tree(&mut self, expr: &Expression) -> RhaiResult {
|
pub fn eval_expression_tree(&mut self, expr: &crate::Expression) -> crate::RhaiResult {
|
||||||
let mut new_caches = Caches::new();
|
let mut new_caches = Caches::new();
|
||||||
|
|
||||||
let caches = match self.caches.as_mut() {
|
let caches = match self.caches.as_mut() {
|
||||||
|
@ -4,7 +4,7 @@ use super::{Caches, EvalContext, GlobalRuntimeState, Target};
|
|||||||
use crate::ast::{Expr, FnCallExpr, OpAssignment};
|
use crate::ast::{Expr, FnCallExpr, OpAssignment};
|
||||||
use crate::engine::{KEYWORD_THIS, OP_CONCAT};
|
use crate::engine::{KEYWORD_THIS, OP_CONCAT};
|
||||||
use crate::types::dynamic::AccessMode;
|
use crate::types::dynamic::AccessMode;
|
||||||
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, StaticVec, ERR};
|
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -475,8 +475,10 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Expr::Custom(custom, pos) => {
|
Expr::Custom(custom, pos) => {
|
||||||
let expressions: StaticVec<_> = custom.inputs.iter().map(Into::into).collect();
|
let expressions: crate::StaticVec<_> =
|
||||||
|
custom.inputs.iter().map(Into::into).collect();
|
||||||
// The first token acts as the custom syntax's key
|
// The first token acts as the custom syntax's key
|
||||||
let key_token = custom.tokens.first().unwrap();
|
let key_token = custom.tokens.first().unwrap();
|
||||||
// The key should exist, unless the AST is compiled in a different Engine
|
// The key should exist, unless the AST is compiled in a different Engine
|
||||||
|
13
src/lib.rs
13
src/lib.rs
@ -165,7 +165,6 @@ type ExclusiveRange = std::ops::Range<INT>;
|
|||||||
/// An inclusive integer range.
|
/// An inclusive integer range.
|
||||||
type InclusiveRange = std::ops::RangeInclusive<INT>;
|
type InclusiveRange = std::ops::RangeInclusive<INT>;
|
||||||
|
|
||||||
pub use api::custom_syntax::Expression;
|
|
||||||
pub use api::events::VarDefInfo;
|
pub use api::events::VarDefInfo;
|
||||||
pub use ast::{FnAccess, AST};
|
pub use ast::{FnAccess, AST};
|
||||||
pub use engine::{Engine, OP_CONTAINS, OP_EQUALS};
|
pub use engine::{Engine, OP_CONTAINS, OP_EQUALS};
|
||||||
@ -179,6 +178,9 @@ pub use types::{
|
|||||||
Dynamic, EvalAltResult, FnPtr, ImmutableString, LexError, ParseError, ParseErrorType, Scope,
|
Dynamic, EvalAltResult, FnPtr, ImmutableString, LexError, ParseError, ParseErrorType, Scope,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
pub use api::custom_syntax::Expression;
|
||||||
|
|
||||||
/// _(debugging)_ Module containing types for debugging.
|
/// _(debugging)_ Module containing types for debugging.
|
||||||
/// Exported under the `debugging` feature only.
|
/// Exported under the `debugging` feature only.
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
@ -282,11 +284,14 @@ pub use parser::ParseState;
|
|||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use ast::{
|
pub use ast::{
|
||||||
ASTFlags, ASTNode, BinaryExpr, ConditionalStmtBlock, CustomExpr, Expr, FnCallExpr,
|
ASTFlags, ASTNode, BinaryExpr, ConditionalStmtBlock, Expr, FnCallExpr, FnCallHashes, Ident,
|
||||||
FnCallHashes, Ident, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, SwitchCases,
|
OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, SwitchCases, TryCatchBlock,
|
||||||
TryCatchBlock,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
pub use ast::CustomExpr;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub use ast::Namespace;
|
pub use ast::Namespace;
|
||||||
|
@ -1231,6 +1231,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Custom syntax
|
// Custom syntax
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Expr::Custom(x, ..) => {
|
Expr::Custom(x, ..) => {
|
||||||
if x.scope_may_be_changed {
|
if x.scope_may_be_changed {
|
||||||
state.propagate_constants = false;
|
state.propagate_constants = false;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
//! Main module defining the lexer and parser.
|
//! Main module defining the lexer and parser.
|
||||||
|
|
||||||
use crate::api::custom_syntax::{markers::*, CustomSyntax};
|
|
||||||
use crate::api::events::VarDefInfo;
|
use crate::api::events::VarDefInfo;
|
||||||
use crate::api::options::LangOptions;
|
use crate::api::options::LangOptions;
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
ASTFlags, BinaryExpr, ConditionalStmtBlock, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident,
|
ASTFlags, BinaryExpr, ConditionalStmtBlock, Expr, FnCallExpr, FnCallHashes, Ident,
|
||||||
OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlockContainer, SwitchCases, TryCatchBlock,
|
OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlockContainer, SwitchCases, TryCatchBlock,
|
||||||
};
|
};
|
||||||
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
||||||
@ -428,6 +427,7 @@ fn parse_var_name(input: &mut TokenStream) -> ParseResult<(SmartString, Position
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a symbol.
|
/// Parse a symbol.
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parse_symbol(input: &mut TokenStream) -> ParseResult<(SmartString, Position)> {
|
fn parse_symbol(input: &mut TokenStream) -> ParseResult<(SmartString, Position)> {
|
||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
@ -1449,6 +1449,7 @@ impl Engine {
|
|||||||
Token::MapStart => self.parse_map_literal(input, state, lib, settings.level_up())?,
|
Token::MapStart => self.parse_map_literal(input, state, lib, settings.level_up())?,
|
||||||
|
|
||||||
// Custom syntax.
|
// Custom syntax.
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key)
|
Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key)
|
||||||
if !self.custom_syntax.is_empty() && self.custom_syntax.contains_key(&**key) =>
|
if !self.custom_syntax.is_empty() && self.custom_syntax.contains_key(&**key) =>
|
||||||
{
|
{
|
||||||
@ -2184,6 +2185,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let precedence = match current_op {
|
let precedence = match current_op {
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Token::Custom(c) => self
|
Token::Custom(c) => self
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(c)
|
||||||
@ -2208,6 +2210,7 @@ impl Engine {
|
|||||||
|
|
||||||
let (next_op, next_pos) = input.peek().expect(NEVER_ENDS);
|
let (next_op, next_pos) = input.peek().expect(NEVER_ENDS);
|
||||||
let next_precedence = match next_op {
|
let next_precedence = match next_op {
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Token::Custom(c) => self
|
Token::Custom(c) => self
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(c)
|
||||||
@ -2317,6 +2320,7 @@ impl Engine {
|
|||||||
.into_fn_call_expr(pos)
|
.into_fn_call_expr(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Token::Custom(s)
|
Token::Custom(s)
|
||||||
if self
|
if self
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
@ -2347,6 +2351,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a custom syntax.
|
/// Parse a custom syntax.
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
fn parse_custom_syntax(
|
fn parse_custom_syntax(
|
||||||
&self,
|
&self,
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
@ -2354,9 +2359,11 @@ impl Engine {
|
|||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
key: impl Into<ImmutableString>,
|
key: impl Into<ImmutableString>,
|
||||||
syntax: &CustomSyntax,
|
syntax: &crate::api::custom_syntax::CustomSyntax,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> ParseResult<Expr> {
|
) -> ParseResult<Expr> {
|
||||||
|
use crate::api::custom_syntax::markers::*;
|
||||||
|
|
||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
let mut inputs = StaticVec::<Expr>::new();
|
let mut inputs = StaticVec::<Expr>::new();
|
||||||
let mut segments = StaticVec::new_const();
|
let mut segments = StaticVec::new_const();
|
||||||
@ -2520,7 +2527,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(Expr::Custom(
|
Ok(Expr::Custom(
|
||||||
CustomExpr {
|
crate::ast::CustomExpr {
|
||||||
inputs,
|
inputs,
|
||||||
tokens,
|
tokens,
|
||||||
scope_may_be_changed: syntax.scope_may_be_changed,
|
scope_may_be_changed: syntax.scope_may_be_changed,
|
||||||
|
@ -562,6 +562,9 @@ pub enum Token {
|
|||||||
/// A reserved symbol.
|
/// A reserved symbol.
|
||||||
Reserved(SmartString),
|
Reserved(SmartString),
|
||||||
/// A custom keyword.
|
/// A custom keyword.
|
||||||
|
///
|
||||||
|
/// Not available under the `no_custom_syntax` feature.
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Custom(SmartString),
|
Custom(SmartString),
|
||||||
/// End of the input stream.
|
/// End of the input stream.
|
||||||
EOF,
|
EOF,
|
||||||
@ -682,6 +685,7 @@ impl Token {
|
|||||||
CharConstant(c) => c.to_string().into(),
|
CharConstant(c) => c.to_string().into(),
|
||||||
Identifier(s) => s.to_string().into(),
|
Identifier(s) => s.to_string().into(),
|
||||||
Reserved(s) => s.to_string().into(),
|
Reserved(s) => s.to_string().into(),
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Custom(s) => s.to_string().into(),
|
Custom(s) => s.to_string().into(),
|
||||||
LexError(err) => err.to_string().into(),
|
LexError(err) => err.to_string().into(),
|
||||||
Comment(s) => s.to_string().into(),
|
Comment(s) => s.to_string().into(),
|
||||||
@ -1069,12 +1073,15 @@ impl Token {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn into_function_name_for_override(self) -> Result<SmartString, Self> {
|
pub(crate) fn into_function_name_for_override(self) -> Result<SmartString, Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Custom(s) | Self::Identifier(s) if is_valid_function_name(&s) => Ok(s),
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
Self::Custom(s) if is_valid_function_name(&s) => Ok(s),
|
||||||
|
Self::Identifier(s) if is_valid_function_name(&s) => Ok(s),
|
||||||
_ => Err(self),
|
_ => Err(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this token a custom keyword?
|
/// Is this token a custom keyword?
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_custom(&self) -> bool {
|
pub const fn is_custom(&self) -> bool {
|
||||||
@ -2329,7 +2336,12 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
}
|
}
|
||||||
// Reserved keyword/symbol
|
// Reserved keyword/symbol
|
||||||
Some((Token::Reserved(s), pos)) => (match
|
Some((Token::Reserved(s), pos)) => (match
|
||||||
(&*s, !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s))
|
(&*s,
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
(!self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s)),
|
||||||
|
#[cfg(feature = "no_custom_syntax")]
|
||||||
|
false
|
||||||
|
)
|
||||||
{
|
{
|
||||||
("===", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
("===", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(),
|
||||||
"'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(),
|
"'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(),
|
||||||
@ -2358,7 +2370,10 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
"'#' is not a valid symbol. Should it be '#{'?".to_string(),
|
"'#' is not a valid symbol. Should it be '#{'?".to_string(),
|
||||||
).into()),
|
).into()),
|
||||||
// Reserved keyword/operator that is custom.
|
// Reserved keyword/operator that is custom.
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
(.., true) => Token::Custom(s),
|
(.., true) => Token::Custom(s),
|
||||||
|
#[cfg(feature = "no_custom_syntax")]
|
||||||
|
(.., true) => unreachable!("no custom operators"),
|
||||||
// Reserved keyword that is not custom and disabled.
|
// Reserved keyword that is not custom and disabled.
|
||||||
(token, false) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token) => {
|
(token, false) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token) => {
|
||||||
let msg = format!("reserved {} '{}' is disabled", if is_valid_identifier(token.chars()) { "keyword"} else {"symbol"}, token);
|
let msg = format!("reserved {} '{}' is disabled", if is_valid_identifier(token.chars()) { "keyword"} else {"symbol"}, token);
|
||||||
@ -2368,10 +2383,12 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
(.., false) => Token::Reserved(s),
|
(.., false) => Token::Reserved(s),
|
||||||
}, pos),
|
}, pos),
|
||||||
// Custom keyword
|
// Custom keyword
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Some((Token::Identifier(s), pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s) => {
|
Some((Token::Identifier(s), pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s) => {
|
||||||
(Token::Custom(s), pos)
|
(Token::Custom(s), pos)
|
||||||
}
|
}
|
||||||
// Custom keyword/symbol - must be disabled
|
// Custom keyword/symbol - must be disabled
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Some((token, pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(token.literal_syntax()) => {
|
Some((token, pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(token.literal_syntax()) => {
|
||||||
if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) {
|
if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) {
|
||||||
// Disabled standard keyword/symbol
|
// Disabled standard keyword/symbol
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
|
||||||
use rhai::{
|
use rhai::{
|
||||||
Dynamic, Engine, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position, Scope, INT,
|
Dynamic, Engine, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position, Scope, INT,
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,7 @@ fn test_tokens_disabled() {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tokens_custom_operator_identifiers() -> Result<(), Box<EvalAltResult>> {
|
fn test_tokens_custom_operator_identifiers() -> Result<(), Box<EvalAltResult>> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
@ -60,6 +61,7 @@ fn test_tokens_custom_operator_identifiers() -> Result<(), Box<EvalAltResult>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tokens_custom_operator_symbol() -> Result<(), Box<EvalAltResult>> {
|
fn test_tokens_custom_operator_symbol() -> Result<(), Box<EvalAltResult>> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user