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
16const MAX_CALL_DEPTH: usize = 4096;
20
21#[derive(Debug, PartialEq, Eq)]
22pub enum VmError {
23 StackUnderflow,
24 BetFault(BetFault),
25 Halt,
26 InvalidOpcode(u8),
27 InvalidRegister(u8),
28 PcOutOfBounds(usize),
29 TypeMismatch { expected: String, found: String },
30 TensorIndexOutOfBounds { tensor_id: usize, index: usize, size: usize },
32 TensorNotAllocated(usize),
33 AgentTypeNotRegistered(u16),
35 AgentIdInvalid(usize),
36 RuntimeError(String),
37 CallStackOverflow,
38 FileOpenError(String),
40 FileReadError(String),
41 FileWriteError(String),
42 FileNotOpen(usize),
43 AssertionFailed,
44}
45
46impl fmt::Display for VmError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 VmError::StackUnderflow =>
50 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"),
51 VmError::BetFault(fault) =>
52 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"),
53 VmError::Halt =>
54 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"),
55 VmError::InvalidOpcode(op) =>
56 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"),
57 VmError::InvalidRegister(reg) =>
58 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"),
59 VmError::PcOutOfBounds(pc) =>
60 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"),
61 VmError::TypeMismatch { expected, found } =>
62 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"),
63 VmError::TensorIndexOutOfBounds { tensor_id, index, size } =>
64 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"),
65 VmError::TensorNotAllocated(idx) =>
66 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"),
67 VmError::AgentTypeNotRegistered(type_id) =>
68 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"),
69 VmError::AgentIdInvalid(id) =>
70 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"),
71 VmError::RuntimeError(msg) =>
72 write!(f, "[BET-012] Runtime error: {msg}"),
73 VmError::CallStackOverflow =>
74 write!(f, "[BET-013] Call stack overflow — max depth ({MAX_CALL_DEPTH}) exceeded. Infinite recursion or unbounded cross-module mutual calls detected.\n → details: stdlib/errors/BET-013.tern | ternlang errors BET-013"),
75 VmError::FileOpenError(e) =>
76 write!(f, "[IO-001] File open error: {e}"),
77 VmError::FileReadError(e) =>
78 write!(f, "[IO-002] File read error: {e}"),
79 VmError::FileWriteError(e) =>
80 write!(f, "[IO-003] File write error: {e}"),
81 VmError::FileNotOpen(id) =>
82 write!(f, "[IO-004] File handle {id} is not open or was closed."),
83 VmError::AssertionFailed =>
84 write!(f, "[ASSERT-001] Assertion failed: an assert() condition evaluated to reject or tend."),
85 }
86 }
87}
88
89#[derive(Debug, Clone, PartialEq)]
90pub enum Value {
91 Trit(Trit),
92 Int(i64),
93 Float(f64),
94 String(String),
95 TensorRef(usize),
96 AgentRef(usize, Option<String>),
97}
98
99impl Default for Value {
100 fn default() -> Self {
101 Value::Trit(Trit::Tend)
102 }
103}
104
105struct TensorInstance {
106 data: Vec<Trit>,
107 rows: usize,
108 cols: usize,
109}
110
111struct AgentInstance {
112 handler_addr: usize,
113 mailbox: std::collections::VecDeque<Value>,
114}
115
116pub struct BetVm {
117 registers: Vec<Value>,
120 register_stack: Vec<Vec<Value>>,
121 carry_reg: Trit,
122 stack: Vec<Value>,
123 call_stack: Vec<usize>,
124 tensors: Vec<TensorInstance>,
125 agents: Vec<AgentInstance>,
126 agent_types: std::collections::HashMap<u16, usize>,
127 pc: usize,
128 code: Vec<u8>,
129 node_id: String,
130 remote: Option<Arc<dyn RemoteTransport>>,
131 open_files: Vec<Option<std::fs::File>>,
132 _instructions_count: u64,
133 pub print_log: Vec<String>,
134}
135
136impl BetVm {
137 pub fn new(code: Vec<u8>) -> Self {
138 Self {
139 registers: vec![Value::default(); 27],
140 register_stack: Vec::new(),
141 carry_reg: Trit::Tend,
142 stack: Vec::new(),
143 call_stack: Vec::new(),
144 tensors: Vec::new(),
145 agents: Vec::new(),
146 agent_types: std::collections::HashMap::new(),
147 pc: 0,
148 code,
149 node_id: "127.0.0.1".into(),
150 remote: None,
151 open_files: Vec::new(),
152 _instructions_count: 0,
153 print_log: Vec::new(),
154 }
155 }
156
157
158 pub fn take_output(&mut self) -> Vec<String> {
160 std::mem::take(&mut self.print_log)
161 }
162
163 pub fn set_node_id(&mut self, node_id: String) {
164 self.node_id = node_id;
165 }
166
167 pub fn set_remote(&mut self, transport: Arc<dyn RemoteTransport>) {
168 self.remote = Some(transport);
169 }
170
171 pub fn register_agent_type(&mut self, type_id: u16, handler_addr: usize) {
172 self.agent_types.insert(type_id, handler_addr);
173 }
174
175 pub fn peek_stack(&self) -> Option<Value> {
176 self.stack.last().cloned()
177 }
178
179 pub fn get_register(&self, reg: u8) -> Value {
180 self.registers.get(reg as usize).cloned().unwrap_or_default()
181 }
182
183 pub fn run(&mut self) -> Result<(), VmError> {
184 loop {
185 if self.pc >= self.code.len() { break; }
186 let opcode = self.code[self.pc];
187 self.pc += 1;
188
189 match opcode {
190 0x01 => { let packed = self.read_u8()?;
192 let trits = unpack_trits(&[packed], 1).map_err(VmError::BetFault)?;
193 self.stack.push(Value::Trit(trits[0]));
194 }
195 0x02 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
197 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
198 match (a.clone(), b.clone()) {
199 (Value::Trit(av), Value::Trit(bv)) => {
200 let (sum, carry) = av + bv;
201 self.stack.push(Value::Trit(sum));
202 self.carry_reg = carry;
203 }
204 (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av + bv)),
205 (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av + bv)),
206 (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av + bv as i64)),
207 (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 + bv)),
208 (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av + (bv as i8 as f64))),
209 (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) + bv)),
210 (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av + (bv as f64))),
211 (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) + bv)),
212 (Value::String(av), Value::String(bv)) => self.stack.push(Value::String(av + &bv)),
214 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
215 }
216 }
217 0x03 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
219 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
220 match (a.clone(), b.clone()) {
221 (Value::Trit(av), Value::Trit(bv)) => self.stack.push(Value::Trit(av * bv)),
222 (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av * bv)),
223 (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av * bv)),
224 (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av * bv as i64)),
225 (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 * bv)),
226 (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av * (bv as i8 as f64))),
227 (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) * bv)),
228 (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av * (bv as f64))),
229 (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) * bv)),
230 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
231 }
232 }
233 0x04 => { let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
235 match a.clone() {
236 Value::Trit(av) => self.stack.push(Value::Trit(-av)),
237 Value::Int(av) => self.stack.push(Value::Int(-av)),
238 Value::Float(av) => self.stack.push(Value::Float(-av)),
239 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", a) }),
240 }
241 }
242 0x05 => { let addr = self.read_u16()?;
244 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
245 let is_pos = match val {
246 Value::Trit(Trit::Affirm) => true,
247 Value::Int(1) => true,
248 _ => false,
249 };
250 if is_pos { self.pc = addr as usize; }
251 }
252 0x06 => { let addr = self.read_u16()?;
254 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
255 let is_zero = match val {
256 Value::Trit(Trit::Tend) => true,
257 Value::Int(0) => true,
258 _ => false,
259 };
260 if is_zero { self.pc = addr as usize; }
261 }
262 0x07 => { let addr = self.read_u16()?;
264 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
265 let is_neg = match val {
266 Value::Trit(Trit::Reject) => true,
267 Value::Int(-1) => true,
268 _ => false,
269 };
270 if is_neg { self.pc = addr as usize; }
271 }
272 0x08 => { let reg = self.read_u8()? as usize;
274 let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
275 if reg >= self.registers.len() { self.registers.resize(reg + 1, Value::default()); }
276 self.registers[reg] = val;
277 }
278 0x09 => { let reg = self.read_u8()? as usize;
280 if reg >= self.registers.len() { self.registers.resize(reg + 1, Value::default()); }
281 self.stack.push(self.registers[reg].clone());
282 }
283 0x0a => { let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
285 self.stack.push(val.clone());
286 }
287 0x0b => { let addr = self.read_u16()?;
289 self.pc = addr as usize;
290 }
291 0x0c => { self.stack.pop().ok_or(VmError::StackUnderflow)?;
293 }
294 0x0e => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
296 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
297
298 let a = match a_val {
299 Value::Trit(t) => t,
300 Value::Int(v) if v == 1 => Trit::Affirm,
301 Value::Int(v) if v == 0 => Trit::Tend,
302 Value::Int(v) if v == -1 => Trit::Reject,
303 _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", a_val) }),
304 };
305 let b = match b_val {
306 Value::Trit(t) => t,
307 Value::Int(v) if v == 1 => Trit::Affirm,
308 Value::Int(v) if v == 0 => Trit::Tend,
309 Value::Int(v) if v == -1 => Trit::Reject,
310 _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", b_val) }),
311 };
312
313 let result = match (a, b) {
314 (Trit::Affirm, Trit::Affirm) => Trit::Affirm,
315 (Trit::Reject, Trit::Reject) => Trit::Reject,
316 (Trit::Tend, x) => x,
317 (x, Trit::Tend) => x,
318 _ => Trit::Tend,
319 };
320 self.stack.push(Value::Trit(result));
321 }
322 0x0f => { let rows = self.read_u16()? as usize;
324 let cols = self.read_u16()? as usize;
325 let size = rows * cols;
326 let idx = self.tensors.len();
327 self.tensors.push(TensorInstance {
328 data: vec![Trit::Tend; size],
329 rows,
330 cols,
331 });
332 self.stack.push(Value::TensorRef(idx));
333 }
334 0x10 => { if self.call_stack.len() >= MAX_CALL_DEPTH {
336 return Err(VmError::CallStackOverflow);
337 }
338 let addr = self.read_u16()? as usize;
339 self.register_stack.push(self.registers.clone());
340 self.call_stack.push(self.pc);
341 self.pc = addr;
342 }
343 0x11 => { if let Some(prev) = self.register_stack.pop() {
345 self.registers = prev;
346 }
347 match self.call_stack.pop() {
348 Some(ret) => self.pc = ret,
349 None => return Ok(()),
350 }
351 }
352 0x14 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
354 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
355 match (a.clone(), b.clone()) {
356 (Value::Int(x), Value::Int(y)) => {
357 let r = if x < y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
358 self.stack.push(Value::Trit(r));
359 }
360 (Value::Float(x), Value::Float(y)) => {
361 let r = if x < y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
362 self.stack.push(Value::Trit(r));
363 }
364 (Value::Int(x), Value::Trit(y)) => {
365 let bv = y as i64;
366 let r = if x < bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
367 self.stack.push(Value::Trit(r));
368 }
369 (Value::Trit(x), Value::Int(y)) => {
370 let av = x as i64;
371 let r = if av < y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
372 self.stack.push(Value::Trit(r));
373 }
374 (Value::Int(av), Value::Float(bv)) => {
375 let a_val = av as f64;
376 let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
377 self.stack.push(Value::Trit(r));
378 }
379 (Value::Float(av), Value::Int(bv)) => {
380 let b_val = bv as f64;
381 let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
382 self.stack.push(Value::Trit(r));
383 }
384 (Value::Trit(av), Value::Float(bv)) => {
385 let a_val = av as i8 as f64;
386 let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
387 self.stack.push(Value::Trit(r));
388 }
389 (Value::Float(av), Value::Trit(bv)) => {
390 let b_val = bv as i8 as f64;
391 let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
392 self.stack.push(Value::Trit(r));
393 }
394 (Value::Trit(x), Value::Trit(y)) => {
395 let av = x as i64;
396 let bv = y as i64;
397 let r = if av < bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
398 self.stack.push(Value::Trit(r));
399 }
400 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
401 }
402 }
403 0x15 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
405 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
406 match (a.clone(), b.clone()) {
407 (Value::Int(x), Value::Int(y)) => {
408 let r = if x > y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
409 self.stack.push(Value::Trit(r));
410 }
411 (Value::Float(x), Value::Float(y)) => {
412 let r = if x > y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
413 self.stack.push(Value::Trit(r));
414 }
415 (Value::Int(x), Value::Trit(y)) => {
416 let bv = y as i64;
417 let r = if x > bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
418 self.stack.push(Value::Trit(r));
419 }
420 (Value::Trit(x), Value::Int(y)) => {
421 let av = x as i64;
422 let r = if av > y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
423 self.stack.push(Value::Trit(r));
424 }
425 (Value::Int(av), Value::Float(bv)) => {
426 let a_val = av as f64;
427 let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
428 self.stack.push(Value::Trit(r));
429 }
430 (Value::Float(av), Value::Int(bv)) => {
431 let b_val = bv as f64;
432 let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
433 self.stack.push(Value::Trit(r));
434 }
435 (Value::Trit(av), Value::Float(bv)) => {
436 let a_val = av as i8 as f64;
437 let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
438 self.stack.push(Value::Trit(r));
439 }
440 (Value::Float(av), Value::Trit(bv)) => {
441 let b_val = bv as i8 as f64;
442 let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
443 self.stack.push(Value::Trit(r));
444 }
445 (Value::Trit(x), Value::Trit(y)) => {
446 let av = x as i64;
447 let bv = y as i64;
448 let r = if av > bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
449 self.stack.push(Value::Trit(r));
450 }
451 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
452 }
453 }
454 0x16 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
456 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
457 let is_eq = match (a.clone(), b.clone()) {
458 (Value::Int(av), Value::Trit(bv)) => av == bv as i64,
459 (Value::Trit(av), Value::Int(bv)) => av as i64 == bv,
460 (Value::Float(av), Value::Float(bv)) => (av - bv).abs() < f64::EPSILON,
461 (Value::Float(av), Value::Trit(bv)) => (av - (bv as i8 as f64)).abs() < f64::EPSILON,
462 (Value::Trit(av), Value::Float(bv)) => ((av as i8 as f64) - bv).abs() < f64::EPSILON,
463 (Value::Float(av), Value::Int(bv)) => (av - (bv as f64)).abs() < f64::EPSILON,
464 (Value::Int(av), Value::Float(bv)) => ((av as f64) - bv).abs() < f64::EPSILON,
465 _ => a == b,
466 };
467 let r = if is_eq { Trit::Affirm } else { Trit::Reject };
468 self.stack.push(Value::Trit(r));
469 }
470 0x17 => { let mut b = [0u8; 8];
472 for i in 0..8 { b[i] = self.read_u8()?; }
473 self.stack.push(Value::Int(i64::from_le_bytes(b)));
474 }
475 0x18 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
477 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
478 match (a.clone(), b.clone()) {
479 (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x + y)),
480 _ => return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", (a, b)) }),
481 }
482 }
483 0x19 => { let mut b = [0u8; 8];
485 for i in 0..8 { b[i] = self.read_u8()?; }
486 self.stack.push(Value::Float(f64::from_le_bytes(b)));
487 }
488 0x1e => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
490 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
491 match (a_val.clone(), b_val.clone()) {
492 (Value::Int(av), Value::Int(bv)) => {
493 if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
494 self.stack.push(Value::Int(av / bv));
495 }
496 (Value::Float(av), Value::Float(bv)) => {
497 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
498 self.stack.push(Value::Float(av / bv));
499 }
500 (Value::Int(av), Value::Trit(bv)) => {
501 let b = bv as i64;
502 if b == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
503 self.stack.push(Value::Int(av / b));
504 }
505 (Value::Trit(av), Value::Int(bv)) => {
506 if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
507 self.stack.push(Value::Int(av as i64 / bv));
508 }
509 (Value::Float(av), Value::Trit(bv)) => {
510 let b = bv as i8 as f64;
511 if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
512 self.stack.push(Value::Float(av / b));
513 }
514 (Value::Trit(av), Value::Float(bv)) => {
515 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
516 self.stack.push(Value::Float(av as i8 as f64 / bv));
517 }
518 (Value::Float(av), Value::Int(bv)) => {
519 let b = bv as f64;
520 if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
521 self.stack.push(Value::Float(av / b));
522 }
523 (Value::Int(av), Value::Float(bv)) => {
524 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
525 self.stack.push(Value::Float(av as f64 / bv));
526 }
527 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a_val, b_val)) }),
528 }
529 }
530 0x1f => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
532 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
533 match (a_val.clone(), b_val.clone()) {
534 (Value::Int(av), Value::Int(bv)) => {
535 if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
536 self.stack.push(Value::Int(av % bv));
537 }
538 (Value::Int(av), Value::Trit(bv)) => {
539 let b = bv as i64;
540 if b == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
541 self.stack.push(Value::Int(av % b));
542 }
543 (Value::Trit(av), Value::Int(bv)) => {
544 if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
545 self.stack.push(Value::Int(av as i64 % bv));
546 }
547 (Value::Float(av), Value::Float(bv)) => {
548 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
549 self.stack.push(Value::Float(av % bv));
550 }
551 (Value::Float(av), Value::Trit(bv)) => {
552 let b = bv as i8 as f64;
553 if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
554 self.stack.push(Value::Float(av % b));
555 }
556 (Value::Trit(av), Value::Float(bv)) => {
557 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
558 self.stack.push(Value::Float(av as i8 as f64 % bv));
559 }
560 (Value::Float(av), Value::Int(bv)) => {
561 let b = bv as f64;
562 if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
563 self.stack.push(Value::Float(av % b));
564 }
565 (Value::Int(av), Value::Float(bv)) => {
566 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
567 self.stack.push(Value::Float(av as f64 % bv));
568 }
569 _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", (a_val, b_val)) }),
570 }
571 }
572 0x20 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
574 let line = match &val {
575 Value::Trit(t) => format!("{:?}", t),
576 Value::Int(i) => format!("{}", i),
577 Value::Float(f) => format!("{}", f),
578 Value::String(s) => s.clone(),
579 Value::TensorRef(idx) => format!("TensorRef({})", idx),
580 Value::AgentRef(idx, addr) => format!("AgentRef({}, {:?})", idx, addr),
581 };
582 println!("{}", line);
583 self.print_log.push(line);
584 }
585 0x21 => { let len = self.read_u16()? as usize;
587 let mut bytes = vec![0u8; len];
588 for i in 0..len { bytes[i] = self.read_u8()?; }
589 let s = String::from_utf8(bytes).map_err(|_| VmError::RuntimeError("Invalid UTF-8 string".into()))?;
590 self.stack.push(Value::String(s));
591 }
592 0x22 => { let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
594 let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
595 let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
596 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) }) };
597 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) }) };
598 match rf {
599 Value::TensorRef(idx) => {
600 if idx >= self.tensors.len() {
601 return Err(VmError::TensorNotAllocated(idx));
602 }
603 let tensor = &self.tensors[idx];
604 let pos = if tensor.cols > 1 && c >= 0 { r as usize * tensor.cols + c as usize } else { r as usize };
606 if pos >= tensor.data.len() {
607 return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() });
608 }
609 self.stack.push(Value::Trit(tensor.data[pos]));
610 }
611 _ => return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) }),
612 }
613 }
614 0x23 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
616 let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
617 let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
618 let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
619 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) }) };
620 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) }) };
621 match (rf.clone(), val.clone()) {
622 (Value::TensorRef(idx), Value::Trit(t)) => {
623 if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
624 let tensor = &mut self.tensors[idx];
625 let pos = if tensor.cols > 1 && c >= 0 { r as usize * tensor.cols + c as usize } else { r as usize };
627 if pos >= tensor.data.len() { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() }); }
628 tensor.data[pos] = t;
629 }
630 (Value::TensorRef(idx), Value::Int(v)) => {
631 if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
632 let tensor = &mut self.tensors[idx];
633 let pos = if tensor.cols > 1 && c >= 0 { r as usize * tensor.cols + c as usize } else { r as usize };
635 if pos >= tensor.data.len() { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: tensor.data.len() }); }
636 tensor.data[pos] = if v > 0 { Trit::Affirm } else if v < 0 { Trit::Reject } else { Trit::Tend };
637 }
638 _ => return Err(VmError::TypeMismatch { expected: "TensorRef, Trit".into(), found: format!("{:?}", (rf, val)) }),
639 }
640 }
641 0x24 => { let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
643 if let Value::TensorRef(idx) = rf {
644 if idx >= self.tensors.len() {
645 return Err(VmError::TensorNotAllocated(idx));
646 }
647 let tensor = &self.tensors[idx];
648 self.stack.push(Value::Int(tensor.rows as i64));
649 self.stack.push(Value::Int(tensor.cols as i64));
650 } else { return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) }); }
651 }
652 0x30 => { let type_id = self.read_u16()?;
654 if let Some(&handler_addr) = self.agent_types.get(&type_id) {
655 let id = self.agents.len();
656 self.agents.push(AgentInstance { handler_addr, mailbox: Default::default() });
657 self.stack.push(Value::AgentRef(id, None));
658 } else {
659 return Err(VmError::AgentTypeNotRegistered(type_id));
660 }
661 }
662 0x31 => { let msg = self.stack.pop().ok_or(VmError::StackUnderflow)?;
664 let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
665 if let Value::AgentRef(id, None) = target {
666 if id < self.agents.len() {
667 self.agents[id].mailbox.push_back(msg);
668 } else {
669 return Err(VmError::AgentIdInvalid(id));
670 }
671 } else {
672 return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
673 }
674 }
675 0x32 => { let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
677 if let Value::AgentRef(id, None) = target {
678 if id < self.agents.len() {
679 if self.call_stack.len() >= MAX_CALL_DEPTH {
680 return Err(VmError::CallStackOverflow);
681 }
682 let handler_addr = self.agents[id].handler_addr;
683 let msg = self.agents[id].mailbox.pop_front().unwrap_or(Value::default());
684 self.register_stack.push(self.registers.clone());
686 self.call_stack.push(self.pc);
687 self.pc = handler_addr;
688 self.stack.push(msg);
689 } else {
690 return Err(VmError::AgentIdInvalid(id));
691 }
692 } else {
693 return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
694 }
695 }
696 0x25 => { let mut b = [0u8; 8];
698 for i in 0..8 { b[i] = self.read_u8()?; }
699 let target_val = i64::from_le_bytes(b);
700 let addr = self.read_u16()?;
701 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
702 let is_eq = match val {
703 Value::Int(v) => *v == target_val,
704 Value::Trit(t) => (*t as i8) as i64 == target_val,
705 _ => false,
706 };
707 if is_eq { self.pc = addr as usize; }
708 }
709 0x26 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
711 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
712 let is_le = match (a.clone(), b.clone()) {
713 (Value::Int(x), Value::Int(y)) => x <= y,
714 (Value::Float(x), Value::Float(y)) => x <= y || (x - y).abs() < f64::EPSILON,
715 (Value::Int(x), Value::Trit(y)) => x <= y as i64,
716 (Value::Trit(x), Value::Int(y)) => (x as i64) <= y,
717 (Value::Trit(x), Value::Trit(y)) => (x as i64) <= (y as i64),
718 _ => false,
719 };
720 self.stack.push(Value::Trit(if is_le { Trit::Affirm } else { Trit::Reject }));
721 }
722 0x27 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
724 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
725 let is_ge = match (a.clone(), b.clone()) {
726 (Value::Int(x), Value::Int(y)) => x >= y,
727 (Value::Float(x), Value::Float(y)) => x >= y || (x - y).abs() < f64::EPSILON,
728 (Value::Int(x), Value::Trit(y)) => x >= y as i64,
729 (Value::Trit(x), Value::Int(y)) => (x as i64) >= y,
730 (Value::Trit(x), Value::Trit(y)) => (x as i64) >= (y as i64),
731 _ => false,
732 };
733 self.stack.push(Value::Trit(if is_ge { Trit::Affirm } else { Trit::Reject }));
734 }
735 0x28 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
737 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
738 let to_trit = |v: Value| -> Result<Trit, VmError> {
739 match v {
740 Value::Trit(t) => Ok(t),
741 Value::Int(n) if n > 0 => Ok(Trit::Affirm),
742 Value::Int(0) => Ok(Trit::Tend),
743 Value::Int(_) => Ok(Trit::Reject),
744 other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
745 }
746 };
747 let ta = to_trit(a)?;
748 let tb = to_trit(b)?;
749 let result = if (ta as i8) <= (tb as i8) { ta } else { tb };
750 self.stack.push(Value::Trit(result));
751 }
752 0x29 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
754 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
755 let to_trit = |v: Value| -> Result<Trit, VmError> {
756 match v {
757 Value::Trit(t) => Ok(t),
758 Value::Int(n) if n > 0 => Ok(Trit::Affirm),
759 Value::Int(0) => Ok(Trit::Tend),
760 Value::Int(_) => Ok(Trit::Reject),
761 other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
762 }
763 };
764 let ta = to_trit(a)?;
765 let tb = to_trit(b)?;
766 let result = if (ta as i8) >= (tb as i8) { ta } else { tb };
767 self.stack.push(Value::Trit(result));
768 }
769 0x2a => { let mut fb = [0u8; 8];
775 for i in 0..8 { fb[i] = self.read_u8()?; }
776 let target_f = f64::from_le_bytes(fb);
777 let addr = self.read_u16()?;
778 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
779 if let Value::Float(f) = val {
780 if (f - target_f).abs() < 1e-9 {
781 self.pc = addr as usize;
782 }
783 }
784 }
785 0x33 => { let mode = self.stack.pop().ok_or(VmError::StackUnderflow)?;
787 let path = self.stack.pop().ok_or(VmError::StackUnderflow)?;
788 if let (Value::String(p), Value::Int(m)) = (path, mode) {
789 use std::fs::OpenOptions;
790 let mut options = OpenOptions::new();
791 match m {
792 0 => { options.read(true); } 1 => { options.write(true).create(true).truncate(true); } 2 => { options.append(true).create(true); } _ => return Err(VmError::RuntimeError(format!("Invalid file mode: {m}"))),
796 }
797 let file = options.open(&p).map_err(|e| VmError::FileOpenError(e.to_string()))?;
798 let handle = self.open_files.len();
799 self.open_files.push(Some(file));
800 self.stack.push(Value::Int(handle as i64));
801 } else {
802 return Err(VmError::TypeMismatch { expected: "String, Int".into(), found: "Unknown".into() });
803 }
804 }
805 0x34 => { let handle_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
807 if let Value::Int(h) = handle_val {
808 let h = h as usize;
809 if h >= self.open_files.len() || self.open_files[h].is_none() {
810 return Err(VmError::FileNotOpen(h));
811 }
812 let file = self.open_files[h].as_mut().unwrap();
813 let mut buf = [0u8; 1];
814 use std::io::Read;
815 match file.read_exact(&mut buf) {
816 Ok(_) => {
817 let t = match buf[0] {
818 b'+' | b'1' => Trit::Affirm,
819 b'-' => Trit::Reject,
820 _ => Trit::Tend,
821 };
822 self.stack.push(Value::Trit(t));
823 }
824 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
825 self.stack.push(Value::Trit(Trit::Tend)); }
827 Err(e) => return Err(VmError::FileReadError(e.to_string())),
828 }
829 } else {
830 return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", handle_val) });
831 }
832 }
833 0x35 => { let t_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
835 let h_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
836 if let (Value::Int(h), Value::Trit(t)) = (h_val, t_val) {
837 let h = h as usize;
838 if h >= self.open_files.len() || self.open_files[h].is_none() {
839 return Err(VmError::FileNotOpen(h));
840 }
841 let file = self.open_files[h].as_mut().unwrap();
842 let out = match t {
843 Trit::Affirm => b'+',
844 Trit::Reject => b'-',
845 Trit::Tend => b'0',
846 };
847 use std::io::Write;
848 file.write_all(&[out]).map_err(|e| VmError::FileWriteError(e.to_string()))?;
849 } else {
850 return Err(VmError::TypeMismatch { expected: "Int, Trit".into(), found: "Unknown".into() });
851 }
852 }
853 0x36 => { self.stack.push(Value::String(self.node_id.clone()));
858 }
859 0x37 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
861 let is_affirm = match val {
862 Value::Trit(Trit::Affirm) => true,
863 Value::Int(1) => true,
864 _ => false,
865 };
866 if !is_affirm {
867 return Err(VmError::AssertionFailed);
868 }
869 }
870 0x00 => return Ok(()),
871 _ => return Err(VmError::InvalidOpcode(opcode)),
872 }
873 }
874 Ok(())
875 }
876
877 fn read_u8(&mut self) -> Result<u8, VmError> {
878 if self.pc >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
879 let val = self.code[self.pc];
880 self.pc += 1;
881 Ok(val)
882 }
883
884 fn read_u16(&mut self) -> Result<u16, VmError> {
885 if self.pc + 1 >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
886 let val = u16::from_le_bytes([self.code[self.pc], self.code[self.pc + 1]]);
887 self.pc += 2;
888 Ok(val)
889 }
890}