MCPcopy Create free account
hub / github.com/dylan-sutton-chavez/edge-python / handle_side

Method handle_side

compiler/src/modules/vm/handlers/data.rs:177–267  ·  view source on GitHub ↗

Side-effecting / impure ops: assert, del, global/nonlocal, import, type alias, raise, await. */

(&mut self, op: OpCode, operand: u16, chunk: &SSAChunk, slots: &mut [Val])

Source from the content-addressed store, hash-verified

175
176 /* Side-effecting / impure ops: assert, del, global/nonlocal, import, type alias, raise, await. */
177 pub(crate) fn handle_side(&mut self, op: OpCode, operand: u16, chunk: &SSAChunk, slots: &mut [Val]) -> Result<(), VmErr> {
178 match op {
179 OpCode::Assert => {
180 let v = self.pop()?;
181 if !self.truthy_op(v, chunk, slots)? {
182 // Bare `assert` raises a catchable AssertionError with empty args.
183 let inst = self.heap.alloc(HeapObj::ExcInstance("AssertionError".into(), Vec::new()))?;
184 self.pending.exc_val = Some(inst);
185 return Err(VmErr::Raised("AssertionError".into()));
186 }
187 }
188 OpCode::Del => {
189 let slot = operand as usize;
190 // Deleting an already-unbound name raises NameError, matching CPython.
191 match slots.get_mut(slot) {
192 Some(s) if !s.is_undef() => *s = Val::undef(),
193 _ => {
194 let name = chunk.names.get(slot).map(|n| ssa_strip(n)).unwrap_or_default();
195 return Err(VmErr::Name(name.into()));
196 }
197 }
198 // At module scope, drop it from module_state too so later reads see the deletion.
199 if core::ptr::eq(chunk, self.chunk) && let Some(n) = chunk.names.get(slot) {
200 self.module_state.remove(ssa_strip(n));
201 }
202 // Unbind the shared closure cell too, so closures over this name see the deletion.
203 let cell = self.call_stack.last()
204 .and_then(|f| f.cells.iter().find(|(s, _)| *s == slot).map(|&(_, c)| c));
205 if let Some(cell) = cell && cell.is_heap() && let HeapObj::List(rc) = self.heap.get(cell) {
206 rc.borrow_mut()[0] = Val::undef(); // cells are 1-element boxes
207 }
208 }
209 OpCode::Global | OpCode::Nonlocal => self.mark_impure(),
210 OpCode::Raise | OpCode::RaiseFrom => {
211 self.mark_impure();
212 // Bare `raise` (operand 1): re-raise the exception currently being handled.
213 if op == OpCode::Raise && operand == 1 {
214 let Some(exc) = self.handling_exc else {
215 return Err(VmErr::Runtime("No active exception to re-raise"));
216 };
217 let name = self.exc_type_name(exc);
218 self.pending.exc_val = Some(exc);
219 return Err(VmErr::Raised(name));
220 }
221 // RaiseFrom emits both `expr` then `from expr`, the topmost value is the cause, but the exception to raise is the LHS.
222 if op == OpCode::RaiseFrom { let _cause = self.pop()?; }
223 let exc = self.pop()?;
224 // Stash the Val for `except as e` binding; non-Exc values use `display()`.
225 self.pending.exc_val = None;
226 // Extract owned (class name, first arg) so display() can run after the heap borrow ends.
227 let info: Option<(alloc::string::String, Option<Val>)> = if exc.is_heap() {
228 match self.heap.get(exc) {
229 HeapObj::ExcInstance(n, args) => {
230 self.pending.exc_val = Some(exc);
231 Some((n.clone(), args.first().copied()))
232 }
233 HeapObj::Type(n) => {
234 // Bare `raise X`: build empty ExcInstance so `e.args` is `()`.

Callers 1

dispatch_genericMethod · 0.80

Calls 15

ssa_stripFunction · 0.85
cold_runtimeFunction · 0.85
truthy_opMethod · 0.80
get_mutMethod · 0.80
is_undefMethod · 0.80
removeMethod · 0.80
is_heapMethod · 0.80
mark_impureMethod · 0.80
exc_type_nameMethod · 0.80
displayMethod · 0.80
await_coroutineMethod · 0.80
pushMethod · 0.80

Tested by

no test coverage detected