pyvm: split op handlers into ops_core/ops_box/ops_ctrl; add ops_flow + intrinsic; delegate vm.py without behavior change
net-plugin: modularize constants (consts.rs) and sockets (sockets.rs); remove legacy commented socket code; fix unused imports mir: move instruction unit tests to tests/mir_instruction_unit.rs (file lean-up); no semantic changes runner/pyvm: ensure using pre-strip; misc docs updates Build: cargo build ok; legacy cfg warnings remain as before
This commit is contained in:
71
src/llvm_py/pyvm/ops_flow.py
Normal file
71
src/llvm_py/pyvm/ops_flow.py
Normal file
@ -0,0 +1,71 @@
|
||||
"""
|
||||
Flow/control-related ops for Nyash PyVM: branch, jump, ret, call.
|
||||
These mutate the control flow (cur/prev) or return from the function.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
|
||||
def op_branch(owner, inst: Dict[str, Any], regs: Dict[int, Any], cur: int, prev: int | None) -> Tuple[int | None, int]:
|
||||
cond = owner._read(regs, inst.get("cond"))
|
||||
tid = int(inst.get("then"))
|
||||
eid = int(inst.get("else"))
|
||||
prev = cur
|
||||
cur = tid if owner._truthy(cond) else eid
|
||||
owner._dbg(f"[pyvm] branch cond={cond} -> next={cur}")
|
||||
return prev, cur
|
||||
|
||||
|
||||
def op_jump(owner, inst: Dict[str, Any], _regs: Dict[int, Any], cur: int, prev: int | None) -> Tuple[int | None, int]:
|
||||
tgt = int(inst.get("target"))
|
||||
prev = cur
|
||||
cur = tgt
|
||||
owner._dbg(f"[pyvm] jump -> {cur}")
|
||||
return prev, cur
|
||||
|
||||
|
||||
def op_ret(owner, inst: Dict[str, Any], regs: Dict[int, Any]) -> Any:
|
||||
v = owner._read(regs, inst.get("value"))
|
||||
if getattr(owner, "_debug", False):
|
||||
owner._dbg(f"[pyvm] ret {owner._type_name(v)} value={v}")
|
||||
return v
|
||||
|
||||
|
||||
def op_call(owner, fn, inst: Dict[str, Any], regs: Dict[int, Any]) -> Any:
|
||||
# Resolve function name from value or take as literal
|
||||
fval = inst.get("func")
|
||||
if isinstance(fval, str):
|
||||
fname = fval
|
||||
else:
|
||||
fname = owner._read(regs, fval)
|
||||
if not isinstance(fname, str):
|
||||
# Fallback: if JSON encoded a literal name
|
||||
fname = fval if isinstance(fval, str) else None
|
||||
call_args = [owner._read(regs, a) for a in inst.get("args", [])]
|
||||
result = None
|
||||
if isinstance(fname, str):
|
||||
# Direct hit
|
||||
if fname in owner.functions:
|
||||
callee = owner.functions[fname]
|
||||
owner._dbg(f"[pyvm] call -> {fname} args={call_args}")
|
||||
result = owner._exec_function(callee, call_args)
|
||||
else:
|
||||
# Heuristic resolution: match suffix ".name/arity"
|
||||
arity = len(call_args)
|
||||
suffix = f".{fname}/{arity}"
|
||||
candidates = [k for k in owner.functions.keys() if k.endswith(suffix)]
|
||||
if len(candidates) == 1:
|
||||
callee = owner.functions[candidates[0]]
|
||||
owner._dbg(f"[pyvm] call -> {candidates[0]} args={call_args}")
|
||||
result = owner._exec_function(callee, call_args)
|
||||
elif getattr(owner, "_debug", False) and len(candidates) > 1:
|
||||
owner._dbg(f"[pyvm] call unresolved: '{fname}'/{arity} has multiple candidates: {candidates}")
|
||||
elif getattr(owner, "_debug", False):
|
||||
# Suggest close candidates across arities using suffix ".name/"
|
||||
any_cands = sorted([k for k in owner.functions.keys() if k.endswith(f".{fname}/") or f".{fname}/" in k])
|
||||
if any_cands:
|
||||
owner._dbg(f"[pyvm] call unresolved: '{fname}'/{arity} — available: {any_cands}")
|
||||
else:
|
||||
owner._dbg(f"[pyvm] call unresolved: '{fname}'/{arity} not found")
|
||||
return result
|
||||
Reference in New Issue
Block a user