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.
#[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,
}

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,
// 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))?;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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