Move Assignment to Stmt.
This commit is contained in:
parent
fd2ba54b49
commit
51fca1e757
306
src/engine.rs
306
src/engine.rs
@ -1520,159 +1520,6 @@ impl Engine {
|
|||||||
// Statement block
|
// Statement block
|
||||||
Expr::Stmt(x) => self.eval_stmt(scope, mods, state, lib, this_ptr, &x.0, level),
|
Expr::Stmt(x) => self.eval_stmt(scope, mods, state, lib, this_ptr, &x.0, level),
|
||||||
|
|
||||||
// var op= rhs
|
|
||||||
Expr::Assignment(x) if x.0.get_variable_access(false).is_some() => {
|
|
||||||
let (lhs_expr, op, rhs_expr, op_pos) = x.as_ref();
|
|
||||||
let mut rhs_val = self
|
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?
|
|
||||||
.flatten();
|
|
||||||
let (mut lhs_ptr, name, typ, pos) =
|
|
||||||
self.search_namespace(scope, mods, state, lib, this_ptr, lhs_expr)?;
|
|
||||||
|
|
||||||
if !lhs_ptr.is_ref() {
|
|
||||||
return EvalAltResult::ErrorAssignmentToConstant(name.to_string(), pos).into();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.inc_operations(state)
|
|
||||||
.map_err(|err| err.fill_position(pos))?;
|
|
||||||
|
|
||||||
match typ {
|
|
||||||
// Assignment to constant variable
|
|
||||||
ScopeEntryType::Constant => Err(Box::new(
|
|
||||||
EvalAltResult::ErrorAssignmentToConstant(name.to_string(), pos),
|
|
||||||
)),
|
|
||||||
// Normal assignment
|
|
||||||
ScopeEntryType::Normal if op.is_empty() => {
|
|
||||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
|
||||||
*lhs_ptr.as_mut().write_lock::<Dynamic>().unwrap() = rhs_val;
|
|
||||||
} else {
|
|
||||||
*lhs_ptr.as_mut() = rhs_val;
|
|
||||||
}
|
|
||||||
Ok(Default::default())
|
|
||||||
}
|
|
||||||
// Op-assignment - in order of precedence:
|
|
||||||
ScopeEntryType::Normal => {
|
|
||||||
// 1) Native registered overriding function
|
|
||||||
// 2) Built-in implementation
|
|
||||||
// 3) Map to `var = var op rhs`
|
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
|
||||||
let arg_types =
|
|
||||||
once(lhs_ptr.as_mut().type_id()).chain(once(rhs_val.type_id()));
|
|
||||||
let hash_fn = calc_fn_hash(empty(), op, 2, arg_types);
|
|
||||||
|
|
||||||
match self
|
|
||||||
.global_module
|
|
||||||
.get_fn(hash_fn, false)
|
|
||||||
.or_else(|| self.packages.get_fn(hash_fn, false))
|
|
||||||
{
|
|
||||||
// op= function registered as method
|
|
||||||
Some(func) if func.is_method() => {
|
|
||||||
let mut lock_guard;
|
|
||||||
let lhs_ptr_inner;
|
|
||||||
|
|
||||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
|
||||||
lock_guard = lhs_ptr.as_mut().write_lock::<Dynamic>().unwrap();
|
|
||||||
lhs_ptr_inner = lock_guard.deref_mut();
|
|
||||||
} else {
|
|
||||||
lhs_ptr_inner = lhs_ptr.as_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
let args = &mut [lhs_ptr_inner, &mut rhs_val];
|
|
||||||
|
|
||||||
// Overriding exact implementation
|
|
||||||
if func.is_plugin_fn() {
|
|
||||||
func.get_plugin_fn().call((self, lib).into(), args)?;
|
|
||||||
} else {
|
|
||||||
func.get_native_fn()((self, lib).into(), args)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Built-in op-assignment function
|
|
||||||
_ if run_builtin_op_assignment(op, lhs_ptr.as_mut(), &rhs_val)?
|
|
||||||
.is_some() => {}
|
|
||||||
// Not built-in: expand to `var = var op rhs`
|
|
||||||
_ => {
|
|
||||||
let op = &op[..op.len() - 1]; // extract operator without =
|
|
||||||
|
|
||||||
// Clone the LHS value
|
|
||||||
let args = &mut [&mut lhs_ptr.as_mut().clone(), &mut rhs_val];
|
|
||||||
|
|
||||||
// Run function
|
|
||||||
let (value, _) = self
|
|
||||||
.exec_fn_call(
|
|
||||||
state, lib, op, 0, args, false, false, false, None, &None,
|
|
||||||
level,
|
|
||||||
)
|
|
||||||
.map_err(|err| err.fill_position(*op_pos))?;
|
|
||||||
|
|
||||||
let value = value.flatten();
|
|
||||||
|
|
||||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
|
||||||
*lhs_ptr.as_mut().write_lock::<Dynamic>().unwrap() = value;
|
|
||||||
} else {
|
|
||||||
*lhs_ptr.as_mut() = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// lhs op= rhs
|
|
||||||
Expr::Assignment(x) => {
|
|
||||||
let (lhs_expr, op, rhs_expr, op_pos) = x.as_ref();
|
|
||||||
let mut rhs_val =
|
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?;
|
|
||||||
|
|
||||||
let _new_val = if op.is_empty() {
|
|
||||||
// Normal assignment
|
|
||||||
Some((rhs_val, rhs_expr.position()))
|
|
||||||
} else {
|
|
||||||
// Op-assignment - always map to `lhs = lhs op rhs`
|
|
||||||
let op = &op[..op.len() - 1]; // extract operator without =
|
|
||||||
let args = &mut [
|
|
||||||
&mut self.eval_expr(scope, mods, state, lib, this_ptr, lhs_expr, level)?,
|
|
||||||
&mut rhs_val,
|
|
||||||
];
|
|
||||||
|
|
||||||
let result = self
|
|
||||||
.exec_fn_call(
|
|
||||||
state, lib, op, 0, args, false, false, false, None, &None, level,
|
|
||||||
)
|
|
||||||
.map(|(v, _)| v)
|
|
||||||
.map_err(|err| err.fill_position(*op_pos))?;
|
|
||||||
|
|
||||||
Some((result, rhs_expr.position()))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
|
||||||
match lhs_expr {
|
|
||||||
// name op= rhs (handled above)
|
|
||||||
Expr::Variable(_) => unreachable!(),
|
|
||||||
// idx_lhs[idx_expr] op= rhs
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
Expr::Index(_) => {
|
|
||||||
self.eval_dot_index_chain(
|
|
||||||
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
|
||||||
)?;
|
|
||||||
Ok(Default::default())
|
|
||||||
}
|
|
||||||
// dot_lhs.dot_rhs op= rhs
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
Expr::Dot(_) => {
|
|
||||||
self.eval_dot_index_chain(
|
|
||||||
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
|
||||||
)?;
|
|
||||||
Ok(Default::default())
|
|
||||||
}
|
|
||||||
// Constant expression (should be caught during parsing)
|
|
||||||
expr if expr.is_constant() => unreachable!(),
|
|
||||||
// Syntax error
|
|
||||||
expr => EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// lhs[idx_expr]
|
// lhs[idx_expr]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_) => {
|
Expr::Index(_) => {
|
||||||
@ -1810,6 +1657,159 @@ impl Engine {
|
|||||||
// Expression as statement
|
// Expression as statement
|
||||||
Stmt::Expr(expr) => self.eval_expr(scope, mods, state, lib, this_ptr, expr, level),
|
Stmt::Expr(expr) => self.eval_expr(scope, mods, state, lib, this_ptr, expr, level),
|
||||||
|
|
||||||
|
// var op= rhs
|
||||||
|
Stmt::Assignment(x, op_pos) if x.0.get_variable_access(false).is_some() => {
|
||||||
|
let (lhs_expr, op, rhs_expr) = x.as_ref();
|
||||||
|
let mut rhs_val = self
|
||||||
|
.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?
|
||||||
|
.flatten();
|
||||||
|
let (mut lhs_ptr, name, typ, pos) =
|
||||||
|
self.search_namespace(scope, mods, state, lib, this_ptr, lhs_expr)?;
|
||||||
|
|
||||||
|
if !lhs_ptr.is_ref() {
|
||||||
|
return EvalAltResult::ErrorAssignmentToConstant(name.to_string(), pos).into();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inc_operations(state)
|
||||||
|
.map_err(|err| err.fill_position(pos))?;
|
||||||
|
|
||||||
|
match typ {
|
||||||
|
// Assignment to constant variable
|
||||||
|
ScopeEntryType::Constant => Err(Box::new(
|
||||||
|
EvalAltResult::ErrorAssignmentToConstant(name.to_string(), pos),
|
||||||
|
)),
|
||||||
|
// Normal assignment
|
||||||
|
ScopeEntryType::Normal if op.is_empty() => {
|
||||||
|
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||||
|
*lhs_ptr.as_mut().write_lock::<Dynamic>().unwrap() = rhs_val;
|
||||||
|
} else {
|
||||||
|
*lhs_ptr.as_mut() = rhs_val;
|
||||||
|
}
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
// Op-assignment - in order of precedence:
|
||||||
|
ScopeEntryType::Normal => {
|
||||||
|
// 1) Native registered overriding function
|
||||||
|
// 2) Built-in implementation
|
||||||
|
// 3) Map to `var = var op rhs`
|
||||||
|
|
||||||
|
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
||||||
|
let arg_types =
|
||||||
|
once(lhs_ptr.as_mut().type_id()).chain(once(rhs_val.type_id()));
|
||||||
|
let hash_fn = calc_fn_hash(empty(), op, 2, arg_types);
|
||||||
|
|
||||||
|
match self
|
||||||
|
.global_module
|
||||||
|
.get_fn(hash_fn, false)
|
||||||
|
.or_else(|| self.packages.get_fn(hash_fn, false))
|
||||||
|
{
|
||||||
|
// op= function registered as method
|
||||||
|
Some(func) if func.is_method() => {
|
||||||
|
let mut lock_guard;
|
||||||
|
let lhs_ptr_inner;
|
||||||
|
|
||||||
|
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||||
|
lock_guard = lhs_ptr.as_mut().write_lock::<Dynamic>().unwrap();
|
||||||
|
lhs_ptr_inner = lock_guard.deref_mut();
|
||||||
|
} else {
|
||||||
|
lhs_ptr_inner = lhs_ptr.as_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = &mut [lhs_ptr_inner, &mut rhs_val];
|
||||||
|
|
||||||
|
// Overriding exact implementation
|
||||||
|
if func.is_plugin_fn() {
|
||||||
|
func.get_plugin_fn().call((self, lib).into(), args)?;
|
||||||
|
} else {
|
||||||
|
func.get_native_fn()((self, lib).into(), args)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Built-in op-assignment function
|
||||||
|
_ if run_builtin_op_assignment(op, lhs_ptr.as_mut(), &rhs_val)?
|
||||||
|
.is_some() => {}
|
||||||
|
// Not built-in: expand to `var = var op rhs`
|
||||||
|
_ => {
|
||||||
|
let op = &op[..op.len() - 1]; // extract operator without =
|
||||||
|
|
||||||
|
// Clone the LHS value
|
||||||
|
let args = &mut [&mut lhs_ptr.as_mut().clone(), &mut rhs_val];
|
||||||
|
|
||||||
|
// Run function
|
||||||
|
let (value, _) = self
|
||||||
|
.exec_fn_call(
|
||||||
|
state, lib, op, 0, args, false, false, false, None, &None,
|
||||||
|
level,
|
||||||
|
)
|
||||||
|
.map_err(|err| err.fill_position(*op_pos))?;
|
||||||
|
|
||||||
|
let value = value.flatten();
|
||||||
|
|
||||||
|
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||||
|
*lhs_ptr.as_mut().write_lock::<Dynamic>().unwrap() = value;
|
||||||
|
} else {
|
||||||
|
*lhs_ptr.as_mut() = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lhs op= rhs
|
||||||
|
Stmt::Assignment(x, op_pos) => {
|
||||||
|
let (lhs_expr, op, rhs_expr) = x.as_ref();
|
||||||
|
let mut rhs_val =
|
||||||
|
self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?;
|
||||||
|
|
||||||
|
let _new_val = if op.is_empty() {
|
||||||
|
// Normal assignment
|
||||||
|
Some((rhs_val, rhs_expr.position()))
|
||||||
|
} else {
|
||||||
|
// Op-assignment - always map to `lhs = lhs op rhs`
|
||||||
|
let op = &op[..op.len() - 1]; // extract operator without =
|
||||||
|
let args = &mut [
|
||||||
|
&mut self.eval_expr(scope, mods, state, lib, this_ptr, lhs_expr, level)?,
|
||||||
|
&mut rhs_val,
|
||||||
|
];
|
||||||
|
|
||||||
|
let result = self
|
||||||
|
.exec_fn_call(
|
||||||
|
state, lib, op, 0, args, false, false, false, None, &None, level,
|
||||||
|
)
|
||||||
|
.map(|(v, _)| v)
|
||||||
|
.map_err(|err| err.fill_position(*op_pos))?;
|
||||||
|
|
||||||
|
Some((result, rhs_expr.position()))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||||
|
match lhs_expr {
|
||||||
|
// name op= rhs (handled above)
|
||||||
|
Expr::Variable(_) => unreachable!(),
|
||||||
|
// idx_lhs[idx_expr] op= rhs
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Expr::Index(_) => {
|
||||||
|
self.eval_dot_index_chain(
|
||||||
|
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
||||||
|
)?;
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
// dot_lhs.dot_rhs op= rhs
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Expr::Dot(_) => {
|
||||||
|
self.eval_dot_index_chain(
|
||||||
|
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
||||||
|
)?;
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
// Constant expression (should be caught during parsing)
|
||||||
|
expr if expr.is_constant() => unreachable!(),
|
||||||
|
// Syntax error
|
||||||
|
expr => EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Block scope
|
// Block scope
|
||||||
Stmt::Block(statements, _) => {
|
Stmt::Block(statements, _) => {
|
||||||
let prev_scope_len = scope.len();
|
let prev_scope_len = scope.len();
|
||||||
|
@ -163,6 +163,11 @@ fn call_fn_with_constant_arguments(
|
|||||||
/// Optimize a statement.
|
/// Optimize a statement.
|
||||||
fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
||||||
match stmt {
|
match stmt {
|
||||||
|
// id op= expr
|
||||||
|
Stmt::Assignment(x, pos) => Stmt::Assignment(
|
||||||
|
Box::new((optimize_expr(x.0, state), x.1, optimize_expr(x.2, state))),
|
||||||
|
pos,
|
||||||
|
),
|
||||||
// if false { if_block } -> Noop
|
// if false { if_block } -> Noop
|
||||||
Stmt::IfThenElse(Expr::False(pos), x, _) if x.1.is_none() => {
|
Stmt::IfThenElse(Expr::False(pos), x, _) if x.1.is_none() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -442,8 +447,6 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
// ( stmt )
|
// ( stmt )
|
||||||
stmt => Expr::Stmt(Box::new((stmt, x.1))),
|
stmt => Expr::Stmt(Box::new((stmt, x.1))),
|
||||||
},
|
},
|
||||||
// id op= expr
|
|
||||||
Expr::Assignment(x) => Expr::Assignment(Box::new((x.0, x.1, optimize_expr(x.2, state), x.3))),
|
|
||||||
|
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
@ -753,6 +753,8 @@ pub enum Stmt {
|
|||||||
Let(Box<(String, Position)>, Option<Expr>, Position),
|
Let(Box<(String, Position)>, Option<Expr>, Position),
|
||||||
/// const id = expr
|
/// const id = expr
|
||||||
Const(Box<(String, Position)>, Option<Expr>, Position),
|
Const(Box<(String, Position)>, Option<Expr>, Position),
|
||||||
|
/// expr op= expr
|
||||||
|
Assignment(Box<(Expr, Cow<'static, str>, Expr)>, Position),
|
||||||
/// { stmt; ... }
|
/// { stmt; ... }
|
||||||
Block(Vec<Stmt>, Position),
|
Block(Vec<Stmt>, Position),
|
||||||
/// try { stmt; ... } catch ( var ) { stmt; ... }
|
/// try { stmt; ... } catch ( var ) { stmt; ... }
|
||||||
@ -808,6 +810,7 @@ impl Stmt {
|
|||||||
| Self::Continue(pos)
|
| Self::Continue(pos)
|
||||||
| Self::Break(pos)
|
| Self::Break(pos)
|
||||||
| Self::Block(_, pos)
|
| Self::Block(_, pos)
|
||||||
|
| Self::Assignment(_, pos)
|
||||||
| Self::IfThenElse(_, _, pos)
|
| Self::IfThenElse(_, _, pos)
|
||||||
| Self::While(_, _, pos)
|
| Self::While(_, _, pos)
|
||||||
| Self::Loop(_, pos)
|
| Self::Loop(_, pos)
|
||||||
@ -836,6 +839,7 @@ impl Stmt {
|
|||||||
| Self::Continue(pos)
|
| Self::Continue(pos)
|
||||||
| Self::Break(pos)
|
| Self::Break(pos)
|
||||||
| Self::Block(_, pos)
|
| Self::Block(_, pos)
|
||||||
|
| Self::Assignment(_, pos)
|
||||||
| Self::IfThenElse(_, _, pos)
|
| Self::IfThenElse(_, _, pos)
|
||||||
| Self::While(_, _, pos)
|
| Self::While(_, _, pos)
|
||||||
| Self::Loop(_, pos)
|
| Self::Loop(_, pos)
|
||||||
@ -876,6 +880,7 @@ impl Stmt {
|
|||||||
|
|
||||||
Self::Let(_, _, _)
|
Self::Let(_, _, _)
|
||||||
| Self::Const(_, _, _)
|
| Self::Const(_, _, _)
|
||||||
|
| Self::Assignment(_, _)
|
||||||
| Self::Expr(_)
|
| Self::Expr(_)
|
||||||
| Self::Continue(_)
|
| Self::Continue(_)
|
||||||
| Self::Break(_)
|
| Self::Break(_)
|
||||||
@ -901,7 +906,7 @@ impl Stmt {
|
|||||||
Self::While(condition, block, _) => condition.is_pure() && block.is_pure(),
|
Self::While(condition, block, _) => condition.is_pure() && block.is_pure(),
|
||||||
Self::Loop(block, _) => block.is_pure(),
|
Self::Loop(block, _) => block.is_pure(),
|
||||||
Self::For(iterable, x, _) => iterable.is_pure() && x.1.is_pure(),
|
Self::For(iterable, x, _) => iterable.is_pure() && x.1.is_pure(),
|
||||||
Self::Let(_, _, _) | Self::Const(_, _, _) => false,
|
Self::Let(_, _, _) | Self::Const(_, _, _) | Self::Assignment(_, _) => false,
|
||||||
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
||||||
Self::Continue(_) | Self::Break(_) | Self::ReturnWithVal(_, _, _) => false,
|
Self::Continue(_) | Self::Break(_) | Self::ReturnWithVal(_, _, _) => false,
|
||||||
Self::TryCatch(x) => (x.0).0.is_pure() && (x.2).0.is_pure(),
|
Self::TryCatch(x) => (x.0).0.is_pure() && (x.2).0.is_pure(),
|
||||||
@ -1040,8 +1045,6 @@ pub enum Expr {
|
|||||||
Option<bool>, // Default value is `bool` in order for `Expr` to be `Hash`.
|
Option<bool>, // Default value is `bool` in order for `Expr` to be `Hash`.
|
||||||
)>,
|
)>,
|
||||||
),
|
),
|
||||||
/// expr op= expr
|
|
||||||
Assignment(Box<(Expr, Cow<'static, str>, Expr, Position)>),
|
|
||||||
/// lhs.rhs
|
/// lhs.rhs
|
||||||
Dot(Box<BinaryExpr>),
|
Dot(Box<BinaryExpr>),
|
||||||
/// expr[expr]
|
/// expr[expr]
|
||||||
@ -1168,7 +1171,6 @@ impl Expr {
|
|||||||
Self::Stmt(x) => x.1,
|
Self::Stmt(x) => x.1,
|
||||||
Self::Variable(x) => (x.0).1,
|
Self::Variable(x) => (x.0).1,
|
||||||
Self::FnCall(x) => (x.0).3,
|
Self::FnCall(x) => (x.0).3,
|
||||||
Self::Assignment(x) => x.0.position(),
|
|
||||||
|
|
||||||
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos,
|
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos,
|
||||||
|
|
||||||
@ -1202,7 +1204,6 @@ impl Expr {
|
|||||||
Self::FnCall(x) => (x.0).3 = new_pos,
|
Self::FnCall(x) => (x.0).3 = new_pos,
|
||||||
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos = new_pos,
|
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos = new_pos,
|
||||||
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos = new_pos,
|
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos = new_pos,
|
||||||
Self::Assignment(x) => x.3 = new_pos,
|
|
||||||
Self::Dot(x) | Self::Index(x) => x.pos = new_pos,
|
Self::Dot(x) | Self::Index(x) => x.pos = new_pos,
|
||||||
Self::Custom(x) => x.pos = new_pos,
|
Self::Custom(x) => x.pos = new_pos,
|
||||||
}
|
}
|
||||||
@ -1322,8 +1323,7 @@ impl Expr {
|
|||||||
| Self::Or(_)
|
| Self::Or(_)
|
||||||
| Self::True(_)
|
| Self::True(_)
|
||||||
| Self::False(_)
|
| Self::False(_)
|
||||||
| Self::Unit(_)
|
| Self::Unit(_) => false,
|
||||||
| Self::Assignment(_) => false,
|
|
||||||
|
|
||||||
Self::StringConstant(_)
|
Self::StringConstant(_)
|
||||||
| Self::Stmt(_)
|
| Self::Stmt(_)
|
||||||
@ -1598,7 +1598,6 @@ fn parse_index_chain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::CharConstant(_)
|
Expr::CharConstant(_)
|
||||||
| Expr::Assignment(_)
|
|
||||||
| Expr::And(_)
|
| Expr::And(_)
|
||||||
| Expr::Or(_)
|
| Expr::Or(_)
|
||||||
| Expr::In(_)
|
| Expr::In(_)
|
||||||
@ -1634,7 +1633,6 @@ fn parse_index_chain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::CharConstant(_)
|
Expr::CharConstant(_)
|
||||||
| Expr::Assignment(_)
|
|
||||||
| Expr::And(_)
|
| Expr::And(_)
|
||||||
| Expr::Or(_)
|
| Expr::Or(_)
|
||||||
| Expr::In(_)
|
| Expr::In(_)
|
||||||
@ -1665,13 +1663,6 @@ fn parse_index_chain(
|
|||||||
)
|
)
|
||||||
.into_err(x.position()))
|
.into_err(x.position()))
|
||||||
}
|
}
|
||||||
// lhs[??? = ??? ]
|
|
||||||
x @ Expr::Assignment(_) => {
|
|
||||||
return Err(PERR::MalformedIndexExpr(
|
|
||||||
"Array access expects integer index, not an assignment".into(),
|
|
||||||
)
|
|
||||||
.into_err(x.position()))
|
|
||||||
}
|
|
||||||
// lhs[()]
|
// lhs[()]
|
||||||
x @ Expr::Unit(_) => {
|
x @ Expr::Unit(_) => {
|
||||||
return Err(PERR::MalformedIndexExpr(
|
return Err(PERR::MalformedIndexExpr(
|
||||||
@ -2249,18 +2240,18 @@ fn make_assignment_stmt<'a>(
|
|||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
rhs: Expr,
|
rhs: Expr,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
match &lhs {
|
match &lhs {
|
||||||
// var (non-indexed) = rhs
|
// var (non-indexed) = rhs
|
||||||
Expr::Variable(x) if x.3.is_none() => {
|
Expr::Variable(x) if x.3.is_none() => {
|
||||||
Ok(Expr::Assignment(Box::new((lhs, fn_name.into(), rhs, pos))))
|
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||||
}
|
}
|
||||||
// var (indexed) = rhs
|
// var (indexed) = rhs
|
||||||
Expr::Variable(x) => {
|
Expr::Variable(x) => {
|
||||||
let ((name, name_pos), _, _, index) = x.as_ref();
|
let ((name, name_pos), _, _, index) = x.as_ref();
|
||||||
match state.stack[(state.stack.len() - index.unwrap().get())].1 {
|
match state.stack[(state.stack.len() - index.unwrap().get())].1 {
|
||||||
ScopeEntryType::Normal => {
|
ScopeEntryType::Normal => {
|
||||||
Ok(Expr::Assignment(Box::new((lhs, fn_name.into(), rhs, pos))))
|
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||||
}
|
}
|
||||||
// Constant values cannot be assigned to
|
// Constant values cannot be assigned to
|
||||||
ScopeEntryType::Constant => {
|
ScopeEntryType::Constant => {
|
||||||
@ -2272,14 +2263,14 @@ fn make_assignment_stmt<'a>(
|
|||||||
Expr::Index(x) | Expr::Dot(x) => match &x.lhs {
|
Expr::Index(x) | Expr::Dot(x) => match &x.lhs {
|
||||||
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
|
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
|
||||||
Expr::Variable(x) if x.3.is_none() => {
|
Expr::Variable(x) if x.3.is_none() => {
|
||||||
Ok(Expr::Assignment(Box::new((lhs, fn_name.into(), rhs, pos))))
|
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||||
}
|
}
|
||||||
// var[???] (indexed) = rhs, var.??? (indexed) = rhs
|
// var[???] (indexed) = rhs, var.??? (indexed) = rhs
|
||||||
Expr::Variable(x) => {
|
Expr::Variable(x) => {
|
||||||
let ((name, name_pos), _, _, index) = x.as_ref();
|
let ((name, name_pos), _, _, index) = x.as_ref();
|
||||||
match state.stack[(state.stack.len() - index.unwrap().get())].1 {
|
match state.stack[(state.stack.len() - index.unwrap().get())].1 {
|
||||||
ScopeEntryType::Normal => {
|
ScopeEntryType::Normal => {
|
||||||
Ok(Expr::Assignment(Box::new((lhs, fn_name.into(), rhs, pos))))
|
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||||
}
|
}
|
||||||
// Constant values cannot be assigned to
|
// Constant values cannot be assigned to
|
||||||
ScopeEntryType::Constant => {
|
ScopeEntryType::Constant => {
|
||||||
@ -2310,7 +2301,7 @@ fn parse_op_assignment_stmt(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
settings.pos = *token_pos;
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
@ -2332,7 +2323,7 @@ fn parse_op_assignment_stmt(
|
|||||||
| Token::OrAssign
|
| Token::OrAssign
|
||||||
| Token::XOrAssign => token.syntax(),
|
| Token::XOrAssign => token.syntax(),
|
||||||
|
|
||||||
_ => return Ok(lhs),
|
_ => return Ok(Stmt::Expr(lhs)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_, pos) = input.next().unwrap();
|
let (_, pos) = input.next().unwrap();
|
||||||
@ -2436,7 +2427,6 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseErr
|
|||||||
| (_, x @ Expr::And(_))
|
| (_, x @ Expr::And(_))
|
||||||
| (_, x @ Expr::Or(_))
|
| (_, x @ Expr::Or(_))
|
||||||
| (_, x @ Expr::In(_))
|
| (_, x @ Expr::In(_))
|
||||||
| (_, x @ Expr::Assignment(_))
|
|
||||||
| (_, x @ Expr::True(_))
|
| (_, x @ Expr::True(_))
|
||||||
| (_, x @ Expr::False(_))
|
| (_, x @ Expr::False(_))
|
||||||
| (_, x @ Expr::Unit(_)) => {
|
| (_, x @ Expr::Unit(_)) => {
|
||||||
@ -2499,13 +2489,6 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseErr
|
|||||||
)
|
)
|
||||||
.into_err(x.position()))
|
.into_err(x.position()))
|
||||||
}
|
}
|
||||||
// (??? = ???) in "xxxx"
|
|
||||||
(x @ Expr::Assignment(_), Expr::StringConstant(_)) => {
|
|
||||||
return Err(PERR::MalformedInExpr(
|
|
||||||
"'in' expression for a string expects a string, not an assignment".into(),
|
|
||||||
)
|
|
||||||
.into_err(x.position()))
|
|
||||||
}
|
|
||||||
// () in "xxxx"
|
// () in "xxxx"
|
||||||
(x @ Expr::Unit(_), Expr::StringConstant(_)) => {
|
(x @ Expr::Unit(_), Expr::StringConstant(_)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
@ -2558,13 +2541,6 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseErr
|
|||||||
)
|
)
|
||||||
.into_err(x.position()))
|
.into_err(x.position()))
|
||||||
}
|
}
|
||||||
// (??? = ???) in #{...}
|
|
||||||
(x @ Expr::Assignment(_), Expr::Map(_)) => {
|
|
||||||
return Err(PERR::MalformedInExpr(
|
|
||||||
"'in' expression for an object map expects a string, not an assignment".into(),
|
|
||||||
)
|
|
||||||
.into_err(x.position()))
|
|
||||||
}
|
|
||||||
// () in #{...}
|
// () in #{...}
|
||||||
(x @ Expr::Unit(_), Expr::Map(_)) => {
|
(x @ Expr::Unit(_), Expr::Map(_)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
@ -3290,8 +3266,8 @@ fn parse_expr_stmt(
|
|||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
let expr = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?;
|
let stmt = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?;
|
||||||
Ok(Stmt::Expr(expr))
|
Ok(stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a single statement.
|
/// Parse a single statement.
|
||||||
|
Loading…
Reference in New Issue
Block a user