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".into(),
123            remote: None,
124            _instructions_count: 0,
125            print_log: Vec::new(),
126        }
127    }
128
129
130    /// Drain all lines printed by `print()`/`println()` during execution.
131    pub fn take_output(&mut self) -> Vec<String> {
132        std::mem::take(&mut self.print_log)
133    }
134
135    pub fn set_node_id(&mut self, node_id: String) {
136        self.node_id = node_id;
137    }
138
139    pub fn set_remote(&mut self, transport: Arc<dyn RemoteTransport>) {
140        self.remote = Some(transport);
141    }
142
143    pub fn register_agent_type(&mut self, type_id: u16, handler_addr: usize) {
144        self.agent_types.insert(type_id, handler_addr);
145    }
146
147    pub fn peek_stack(&self) -> Option<Value> {
148        self.stack.last().cloned()
149    }
150
151    pub fn get_register(&self, reg: u8) -> Value {
152        if reg < 27 { self.registers[reg as usize].clone() } else { Value::default() }
153    }
154
155    pub fn run(&mut self) -> Result<(), VmError> {
156        loop {
157            if self.pc >= self.code.len() { break; }
158            let opcode = self.code[self.pc];
159            self.pc += 1;
160
161            match opcode {
162                0x01 => { // Tpush
163                    let packed = self.read_u8()?;
164                    let trits = unpack_trits(&[packed], 1).map_err(VmError::BetFault)?;
165                    self.stack.push(Value::Trit(trits[0]));
166                }
167                0x02 => { // Tadd
168                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
169                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
170                    match (a.clone(), b.clone()) {
171                        (Value::Trit(av), Value::Trit(bv)) => {
172                            let (sum, carry) = av + bv;
173                            self.stack.push(Value::Trit(sum));
174                            self.carry_reg = carry;
175                        }
176                        (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av + bv)),
177                        (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av + bv)),
178                        (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av + bv as i64)),
179                        (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 + bv)),
180                        (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av + (bv as i8 as f64))),
181                        (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) + bv)),
182                        (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av + (bv as f64))),
183                        (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) + bv)),
184                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
185                    }
186                }
187                0x03 => { // Tmul
188                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
189                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
190                    match (a.clone(), b.clone()) {
191                        (Value::Trit(av), Value::Trit(bv)) => self.stack.push(Value::Trit(av * bv)),
192                        (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av * bv)),
193                        (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av * bv)),
194                        (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av * bv as i64)),
195                        (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 * bv)),
196                        (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av * (bv as i8 as f64))),
197                        (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) * bv)),
198                        (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av * (bv as f64))),
199                        (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) * bv)),
200                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
201                    }
202                }
203                0x04 => { // Tneg
204                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
205                    match a.clone() {
206                        Value::Trit(av) => self.stack.push(Value::Trit(-av)),
207                        Value::Int(av) => self.stack.push(Value::Int(-av)),
208                        Value::Float(av) => self.stack.push(Value::Float(-av)),
209                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", a) }),
210                    }
211                }
212                0x05 => { // TjmpPos — jumps if top is +1
213                    let addr = self.read_u16()?;
214                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
215                    let is_pos = match val {
216                        Value::Trit(Trit::Affirm) => true,
217                        Value::Int(1) => true,
218                        _ => false,
219                    };
220                    if is_pos { self.pc = addr as usize; }
221                }
222                0x06 => { // TjmpZero — jumps if top is 0
223                    let addr = self.read_u16()?;
224                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
225                    let is_zero = match val {
226                        Value::Trit(Trit::Tend) => true,
227                        Value::Int(0) => true,
228                        _ => false,
229                    };
230                    if is_zero { self.pc = addr as usize; }
231                }
232                0x07 => { // TjmpNeg — jumps if top is -1
233                    let addr = self.read_u16()?;
234                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
235                    let is_neg = match val {
236                        Value::Trit(Trit::Reject) => true,
237                        Value::Int(-1) => true,
238                        _ => false,
239                    };
240                    if is_neg { self.pc = addr as usize; }
241                }
242                0x08 => { // Tstore
243                    let reg = self.read_u8()?;
244                    let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
245                    if reg < 27 { self.registers[reg as usize] = val; }
246                }
247                0x09 => { // Tload
248                    let reg = self.read_u8()?;
249                    if reg < 27 { self.stack.push(self.registers[reg as usize].clone()); }
250                    else { self.stack.push(Value::default()); }
251                }
252                0x0a => { // Tdup
253                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
254                    self.stack.push(val.clone());
255                }
256                0x0b => { // Tjmp
257                    let addr = self.read_u16()?;
258                    self.pc = addr as usize;
259                }
260                0x0c => { // Tpop
261                    self.stack.pop().ok_or(VmError::StackUnderflow)?;
262                }
263                0x0e => { // Tcons
264                    let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
265                    let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
266                    
267                    let a = match a_val {
268                        Value::Trit(t) => t,
269                        Value::Int(v) if v == 1 => Trit::Affirm,
270                        Value::Int(v) if v == 0 => Trit::Tend,
271                        Value::Int(v) if v == -1 => Trit::Reject,
272                        _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", a_val) }),
273                    };
274                    let b = match b_val {
275                        Value::Trit(t) => t,
276                        Value::Int(v) if v == 1 => Trit::Affirm,
277                        Value::Int(v) if v == 0 => Trit::Tend,
278                        Value::Int(v) if v == -1 => Trit::Reject,
279                        _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", b_val) }),
280                    };
281
282                    let result = match (a, b) {
283                        (Trit::Affirm, Trit::Affirm) => Trit::Affirm,
284                        (Trit::Reject, Trit::Reject) => Trit::Reject,
285                        (Trit::Tend, x) => x,
286                        (x, Trit::Tend) => x,
287                        _ => Trit::Tend,
288                    };
289                    self.stack.push(Value::Trit(result));
290                }
291                0x0f => { // Talloc
292                    let rows = self.read_u16()? as usize;
293                    let cols = self.read_u16()? as usize;
294                    let size = rows * cols;
295                    let idx = self.tensors.len();
296                    self.tensors.push(TensorInstance {
297                        data: vec![Trit::Tend; size],
298                        rows,
299                        cols,
300                    });
301                    self.stack.push(Value::TensorRef(idx));
302                }
303                0x10 => { // Tcall
304                    let addr = self.read_u16()? as usize;
305                    self.register_stack.push(self.registers.clone());
306                    self.call_stack.push(self.pc);
307                    self.pc = addr;
308                }
309                0x11 => { // Tret
310                    if let Some(prev) = self.register_stack.pop() {
311                        self.registers = prev;
312                    }
313                    match self.call_stack.pop() {
314                        Some(ret) => self.pc = ret,
315                        None => return Ok(()),
316                    }
317                }
318                0x14 => { // Tless
319                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
320                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
321                    match (a.clone(), b.clone()) {
322                        (Value::Int(x), Value::Int(y)) => {
323                            let r = if x < y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
324                            self.stack.push(Value::Trit(r));
325                        }
326                        (Value::Float(x), Value::Float(y)) => {
327                            let r = if x < y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
328                            self.stack.push(Value::Trit(r));
329                        }
330                        (Value::Int(x), Value::Trit(y)) => {
331                            let bv = y as i64;
332                            let r = if x < bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
333                            self.stack.push(Value::Trit(r));
334                        }
335                        (Value::Trit(x), Value::Int(y)) => {
336                            let av = x as i64;
337                            let r = if av < y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
338                            self.stack.push(Value::Trit(r));
339                        }
340                        (Value::Int(av), Value::Float(bv)) => {
341                            let a_val = av as f64;
342                            let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
343                            self.stack.push(Value::Trit(r));
344                        }
345                        (Value::Float(av), Value::Int(bv)) => {
346                            let b_val = bv as f64;
347                            let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
348                            self.stack.push(Value::Trit(r));
349                        }
350                        (Value::Trit(av), Value::Float(bv)) => {
351                            let a_val = av as i8 as f64;
352                            let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
353                            self.stack.push(Value::Trit(r));
354                        }
355                        (Value::Float(av), Value::Trit(bv)) => {
356                            let b_val = bv as i8 as f64;
357                            let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
358                            self.stack.push(Value::Trit(r));
359                        }
360                        (Value::Trit(x), Value::Trit(y)) => {
361                            let av = x as i64;
362                            let bv = y as i64;
363                            let r = if av < bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
364                            self.stack.push(Value::Trit(r));
365                        }
366                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
367                    }
368                }
369                0x15 => { // Tgreater
370                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
371                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
372                    match (a.clone(), b.clone()) {
373                        (Value::Int(x), Value::Int(y)) => {
374                            let r = if x > y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
375                            self.stack.push(Value::Trit(r));
376                        }
377                        (Value::Float(x), Value::Float(y)) => {
378                            let r = if x > y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
379                            self.stack.push(Value::Trit(r));
380                        }
381                        (Value::Int(x), Value::Trit(y)) => {
382                            let bv = y as i64;
383                            let r = if x > bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
384                            self.stack.push(Value::Trit(r));
385                        }
386                        (Value::Trit(x), Value::Int(y)) => {
387                            let av = x as i64;
388                            let r = if av > y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
389                            self.stack.push(Value::Trit(r));
390                        }
391                        (Value::Int(av), Value::Float(bv)) => {
392                            let a_val = av as f64;
393                            let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
394                            self.stack.push(Value::Trit(r));
395                        }
396                        (Value::Float(av), Value::Int(bv)) => {
397                            let b_val = bv as f64;
398                            let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
399                            self.stack.push(Value::Trit(r));
400                        }
401                        (Value::Trit(av), Value::Float(bv)) => {
402                            let a_val = av as i8 as f64;
403                            let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
404                            self.stack.push(Value::Trit(r));
405                        }
406                        (Value::Float(av), Value::Trit(bv)) => {
407                            let b_val = bv as i8 as f64;
408                            let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
409                            self.stack.push(Value::Trit(r));
410                        }
411                        (Value::Trit(x), Value::Trit(y)) => {
412                            let av = x as i64;
413                            let bv = y as i64;
414                            let r = if av > bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
415                            self.stack.push(Value::Trit(r));
416                        }
417                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
418                    }
419                }
420                0x16 => { // Teq
421                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
422                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
423                    let is_eq = match (a.clone(), b.clone()) {
424                        (Value::Int(av), Value::Trit(bv)) => av == bv as i64,
425                        (Value::Trit(av), Value::Int(bv)) => av as i64 == bv,
426                        (Value::Float(av), Value::Float(bv)) => (av - bv).abs() < f64::EPSILON,
427                        (Value::Float(av), Value::Trit(bv)) => (av - (bv as i8 as f64)).abs() < f64::EPSILON,
428                        (Value::Trit(av), Value::Float(bv)) => ((av as i8 as f64) - bv).abs() < f64::EPSILON,
429                        (Value::Float(av), Value::Int(bv)) => (av - (bv as f64)).abs() < f64::EPSILON,
430                        (Value::Int(av), Value::Float(bv)) => ((av as f64) - bv).abs() < f64::EPSILON,
431                        _ => a == b,
432                    };
433                    let r = if is_eq { Trit::Affirm } else { Trit::Reject };
434                    self.stack.push(Value::Trit(r));
435                }
436                0x17 => { // TpushInt
437                    let mut b = [0u8; 8];
438                    for i in 0..8 { b[i] = self.read_u8()?; }
439                    self.stack.push(Value::Int(i64::from_le_bytes(b)));
440                }
441                0x18 => { // TaddInt
442                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
443                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
444                    match (a.clone(), b.clone()) {
445                        (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x + y)),
446                        _ => return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", (a, b)) }),
447                    }
448                }
449                0x19 => { // TpushFloat
450                    let mut b = [0u8; 8];
451                    for i in 0..8 { b[i] = self.read_u8()?; }
452                    self.stack.push(Value::Float(f64::from_le_bytes(b)));
453                }
454                0x1e => { // Tdiv
455                    let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
456                    let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
457                    match (a_val.clone(), b_val.clone()) {
458                        (Value::Int(av), Value::Int(bv)) => {
459                            if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
460                            self.stack.push(Value::Int(av / bv));
461                        }
462                        (Value::Float(av), Value::Float(bv)) => {
463                            if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
464                            self.stack.push(Value::Float(av / bv));
465                        }
466                        (Value::Int(av), Value::Trit(bv)) => {
467                            let b = bv as i64;
468                            if b == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
469                            self.stack.push(Value::Int(av / b));
470                        }
471                        (Value::Trit(av), Value::Int(bv)) => {
472                            if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
473                            self.stack.push(Value::Int(av as i64 / bv));
474                        }
475                        (Value::Float(av), Value::Trit(bv)) => {
476                            let b = bv as i8 as f64;
477                            if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
478                            self.stack.push(Value::Float(av / b));
479                        }
480                        (Value::Trit(av), Value::Float(bv)) => {
481                            if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
482                            self.stack.push(Value::Float(av as i8 as f64 / bv));
483                        }
484                        (Value::Float(av), Value::Int(bv)) => {
485                            let b = bv as f64;
486                            if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
487                            self.stack.push(Value::Float(av / b));
488                        }
489                        (Value::Int(av), Value::Float(bv)) => {
490                            if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
491                            self.stack.push(Value::Float(av as f64 / bv));
492                        }
493                        _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a_val, b_val)) }),
494                    }
495                }
496                0x1f => { // Tmod
497                    let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
498                    let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
499                    match (a_val.clone(), b_val.clone()) {
500                        (Value::Int(av), Value::Int(bv)) => {
501                            if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
502                            self.stack.push(Value::Int(av % bv));
503                        }
504                        (Value::Int(av), Value::Trit(bv)) => {
505                            let b = bv as i64;
506                            if b == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
507                            self.stack.push(Value::Int(av % b));
508                        }
509                        (Value::Trit(av), Value::Int(bv)) => {
510                            if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
511                            self.stack.push(Value::Int(av as i64 % bv));
512                        }
513                        (Value::Float(av), Value::Float(bv)) => {
514                             if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
515                             self.stack.push(Value::Float(av % bv));
516                        }
517                        (Value::Float(av), Value::Trit(bv)) => {
518                             let b = bv as i8 as f64;
519                             if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
520                             self.stack.push(Value::Float(av % b));
521                        }
522                        (Value::Trit(av), Value::Float(bv)) => {
523                             if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
524                             self.stack.push(Value::Float(av as i8 as f64 % bv));
525                        }
526                        (Value::Float(av), Value::Int(bv)) => {
527                             let b = bv as f64;
528                             if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
529                             self.stack.push(Value::Float(av % b));
530                        }
531                        (Value::Int(av), Value::Float(bv)) => {
532                             if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
533                             self.stack.push(Value::Float(av as f64 % bv));
534                        }
535                        _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", (a_val, b_val)) }),
536                    }
537                }
538                0x20 => { // Tprint
539                    let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
540                    let line = match &val {
541                        Value::Trit(t) => format!("{:?}", t),
542                        Value::Int(i) => format!("{}", i),
543                        Value::Float(f) => format!("{}", f),
544                        Value::String(s) => s.clone(),
545                        Value::TensorRef(idx) => format!("TensorRef({})", idx),
546                        Value::AgentRef(idx, addr) => format!("AgentRef({}, {:?})", idx, addr),
547                    };
548                    println!("{}", line);
549                    self.print_log.push(line);
550                }
551                0x21 => { // TpushString
552                    let len = self.read_u16()? as usize;
553                    let mut bytes = vec![0u8; len];
554                    for i in 0..len { bytes[i] = self.read_u8()?; }
555                    let s = String::from_utf8(bytes).map_err(|_| VmError::RuntimeError("Invalid UTF-8 string".into()))?;
556                    self.stack.push(Value::String(s));
557                }
558                0x22 => { // Tidx
559                    let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
560                    let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
561                    let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
562                    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) }) };
563                    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) }) };
564                    match rf {
565                        Value::TensorRef(idx) => {
566                            if idx >= self.tensors.len() {
567                                return Err(VmError::TensorNotAllocated(idx));
568                            }
569                            let tensor = &self.tensors[idx];
570                            let pos = if tensor.cols > 1 { r as usize * tensor.cols + c as usize } else { r as usize };
571                            if pos >= tensor.data.len() {
572                                return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() });
573                            }
574                            self.stack.push(Value::Trit(tensor.data[pos]));
575                        }
576                        _ => return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) }),
577                    }
578                }
579                0x23 => { // Tset
580                    let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
581                    let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
582                    let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
583                    let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
584                    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) }) };
585                    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) }) };
586                    match (rf.clone(), val.clone()) {
587                        (Value::TensorRef(idx), Value::Trit(t)) => {
588                            if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
589                            let tensor = &mut self.tensors[idx];
590                            let pos = if tensor.cols > 1 { r as usize * tensor.cols + c as usize } else { r as usize };
591                            if pos >= tensor.data.len() { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() }); }
592                            tensor.data[pos] = t;
593                        }
594                        (Value::TensorRef(idx), Value::Int(v)) => {
595                            if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
596                            let tensor = &mut self.tensors[idx];
597                            let pos = if tensor.cols > 1 { r as usize * tensor.cols + c as usize } else { r as usize };
598                            if pos >= tensor.data.len() { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() }); }
599                            tensor.data[pos] = Trit::from(v as i8);
600                        }
601                        _ => return Err(VmError::TypeMismatch { expected: "TensorRef, Trit".into(), found: format!("{:?}", (rf, val)) }),
602                    }
603                }
604                0x24 => { // Tshape
605                    let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
606                    if let Value::TensorRef(idx) = rf {
607                        if idx >= self.tensors.len() {
608                            return Err(VmError::TensorNotAllocated(idx));
609                        }
610                        let tensor = &self.tensors[idx];
611                        self.stack.push(Value::Int(tensor.rows as i64));
612                        self.stack.push(Value::Int(tensor.cols as i64));
613                    } else { return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) }); }
614                }
615                0x30 => { // Tspawn — (type_id) → AgentRef
616                    let type_id = self.read_u16()?;
617                    if let Some(&handler_addr) = self.agent_types.get(&type_id) {
618                        let id = self.agents.len();
619                        self.agents.push(AgentInstance { handler_addr, mailbox: Default::default() });
620                        self.stack.push(Value::AgentRef(id, None));
621                    } else {
622                        return Err(VmError::AgentTypeNotRegistered(type_id));
623                    }
624                }
625                0x31 => { // Tsend — msg, target → void
626                    let msg = self.stack.pop().ok_or(VmError::StackUnderflow)?;
627                    let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
628                    if let Value::AgentRef(id, None) = target {
629                        if id < self.agents.len() {
630                            self.agents[id].mailbox.push_back(msg);
631                        } else {
632                            return Err(VmError::AgentIdInvalid(id));
633                        }
634                    } else {
635                        return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
636                    }
637                }
638                0x32 => { // Tawait — target → result
639                    let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
640                    if let Value::AgentRef(id, None) = target {
641                        if id < self.agents.len() {
642                            let handler_addr = self.agents[id].handler_addr;
643                            let msg = self.agents[id].mailbox.pop_front().unwrap_or(Value::default());
644                            // Synchronous handler dispatch — identical to TCALL
645                            self.register_stack.push(self.registers.clone());
646                            self.call_stack.push(self.pc);
647                            self.pc = handler_addr;
648                            self.stack.push(msg);
649                        } else {
650                            return Err(VmError::AgentIdInvalid(id));
651                        }
652                    } else {
653                        return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
654                    }
655                }
656                0x25 => { // TjmpEqInt — imm_int, imm_addr → peek, jumps if eq
657                    let mut b = [0u8; 8];
658                    for i in 0..8 { b[i] = self.read_u8()?; }
659                    let target_val = i64::from_le_bytes(b);
660                    let addr = self.read_u16()?;
661                    let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
662                    let is_eq = match val {
663                        Value::Int(v) => *v == target_val,
664                        Value::Trit(t) => (*t as i8) as i64 == target_val,
665                        _ => false,
666                    };
667                    if is_eq { self.pc = addr as usize; }
668                }
669                0x26 => { // TlessEqual
670                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
671                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
672                    let is_le = match (a.clone(), b.clone()) {
673                        (Value::Int(x), Value::Int(y)) => x <= y,
674                        (Value::Float(x), Value::Float(y)) => x <= y || (x - y).abs() < f64::EPSILON,
675                        (Value::Int(x), Value::Trit(y)) => x <= y as i64,
676                        (Value::Trit(x), Value::Int(y)) => (x as i64) <= y,
677                        (Value::Trit(x), Value::Trit(y)) => (x as i64) <= (y as i64),
678                        _ => false,
679                    };
680                    self.stack.push(Value::Trit(if is_le { Trit::Affirm } else { Trit::Reject }));
681                }
682                0x27 => { // TgreaterEqual
683                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
684                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
685                    let is_ge = match (a.clone(), b.clone()) {
686                        (Value::Int(x), Value::Int(y)) => x >= y,
687                        (Value::Float(x), Value::Float(y)) => x >= y || (x - y).abs() < f64::EPSILON,
688                        (Value::Int(x), Value::Trit(y)) => x >= y as i64,
689                        (Value::Trit(x), Value::Int(y)) => (x as i64) >= y,
690                        (Value::Trit(x), Value::Trit(y)) => (x as i64) >= (y as i64),
691                        _ => false,
692                    };
693                    self.stack.push(Value::Trit(if is_ge { Trit::Affirm } else { Trit::Reject }));
694                }
695                0x28 => { // Tand — min(a, b) in balanced ternary (logical AND)
696                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
697                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
698                    let to_trit = |v: Value| -> Result<Trit, VmError> {
699                        match v {
700                            Value::Trit(t) => Ok(t),
701                            Value::Int(n) if n > 0 => Ok(Trit::Affirm),
702                            Value::Int(0) => Ok(Trit::Tend),
703                            Value::Int(_) => Ok(Trit::Reject),
704                            other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
705                        }
706                    };
707                    let ta = to_trit(a)?;
708                    let tb = to_trit(b)?;
709                    let result = if (ta as i8) <= (tb as i8) { ta } else { tb };
710                    self.stack.push(Value::Trit(result));
711                }
712                0x29 => { // Tor — max(a, b) in balanced ternary (logical OR)
713                    let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
714                    let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
715                    let to_trit = |v: Value| -> Result<Trit, VmError> {
716                        match v {
717                            Value::Trit(t) => Ok(t),
718                            Value::Int(n) if n > 0 => Ok(Trit::Affirm),
719                            Value::Int(0) => Ok(Trit::Tend),
720                            Value::Int(_) => Ok(Trit::Reject),
721                            other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
722                        }
723                    };
724                    let ta = to_trit(a)?;
725                    let tb = to_trit(b)?;
726                    let result = if (ta as i8) >= (tb as i8) { ta } else { tb };
727                    self.stack.push(Value::Trit(result));
728                }
729                0x00 => return Ok(()),
730                _ => return Err(VmError::InvalidOpcode(opcode)),
731            }
732        }
733        Ok(())
734    }
735
736    fn read_u8(&mut self) -> Result<u8, VmError> {
737        if self.pc >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
738        let val = self.code[self.pc];
739        self.pc += 1;
740        Ok(val)
741    }
742
743    fn read_u16(&mut self) -> Result<u16, VmError> {
744        if self.pc + 1 >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
745        let val = u16::from_le_bytes([self.code[self.pc], self.code[self.pc + 1]]);
746        self.pc += 2;
747        Ok(val)
748    }
749}