Minor code refactor.
This commit is contained in:
parent
cc304ba513
commit
b9de8eaa7f
42
src/ast.rs
42
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<ModuleRef>,
|
||||
/// 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<Expr>,
|
||||
/// 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<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.
|
||||
@ -903,10 +903,10 @@ pub enum Expr {
|
||||
StringConstant(Box<IdentX>),
|
||||
/// FnPtr constant.
|
||||
FnPointer(Box<IdentX>),
|
||||
/// Variable access - (variable name, optional modules, hash, optional index)
|
||||
Variable(Box<(Ident, Option<ModuleRef>, u64, Option<NonZeroUsize>)>),
|
||||
/// Property access.
|
||||
Property(Box<(IdentX, (String, String))>),
|
||||
/// Variable access - (optional index, optional modules, hash, variable name)
|
||||
Variable(Box<(Option<NonZeroUsize>, Option<Box<ModuleRef>>, u64, Ident)>),
|
||||
/// Property access - (getter, setter), prop
|
||||
Property(Box<((String, String), IdentX)>),
|
||||
/// { stmt }
|
||||
Stmt(Box<Stmt>, 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,
|
||||
}
|
||||
|
@ -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,
|
||||
// so packing the import names together improves cache locality.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Imports(StaticVec<ImmutableString>, StaticVec<Module>);
|
||||
pub struct Imports(StaticVec<Module>, StaticVec<ImmutableString>);
|
||||
|
||||
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<usize> {
|
||||
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<ImmutableString>, 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<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.
|
||||
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 {
|
||||
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<EvalAltResult>> {
|
||||
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::<Dynamic>::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::<Map>() && 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::<Map>() => {
|
||||
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::<Map>() => {
|
||||
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::<Dynamic>::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))?;
|
||||
|
@ -186,7 +186,7 @@ impl Engine {
|
||||
args: &mut FnCallArgs,
|
||||
is_ref: bool,
|
||||
pub_only: bool,
|
||||
def_val: &Option<Dynamic>,
|
||||
def_val: Option<Dynamic>,
|
||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||
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<Scope>,
|
||||
def_val: &Option<Dynamic>,
|
||||
def_val: Option<Dynamic>,
|
||||
_level: usize,
|
||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||
// Check for data race.
|
||||
@ -686,7 +686,7 @@ impl Engine {
|
||||
hash_script: u64,
|
||||
target: &mut Target,
|
||||
mut call_args: StaticVec<Dynamic>,
|
||||
def_val: &Option<Dynamic>,
|
||||
def_val: Option<Dynamic>,
|
||||
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<Dynamic>,
|
||||
def_val: Option<Dynamic>,
|
||||
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<ModuleRef>,
|
||||
modules: Option<&ModuleRef>,
|
||||
name: &str,
|
||||
args_expr: impl AsRef<[Expr]>,
|
||||
def_val: Option<bool>,
|
||||
|
@ -193,7 +193,7 @@ impl FnPtr {
|
||||
has_this,
|
||||
true,
|
||||
None,
|
||||
&None,
|
||||
None,
|
||||
0,
|
||||
)
|
||||
.map(|(v, _)| v)
|
||||
|
@ -147,7 +147,7 @@ fn call_fn_with_constant_arguments(
|
||||
arg_values.iter_mut().collect::<StaticVec<_>>().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
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ fn parse_fn_call(
|
||||
lib: &mut FunctionsLib,
|
||||
id: String,
|
||||
capture: bool,
|
||||
mut namespace: Option<ModuleRef>,
|
||||
mut namespace: Option<Box<ModuleRef>>,
|
||||
settings: ParseSettings,
|
||||
) -> Result<Expr, ParseError> {
|
||||
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<Stmt, ParseError> {
|
||||
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<Expr, ParseEr
|
||||
}
|
||||
// lhs.id
|
||||
(lhs, Expr::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);
|
||||
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<Ident>, 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);
|
||||
|
@ -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<String>)>,
|
||||
/// Type of the entry.
|
||||
types: Vec<EntryType>,
|
||||
/// Current value of the entry.
|
||||
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> {
|
||||
|
101
src/token.rs
101
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<usize> {
|
||||
pub fn line(self) -> Option<usize> {
|
||||
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<usize> {
|
||||
pub fn position(self) -> Option<usize> {
|
||||
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(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,
|
||||
))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user