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