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

Function dispatch_call

compiler/src/main/abi_bridge.rs:42–69  ·  view source on GitHub ↗
(recv_h: u32, name: &str, args: &[Val])

Source from the content-addressed store, hash-verified

40}
41
42fn dispatch_call(recv_h: u32, name: &str, args: &[Val]) -> Result<Val, VmErr> {
43 with_recv("edge_op call: invalid receiver handle", recv_h, |vm, recv| {
44 // `__call__` means "invoke `recv` as a callable", letting plugins forward arbitrary Python hooks (lambdas, builtins, classes) through `Handle::call("__call__", args)`. Pushes args + callee then drives `exec_call` so every callable kind (`Extern`, `NativeFn`, `Func`, `BoundMethod`, `Class`, ...) routes through the same dispatch path the VM uses normally. Empty caller-slots are fine because lambdas/hooks that escape a plugin call cannot reference caller-frame locals, they can still capture their own defining scope through the regular Func captures vector.
45 if name == "__call__" {
46 // Stack layout for `Call`: callee at the bottom, then positional args (top is the rightmost). `parse_call_args` pops args first, then `exec_call` pops the callee.
47 let stack_before = vm.stack.len();
48 vm.stack.push(recv);
49 for a in args { vm.stack.push(*a); }
50 let operand = args.len() as u16; // (num_kw<<8)|num_pos; no kwargs from FFI hooks.
51 let chunk: &crate::modules::parser::SSAChunk = unsafe { &*(vm.chunk as *const _) };
52 let mut empty_slots: [Val; 0] = [];
53 vm.exec_call(operand, chunk, &mut empty_slots)?;
54 if vm.stack.len() != stack_before + 1 {
55 return Err(VmErr::Runtime("edge_op call(__call__): callable left no result"));
56 }
57 return vm.stack.pop().ok_or(VmErr::Runtime("edge_op call(__call__): stack drained"));
58 }
59 let ty = vm.type_name(recv);
60 let mid = lookup_method(ty, name).ok_or_else(|| VmErr::Attribute(s!("'", str ty, "' object has no method '", str name, "'")))?;
61 let stack_before = vm.stack.len();
62 dispatch_method(vm, mid, recv, args, &[])?;
63 if vm.stack.len() != stack_before + 1 {
64 return Err(VmErr::Runtime("edge_op call: method left no result"));
65 }
66 // The length check above guarantees a value is present; `ok_or` keeps the FFI boundary panic-free if a future change drops the invariant.
67 vm.stack.pop().ok_or(VmErr::Runtime("edge_op call: stack drained mid-dispatch"))
68 })
69}
70
71/* GetAttr: module/instance attr, or bind builtin method as BoundMethod. */
72fn dispatch_get_attr(recv_h: u32, name: &str) -> Result<Val, VmErr> {

Callers 1

host_edge_opFunction · 0.85

Calls 8

with_recvFunction · 0.85
lookup_methodFunction · 0.85
dispatch_methodFunction · 0.85
pushMethod · 0.80
exec_callMethod · 0.80
type_nameMethod · 0.80
lenMethod · 0.45
popMethod · 0.45

Tested by

no test coverage detected