diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 282c2dcf4..85972d332 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -709,11 +709,16 @@ impl Engine { // Add the loop variables let counter_index = counter.as_ref().map(|counter| { - scope.push(counter.name.clone(), 0 as INT); + let name = self.get_interned_string(&counter.name); + scope.push_entry(name, AccessMode::ReadWrite, Dynamic::ZERO); scope.len() - 1 }); - scope.push(var_name.name.clone(), ()); + scope.push_entry( + self.get_interned_string(&var_name.name), + AccessMode::ReadWrite, + Dynamic::UNIT, + ); let index = scope.len() - 1; let mut result = Dynamic::UNIT; @@ -855,7 +860,7 @@ impl Engine { if scope.len() >= self.max_variables() { return Err(ERR::ErrorTooManyVariables(catch_var.position()).into()); } - scope.push(x.1.clone(), err_value); + scope.push_entry(x.1.clone(), AccessMode::ReadWrite, err_value); } let this_ptr = this_ptr.as_deref_mut(); diff --git a/src/grain/compile/mod.rs b/src/grain/compile/mod.rs index 2576e6b4e..cdd7d63e7 100644 --- a/src/grain/compile/mod.rs +++ b/src/grain/compile/mod.rs @@ -430,34 +430,12 @@ impl Lowering { // the root and steps. let rewind_mark = self.mark(); - let unwind_depth = self.slots.depth(); - - let value_slot = if let Some(value) = value { - if self.slots.is_full() { - return false; - } - - let value_name = ImmutableString::from("$CHAIN_SET_VALUE$"); - let value_name_index = self.push_name(value_name.clone()); - let value_slot = self.slots.declare(value_name); + if let Some(value) = value { // First evaluate the assigned value first, stash it so the chain // can read it back after the lvalue steps have been resolved. - self.emit(Op::Unit); - self.emit(Op::DeclareLocal { - name: value_name_index, - is_const: false, - }); self.expression(value); - self.emit(Op::StoreLocal { - slot: value_slot, - is_const: false, - }); - - Some(value_slot) - } else { - None - }; + } // Index values and method arguments are evaluated first, in step // order, exactly as Rhai collects them before walking @@ -493,16 +471,14 @@ impl Lowering { ChainStep::Method(call, pos, flags) => { self.caps.insert(Caps::METHOD); if !self.is_lowerable_call(call) { - if value_slot.is_some() { + if value.is_some() { self.rewind(rewind_mark); - self.slots.unwind_to(unwind_depth); } return false; } let Ok(argc) = u8::try_from(call.args.len()) else { - if value_slot.is_some() { + if value.is_some() { self.rewind(rewind_mark); - self.slots.unwind_to(unwind_depth); } return false; }; @@ -529,10 +505,6 @@ impl Lowering { self.expression(root); } - if let Some(value_slot) = value_slot { - self.emit(Op::LoadLocal(value_slot)); - } - let index = self.push_chain(Chain { root: root_spec, steps: lowered, @@ -540,7 +512,6 @@ impl Lowering { operands, }); self.emit_at(Op::Chain(index), expr.position()); - self.unwind_to(unwind_depth); true } diff --git a/src/grain/vm/mod.rs b/src/grain/vm/mod.rs index 2657ba1cc..4f60212f2 100644 --- a/src/grain/vm/mod.rs +++ b/src/grain/vm/mod.rs @@ -1093,12 +1093,14 @@ impl<'e> Vm<'e> { ) -> VmResult { // Step operands were pushed first, then the root if it is one that has // to be evaluated, then the value being assigned. - let operands_at = self + let frame_pointer = self .stack .len() .checked_sub(chain.consumes()) .ok_or_else(|| malformed("chain with too few operands".to_string()))?; + let operands_at = frame_pointer + usize::from(chain.assigns()); + let ChainRoot { value: mut root, pos: root_pos, @@ -1131,7 +1133,7 @@ impl<'e> Vm<'e> { }), // Rhai flattens the right-hand side before assigning, so a shared // cell is copied out rather than aliased in. - (true, _) => Ok(Some(self.stack[self.stack.len() - 1].clone().flatten())), + (true, _) => Ok(Some(self.stack[frame_pointer].take().flatten())), }; let result = value.and_then(|value| { @@ -1187,7 +1189,7 @@ impl<'e> Vm<'e> { } let (out, _) = result?; - self.stack.truncate(operands_at); + self.stack.truncate(frame_pointer); Ok(out) } @@ -2977,7 +2979,11 @@ impl<'e> Vm<'e> { .get_mut(slot) .ok_or_else(|| malformed("call with too few arguments".to_string()))? .take(); - scope.push_dynamic(name, value); + scope.push_entry( + self.strings_interner.get(name), + AccessMode::ReadWrite, + value, + ); } let scope_end_len = scope.len(); @@ -3444,7 +3450,11 @@ impl<'e> Vm<'e> { program.position(target), ))); } - scope.push_dynamic(name, value); + scope.push_entry( + self.strings_interner.get(name), + AccessMode::ReadWrite, + value, + ); } self.handlers.last_mut().expect("checked").caught = Some(err); @@ -3701,11 +3711,15 @@ impl<'e> Vm<'e> { return Err(EvalAltResult::ErrorTooManyVariables(pos()).into()); } - if tag == code::tag::DECLARE_CONST { - scope.push_constant_dynamic(name, value); - } else { - scope.push_dynamic(name, value); - } + scope.push_entry( + self.strings_interner.get(name), + if tag == code::tag::DECLARE_CONST { + AccessMode::ReadOnly + } else { + AccessMode::ReadWrite + }, + value, + ); } code::tag::ASSIGN_LOCAL | code::tag::ASSIGN_LOCAL_OP => {