diff --git a/src/ast.rs b/src/ast.rs index bb99d2f3..c13c2b8b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -861,24 +861,24 @@ pub struct BinaryExpr { /// A function call. #[derive(Debug, Clone, Hash, Default)] pub struct FnCallInfo { - /// 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>, - /// Namespace of the function, if any. - pub namespace: Option, + /// Pre-calculated hash for a script-defined function of the same name and number of parameters. + pub hash: u64, /// 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). pub native_only: bool, /// Does this function call capture the parent scope? 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, /// 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` pub def_value: Option, + /// Namespace of the function, if any. + pub namespace: Option>, + /// 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, } /// _[INTERNALS]_ An expression sub-tree. @@ -903,10 +903,10 @@ pub enum Expr { StringConstant(Box), /// FnPtr constant. FnPointer(Box), - /// Variable access - (variable name, optional modules, hash, optional index) - Variable(Box<(Ident, Option, u64, Option)>), - /// Property access. - Property(Box<(IdentX, (String, String))>), + /// Variable access - (optional index, optional modules, hash, variable name) + Variable(Box<(Option, Option>, u64, Ident)>), + /// Property access - (getter, setter), prop + Property(Box<((String, String), IdentX)>), /// { stmt } Stmt(Box, Position), /// Wrapped expression - should not be optimized away. @@ -1014,7 +1014,7 @@ impl Expr { /// Is the expression a simple variable access? pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> { 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, } } @@ -1033,9 +1033,9 @@ impl Expr { Self::FnPointer(x) => x.pos, Self::Array(_, pos) => *pos, Self::Map(_, pos) => *pos, - Self::Property(x) => (x.0).pos, + Self::Property(x) => (x.1).pos, Self::Stmt(_, pos) => *pos, - Self::Variable(x) => (x.0).pos, + Self::Variable(x) => (x.3).pos, Self::FnCall(_, pos) => *pos, 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::Array(_, pos) => *pos = new_pos, Self::Map(_, pos) => *pos = new_pos, - Self::Variable(x) => (x.0).pos = new_pos, - Self::Property(x) => (x.0).pos = new_pos, + Self::Variable(x) => (x.3).pos = new_pos, + Self::Property(x) => (x.1).pos = new_pos, Self::Stmt(_, pos) => *pos = new_pos, Self::FnCall(_, 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 { match self { Self::Variable(x) if x.1.is_none() => { - let ident = x.0; + let ident = x.3; let getter = make_getter(&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, } diff --git a/src/engine.rs b/src/engine.rs index a9a2a636..9792c766 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -77,7 +77,7 @@ pub type Map = HashMap; // `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. #[derive(Debug, Clone, Default)] -pub struct Imports(StaticVec, StaticVec); +pub struct Imports(StaticVec, StaticVec); impl Imports { /// Get the length of this stack of imported modules. @@ -86,15 +86,15 @@ impl Imports { } /// Get the imported module at a particular index. 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. 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. pub fn find(&self, name: &str) -> Option { - self.0 + self.1 .iter() .enumerate() .rev() @@ -103,8 +103,8 @@ impl Imports { } /// Push an imported module onto the stack. pub fn push(&mut self, name: impl Into, module: Module) { - self.0.push(name.into()); - self.1.push(module); + self.0.push(module); + self.1.push(name.into()); } /// Truncate the stack of imported modules to a particular length. pub fn truncate(&mut self, size: usize) { @@ -114,11 +114,11 @@ impl Imports { /// Get an iterator to this stack of imported modules. #[allow(dead_code)] pub fn iter(&self) -> impl Iterator { - 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. pub fn into_iter(self) -> impl Iterator { - 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 { Expr::Variable(v) => match v.as_ref() { // 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 target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| { match *err { @@ -844,7 +844,7 @@ impl Engine { this_ptr: &'s mut Option<&mut Dynamic>, expr: &'a Expr, ) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box> { - let (Ident { name, pos }, _, _, index) = match expr { + let (index, _, _, Ident { name, pos }) = match expr { Expr::Variable(v) => v.as_ref(), _ => unreachable!(), }; @@ -984,7 +984,7 @@ impl Engine { let args = &mut [val, &mut idx_val2, &mut new_val.0]; 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, ) .map_err(|err| match *err { @@ -1026,8 +1026,7 @@ impl Engine { let def_value = def_value.map(Into::::into); let args = idx_val.as_fn_call_args(); self.make_method_call( - state, lib, name, *hash, target, args, &def_value, *native, false, - level, + state, lib, name, *hash, target, args, def_value, *native, false, level, ) .map_err(|err| err.fill_position(*pos)) } @@ -1035,7 +1034,7 @@ impl Engine { Expr::FnCall(_, _) => unreachable!(), // {xxx:map}.id = ??? Expr::Property(x) if target.is::() && new_val.is_some() => { - let IdentX { name, pos } = &x.0; + let IdentX { name, pos } = &x.1; let index = name.clone().into(); let mut val = self .get_indexed_mut(state, lib, target, index, *pos, true, false, level)?; @@ -1045,7 +1044,7 @@ impl Engine { } // {xxx:map}.id Expr::Property(x) if target.is::() => { - let IdentX { name, pos } = &x.0; + let IdentX { name, pos } = &x.1; let index = name.clone().into(); let val = self.get_indexed_mut( state, lib, target, index, *pos, false, false, level, @@ -1055,11 +1054,11 @@ impl Engine { } // xxx.id = ??? 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 args = [target.as_mut(), &mut new_val.as_mut().unwrap().0]; 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, ) .map(|(v, _)| (v, true)) @@ -1067,10 +1066,10 @@ impl Engine { } // xxx.id Expr::Property(x) => { - let (IdentX { pos, .. }, (getter, _)) = x.as_ref(); + let ((getter, _), IdentX { pos, .. }) = x.as_ref(); let mut args = [target.as_mut()]; 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, ) .map(|(v, _)| (v, false)) @@ -1080,7 +1079,7 @@ impl Engine { Expr::Index(x, x_pos) | Expr::Dot(x, x_pos) if target.is::() => { let mut val = match &x.lhs { Expr::Property(p) => { - let IdentX { name, pos } = &p.0; + let IdentX { name, pos } = &p.1; let index = name.clone().into(); self.get_indexed_mut( state, lib, target, index, *pos, false, true, level, @@ -1099,7 +1098,7 @@ impl Engine { let args = idx_val.as_fn_call_args(); let (val, _) = self .make_method_call( - state, lib, name, *hash, target, args, &def_value, *native, + state, lib, name, *hash, target, args, def_value, *native, false, level, ) .map_err(|err| err.fill_position(*pos))?; @@ -1122,13 +1121,13 @@ impl Engine { match &x.lhs { // xxx.prop[expr] | xxx.prop.expr 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 args = &mut arg_values[..1]; let (mut val, updated) = self .exec_fn_call( state, lib, getter, 0, args, is_ref, true, false, None, - &None, level, + None, level, ) .map_err(|err| err.fill_position(*pos))?; @@ -1154,7 +1153,7 @@ impl Engine { arg_values[1] = val; self.exec_fn_call( state, lib, setter, 0, arg_values, is_ref, true, false, - None, &None, level, + None, None, level, ) .or_else( |err| match *err { @@ -1182,7 +1181,7 @@ impl Engine { let args = idx_val.as_fn_call_args(); let (mut val, _) = self .make_method_call( - state, lib, name, *hash, target, args, &def_value, *native, + state, lib, name, *hash, target, args, def_value, *native, false, level, ) .map_err(|err| err.fill_position(*pos))?; @@ -1257,7 +1256,7 @@ impl Engine { let Ident { name: var_name, pos: var_pos, - } = &x.0; + } = &x.3; self.inc_operations(state) .map_err(|err| err.fill_position(*var_pos))?; @@ -1458,7 +1457,7 @@ impl Engine { let mut idx = idx; let args = &mut [val, &mut idx]; 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_err(|err| match *err { @@ -1504,13 +1503,14 @@ impl Engine { for value in rhs_value.iter_mut() { let args = &mut [&mut lhs_value.clone(), value]; + let def_value = def_value.clone(); // Qualifiers (none) + function name + number of arguments + argument `TypeId`'s. let hash = calc_native_fn_hash(empty(), OP_FUNC, args.iter().map(|a| a.type_id())); 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()))? .0 .as_bool() @@ -1520,7 +1520,7 @@ impl Engine { } } - Ok(def_value.unwrap()) + Ok(false.into()) } #[cfg(not(feature = "no_object"))] Dynamic(Union::Map(rhs_value)) => match lhs_value { @@ -1564,11 +1564,11 @@ impl Engine { Expr::FnPointer(x) => { 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 { Ok(val.clone()) } else { - EvalAltResult::ErrorUnboundThis((x.0).pos).into() + EvalAltResult::ErrorUnboundThis((x.3).pos).into() } } Expr::Variable(_) => { @@ -1623,7 +1623,7 @@ impl Engine { } = x.as_ref(); let def_value = def_value.map(Into::::into); 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, ) .map_err(|err| err.fill_position(*pos)) @@ -1639,8 +1639,9 @@ impl Engine { def_value, .. } = x.as_ref(); + let modules = namespace.as_ref().map(|v| v.as_ref()); 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, ) .map_err(|err| err.fill_position(*pos)) @@ -1812,7 +1813,7 @@ impl Engine { // Run function let (value, _) = self .exec_fn_call( - state, lib, op, 0, args, false, false, false, None, &None, + state, lib, op, 0, args, false, false, false, None, None, level, ) .map_err(|err| err.fill_position(*op_pos))?; @@ -1850,7 +1851,7 @@ impl Engine { let result = self .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_err(|err| err.fill_position(*op_pos))?; diff --git a/src/fn_call.rs b/src/fn_call.rs index 313b4b15..1a645870 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -186,7 +186,7 @@ impl Engine { args: &mut FnCallArgs, is_ref: bool, pub_only: bool, - def_val: &Option, + def_val: Option, ) -> Result<(Dynamic, bool), Box> { self.inc_operations(state)?; @@ -254,7 +254,7 @@ impl Engine { // Return default value (if any) if let Some(val) = def_val { - return Ok((val.clone(), false)); + return Ok((val, false)); } // Getter function not found? @@ -479,7 +479,7 @@ impl Engine { _is_method: bool, pub_only: bool, _capture_scope: Option, - def_val: &Option, + def_val: Option, _level: usize, ) -> Result<(Dynamic, bool), Box> { // Check for data race. @@ -686,7 +686,7 @@ impl Engine { hash_script: u64, target: &mut Target, mut call_args: StaticVec, - def_val: &Option, + def_val: Option, native: bool, pub_only: bool, level: usize, @@ -837,7 +837,7 @@ impl Engine { this_ptr: &mut Option<&mut Dynamic>, name: &str, args_expr: impl AsRef<[Expr]>, - def_val: &Option, + def_val: Option, mut hash_script: u64, native: bool, pub_only: bool, @@ -1074,7 +1074,7 @@ impl Engine { state: &mut State, lib: &[&Module], this_ptr: &mut Option<&mut Dynamic>, - modules: &Option, + modules: Option<&ModuleRef>, name: &str, args_expr: impl AsRef<[Expr]>, def_val: Option, diff --git a/src/fn_native.rs b/src/fn_native.rs index f41490d0..56488ac2 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -193,7 +193,7 @@ impl FnPtr { has_this, true, None, - &None, + None, 0, ) .map(|(v, _)| v) diff --git a/src/optimize.rs b/src/optimize.rs index 55c5d988..3895fd52 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -147,7 +147,7 @@ fn call_fn_with_constant_arguments( arg_values.iter_mut().collect::>().as_mut(), false, true, - &None, + None, ) .ok() .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) { // map.string (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. // All other items can be thrown away. state.set_dirty(); @@ -686,12 +686,12 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr { } // 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(); // Replace constant with value - let mut expr = state.find_constant(&x.0.name).unwrap().clone(); - expr.set_position(x.0.pos); + let mut expr = state.find_constant(&x.3.name).unwrap().clone(); + expr.set_position(x.3.pos); expr } diff --git a/src/parser.rs b/src/parser.rs index 61fc858b..df7a28ad 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -267,7 +267,7 @@ fn parse_fn_call( lib: &mut FunctionsLib, id: String, capture: bool, - mut namespace: Option, + mut namespace: Option>, settings: ParseSettings, ) -> Result { let (token, token_pos) = input.peek().unwrap(); @@ -788,7 +788,7 @@ fn parse_primary( { 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 #[cfg(not(feature = "no_module"))] @@ -798,18 +798,18 @@ fn parse_primary( { 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 Token::Identifier(s) => { 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 Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => { 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 { return Err(PERR::Reserved(s).into_err(settings.pos)); } @@ -824,7 +824,7 @@ fn parse_primary( ))) .into_err(settings.pos)); } 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)); } - let (Ident { name, pos }, modules, _, _) = *x; + let (_, modules, _, Ident { name, pos }) = *x; settings.pos = pos; parse_fn_call(input, state, lib, name, true, modules, settings.level_up())? } // Function call (Expr::Variable(x), Token::LeftParen) => { - let (Ident { name, pos }, modules, _, _) = *x; + let (_, modules, _, Ident { name, pos }) = *x; settings.pos = pos; parse_fn_call(input, state, lib, name, false, modules, settings.level_up())? } @@ -897,17 +897,17 @@ fn parse_primary( // module access (Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() { (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 { modules.push(var_name_def); } else { let mut m: ModuleRef = Default::default(); 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()) => { return Err(PERR::Reserved(id2).into_err(pos2)); @@ -931,7 +931,7 @@ fn parse_primary( match &mut root_expr { // Cache the hash key for module-qualified variables 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(); // Qualifiers + variable name @@ -1087,19 +1087,19 @@ fn make_assignment_stmt<'a>( ) -> Result { match &lhs { // 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)) } // var (indexed) = rhs Expr::Variable(x) => { let ( + index, + _, + _, Ident { name, pos: name_pos, }, - _, - _, - index, ) = x.as_ref(); match state.stack[(state.stack.len() - index.unwrap().get())].1 { ScopeEntryType::Normal => { @@ -1114,19 +1114,19 @@ fn make_assignment_stmt<'a>( // xxx[???] = rhs, xxx.??? = rhs Expr::Index(x, _) | Expr::Dot(x, _) => match &x.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)) } // var[???] (indexed) = rhs, var.??? (indexed) = rhs Expr::Variable(x) => { let ( + index, + _, + _, Ident { name, pos: name_pos, }, - _, - _, - index, ) = x.as_ref(); match state.stack[(state.stack.len() - index.unwrap().get())].1 { ScopeEntryType::Normal => { @@ -1204,10 +1204,10 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result { - let ident = x.0; + let ident = x.3; let getter = make_getter(&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) } @@ -1642,10 +1642,10 @@ fn parse_custom_syntax( (Token::Identifier(s), pos) => { segments.push(s.clone()); exprs.push(Expr::Variable(Box::new(( - Ident::new(s, pos), + None, None, 0, - None, + Ident::new(s, pos), )))); } (Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => { @@ -2500,12 +2500,12 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec, pos: Po #[cfg(not(feature = "no_closure"))] 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")] 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); diff --git a/src/scope.rs b/src/scope.rs index 77e45a87..970ecba0 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -66,12 +66,12 @@ impl EntryType { // The variable type is packed separately into another array because it is even smaller. #[derive(Debug, Clone, Default)] pub struct Scope<'a> { - /// (Name, alias) of the entry. - names: Vec<(Cow<'a, str>, Option)>, - /// Type of the entry. - types: Vec, /// Current value of the entry. values: Vec, + /// Type of the entry. + types: Vec, + /// (Name, alias) of the entry. + names: Vec<(Cow<'a, str>, Option)>, } impl<'a> Scope<'a> { diff --git a/src/token.rs b/src/token.rs index 944b2f48..a27dcd82 100644 --- a/src/token.rs +++ b/src/token.rs @@ -45,9 +45,14 @@ pub struct Position { } /// No `Position`. -pub const NO_POS: Position = Position { line: 0, pos: 0 }; +pub const NO_POS: Position = Position::NONE; 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`. /// /// `line` must not be zero. @@ -65,27 +70,24 @@ impl Position { pos: position, } } - /// Get the line number (1-based), or `None` if there is no position. #[inline(always)] - pub fn line(&self) -> Option { + pub fn line(self) -> Option { if self.is_none() { None } else { Some(self.line as usize) } } - /// Get the character position (1-based), or `None` if at beginning of a line. #[inline(always)] - pub fn position(&self) -> Option { + pub fn position(self) -> Option { if self.is_none() || self.pos == 0 { None } else { Some(self.pos as usize) } } - /// Advance by one character position. #[inline(always)] pub(crate) fn advance(&mut self) { @@ -96,7 +98,6 @@ impl Position { self.pos += 1; } } - /// Go backwards by one character position. /// /// # Panics @@ -108,7 +109,6 @@ impl Position { assert!(self.pos > 0, "cannot rewind at position 0"); self.pos -= 1; } - /// Advance to the next line. #[inline(always)] pub(crate) fn new_line(&mut self) { @@ -120,24 +120,22 @@ impl Position { self.pos = 0; } } - - /// Create a `Position` representing no position. + /// Is this `Position` at the beginning of a line? #[inline(always)] - pub fn none() -> Self { - NO_POS + pub fn is_beginning_of_line(self) -> bool { + self.line == 0 && !self.is_none() } - /// Is there no `Position`? #[inline(always)] - pub fn is_none(&self) -> bool { - self.line == 0 && self.pos == 0 + pub fn is_none(self) -> bool { + self == Self::NONE } } impl Default for Position { #[inline(always)] fn default() -> Self { - Self::new(1, 0) + Self::START } } @@ -330,7 +328,7 @@ pub enum Token { #[cfg(not(feature = "no_module"))] As, /// A lexer error. - LexError(Box), + LexError(LexError), /// A comment block. Comment(String), /// A reserved symbol. @@ -1120,9 +1118,7 @@ fn get_next_token_inner( INT::from_str_radix(&out, radix) .map(Token::IntegerConstant) .unwrap_or_else(|_| { - Token::LexError(Box::new(LERR::MalformedNumber( - result.into_iter().collect(), - ))) + Token::LexError(LERR::MalformedNumber(result.into_iter().collect())) }), start_pos, )); @@ -1136,9 +1132,7 @@ fn get_next_token_inner( return Some(( num.unwrap_or_else(|_| { - Token::LexError(Box::new(LERR::MalformedNumber( - result.into_iter().collect(), - ))) + Token::LexError(LERR::MalformedNumber(result.into_iter().collect())) }), start_pos, )); @@ -1153,7 +1147,7 @@ fn get_next_token_inner( // " - string literal ('"', _) => { 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)), ) } @@ -1161,22 +1155,19 @@ fn get_next_token_inner( // ' - character literal ('\'', '\'') => { return Some(( - Token::LexError(Box::new(LERR::MalformedChar("".to_string()))), + Token::LexError(LERR::MalformedChar("".to_string())), start_pos, )) } ('\'', _) => { 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| { let mut chars = result.chars(); let first = chars.next().unwrap(); if chars.next().is_some() { - ( - Token::LexError(Box::new(LERR::MalformedChar(result))), - start_pos, - ) + (Token::LexError(LERR::MalformedChar(result)), start_pos) } else { (Token::CharConstant(first), start_pos) } @@ -1452,7 +1443,7 @@ fn get_next_token_inner( } (ch, _) => { return Some(( - Token::LexError(Box::new(LERR::UnexpectedInput(ch.to_string()))), + Token::LexError(LERR::UnexpectedInput(ch.to_string())), start_pos, )) } @@ -1494,7 +1485,7 @@ fn get_identifier( if !is_valid_identifier { return Some(( - Token::LexError(Box::new(LERR::MalformedIdentifier(identifier))), + Token::LexError(LERR::MalformedIdentifier(identifier)), start_pos, )); } @@ -1652,42 +1643,42 @@ impl<'a> Iterator for TokenIterator<'a, '_> { Some((Token::Reserved(s), pos)) => Some((match (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(), - ))), - ("!==", 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(), - ))), - ("->", false) => Token::LexError(Box::new(LERR::ImproperSymbol( - "'->' 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 C or C++!".to_string())), + ("<-", false) => Token::LexError(LERR::ImproperSymbol( "'<-' 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(), - ))), - (":=", 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(), - ))), - ("::<", 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(), - ))), - ("(*", 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(), - ))), - ("#", false) => Token::LexError(Box::new(LERR::ImproperSymbol( + )), + ("#", false) => Token::LexError(LERR::ImproperSymbol( "'#' is not a valid symbol. Should it be '#{'?".to_string(), - ))), + )), // Reserved keyword/operator that is custom. (_, true) => Token::Custom(s), // 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) - ))), + )), // 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) - ))), + )), // Reserved keyword/operator that is not custom. (_, false) => Token::Reserved(s), }, pos)), @@ -1708,7 +1699,7 @@ impl<'a> Iterator for TokenIterator<'a, '_> { // Disabled operator Some((token, pos)) if token.is_operator() && self.engine.disabled_symbols.contains(token.syntax().as_ref()) => { Some(( - Token::LexError(Box::new(LexError::UnexpectedInput(token.syntax().into()))), + Token::LexError(LexError::UnexpectedInput(token.syntax().into())), pos, )) }