Minor code refactor.

This commit is contained in:
Stephen Chung 2020-11-02 23:54:19 +08:00
parent cc304ba513
commit b9de8eaa7f
8 changed files with 145 additions and 153 deletions

View File

@ -861,24 +861,24 @@ pub struct BinaryExpr {
/// A function call. /// A function call.
#[derive(Debug, Clone, Hash, Default)] #[derive(Debug, Clone, Hash, Default)]
pub struct FnCallInfo { pub struct FnCallInfo {
/// Function name. /// Pre-calculated hash for a script-defined function of the same name and number of parameters.
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls pub hash: u64,
/// and the function names are predictable, so no need to allocate a new `String`.
pub name: Cow<'static, str>,
/// Namespace of the function, if any.
pub namespace: Option<ModuleRef>,
/// Call native functions only? Set to `true` to skip searching for script-defined function overrides /// Call native functions only? Set to `true` to skip searching for script-defined function overrides
/// when it is certain that the function must be native (e.g. an operator). /// when it is certain that the function must be native (e.g. an operator).
pub native_only: bool, pub native_only: bool,
/// Does this function call capture the parent scope? /// Does this function call capture the parent scope?
pub capture: bool, pub capture: bool,
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
pub hash: u64,
/// List of function call arguments.
pub args: StaticVec<Expr>,
/// Default value when the function is not found, mostly used to provide a default for comparison functions. /// Default value when the function is not found, mostly used to provide a default for comparison functions.
/// Type is `bool` in order for `FnCallInfo` to be `Hash` /// Type is `bool` in order for `FnCallInfo` to be `Hash`
pub def_value: Option<bool>, pub def_value: Option<bool>,
/// Namespace of the function, if any.
pub namespace: Option<Box<ModuleRef>>,
/// Function name.
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
/// and the function names are predictable, so no need to allocate a new `String`.
pub name: Cow<'static, str>,
/// List of function call arguments.
pub args: StaticVec<Expr>,
} }
/// _[INTERNALS]_ An expression sub-tree. /// _[INTERNALS]_ An expression sub-tree.
@ -903,10 +903,10 @@ pub enum Expr {
StringConstant(Box<IdentX>), StringConstant(Box<IdentX>),
/// FnPtr constant. /// FnPtr constant.
FnPointer(Box<IdentX>), FnPointer(Box<IdentX>),
/// Variable access - (variable name, optional modules, hash, optional index) /// Variable access - (optional index, optional modules, hash, variable name)
Variable(Box<(Ident, Option<ModuleRef>, u64, Option<NonZeroUsize>)>), Variable(Box<(Option<NonZeroUsize>, Option<Box<ModuleRef>>, u64, Ident)>),
/// Property access. /// Property access - (getter, setter), prop
Property(Box<(IdentX, (String, String))>), Property(Box<((String, String), IdentX)>),
/// { stmt } /// { stmt }
Stmt(Box<Stmt>, Position), Stmt(Box<Stmt>, Position),
/// Wrapped expression - should not be optimized away. /// Wrapped expression - should not be optimized away.
@ -1014,7 +1014,7 @@ impl Expr {
/// Is the expression a simple variable access? /// Is the expression a simple variable access?
pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> { pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> {
match self { match self {
Self::Variable(x) if !non_qualified || x.1.is_none() => Some((x.0).name.as_str()), Self::Variable(x) if !non_qualified || x.1.is_none() => Some((x.3).name.as_str()),
_ => None, _ => None,
} }
} }
@ -1033,9 +1033,9 @@ impl Expr {
Self::FnPointer(x) => x.pos, Self::FnPointer(x) => x.pos,
Self::Array(_, pos) => *pos, Self::Array(_, pos) => *pos,
Self::Map(_, pos) => *pos, Self::Map(_, pos) => *pos,
Self::Property(x) => (x.0).pos, Self::Property(x) => (x.1).pos,
Self::Stmt(_, pos) => *pos, Self::Stmt(_, pos) => *pos,
Self::Variable(x) => (x.0).pos, Self::Variable(x) => (x.3).pos,
Self::FnCall(_, pos) => *pos, Self::FnCall(_, pos) => *pos,
Self::And(x, _) | Self::Or(x, _) | Self::In(x, _) => x.lhs.position(), Self::And(x, _) | Self::Or(x, _) | Self::In(x, _) => x.lhs.position(),
@ -1064,8 +1064,8 @@ impl Expr {
Self::FnPointer(x) => x.pos = new_pos, Self::FnPointer(x) => x.pos = new_pos,
Self::Array(_, pos) => *pos = new_pos, Self::Array(_, pos) => *pos = new_pos,
Self::Map(_, pos) => *pos = new_pos, Self::Map(_, pos) => *pos = new_pos,
Self::Variable(x) => (x.0).pos = new_pos, Self::Variable(x) => (x.3).pos = new_pos,
Self::Property(x) => (x.0).pos = new_pos, Self::Property(x) => (x.1).pos = new_pos,
Self::Stmt(_, pos) => *pos = new_pos, Self::Stmt(_, pos) => *pos = new_pos,
Self::FnCall(_, pos) => *pos = new_pos, Self::FnCall(_, pos) => *pos = new_pos,
Self::And(_, pos) | Self::Or(_, pos) | Self::In(_, pos) => *pos = new_pos, Self::And(_, pos) | Self::Or(_, pos) | Self::In(_, pos) => *pos = new_pos,
@ -1231,10 +1231,10 @@ impl Expr {
pub(crate) fn into_property(self) -> Self { pub(crate) fn into_property(self) -> Self {
match self { match self {
Self::Variable(x) if x.1.is_none() => { Self::Variable(x) if x.1.is_none() => {
let ident = x.0; let ident = x.3;
let getter = make_getter(&ident.name); let getter = make_getter(&ident.name);
let setter = make_setter(&ident.name); let setter = make_setter(&ident.name);
Self::Property(Box::new((ident.into(), (getter, setter)))) Self::Property(Box::new(((getter, setter), ident.into())))
} }
_ => self, _ => self,
} }

View File

@ -77,7 +77,7 @@ pub type Map = HashMap<ImmutableString, Dynamic>;
// `Imports` is implemented as two `Vec`'s of exactly the same length. That's because a `Module` is large, // `Imports` is implemented as two `Vec`'s of exactly the same length. That's because a `Module` is large,
// so packing the import names together improves cache locality. // so packing the import names together improves cache locality.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Imports(StaticVec<ImmutableString>, StaticVec<Module>); pub struct Imports(StaticVec<Module>, StaticVec<ImmutableString>);
impl Imports { impl Imports {
/// Get the length of this stack of imported modules. /// Get the length of this stack of imported modules.
@ -86,15 +86,15 @@ impl Imports {
} }
/// Get the imported module at a particular index. /// Get the imported module at a particular index.
pub fn get(&self, index: usize) -> Option<&Module> { pub fn get(&self, index: usize) -> Option<&Module> {
self.1.get(index) self.0.get(index)
} }
/// Get a mutable reference to the imported module at a particular index. /// Get a mutable reference to the imported module at a particular index.
pub fn get_mut(&mut self, index: usize) -> Option<&mut Module> { pub fn get_mut(&mut self, index: usize) -> Option<&mut Module> {
self.1.get_mut(index) self.0.get_mut(index)
} }
/// Get the index of an imported module by name. /// Get the index of an imported module by name.
pub fn find(&self, name: &str) -> Option<usize> { pub fn find(&self, name: &str) -> Option<usize> {
self.0 self.1
.iter() .iter()
.enumerate() .enumerate()
.rev() .rev()
@ -103,8 +103,8 @@ impl Imports {
} }
/// Push an imported module onto the stack. /// Push an imported module onto the stack.
pub fn push(&mut self, name: impl Into<ImmutableString>, module: Module) { pub fn push(&mut self, name: impl Into<ImmutableString>, module: Module) {
self.0.push(name.into()); self.0.push(module);
self.1.push(module); self.1.push(name.into());
} }
/// Truncate the stack of imported modules to a particular length. /// Truncate the stack of imported modules to a particular length.
pub fn truncate(&mut self, size: usize) { pub fn truncate(&mut self, size: usize) {
@ -114,11 +114,11 @@ impl Imports {
/// Get an iterator to this stack of imported modules. /// Get an iterator to this stack of imported modules.
#[allow(dead_code)] #[allow(dead_code)]
pub fn iter(&self) -> impl Iterator<Item = (&str, &Module)> { pub fn iter(&self) -> impl Iterator<Item = (&str, &Module)> {
self.0.iter().map(|name| name.as_str()).zip(self.1.iter()) self.1.iter().map(|name| name.as_str()).zip(self.0.iter())
} }
/// Get a consuming iterator to this stack of imported modules. /// Get a consuming iterator to this stack of imported modules.
pub fn into_iter(self) -> impl Iterator<Item = (ImmutableString, Module)> { pub fn into_iter(self) -> impl Iterator<Item = (ImmutableString, Module)> {
self.0.into_iter().zip(self.1.into_iter()) self.1.into_iter().zip(self.0.into_iter())
} }
} }
@ -812,7 +812,7 @@ impl Engine {
match expr { match expr {
Expr::Variable(v) => match v.as_ref() { Expr::Variable(v) => match v.as_ref() {
// Qualified variable // Qualified variable
(Ident { name, pos }, Some(modules), hash_var, _) => { (_, Some(modules), hash_var, Ident { name, pos }) => {
let module = search_imports_mut(mods, state, modules)?; let module = search_imports_mut(mods, state, modules)?;
let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| { let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| {
match *err { match *err {
@ -844,7 +844,7 @@ impl Engine {
this_ptr: &'s mut Option<&mut Dynamic>, this_ptr: &'s mut Option<&mut Dynamic>,
expr: &'a Expr, expr: &'a Expr,
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> { ) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
let (Ident { name, pos }, _, _, index) = match expr { let (index, _, _, Ident { name, pos }) = match expr {
Expr::Variable(v) => v.as_ref(), Expr::Variable(v) => v.as_ref(),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -984,7 +984,7 @@ impl Engine {
let args = &mut [val, &mut idx_val2, &mut new_val.0]; let args = &mut [val, &mut idx_val2, &mut new_val.0];
self.exec_fn_call( self.exec_fn_call(
state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None, &None, state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None, None,
level, level,
) )
.map_err(|err| match *err { .map_err(|err| match *err {
@ -1026,8 +1026,7 @@ impl Engine {
let def_value = def_value.map(Into::<Dynamic>::into); let def_value = def_value.map(Into::<Dynamic>::into);
let args = idx_val.as_fn_call_args(); let args = idx_val.as_fn_call_args();
self.make_method_call( self.make_method_call(
state, lib, name, *hash, target, args, &def_value, *native, false, state, lib, name, *hash, target, args, def_value, *native, false, level,
level,
) )
.map_err(|err| err.fill_position(*pos)) .map_err(|err| err.fill_position(*pos))
} }
@ -1035,7 +1034,7 @@ impl Engine {
Expr::FnCall(_, _) => unreachable!(), Expr::FnCall(_, _) => unreachable!(),
// {xxx:map}.id = ??? // {xxx:map}.id = ???
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => { Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
let IdentX { name, pos } = &x.0; let IdentX { name, pos } = &x.1;
let index = name.clone().into(); let index = name.clone().into();
let mut val = self let mut val = self
.get_indexed_mut(state, lib, target, index, *pos, true, false, level)?; .get_indexed_mut(state, lib, target, index, *pos, true, false, level)?;
@ -1045,7 +1044,7 @@ impl Engine {
} }
// {xxx:map}.id // {xxx:map}.id
Expr::Property(x) if target.is::<Map>() => { Expr::Property(x) if target.is::<Map>() => {
let IdentX { name, pos } = &x.0; let IdentX { name, pos } = &x.1;
let index = name.clone().into(); let index = name.clone().into();
let val = self.get_indexed_mut( let val = self.get_indexed_mut(
state, lib, target, index, *pos, false, false, level, state, lib, target, index, *pos, false, false, level,
@ -1055,11 +1054,11 @@ impl Engine {
} }
// xxx.id = ??? // xxx.id = ???
Expr::Property(x) if new_val.is_some() => { Expr::Property(x) if new_val.is_some() => {
let (IdentX { pos, .. }, (_, setter)) = x.as_ref(); let ((_, setter), IdentX { pos, .. }) = x.as_ref();
let mut new_val = new_val; let mut new_val = new_val;
let mut args = [target.as_mut(), &mut new_val.as_mut().unwrap().0]; let mut args = [target.as_mut(), &mut new_val.as_mut().unwrap().0];
self.exec_fn_call( self.exec_fn_call(
state, lib, setter, 0, &mut args, is_ref, true, false, None, &None, state, lib, setter, 0, &mut args, is_ref, true, false, None, None,
level, level,
) )
.map(|(v, _)| (v, true)) .map(|(v, _)| (v, true))
@ -1067,10 +1066,10 @@ impl Engine {
} }
// xxx.id // xxx.id
Expr::Property(x) => { Expr::Property(x) => {
let (IdentX { pos, .. }, (getter, _)) = x.as_ref(); let ((getter, _), IdentX { pos, .. }) = x.as_ref();
let mut args = [target.as_mut()]; let mut args = [target.as_mut()];
self.exec_fn_call( self.exec_fn_call(
state, lib, getter, 0, &mut args, is_ref, true, false, None, &None, state, lib, getter, 0, &mut args, is_ref, true, false, None, None,
level, level,
) )
.map(|(v, _)| (v, false)) .map(|(v, _)| (v, false))
@ -1080,7 +1079,7 @@ impl Engine {
Expr::Index(x, x_pos) | Expr::Dot(x, x_pos) if target.is::<Map>() => { Expr::Index(x, x_pos) | Expr::Dot(x, x_pos) if target.is::<Map>() => {
let mut val = match &x.lhs { let mut val = match &x.lhs {
Expr::Property(p) => { Expr::Property(p) => {
let IdentX { name, pos } = &p.0; let IdentX { name, pos } = &p.1;
let index = name.clone().into(); let index = name.clone().into();
self.get_indexed_mut( self.get_indexed_mut(
state, lib, target, index, *pos, false, true, level, state, lib, target, index, *pos, false, true, level,
@ -1099,7 +1098,7 @@ impl Engine {
let args = idx_val.as_fn_call_args(); let args = idx_val.as_fn_call_args();
let (val, _) = self let (val, _) = self
.make_method_call( .make_method_call(
state, lib, name, *hash, target, args, &def_value, *native, state, lib, name, *hash, target, args, def_value, *native,
false, level, false, level,
) )
.map_err(|err| err.fill_position(*pos))?; .map_err(|err| err.fill_position(*pos))?;
@ -1122,13 +1121,13 @@ impl Engine {
match &x.lhs { match &x.lhs {
// xxx.prop[expr] | xxx.prop.expr // xxx.prop[expr] | xxx.prop.expr
Expr::Property(p) => { Expr::Property(p) => {
let (IdentX { pos, .. }, (getter, setter)) = p.as_ref(); let ((getter, setter), IdentX { pos, .. }) = p.as_ref();
let arg_values = &mut [target.as_mut(), &mut Default::default()]; let arg_values = &mut [target.as_mut(), &mut Default::default()];
let args = &mut arg_values[..1]; let args = &mut arg_values[..1];
let (mut val, updated) = self let (mut val, updated) = self
.exec_fn_call( .exec_fn_call(
state, lib, getter, 0, args, is_ref, true, false, None, state, lib, getter, 0, args, is_ref, true, false, None,
&None, level, None, level,
) )
.map_err(|err| err.fill_position(*pos))?; .map_err(|err| err.fill_position(*pos))?;
@ -1154,7 +1153,7 @@ impl Engine {
arg_values[1] = val; arg_values[1] = val;
self.exec_fn_call( self.exec_fn_call(
state, lib, setter, 0, arg_values, is_ref, true, false, state, lib, setter, 0, arg_values, is_ref, true, false,
None, &None, level, None, None, level,
) )
.or_else( .or_else(
|err| match *err { |err| match *err {
@ -1182,7 +1181,7 @@ impl Engine {
let args = idx_val.as_fn_call_args(); let args = idx_val.as_fn_call_args();
let (mut val, _) = self let (mut val, _) = self
.make_method_call( .make_method_call(
state, lib, name, *hash, target, args, &def_value, *native, state, lib, name, *hash, target, args, def_value, *native,
false, level, false, level,
) )
.map_err(|err| err.fill_position(*pos))?; .map_err(|err| err.fill_position(*pos))?;
@ -1257,7 +1256,7 @@ impl Engine {
let Ident { let Ident {
name: var_name, name: var_name,
pos: var_pos, pos: var_pos,
} = &x.0; } = &x.3;
self.inc_operations(state) self.inc_operations(state)
.map_err(|err| err.fill_position(*var_pos))?; .map_err(|err| err.fill_position(*var_pos))?;
@ -1458,7 +1457,7 @@ impl Engine {
let mut idx = idx; let mut idx = idx;
let args = &mut [val, &mut idx]; let args = &mut [val, &mut idx];
self.exec_fn_call( self.exec_fn_call(
state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, &None, _level, state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None, _level,
) )
.map(|(v, _)| v.into()) .map(|(v, _)| v.into())
.map_err(|err| match *err { .map_err(|err| match *err {
@ -1504,13 +1503,14 @@ impl Engine {
for value in rhs_value.iter_mut() { for value in rhs_value.iter_mut() {
let args = &mut [&mut lhs_value.clone(), value]; let args = &mut [&mut lhs_value.clone(), value];
let def_value = def_value.clone();
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s. // Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
let hash = let hash =
calc_native_fn_hash(empty(), OP_FUNC, args.iter().map(|a| a.type_id())); calc_native_fn_hash(empty(), OP_FUNC, args.iter().map(|a| a.type_id()));
if self if self
.call_native_fn(state, lib, OP_FUNC, hash, args, false, false, &def_value) .call_native_fn(state, lib, OP_FUNC, hash, args, false, false, def_value)
.map_err(|err| err.fill_position(rhs.position()))? .map_err(|err| err.fill_position(rhs.position()))?
.0 .0
.as_bool() .as_bool()
@ -1520,7 +1520,7 @@ impl Engine {
} }
} }
Ok(def_value.unwrap()) Ok(false.into())
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Dynamic(Union::Map(rhs_value)) => match lhs_value { Dynamic(Union::Map(rhs_value)) => match lhs_value {
@ -1564,11 +1564,11 @@ impl Engine {
Expr::FnPointer(x) => { Expr::FnPointer(x) => {
Ok(FnPtr::new_unchecked(x.name.clone(), Default::default()).into()) Ok(FnPtr::new_unchecked(x.name.clone(), Default::default()).into())
} }
Expr::Variable(x) if (x.0).name == KEYWORD_THIS => { Expr::Variable(x) if (x.3).name == KEYWORD_THIS => {
if let Some(val) = this_ptr { if let Some(val) = this_ptr {
Ok(val.clone()) Ok(val.clone())
} else { } else {
EvalAltResult::ErrorUnboundThis((x.0).pos).into() EvalAltResult::ErrorUnboundThis((x.3).pos).into()
} }
} }
Expr::Variable(_) => { Expr::Variable(_) => {
@ -1623,7 +1623,7 @@ impl Engine {
} = x.as_ref(); } = x.as_ref();
let def_value = def_value.map(Into::<Dynamic>::into); let def_value = def_value.map(Into::<Dynamic>::into);
self.make_function_call( self.make_function_call(
scope, mods, state, lib, this_ptr, name, args, &def_value, *hash, *native, scope, mods, state, lib, this_ptr, name, args, def_value, *hash, *native,
false, *cap_scope, level, false, *cap_scope, level,
) )
.map_err(|err| err.fill_position(*pos)) .map_err(|err| err.fill_position(*pos))
@ -1639,8 +1639,9 @@ impl Engine {
def_value, def_value,
.. ..
} = x.as_ref(); } = x.as_ref();
let modules = namespace.as_ref().map(|v| v.as_ref());
self.make_qualified_function_call( self.make_qualified_function_call(
scope, mods, state, lib, this_ptr, namespace, name, args, *def_value, *hash, scope, mods, state, lib, this_ptr, modules, name, args, *def_value, *hash,
level, level,
) )
.map_err(|err| err.fill_position(*pos)) .map_err(|err| err.fill_position(*pos))
@ -1812,7 +1813,7 @@ impl Engine {
// Run function // Run function
let (value, _) = self let (value, _) = self
.exec_fn_call( .exec_fn_call(
state, lib, op, 0, args, false, false, false, None, &None, state, lib, op, 0, args, false, false, false, None, None,
level, level,
) )
.map_err(|err| err.fill_position(*op_pos))?; .map_err(|err| err.fill_position(*op_pos))?;
@ -1850,7 +1851,7 @@ impl Engine {
let result = self let result = self
.exec_fn_call( .exec_fn_call(
state, lib, op, 0, args, false, false, false, None, &None, level, state, lib, op, 0, args, false, false, false, None, None, level,
) )
.map(|(v, _)| v) .map(|(v, _)| v)
.map_err(|err| err.fill_position(*op_pos))?; .map_err(|err| err.fill_position(*op_pos))?;

View File

@ -186,7 +186,7 @@ impl Engine {
args: &mut FnCallArgs, args: &mut FnCallArgs,
is_ref: bool, is_ref: bool,
pub_only: bool, pub_only: bool,
def_val: &Option<Dynamic>, def_val: Option<Dynamic>,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
self.inc_operations(state)?; self.inc_operations(state)?;
@ -254,7 +254,7 @@ impl Engine {
// Return default value (if any) // Return default value (if any)
if let Some(val) = def_val { if let Some(val) = def_val {
return Ok((val.clone(), false)); return Ok((val, false));
} }
// Getter function not found? // Getter function not found?
@ -479,7 +479,7 @@ impl Engine {
_is_method: bool, _is_method: bool,
pub_only: bool, pub_only: bool,
_capture_scope: Option<Scope>, _capture_scope: Option<Scope>,
def_val: &Option<Dynamic>, def_val: Option<Dynamic>,
_level: usize, _level: usize,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
// Check for data race. // Check for data race.
@ -686,7 +686,7 @@ impl Engine {
hash_script: u64, hash_script: u64,
target: &mut Target, target: &mut Target,
mut call_args: StaticVec<Dynamic>, mut call_args: StaticVec<Dynamic>,
def_val: &Option<Dynamic>, def_val: Option<Dynamic>,
native: bool, native: bool,
pub_only: bool, pub_only: bool,
level: usize, level: usize,
@ -837,7 +837,7 @@ impl Engine {
this_ptr: &mut Option<&mut Dynamic>, this_ptr: &mut Option<&mut Dynamic>,
name: &str, name: &str,
args_expr: impl AsRef<[Expr]>, args_expr: impl AsRef<[Expr]>,
def_val: &Option<Dynamic>, def_val: Option<Dynamic>,
mut hash_script: u64, mut hash_script: u64,
native: bool, native: bool,
pub_only: bool, pub_only: bool,
@ -1074,7 +1074,7 @@ impl Engine {
state: &mut State, state: &mut State,
lib: &[&Module], lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>, this_ptr: &mut Option<&mut Dynamic>,
modules: &Option<ModuleRef>, modules: Option<&ModuleRef>,
name: &str, name: &str,
args_expr: impl AsRef<[Expr]>, args_expr: impl AsRef<[Expr]>,
def_val: Option<bool>, def_val: Option<bool>,

View File

@ -193,7 +193,7 @@ impl FnPtr {
has_this, has_this,
true, true,
None, None,
&None, None,
0, 0,
) )
.map(|(v, _)| v) .map(|(v, _)| v)

View File

@ -147,7 +147,7 @@ fn call_fn_with_constant_arguments(
arg_values.iter_mut().collect::<StaticVec<_>>().as_mut(), arg_values.iter_mut().collect::<StaticVec<_>>().as_mut(),
false, false,
true, true,
&None, None,
) )
.ok() .ok()
.map(|(v, _)| v) .map(|(v, _)| v)
@ -454,7 +454,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
Expr::Dot(x, dot_pos) => match (x.lhs, x.rhs) { Expr::Dot(x, dot_pos) => match (x.lhs, x.rhs) {
// map.string // map.string
(Expr::Map(m, pos), Expr::Property(p)) if m.iter().all(|(_, x)| x.is_pure()) => { (Expr::Map(m, pos), Expr::Property(p)) if m.iter().all(|(_, x)| x.is_pure()) => {
let prop = &p.0.name; let prop = &p.1.name;
// Map literal where everything is pure - promote the indexed item. // Map literal where everything is pure - promote the indexed item.
// All other items can be thrown away. // All other items can be thrown away.
state.set_dirty(); state.set_dirty();
@ -686,12 +686,12 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
} }
// constant-name // constant-name
Expr::Variable(x) if x.1.is_none() && state.contains_constant(&x.0.name) => { Expr::Variable(x) if x.1.is_none() && state.contains_constant(&x.3.name) => {
state.set_dirty(); state.set_dirty();
// Replace constant with value // Replace constant with value
let mut expr = state.find_constant(&x.0.name).unwrap().clone(); let mut expr = state.find_constant(&x.3.name).unwrap().clone();
expr.set_position(x.0.pos); expr.set_position(x.3.pos);
expr expr
} }

View File

@ -267,7 +267,7 @@ fn parse_fn_call(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
id: String, id: String,
capture: bool, capture: bool,
mut namespace: Option<ModuleRef>, mut namespace: Option<Box<ModuleRef>>,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let (token, token_pos) = input.peek().unwrap(); let (token, token_pos) = input.peek().unwrap();
@ -788,7 +788,7 @@ fn parse_primary(
{ {
state.allow_capture = true; state.allow_capture = true;
} }
Expr::Variable(Box::new((Ident::new(s, settings.pos), None, 0, None))) Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
} }
// Module qualification // Module qualification
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -798,18 +798,18 @@ fn parse_primary(
{ {
state.allow_capture = true; state.allow_capture = true;
} }
Expr::Variable(Box::new((Ident::new(s, settings.pos), None, 0, None))) Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
} }
// Normal variable access // Normal variable access
Token::Identifier(s) => { Token::Identifier(s) => {
let index = state.access_var(&s, settings.pos); let index = state.access_var(&s, settings.pos);
Expr::Variable(Box::new((Ident::new(s, settings.pos), None, 0, index))) Expr::Variable(Box::new((index, None, 0, Ident::new(s, settings.pos))))
} }
// Function call is allowed to have reserved keyword // Function call is allowed to have reserved keyword
Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => { Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
if is_keyword_function(&s) { if is_keyword_function(&s) {
Expr::Variable(Box::new((Ident::new(s, settings.pos), None, 0, None))) Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
} else { } else {
return Err(PERR::Reserved(s).into_err(settings.pos)); return Err(PERR::Reserved(s).into_err(settings.pos));
} }
@ -824,7 +824,7 @@ fn parse_primary(
))) )))
.into_err(settings.pos)); .into_err(settings.pos));
} else { } else {
Expr::Variable(Box::new((Ident::new(s, settings.pos), None, 0, None))) Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
} }
} }
@ -883,13 +883,13 @@ fn parse_primary(
.into_err(pos)); .into_err(pos));
} }
let (Ident { name, pos }, modules, _, _) = *x; let (_, modules, _, Ident { name, pos }) = *x;
settings.pos = pos; settings.pos = pos;
parse_fn_call(input, state, lib, name, true, modules, settings.level_up())? parse_fn_call(input, state, lib, name, true, modules, settings.level_up())?
} }
// Function call // Function call
(Expr::Variable(x), Token::LeftParen) => { (Expr::Variable(x), Token::LeftParen) => {
let (Ident { name, pos }, modules, _, _) = *x; let (_, modules, _, Ident { name, pos }) = *x;
settings.pos = pos; settings.pos = pos;
parse_fn_call(input, state, lib, name, false, modules, settings.level_up())? parse_fn_call(input, state, lib, name, false, modules, settings.level_up())?
} }
@ -897,17 +897,17 @@ fn parse_primary(
// module access // module access
(Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() { (Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() {
(Token::Identifier(id2), pos2) => { (Token::Identifier(id2), pos2) => {
let (var_name_def, mut modules, _, index) = *x; let (index, mut modules, _, var_name_def) = *x;
if let Some(ref mut modules) = modules { if let Some(ref mut modules) = modules {
modules.push(var_name_def); modules.push(var_name_def);
} else { } else {
let mut m: ModuleRef = Default::default(); let mut m: ModuleRef = Default::default();
m.push(var_name_def); m.push(var_name_def);
modules = Some(m); modules = Some(Box::new(m));
} }
Expr::Variable(Box::new((Ident::new(id2, pos2), modules, 0, index))) Expr::Variable(Box::new((index, modules, 0, Ident::new(id2, pos2))))
} }
(Token::Reserved(id2), pos2) if is_valid_identifier(id2.chars()) => { (Token::Reserved(id2), pos2) if is_valid_identifier(id2.chars()) => {
return Err(PERR::Reserved(id2).into_err(pos2)); return Err(PERR::Reserved(id2).into_err(pos2));
@ -931,7 +931,7 @@ fn parse_primary(
match &mut root_expr { match &mut root_expr {
// Cache the hash key for module-qualified variables // Cache the hash key for module-qualified variables
Expr::Variable(x) if x.1.is_some() => { Expr::Variable(x) if x.1.is_some() => {
let (Ident { name, .. }, modules, hash, _) = x.as_mut(); let (_, modules, hash, Ident { name, .. }) = x.as_mut();
let modules = modules.as_mut().unwrap(); let modules = modules.as_mut().unwrap();
// Qualifiers + variable name // Qualifiers + variable name
@ -1087,19 +1087,19 @@ fn make_assignment_stmt<'a>(
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
match &lhs { match &lhs {
// var (non-indexed) = rhs // var (non-indexed) = rhs
Expr::Variable(x) if x.3.is_none() => { Expr::Variable(x) if x.1.is_none() => {
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos)) Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
} }
// var (indexed) = rhs // var (indexed) = rhs
Expr::Variable(x) => { Expr::Variable(x) => {
let ( let (
index,
_,
_,
Ident { Ident {
name, name,
pos: name_pos, pos: name_pos,
}, },
_,
_,
index,
) = x.as_ref(); ) = x.as_ref();
match state.stack[(state.stack.len() - index.unwrap().get())].1 { match state.stack[(state.stack.len() - index.unwrap().get())].1 {
ScopeEntryType::Normal => { ScopeEntryType::Normal => {
@ -1114,19 +1114,19 @@ fn make_assignment_stmt<'a>(
// xxx[???] = rhs, xxx.??? = rhs // xxx[???] = rhs, xxx.??? = rhs
Expr::Index(x, _) | Expr::Dot(x, _) => match &x.lhs { Expr::Index(x, _) | Expr::Dot(x, _) => match &x.lhs {
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs // var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
Expr::Variable(x) if x.3.is_none() => { Expr::Variable(x) if x.1.is_none() => {
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos)) Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
} }
// var[???] (indexed) = rhs, var.??? (indexed) = rhs // var[???] (indexed) = rhs, var.??? (indexed) = rhs
Expr::Variable(x) => { Expr::Variable(x) => {
let ( let (
index,
_,
_,
Ident { Ident {
name, name,
pos: name_pos, pos: name_pos,
}, },
_,
_,
index,
) = x.as_ref(); ) = x.as_ref();
match state.stack[(state.stack.len() - index.unwrap().get())].1 { match state.stack[(state.stack.len() - index.unwrap().get())].1 {
ScopeEntryType::Normal => { ScopeEntryType::Normal => {
@ -1204,10 +1204,10 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseEr
} }
// lhs.id // lhs.id
(lhs, Expr::Variable(x)) if x.1.is_none() => { (lhs, Expr::Variable(x)) if x.1.is_none() => {
let ident = x.0; let ident = x.3;
let getter = make_getter(&ident.name); let getter = make_getter(&ident.name);
let setter = make_setter(&ident.name); let setter = make_setter(&ident.name);
let rhs = Expr::Property(Box::new((ident.into(), (getter, setter)))); let rhs = Expr::Property(Box::new(((getter, setter), ident.into())));
Expr::Dot(Box::new(BinaryExpr { lhs, rhs }), op_pos) Expr::Dot(Box::new(BinaryExpr { lhs, rhs }), op_pos)
} }
@ -1642,10 +1642,10 @@ fn parse_custom_syntax(
(Token::Identifier(s), pos) => { (Token::Identifier(s), pos) => {
segments.push(s.clone()); segments.push(s.clone());
exprs.push(Expr::Variable(Box::new(( exprs.push(Expr::Variable(Box::new((
Ident::new(s, pos), None,
None, None,
0, 0,
None, Ident::new(s, pos),
)))); ))));
} }
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => { (Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
@ -2500,12 +2500,12 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Po
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
externals.iter().for_each(|x| { externals.iter().for_each(|x| {
args.push(Expr::Variable(Box::new((x.clone(), None, 0, None)))); args.push(Expr::Variable(Box::new((None, None, 0, x.clone()))));
}); });
#[cfg(feature = "no_closure")] #[cfg(feature = "no_closure")]
externals.into_iter().for_each(|x| { externals.into_iter().for_each(|x| {
args.push(Expr::Variable(Box::new((x.clone(), None, 0, None)))); args.push(Expr::Variable(Box::new((None, None, 0, x.clone()))));
}); });
let hash = calc_script_fn_hash(empty(), KEYWORD_FN_PTR_CURRY, num_externals + 1); let hash = calc_script_fn_hash(empty(), KEYWORD_FN_PTR_CURRY, num_externals + 1);

View File

@ -66,12 +66,12 @@ impl EntryType {
// The variable type is packed separately into another array because it is even smaller. // The variable type is packed separately into another array because it is even smaller.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Scope<'a> { pub struct Scope<'a> {
/// (Name, alias) of the entry.
names: Vec<(Cow<'a, str>, Option<String>)>,
/// Type of the entry.
types: Vec<EntryType>,
/// Current value of the entry. /// Current value of the entry.
values: Vec<Dynamic>, values: Vec<Dynamic>,
/// Type of the entry.
types: Vec<EntryType>,
/// (Name, alias) of the entry.
names: Vec<(Cow<'a, str>, Option<String>)>,
} }
impl<'a> Scope<'a> { impl<'a> Scope<'a> {

View File

@ -45,9 +45,14 @@ pub struct Position {
} }
/// No `Position`. /// No `Position`.
pub const NO_POS: Position = Position { line: 0, pos: 0 }; pub const NO_POS: Position = Position::NONE;
impl Position { impl Position {
/// A `Position` representing no position.
pub const NONE: Self = Self { line: 0, pos: 0 };
/// A `Position` representing the first position.
pub const START: Self = Self { line: 1, pos: 0 };
/// Create a new `Position`. /// Create a new `Position`.
/// ///
/// `line` must not be zero. /// `line` must not be zero.
@ -65,27 +70,24 @@ impl Position {
pos: position, pos: position,
} }
} }
/// Get the line number (1-based), or `None` if there is no position. /// Get the line number (1-based), or `None` if there is no position.
#[inline(always)] #[inline(always)]
pub fn line(&self) -> Option<usize> { pub fn line(self) -> Option<usize> {
if self.is_none() { if self.is_none() {
None None
} else { } else {
Some(self.line as usize) Some(self.line as usize)
} }
} }
/// Get the character position (1-based), or `None` if at beginning of a line. /// Get the character position (1-based), or `None` if at beginning of a line.
#[inline(always)] #[inline(always)]
pub fn position(&self) -> Option<usize> { pub fn position(self) -> Option<usize> {
if self.is_none() || self.pos == 0 { if self.is_none() || self.pos == 0 {
None None
} else { } else {
Some(self.pos as usize) Some(self.pos as usize)
} }
} }
/// Advance by one character position. /// Advance by one character position.
#[inline(always)] #[inline(always)]
pub(crate) fn advance(&mut self) { pub(crate) fn advance(&mut self) {
@ -96,7 +98,6 @@ impl Position {
self.pos += 1; self.pos += 1;
} }
} }
/// Go backwards by one character position. /// Go backwards by one character position.
/// ///
/// # Panics /// # Panics
@ -108,7 +109,6 @@ impl Position {
assert!(self.pos > 0, "cannot rewind at position 0"); assert!(self.pos > 0, "cannot rewind at position 0");
self.pos -= 1; self.pos -= 1;
} }
/// Advance to the next line. /// Advance to the next line.
#[inline(always)] #[inline(always)]
pub(crate) fn new_line(&mut self) { pub(crate) fn new_line(&mut self) {
@ -120,24 +120,22 @@ impl Position {
self.pos = 0; self.pos = 0;
} }
} }
/// Is this `Position` at the beginning of a line?
/// Create a `Position` representing no position.
#[inline(always)] #[inline(always)]
pub fn none() -> Self { pub fn is_beginning_of_line(self) -> bool {
NO_POS self.line == 0 && !self.is_none()
} }
/// Is there no `Position`? /// Is there no `Position`?
#[inline(always)] #[inline(always)]
pub fn is_none(&self) -> bool { pub fn is_none(self) -> bool {
self.line == 0 && self.pos == 0 self == Self::NONE
} }
} }
impl Default for Position { impl Default for Position {
#[inline(always)] #[inline(always)]
fn default() -> Self { fn default() -> Self {
Self::new(1, 0) Self::START
} }
} }
@ -330,7 +328,7 @@ pub enum Token {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
As, As,
/// A lexer error. /// A lexer error.
LexError(Box<LexError>), LexError(LexError),
/// A comment block. /// A comment block.
Comment(String), Comment(String),
/// A reserved symbol. /// A reserved symbol.
@ -1120,9 +1118,7 @@ fn get_next_token_inner(
INT::from_str_radix(&out, radix) INT::from_str_radix(&out, radix)
.map(Token::IntegerConstant) .map(Token::IntegerConstant)
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
Token::LexError(Box::new(LERR::MalformedNumber( Token::LexError(LERR::MalformedNumber(result.into_iter().collect()))
result.into_iter().collect(),
)))
}), }),
start_pos, start_pos,
)); ));
@ -1136,9 +1132,7 @@ fn get_next_token_inner(
return Some(( return Some((
num.unwrap_or_else(|_| { num.unwrap_or_else(|_| {
Token::LexError(Box::new(LERR::MalformedNumber( Token::LexError(LERR::MalformedNumber(result.into_iter().collect()))
result.into_iter().collect(),
)))
}), }),
start_pos, start_pos,
)); ));
@ -1153,7 +1147,7 @@ fn get_next_token_inner(
// " - string literal // " - string literal
('"', _) => { ('"', _) => {
return parse_string_literal(stream, state, pos, '"').map_or_else( return parse_string_literal(stream, state, pos, '"').map_or_else(
|err| Some((Token::LexError(Box::new(err.0)), err.1)), |err| Some((Token::LexError(err.0), err.1)),
|out| Some((Token::StringConstant(out), start_pos)), |out| Some((Token::StringConstant(out), start_pos)),
) )
} }
@ -1161,22 +1155,19 @@ fn get_next_token_inner(
// ' - character literal // ' - character literal
('\'', '\'') => { ('\'', '\'') => {
return Some(( return Some((
Token::LexError(Box::new(LERR::MalformedChar("".to_string()))), Token::LexError(LERR::MalformedChar("".to_string())),
start_pos, start_pos,
)) ))
} }
('\'', _) => { ('\'', _) => {
return Some(parse_string_literal(stream, state, pos, '\'').map_or_else( return Some(parse_string_literal(stream, state, pos, '\'').map_or_else(
|err| (Token::LexError(Box::new(err.0)), err.1), |err| (Token::LexError(err.0), err.1),
|result| { |result| {
let mut chars = result.chars(); let mut chars = result.chars();
let first = chars.next().unwrap(); let first = chars.next().unwrap();
if chars.next().is_some() { if chars.next().is_some() {
( (Token::LexError(LERR::MalformedChar(result)), start_pos)
Token::LexError(Box::new(LERR::MalformedChar(result))),
start_pos,
)
} else { } else {
(Token::CharConstant(first), start_pos) (Token::CharConstant(first), start_pos)
} }
@ -1452,7 +1443,7 @@ fn get_next_token_inner(
} }
(ch, _) => { (ch, _) => {
return Some(( return Some((
Token::LexError(Box::new(LERR::UnexpectedInput(ch.to_string()))), Token::LexError(LERR::UnexpectedInput(ch.to_string())),
start_pos, start_pos,
)) ))
} }
@ -1494,7 +1485,7 @@ fn get_identifier(
if !is_valid_identifier { if !is_valid_identifier {
return Some(( return Some((
Token::LexError(Box::new(LERR::MalformedIdentifier(identifier))), Token::LexError(LERR::MalformedIdentifier(identifier)),
start_pos, start_pos,
)); ));
} }
@ -1652,42 +1643,42 @@ impl<'a> Iterator for TokenIterator<'a, '_> {
Some((Token::Reserved(s), pos)) => Some((match Some((Token::Reserved(s), pos)) => Some((match
(s.as_str(), self.engine.custom_keywords.contains_key(&s)) (s.as_str(), self.engine.custom_keywords.contains_key(&s))
{ {
("===", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("===", false) => Token::LexError(LERR::ImproperSymbol(
"'===' 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(),
))), )),
("!==", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("!==", false) => Token::LexError(LERR::ImproperSymbol(
"'!==' 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(),
))), )),
("->", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("->", false) => Token::LexError(LERR::ImproperSymbol(
"'->' is not a valid symbol. This is not C or C++!".to_string()))), "'->' is not a valid symbol. This is not C or C++!".to_string())),
("<-", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("<-", false) => Token::LexError(LERR::ImproperSymbol(
"'<-' is not a valid symbol. This is not Go! Should it be '<='?".to_string(), "'<-' is not a valid symbol. This is not Go! Should it be '<='?".to_string(),
))), )),
("=>", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("=>", false) => Token::LexError(LERR::ImproperSymbol(
"'=>' is not a valid symbol. This is not Rust! Should it be '>='?".to_string(), "'=>' is not a valid symbol. This is not Rust! Should it be '>='?".to_string(),
))), )),
(":=", false) => Token::LexError(Box::new(LERR::ImproperSymbol( (":=", false) => Token::LexError(LERR::ImproperSymbol(
"':=' is not a valid assignment operator. This is not Go! Should it be simply '='?".to_string(), "':=' is not a valid assignment operator. This is not Go! Should it be simply '='?".to_string(),
))), )),
("::<", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("::<", false) => Token::LexError(LERR::ImproperSymbol(
"'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(), "'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(),
))), )),
("(*", false) | ("*)", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol(
"'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(), "'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(),
))), )),
("#", false) => Token::LexError(Box::new(LERR::ImproperSymbol( ("#", false) => Token::LexError(LERR::ImproperSymbol(
"'#' is not a valid symbol. Should it be '#{'?".to_string(), "'#' is not a valid symbol. Should it be '#{'?".to_string(),
))), )),
// Reserved keyword/operator that is custom. // Reserved keyword/operator that is custom.
(_, true) => Token::Custom(s), (_, true) => Token::Custom(s),
// Reserved operator that is not custom. // Reserved operator that is not custom.
(token, false) if !is_valid_identifier(token.chars()) => Token::LexError(Box::new(LERR::ImproperSymbol( (token, false) if !is_valid_identifier(token.chars()) => Token::LexError(LERR::ImproperSymbol(
format!("'{}' is a reserved symbol", token) format!("'{}' is a reserved symbol", token)
))), )),
// Reserved keyword that is not custom and disabled. // Reserved keyword that is not custom and disabled.
(token, false) if self.engine.disabled_symbols.contains(token) => Token::LexError(Box::new(LERR::ImproperSymbol( (token, false) if self.engine.disabled_symbols.contains(token) => Token::LexError(LERR::ImproperSymbol(
format!("reserved symbol '{}' is disabled", token) format!("reserved symbol '{}' is disabled", token)
))), )),
// Reserved keyword/operator that is not custom. // Reserved keyword/operator that is not custom.
(_, false) => Token::Reserved(s), (_, false) => Token::Reserved(s),
}, pos)), }, pos)),
@ -1708,7 +1699,7 @@ impl<'a> Iterator for TokenIterator<'a, '_> {
// Disabled operator // Disabled operator
Some((token, pos)) if token.is_operator() && self.engine.disabled_symbols.contains(token.syntax().as_ref()) => { Some((token, pos)) if token.is_operator() && self.engine.disabled_symbols.contains(token.syntax().as_ref()) => {
Some(( Some((
Token::LexError(Box::new(LexError::UnexpectedInput(token.syntax().into()))), Token::LexError(LexError::UnexpectedInput(token.syntax().into())),
pos, pos,
)) ))
} }