Skip to main content

ternlang_core/vm/
mod.rs

1pub mod bet;
2
3use crate::trit::Trit;
4use crate::vm::bet::{unpack_trits, BetFault};
5
6use std::fmt;
7use std::sync::Arc;
8
9// ─── Remote transport trait ───────────────────────────────────────────────────
10
11pub trait RemoteTransport: Send + Sync {
12    fn remote_send(&self, node_addr: &str, agent_id: usize, trit: i8) -> std::io::Result<()>;
13    fn remote_await(&self, node_addr: &str, agent_id: usize) -> std::io::Result<i8>;
14}
15
16#[derive(Debug, PartialEq, Eq)]
17pub enum VmError {
18    StackUnderflow,
19    BetFault(BetFault),
20    Halt,
21    InvalidOpcode(u8),
22    InvalidRegister(u8),
23    PcOutOfBounds(usize),
24    TypeMismatch { expected: String, found: String },
25    // ── Tensor errors ────────────────────────────────────────────────────────
26    TensorIndexOutOfBounds { tensor_id: usize, index: usize, size: usize },
27    TensorNotAllocated(usize),
28    // ── Agent errors ─────────────────────────────────────────────────────────
29    AgentTypeNotRegistered(u16),
30    AgentIdInvalid(usize),
31    RuntimeError(String),
32}
33
34impl fmt::Display for VmError {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            VmError::StackUnderflow =>
38                write!(f, "[BET-001] Stack underflow — you tried to pop a truth that wasn't there.\n          → details: stdlib/errors/BET-001.tern  |  ternlang errors BET-001"),
39            VmError::BetFault(fault) =>
40                write!(f, "[BET-002] BET encoding fault: {fault:?}. The 0b00 state is forbidden — only 01/10/11 are valid trit bits.\n          → details: stdlib/errors/BET-002.tern  |  ternlang errors BET-002"),
41            VmError::Halt =>
42                write!(f, "[BET-003] VM halted cleanly. Execution reached the end. This is not an error — this is peace.\n          → details: stdlib/errors/BET-003.tern  |  ternlang errors BET-003"),
43            VmError::InvalidOpcode(op) =>
44                write!(f, "[BET-004] Unknown opcode 0x{op:02x} — the machine has never seen this instruction. Delete cached .ternbc files and recompile.\n          → details: stdlib/errors/BET-004.tern  |  ternlang errors BET-004"),
45            VmError::InvalidRegister(reg) =>
46                write!(f, "[BET-005] Register {reg} is out of range. The BET has exactly 27 registers (0–26). That's 3³. No more.\n          → details: stdlib/errors/BET-005.tern  |  ternlang errors BET-005"),
47            VmError::PcOutOfBounds(pc) =>
48                write!(f, "[BET-006] PC {pc} is out of bounds — you jumped outside the known universe. Recompile from source.\n          → details: stdlib/errors/BET-006.tern  |  ternlang errors BET-006"),
49            VmError::TypeMismatch { expected, found } =>
50                write!(f, "[BET-007] Runtime type mismatch — expected {expected} but found {found}. Square peg, round hole.\n          → details: stdlib/errors/BET-007.tern  |  ternlang errors BET-007"),
51            VmError::TensorIndexOutOfBounds { tensor_id, index, size } =>
52                write!(f, "[BET-008] Tensor[{tensor_id}]: index {index} is out of bounds — tensor only has {size} element(s). Trittensors don't grow on access.\n          → details: stdlib/errors/BET-008.tern  |  ternlang errors BET-008"),
53            VmError::TensorNotAllocated(idx) =>
54                write!(f, "[BET-009] TensorRef({idx}) doesn't exist — you never allocated it. TALLOC first, then TIDX.\n          → details: stdlib/errors/BET-009.tern  |  ternlang errors BET-009"),
55            VmError::AgentTypeNotRegistered(type_id) =>
56                write!(f, "[BET-010] Agent type_id 0x{type_id:04x} was never registered. You can't spawn what was never declared.\n          → details: stdlib/errors/BET-010.tern  |  ternlang errors BET-010"),
57            VmError::AgentIdInvalid(id) =>
58                write!(f, "[BET-011] Agent #{id} doesn't exist — no agent was spawned at this ID. TSEND and TAWAIT require a live agent.\n          → details: stdlib/errors/BET-011.tern  |  ternlang errors BET-011"),
59            VmError::RuntimeError(msg) =>
60                write!(f, "[BET-012] Runtime error: {msg}"),
61        }
62    }
63}
64
65#[derive(Debug, Clone, PartialEq)]
66pub enum Value {
67    Trit(Trit),
68    Int(i64),
69    Float(f64),
70    String(String),
71    TensorRef(usize),
72    AgentRef(usize, Option<String>),
73}
74
75impl Default for Value {
76    fn default() -> Self {
77        Value::Trit(Trit::Tend)
78    }
79}
80
81struct TensorInstance {
82    data: Vec<Trit>,
83    rows: usize,
84    cols: usize,
85}
86
87struct AgentInstance {
88    handler_addr: usize,
89    mailbox: std::collections::VecDeque<Value>,
90}
91
92pub struct BetVm {
93    registers: [Value; 27],
94    register_stack: Vec<[Value; 27]>,
95    carry_reg: Trit,
96    stack: Vec<Value>,
97    call_stack: Vec<usize>,
98    tensors: Vec<TensorInstance>,
99    agents: Vec<AgentInstance>,
100    agent_types: std::collections::HashMap<u16, usize>,
101    pc: usize,
102    code: Vec<u8>,
103    node_id: String,
104    remote: Option<Arc<dyn RemoteTransport>>,
105    instructions_count: u64,
106    pub print_log: Vec<String>,
107}
108
109impl BetVm {
110    pub fn new(code: Vec<u8>) -> Self {
111        Self {
112            registers: std::array::from_fn(|_| Value::default()),
113            register_stack: Vec::new(),
114            carry_reg: Trit::Tend,
115            stack: Vec::new(),
116            call_stack: Vec::new(),
117            tensors: Vec::new(),
118            agents: Vec::new(),
119            agent_types: std::collections::HashMap::new(),
120            pc: 0,
121            code,
122            node_id: "127.0.0.1:7373".to_string(),
123            remote: None,
124            instructions_count: 0,
125            print_log: Vec::new(),
126        }
127    }
128
129    /// Drain all lines printed by `print()`/`println()` during execution.
130    pub fn take_output(&mut self) -> Vec<String> {
131        std::mem::take(&mut self.print_log)
132    }
133
134    pub fn set_node_id(&mut self, node_id: String) {
135        self.node_id = node_id;
136    }
137
138    pub fn set_remote(&mut self, transport: Arc<dyn RemoteTransport>) {
139        self.remote = Some(transport);
140    }
141
142    pub fn register_agent_type(&mut self, type_id: u16, handler_addr: usize) {
143        self.agent_types.insert(type_id, handler_addr);
144    }
145
146    pub fn peek_stack(&self) -> Option<Value> {
147        self.stack.last().cloned()
148    }
149
150    pub fn get_register(&self, reg: u8) -> Value {
151        if reg < 27 { self.registers[reg as usize].clone() } else { Value::default() }
152    }
153
154    pub fn run(&mut self) -> Result<(), VmError> {
155        loop {
156            if self.pc >= self.code.len() { break; }
157            let opcode = self.code[self.pc];
158            self.pc += 1;
159
160            match opcode {
161                0x01 => { // Tpush
162                    let packed = self.read_u8()?;
163                    let trits = unpack_trits(&[packed], 1).map_err(VmError::BetFault)?;
164                    self.stack.push(Value::Trit(trits[0]));
165                }
166                0x02 => { // Tadd
167                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
168                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
169                    match (a.clone(), b.clone()) {
170                        (Value::Trit(av), Value::Trit(bv)) => {
171                            let (sum, carry) = av + bv;
172                            self.stack.push(Value::Trit(sum));
173                            self.carry_reg = carry;
174                        }
175                        (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av + bv)),
176                        (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av + bv)),
177                        (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av + bv as i64)),
178                        (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 + bv)),
179                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
180                    }
181                }
182                0x03 => { // Tmul
183                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
184                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
185                    match (a.clone(), b.clone()) {
186                        (Value::Trit(av), Value::Trit(bv)) => self.stack.push(Value::Trit(av * bv)),
187                        (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av * bv)),
188                        (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av * bv)),
189                        (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av * bv as i64)),
190                        (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 * bv)),
191                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
192                    }
193                }
194                0x04 => { // Tneg
195                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
196                    match a.clone() {
197                        Value::Trit(av) => self.stack.push(Value::Trit(-av)),
198                        Value::Int(av) => self.stack.push(Value::Int(-av)),
199                        Value::Float(av) => self.stack.push(Value::Float(-av)),
200                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", a) }),
201                    }
202                }
203                0x05 => { // TjmpPos — jumps if top is +1
204                    let addr = self.read_u16()?;
205                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
206                    let is_pos = match val {
207                        Value::Trit(Trit::Affirm) => true,
208                        Value::Int(1) => true,
209                        _ => false,
210                    };
211                    if is_pos { self.pc = addr as usize; }
212                }
213                0x06 => { // TjmpZero — jumps if top is 0
214                    let addr = self.read_u16()?;
215                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
216                    let is_zero = match val {
217                        Value::Trit(Trit::Tend) => true,
218                        Value::Int(0) => true,
219                        _ => false,
220                    };
221                    if is_zero { self.pc = addr as usize; }
222                }
223                0x07 => { // TjmpNeg — jumps if top is -1
224                    let addr = self.read_u16()?;
225                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
226                    let is_neg = match val {
227                        Value::Trit(Trit::Reject) => true,
228                        Value::Int(-1) => true,
229                        _ => false,
230                    };
231                    if is_neg { self.pc = addr as usize; }
232                }
233                0x08 => { // Tstore
234                    let reg = self.read_u8()?;
235                    let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
236                    if reg < 27 { self.registers[reg as usize] = val; }
237                }
238                0x09 => { // Tload
239                    let reg = self.read_u8()?;
240                    if reg < 27 { self.stack.push(self.registers[reg as usize].clone()); }
241                    else { self.stack.push(Value::default()); }
242                }
243                0x0a => { // Tdup
244                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
245                    self.stack.push(val.clone());
246                }
247                0x0b => { // Tjmp
248                    let addr = self.read_u16()?;
249                    self.pc = addr as usize;
250                }
251                0x0c => { // Tpop
252                    self.stack.pop().ok_or(VmError::StackUnderflow)?;
253                }
254                0x0e => { // Tcons
255                    let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
256                    let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
257                    
258                    let a = match a_val {
259                        Value::Trit(t) => t,
260                        Value::Int(v) if v == 1 => Trit::Affirm,
261                        Value::Int(v) if v == 0 => Trit::Tend,
262                        Value::Int(v) if v == -1 => Trit::Reject,
263                        _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", a_val) }),
264                    };
265                    let b = match b_val {
266                        Value::Trit(t) => t,
267                        Value::Int(v) if v == 1 => Trit::Affirm,
268                        Value::Int(v) if v == 0 => Trit::Tend,
269                        Value::Int(v) if v == -1 => Trit::Reject,
270                        _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", b_val) }),
271                    };
272
273                    let result = match (a, b) {
274                        (Trit::Affirm, Trit::Affirm) => Trit::Affirm,
275                        (Trit::Reject, Trit::Reject) => Trit::Reject,
276                        (Trit::Tend, x) => x,
277                        (x, Trit::Tend) => x,
278                        _ => Trit::Tend,
279                    };
280                    self.stack.push(Value::Trit(result));
281                }
282                0x0f => { // Talloc
283                    let rows = self.read_u16()? as usize;
284                    let cols = self.read_u16()? as usize;
285                    let size = rows * cols;
286                    let idx = self.tensors.len();
287                    self.tensors.push(TensorInstance {
288                        data: vec![Trit::Tend; size],
289                        rows,
290                        cols,
291                    });
292                    self.stack.push(Value::TensorRef(idx));
293                }
294                0x10 => { // Tcall
295                    let addr = self.read_u16()? as usize;
296                    self.register_stack.push(self.registers.clone());
297                    self.call_stack.push(self.pc);
298                    self.pc = addr;
299                }
300                0x11 => { // Tret
301                    if let Some(prev) = self.register_stack.pop() {
302                        self.registers = prev;
303                    }
304                    match self.call_stack.pop() {
305                        Some(ret) => self.pc = ret,
306                        None => return Ok(()),
307                    }
308                }
309                0x14 => { // Tless
310                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
311                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
312                    match (a.clone(), b.clone()) {
313                        (Value::Int(x), Value::Int(y)) => {
314                            let r = if x < y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
315                            self.stack.push(Value::Trit(r));
316                        }
317                        (Value::Float(x), Value::Float(y)) => {
318                            let r = if x < y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
319                            self.stack.push(Value::Trit(r));
320                        }
321                        (Value::Int(x), Value::Trit(y)) => {
322                            let bv = y as i64;
323                            let r = if x < bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
324                            self.stack.push(Value::Trit(r));
325                        }
326                        (Value::Trit(x), Value::Int(y)) => {
327                            let av = x as i64;
328                            let r = if av < y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
329                            self.stack.push(Value::Trit(r));
330                        }
331                        (Value::Trit(x), Value::Trit(y)) => {
332                            let av = x as i64;
333                            let bv = y as i64;
334                            let r = if av < bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
335                            self.stack.push(Value::Trit(r));
336                        }
337                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
338                    }
339                }
340                0x15 => { // Tgreater
341                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
342                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
343                    match (a.clone(), b.clone()) {
344                        (Value::Int(x), Value::Int(y)) => {
345                            let r = if x > y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
346                            self.stack.push(Value::Trit(r));
347                        }
348                        (Value::Float(x), Value::Float(y)) => {
349                            let r = if x > y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
350                            self.stack.push(Value::Trit(r));
351                        }
352                        (Value::Int(x), Value::Trit(y)) => {
353                            let bv = y as i64;
354                            let r = if x > bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
355                            self.stack.push(Value::Trit(r));
356                        }
357                        (Value::Trit(x), Value::Int(y)) => {
358                            let av = x as i64;
359                            let r = if av > y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
360                            self.stack.push(Value::Trit(r));
361                        }
362                        (Value::Trit(x), Value::Trit(y)) => {
363                            let av = x as i64;
364                            let bv = y as i64;
365                            let r = if av > bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
366                            self.stack.push(Value::Trit(r));
367                        }
368                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
369                    }
370                }
371                0x16 => { // Teq
372                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
373                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
374                    let is_eq = match (a.clone(), b.clone()) {
375                        (Value::Int(av), Value::Trit(bv)) => av == bv as i64,
376                        (Value::Trit(av), Value::Int(bv)) => av as i64 == bv,
377                        (Value::Float(av), Value::Float(bv)) => (av - bv).abs() < f64::EPSILON,
378                        _ => a == b,
379                    };
380                    let r = if is_eq { Trit::Affirm } else { Trit::Reject };
381                    self.stack.push(Value::Trit(r));
382                }
383                0x17 => { // TpushInt
384                    let mut b = [0u8; 8];
385                    for i in 0..8 { b[i] = self.read_u8()?; }
386                    self.stack.push(Value::Int(i64::from_le_bytes(b)));
387                }
388                0x18 => { // TaddInt
389                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
390                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
391                    match (a.clone(), b.clone()) {
392                        (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x + y)),
393                        _ => return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", (a, b)) }),
394                    }
395                }
396                0x19 => { // TpushFloat
397                    let mut b = [0u8; 8];
398                    for i in 0..8 { b[i] = self.read_u8()?; }
399                    self.stack.push(Value::Float(f64::from_le_bytes(b)));
400                }
401                0x1e => { // Tdiv
402                    let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
403                    let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
404                    match (a_val.clone(), b_val.clone()) {
405                        (Value::Int(av), Value::Int(bv)) => {
406                            if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
407                            self.stack.push(Value::Int(av / bv));
408                        }
409                        (Value::Float(av), Value::Float(bv)) => {
410                            if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
411                            self.stack.push(Value::Float(av / bv));
412                        }
413                        (Value::Int(av), Value::Trit(bv)) => {
414                            let b = bv as i64;
415                            if b == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
416                            self.stack.push(Value::Int(av / b));
417                        }
418                        (Value::Trit(av), Value::Int(bv)) => {
419                            if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
420                            self.stack.push(Value::Int(av as i64 / bv));
421                        }
422                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a_val, b_val)) }),
423                    }
424                }
425                0x1f => { // Tmod
426                    let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
427                    let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
428                    match (a_val.clone(), b_val.clone()) {
429                        (Value::Int(av), Value::Int(bv)) => {
430                            if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
431                            self.stack.push(Value::Int(av % bv));
432                        }
433                        (Value::Int(av), Value::Trit(bv)) => {
434                            let b = bv as i64;
435                            if b == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
436                            self.stack.push(Value::Int(av % b));
437                        }
438                        (Value::Trit(av), Value::Int(bv)) => {
439                            if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
440                            self.stack.push(Value::Int(av as i64 % bv));
441                        }
442                        _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", (a_val, b_val)) }),
443                    }
444                }
445                0x20 => { // Tprint
446                    let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
447                    let line = match &val {
448                        Value::Trit(t) => format!("{:?}", t),
449                        Value::Int(i) => format!("{}", i),
450                        Value::Float(f) => format!("{}", f),
451                        Value::String(s) => s.clone(),
452                        Value::TensorRef(idx) => format!("TensorRef({})", idx),
453                        Value::AgentRef(idx, addr) => format!("AgentRef({}, {:?})", idx, addr),
454                    };
455                    println!("{}", line);
456                    self.print_log.push(line);
457                }
458                0x21 => { // TpushString
459                    let len = self.read_u16()? as usize;
460                    let mut bytes = vec![0u8; len];
461                    for i in 0..len { bytes[i] = self.read_u8()?; }
462                    let s = String::from_utf8(bytes).map_err(|_| VmError::RuntimeError("Invalid UTF-8 string".into()))?;
463                    self.stack.push(Value::String(s));
464                }
465                0x22 => { // Tidx
466                    let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
467                    let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
468                    let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
469                    let r = match row { Value::Int(v) => v, Value::Trit(t) => t as i64, _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", row) }) };
470                    let c = match col { Value::Int(v) => v, Value::Trit(t) => t as i64, _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", col) }) };
471                    match rf {
472                        Value::TensorRef(idx) => {
473                            if idx >= self.tensors.len() {
474                                return Err(VmError::TensorNotAllocated(idx));
475                            }
476                            let tensor = &self.tensors[idx];
477                            let pos = if tensor.cols > 1 { r as usize * tensor.cols + c as usize } else { r as usize };
478                            if pos >= tensor.data.len() {
479                                return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() });
480                            }
481                            self.stack.push(Value::Trit(tensor.data[pos]));
482                        }
483                        _ => return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) }),
484                    }
485                }
486                0x23 => { // Tset
487                    let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
488                    let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
489                    let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
490                    let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
491                    let r = match row { Value::Int(v) => v, Value::Trit(t) => t as i64, _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", row) }) };
492                    let c = match col { Value::Int(v) => v, Value::Trit(t) => t as i64, _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", col) }) };
493                    match (rf.clone(), val.clone()) {
494                        (Value::TensorRef(idx), Value::Trit(t)) => {
495                            if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
496                            let tensor = &mut self.tensors[idx];
497                            let pos = if tensor.cols > 1 { r as usize * tensor.cols + c as usize } else { r as usize };
498                            if pos >= tensor.data.len() { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() }); }
499                            tensor.data[pos] = t;
500                        }
501                        (Value::TensorRef(idx), Value::Int(v)) => {
502                            if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
503                            let tensor = &mut self.tensors[idx];
504                            let pos = if tensor.cols > 1 { r as usize * tensor.cols + c as usize } else { r as usize };
505                            if pos >= tensor.data.len() { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() }); }
506                            tensor.data[pos] = Trit::from(v as i8);
507                        }
508                        _ => return Err(VmError::TypeMismatch { expected: "TensorRef, Trit".into(), found: format!("{:?}", (rf, val)) }),
509                    }
510                }
511                0x24 => { // Tshape
512                    let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
513                    if let Value::TensorRef(idx) = rf {
514                        if idx >= self.tensors.len() {
515                            return Err(VmError::TensorNotAllocated(idx));
516                        }
517                        let tensor = &self.tensors[idx];
518                        self.stack.push(Value::Int(tensor.rows as i64));
519                        self.stack.push(Value::Int(tensor.cols as i64));
520                    } else { return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) }); }
521                }
522                0x30 => { // Tspawn — (type_id) → AgentRef
523                    let type_id = self.read_u16()?;
524                    if let Some(&handler_addr) = self.agent_types.get(&type_id) {
525                        let id = self.agents.len();
526                        self.agents.push(AgentInstance { handler_addr, mailbox: Default::default() });
527                        self.stack.push(Value::AgentRef(id, None));
528                    } else {
529                        return Err(VmError::AgentTypeNotRegistered(type_id));
530                    }
531                }
532                0x31 => { // Tsend — msg, target → void
533                    let msg = self.stack.pop().ok_or(VmError::StackUnderflow)?;
534                    let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
535                    if let Value::AgentRef(id, None) = target {
536                        if id < self.agents.len() {
537                            self.agents[id].mailbox.push_back(msg);
538                        } else {
539                            return Err(VmError::AgentIdInvalid(id));
540                        }
541                    } else {
542                        return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
543                    }
544                }
545                0x32 => { // Tawait — target → result
546                    let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
547                    if let Value::AgentRef(id, None) = target {
548                        if id < self.agents.len() {
549                            let handler_addr = self.agents[id].handler_addr;
550                            let msg = self.agents[id].mailbox.pop_front().unwrap_or(Value::default());
551                            // Synchronous handler dispatch — identical to TCALL
552                            self.register_stack.push(self.registers.clone());
553                            self.call_stack.push(self.pc);
554                            self.pc = handler_addr;
555                            self.stack.push(msg);
556                        } else {
557                            return Err(VmError::AgentIdInvalid(id));
558                        }
559                    } else {
560                        return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
561                    }
562                }
563                0x25 => { // TjmpEqInt — imm_int, imm_addr → peek, jumps if eq
564                    let mut b = [0u8; 8];
565                    for i in 0..8 { b[i] = self.read_u8()?; }
566                    let target_val = i64::from_le_bytes(b);
567                    let addr = self.read_u16()?;
568                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
569                    let is_eq = match val {
570                        Value::Int(v) => *v == target_val,
571                        Value::Trit(t) => (*t as i8) as i64 == target_val,
572                        _ => false,
573                    };
574                    if is_eq { self.pc = addr as usize; }
575                }
576                0x26 => { // TlessEqual
577                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
578                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
579                    let is_le = match (a.clone(), b.clone()) {
580                        (Value::Int(x), Value::Int(y)) => x <= y,
581                        (Value::Float(x), Value::Float(y)) => x <= y || (x - y).abs() < f64::EPSILON,
582                        (Value::Int(x), Value::Trit(y)) => x <= y as i64,
583                        (Value::Trit(x), Value::Int(y)) => (x as i64) <= y,
584                        (Value::Trit(x), Value::Trit(y)) => (x as i64) <= (y as i64),
585                        _ => false,
586                    };
587                    self.stack.push(Value::Trit(if is_le { Trit::Affirm } else { Trit::Reject }));
588                }
589                0x27 => { // TgreaterEqual
590                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
591                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
592                    let is_ge = match (a.clone(), b.clone()) {
593                        (Value::Int(x), Value::Int(y)) => x >= y,
594                        (Value::Float(x), Value::Float(y)) => x >= y || (x - y).abs() < f64::EPSILON,
595                        (Value::Int(x), Value::Trit(y)) => x >= y as i64,
596                        (Value::Trit(x), Value::Int(y)) => (x as i64) >= y,
597                        (Value::Trit(x), Value::Trit(y)) => (x as i64) >= (y as i64),
598                        _ => false,
599                    };
600                    self.stack.push(Value::Trit(if is_ge { Trit::Affirm } else { Trit::Reject }));
601                }
602                0x00 => return Ok(()),
603                _ => return Err(VmError::InvalidOpcode(opcode)),
604            }
605        }
606        Ok(())
607    }
608
609    fn read_u8(&mut self) -> Result<u8, VmError> {
610        if self.pc >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
611        let val = self.code[self.pc];
612        self.pc += 1;
613        Ok(val)
614    }
615
616    fn read_u16(&mut self) -> Result<u16, VmError> {
617        if self.pc + 1 >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
618        let val = u16::from_le_bytes([self.code[self.pc], self.code[self.pc + 1]]);
619        self.pc += 2;
620        Ok(val)
621    }
622}