Factor tuples into structs to aid in understanding.
This commit is contained in:
@@ -290,13 +290,12 @@ impl Engine {
|
||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||
}
|
||||
// {xxx:map}.id op= ???
|
||||
Expr::Property(x) if target.is::<crate::Map>() && new_val.is_some() => {
|
||||
Expr::Property(x, pos) if target.is::<crate::Map>() && new_val.is_some() => {
|
||||
#[cfg(feature = "debugging")]
|
||||
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
|
||||
|
||||
let (name, pos) = &x.2;
|
||||
let index = x.2.clone().into();
|
||||
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
|
||||
let index = name.into();
|
||||
{
|
||||
let val_target = &mut self.get_indexed_mut(
|
||||
global, state, lib, target, index, *pos, true, false, level,
|
||||
@@ -311,23 +310,22 @@ impl Engine {
|
||||
Ok((Dynamic::UNIT, true))
|
||||
}
|
||||
// {xxx:map}.id
|
||||
Expr::Property(x) if target.is::<crate::Map>() => {
|
||||
Expr::Property(x, pos) if target.is::<crate::Map>() => {
|
||||
#[cfg(feature = "debugging")]
|
||||
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
|
||||
|
||||
let (name, pos) = &x.2;
|
||||
let index = name.into();
|
||||
let index = x.2.clone().into();
|
||||
let val = self.get_indexed_mut(
|
||||
global, state, lib, target, index, *pos, false, false, level,
|
||||
)?;
|
||||
Ok((val.take_or_clone(), false))
|
||||
}
|
||||
// xxx.id op= ???
|
||||
Expr::Property(x) if new_val.is_some() => {
|
||||
Expr::Property(x, pos) if new_val.is_some() => {
|
||||
#[cfg(feature = "debugging")]
|
||||
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
|
||||
|
||||
let ((getter, hash_get), (setter, hash_set), (name, pos)) = x.as_ref();
|
||||
let ((getter, hash_get), (setter, hash_set), name) = x.as_ref();
|
||||
let ((mut new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
|
||||
|
||||
if op_info.is_some() {
|
||||
@@ -402,11 +400,11 @@ impl Engine {
|
||||
})
|
||||
}
|
||||
// xxx.id
|
||||
Expr::Property(x) => {
|
||||
Expr::Property(x, pos) => {
|
||||
#[cfg(feature = "debugging")]
|
||||
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
|
||||
|
||||
let ((getter, hash_get), _, (name, pos)) = x.as_ref();
|
||||
let ((getter, hash_get), _, name) = x.as_ref();
|
||||
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
|
||||
let args = &mut [target.as_mut()];
|
||||
self.exec_fn_call(
|
||||
@@ -442,16 +440,15 @@ impl Engine {
|
||||
let _node = &x.lhs;
|
||||
|
||||
let val_target = &mut match x.lhs {
|
||||
Expr::Property(ref p) => {
|
||||
Expr::Property(ref p, pos) => {
|
||||
#[cfg(feature = "debugging")]
|
||||
self.run_debugger(
|
||||
scope, global, state, lib, this_ptr, _node, level,
|
||||
)?;
|
||||
|
||||
let (name, pos) = &p.2;
|
||||
let index = name.into();
|
||||
let index = p.2.clone().into();
|
||||
self.get_indexed_mut(
|
||||
global, state, lib, target, index, *pos, false, true, level,
|
||||
global, state, lib, target, index, pos, false, true, level,
|
||||
)?
|
||||
}
|
||||
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
|
||||
@@ -495,14 +492,13 @@ impl Engine {
|
||||
|
||||
match x.lhs {
|
||||
// xxx.prop[expr] | xxx.prop.expr
|
||||
Expr::Property(ref p) => {
|
||||
Expr::Property(ref p, pos) => {
|
||||
#[cfg(feature = "debugging")]
|
||||
self.run_debugger(
|
||||
scope, global, state, lib, this_ptr, _node, level,
|
||||
)?;
|
||||
|
||||
let ((getter, hash_get), (setter, hash_set), (name, pos)) =
|
||||
p.as_ref();
|
||||
let ((getter, hash_get), (setter, hash_set), name) = p.as_ref();
|
||||
let rhs_chain = rhs.into();
|
||||
let hash_get = crate::ast::FnCallHashes::from_native(*hash_get);
|
||||
let hash_set = crate::ast::FnCallHashes::from_native(*hash_set);
|
||||
@@ -513,15 +509,15 @@ impl Engine {
|
||||
let (mut val, _) = self
|
||||
.exec_fn_call(
|
||||
global, state, lib, getter, hash_get, args, is_ref_mut,
|
||||
true, *pos, None, level,
|
||||
true, pos, None, level,
|
||||
)
|
||||
.or_else(|err| match *err {
|
||||
// Try an indexer if property does not exist
|
||||
ERR::ErrorDotExpr(_, _) => {
|
||||
let prop = name.into();
|
||||
self.get_indexed_mut(
|
||||
global, state, lib, target, prop, *pos, false,
|
||||
true, level,
|
||||
global, state, lib, target, prop, pos, false, true,
|
||||
level,
|
||||
)
|
||||
.map(|v| (v.take_or_clone(), false))
|
||||
.map_err(
|
||||
@@ -561,7 +557,7 @@ impl Engine {
|
||||
let args = &mut arg_values;
|
||||
self.exec_fn_call(
|
||||
global, state, lib, setter, hash_set, args, is_ref_mut,
|
||||
true, *pos, None, level,
|
||||
true, pos, None, level,
|
||||
)
|
||||
.or_else(
|
||||
|err| match *err {
|
||||
@@ -576,7 +572,7 @@ impl Engine {
|
||||
);
|
||||
self.exec_fn_call(
|
||||
global, state, lib, fn_name, hash_set, args,
|
||||
is_ref_mut, true, *pos, None, level,
|
||||
is_ref_mut, true, pos, None, level,
|
||||
)
|
||||
.or_else(|idx_err| match *idx_err {
|
||||
ERR::ErrorIndexingType(_, _) => {
|
||||
@@ -754,10 +750,10 @@ impl Engine {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::Property(x) if _parent_chain_type == ChainType::Dotting => {
|
||||
idx_values.push(super::ChainArgument::Property((x.2).1))
|
||||
Expr::Property(_, pos) if _parent_chain_type == ChainType::Dotting => {
|
||||
idx_values.push(super::ChainArgument::Property(*pos))
|
||||
}
|
||||
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
||||
Expr::Property(_, _) => unreachable!("unexpected Expr::Property for indexing"),
|
||||
|
||||
Expr::Index(x, term, _) | Expr::Dot(x, term, _) if !terminate_chaining => {
|
||||
let crate::ast::BinaryExpr { lhs, rhs, .. } = x.as_ref();
|
||||
@@ -765,10 +761,10 @@ impl Engine {
|
||||
// Evaluate in left-to-right order
|
||||
let lhs_arg_val = match lhs {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::Property(x) if _parent_chain_type == ChainType::Dotting => {
|
||||
super::ChainArgument::Property((x.2).1)
|
||||
Expr::Property(_, pos) if _parent_chain_type == ChainType::Dotting => {
|
||||
super::ChainArgument::Property(*pos)
|
||||
}
|
||||
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
||||
Expr::Property(_, _) => unreachable!("unexpected Expr::Property for indexing"),
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::FnCall(x, _)
|
||||
|
@@ -312,7 +312,7 @@ impl Debugger {
|
||||
},
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
BreakPoint::AtProperty { name, .. } => match node {
|
||||
ASTNode::Expr(Expr::Property(x)) => (x.2).0 == *name,
|
||||
ASTNode::Expr(Expr::Property(x, _)) => x.2 == *name,
|
||||
_ => false,
|
||||
},
|
||||
})
|
||||
|
103
src/eval/stmt.rs
103
src/eval/stmt.rs
@@ -1,7 +1,9 @@
|
||||
//! Module defining functions for evaluating a statement.
|
||||
|
||||
use super::{EvalState, GlobalRuntimeState, Target};
|
||||
use crate::ast::{Expr, Ident, OpAssignment, Stmt, AST_OPTION_FLAGS::*};
|
||||
use crate::ast::{
|
||||
BinaryExpr, Expr, Ident, OpAssignment, Stmt, SwitchCases, TryCatchBlock, AST_OPTION_FLAGS::*,
|
||||
};
|
||||
use crate::func::get_hasher;
|
||||
use crate::types::dynamic::{AccessMode, Union};
|
||||
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR, INT};
|
||||
@@ -225,20 +227,21 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, stmt.position())?;
|
||||
|
||||
let result = if x.0.is_variable_access(false) {
|
||||
let (lhs_expr, op_info, rhs_expr) = x.as_ref();
|
||||
let result = if x.1.lhs.is_variable_access(false) {
|
||||
let (op_info, BinaryExpr { lhs, rhs }) = x.as_ref();
|
||||
|
||||
let rhs_result = self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, rhs_expr, level)
|
||||
.eval_expr(scope, global, state, lib, this_ptr, rhs, level)
|
||||
.map(Dynamic::flatten);
|
||||
|
||||
if let Ok(rhs_val) = rhs_result {
|
||||
let search_result =
|
||||
self.search_namespace(scope, global, state, lib, this_ptr, lhs_expr);
|
||||
self.search_namespace(scope, global, state, lib, this_ptr, lhs);
|
||||
|
||||
if let Ok(search_val) = search_result {
|
||||
let (mut lhs_ptr, pos) = search_val;
|
||||
|
||||
let var_name = lhs_expr.get_variable_name(false).expect("`Expr::Variable`");
|
||||
let var_name = lhs.get_variable_name(false).expect("`Expr::Variable`");
|
||||
|
||||
if !lhs_ptr.is_ref() {
|
||||
return Err(
|
||||
@@ -259,7 +262,7 @@ impl Engine {
|
||||
(var_name, pos),
|
||||
rhs_val,
|
||||
)
|
||||
.map_err(|err| err.fill_position(rhs_expr.position()))
|
||||
.map_err(|err| err.fill_position(rhs.position()))
|
||||
.map(|_| Dynamic::UNIT)
|
||||
} else {
|
||||
search_result.map(|_| Dynamic::UNIT)
|
||||
@@ -268,16 +271,17 @@ impl Engine {
|
||||
rhs_result
|
||||
}
|
||||
} else {
|
||||
let (lhs_expr, op_info, rhs_expr) = x.as_ref();
|
||||
let (op_info, BinaryExpr { lhs, rhs }) = x.as_ref();
|
||||
|
||||
let rhs_result = self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, rhs_expr, level)
|
||||
.eval_expr(scope, global, state, lib, this_ptr, rhs, level)
|
||||
.map(Dynamic::flatten);
|
||||
|
||||
if let Ok(rhs_val) = rhs_result {
|
||||
let _new_val = Some(((rhs_val, rhs_expr.position()), (*op_info, *op_pos)));
|
||||
let _new_val = Some(((rhs_val, rhs.position()), (*op_info, *op_pos)));
|
||||
|
||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||
match lhs_expr {
|
||||
match lhs {
|
||||
// name op= rhs (handled above)
|
||||
Expr::Variable(_, _, _) => {
|
||||
unreachable!("Expr::Variable case is already handled")
|
||||
@@ -286,17 +290,17 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Index(_, _, _) => self
|
||||
.eval_dot_index_chain(
|
||||
scope, global, state, lib, this_ptr, lhs_expr, level, _new_val,
|
||||
scope, global, state, lib, this_ptr, lhs, level, _new_val,
|
||||
)
|
||||
.map(|_| Dynamic::UNIT),
|
||||
// dot_lhs.dot_rhs op= rhs
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::Dot(_, _, _) => self
|
||||
.eval_dot_index_chain(
|
||||
scope, global, state, lib, this_ptr, lhs_expr, level, _new_val,
|
||||
scope, global, state, lib, this_ptr, lhs, level, _new_val,
|
||||
)
|
||||
.map(|_| Dynamic::UNIT),
|
||||
_ => unreachable!("cannot assign to expression: {:?}", lhs_expr),
|
||||
_ => unreachable!("cannot assign to expression: {:?}", lhs),
|
||||
}
|
||||
} else {
|
||||
rhs_result
|
||||
@@ -362,7 +366,11 @@ impl Engine {
|
||||
|
||||
// Switch statement
|
||||
Stmt::Switch(match_expr, x, _) => {
|
||||
let (table, def_stmt, ranges) = x.as_ref();
|
||||
let SwitchCases {
|
||||
cases,
|
||||
def_case,
|
||||
ranges,
|
||||
} = x.as_ref();
|
||||
|
||||
let value_result =
|
||||
self.eval_expr(scope, global, state, lib, this_ptr, match_expr, level);
|
||||
@@ -374,9 +382,9 @@ impl Engine {
|
||||
let hash = hasher.finish();
|
||||
|
||||
// First check hashes
|
||||
if let Some(t) = table.get(&hash) {
|
||||
if let Some(t) = cases.get(&hash) {
|
||||
let cond_result = t
|
||||
.0
|
||||
.condition
|
||||
.as_ref()
|
||||
.map(|cond| {
|
||||
self.eval_expr(scope, global, state, lib, this_ptr, cond, level)
|
||||
@@ -392,7 +400,7 @@ impl Engine {
|
||||
.unwrap_or(Ok(true));
|
||||
|
||||
match cond_result {
|
||||
Ok(true) => Ok(Some(&t.1)),
|
||||
Ok(true) => Ok(Some(&t.statements)),
|
||||
Ok(false) => Ok(None),
|
||||
_ => cond_result.map(|_| None),
|
||||
}
|
||||
@@ -401,13 +409,14 @@ impl Engine {
|
||||
let value = value.as_int().expect("`INT`");
|
||||
let mut result = Ok(None);
|
||||
|
||||
for (_, _, _, condition, stmt_block) in
|
||||
ranges.iter().filter(|&&(start, end, inclusive, _, _)| {
|
||||
for (_, _, _, block) in
|
||||
ranges.iter().filter(|&&(start, end, inclusive, _)| {
|
||||
(!inclusive && (start..end).contains(&value))
|
||||
|| (inclusive && (start..=end).contains(&value))
|
||||
})
|
||||
{
|
||||
let cond_result = condition
|
||||
let cond_result = block
|
||||
.condition
|
||||
.as_ref()
|
||||
.map(|cond| {
|
||||
self.eval_expr(
|
||||
@@ -425,7 +434,7 @@ impl Engine {
|
||||
.unwrap_or(Ok(true));
|
||||
|
||||
match cond_result {
|
||||
Ok(true) => result = Ok(Some(stmt_block)),
|
||||
Ok(true) => result = Ok(Some(&block.statements)),
|
||||
Ok(false) => continue,
|
||||
_ => result = cond_result.map(|_| None),
|
||||
}
|
||||
@@ -453,9 +462,9 @@ impl Engine {
|
||||
}
|
||||
} else if let Ok(None) = stmt_block_result {
|
||||
// Default match clause
|
||||
if !def_stmt.is_empty() {
|
||||
if !def_case.is_empty() {
|
||||
self.eval_stmt_block(
|
||||
scope, global, state, lib, this_ptr, def_stmt, true, level,
|
||||
scope, global, state, lib, this_ptr, def_case, true, level,
|
||||
)
|
||||
} else {
|
||||
Ok(Dynamic::UNIT)
|
||||
@@ -685,10 +694,14 @@ impl Engine {
|
||||
|
||||
// Try/Catch statement
|
||||
Stmt::TryCatch(x, _) => {
|
||||
let (try_stmt, err_var_name, catch_stmt) = x.as_ref();
|
||||
let TryCatchBlock {
|
||||
try_block,
|
||||
catch_var,
|
||||
catch_block,
|
||||
} = x.as_ref();
|
||||
|
||||
let result = self
|
||||
.eval_stmt_block(scope, global, state, lib, this_ptr, try_stmt, true, level)
|
||||
.eval_stmt_block(scope, global, state, lib, this_ptr, try_block, true, level)
|
||||
.map(|_| Dynamic::UNIT);
|
||||
|
||||
match result {
|
||||
@@ -733,12 +746,19 @@ impl Engine {
|
||||
|
||||
let orig_scope_len = scope.len();
|
||||
|
||||
err_var_name
|
||||
catch_var
|
||||
.as_ref()
|
||||
.map(|Ident { name, .. }| scope.push(name.clone(), err_value));
|
||||
|
||||
let result = self.eval_stmt_block(
|
||||
scope, global, state, lib, this_ptr, catch_stmt, true, level,
|
||||
scope,
|
||||
global,
|
||||
state,
|
||||
lib,
|
||||
this_ptr,
|
||||
catch_block,
|
||||
true,
|
||||
level,
|
||||
);
|
||||
|
||||
scope.rewind(orig_scope_len);
|
||||
@@ -896,21 +916,18 @@ impl Engine {
|
||||
|
||||
// Export statement
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Export(list, _) => {
|
||||
list.iter()
|
||||
.try_for_each(|(Ident { name, pos, .. }, Ident { name: rename, .. })| {
|
||||
// Mark scope variables as public
|
||||
if let Some((index, _)) = scope.get_index(name) {
|
||||
scope.add_entry_alias(
|
||||
index,
|
||||
if rename.is_empty() { name } else { rename }.clone(),
|
||||
);
|
||||
Ok(()) as RhaiResultOf<_>
|
||||
} else {
|
||||
Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into())
|
||||
}
|
||||
})
|
||||
.map(|_| Dynamic::UNIT)
|
||||
Stmt::Export(x, _) => {
|
||||
let (Ident { name, pos, .. }, Ident { name: alias, .. }) = x.as_ref();
|
||||
// Mark scope variables as public
|
||||
if let Some((index, _)) = scope.get_index(name) {
|
||||
scope.add_entry_alias(
|
||||
index,
|
||||
if alias.is_empty() { name } else { alias }.clone(),
|
||||
);
|
||||
Ok(Dynamic::UNIT)
|
||||
} else {
|
||||
Err(ERR::ErrorVariableNotFound(name.to_string(), *pos).into())
|
||||
}
|
||||
}
|
||||
|
||||
// Share statement
|
||||
|
Reference in New Issue
Block a user