Add no_custom_syntax.

This commit is contained in:
Stephen Chung 2022-07-05 22:59:03 +08:00
parent b6528bd51d
commit b4dbc7619a
18 changed files with 121 additions and 43 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,
}; };

View File

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