1pub mod bet;
2
3use crate::trit::Trit;
4use crate::vm::bet::{unpack_trits, BetFault};
5
6use std::fmt;
7use std::sync::Arc;
8
9pub 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 TensorIndexOutOfBounds { tensor_id: usize, index: usize, size: usize },
27 TensorNotAllocated(usize),
28 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 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
245 self.stack.push(val.clone());
246 }
247 0x0b => { let addr = self.read_u16()?;
249 self.pc = addr as usize;
250 }
251 0x0c => { self.stack.pop().ok_or(VmError::StackUnderflow)?;
253 }
254 0x0e => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 => { 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 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 => { 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 => { 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 => { 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}