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 Struct(std::collections::HashMap<String, Value>),
98}
99
100impl Default for Value {
101 fn default() -> Self {
102 Value::Trit(Trit::Tend)
103 }
104}
105
106enum TensorData {
107 Trit(Vec<Trit>),
108 Float(Vec<f64>),
109 Int(Vec<i64>),
110}
111
112impl TensorData {
113 fn len(&self) -> usize {
114 match self {
115 TensorData::Trit(v) => v.len(),
116 TensorData::Float(v) => v.len(),
117 TensorData::Int(v) => v.len(),
118 }
119 }
120}
121
122struct TensorInstance {
123 data: TensorData,
124 rows: usize,
125 cols: usize,
126}
127
128struct AgentInstance {
129 handler_addr: usize,
130 mailbox: std::collections::VecDeque<Value>,
131}
132
133pub struct BetVm {
134 registers: Vec<Value>,
137 register_stack: Vec<Vec<Value>>,
138 carry_reg: Trit,
139 stack: Vec<Value>,
140 call_stack: Vec<usize>,
141 tensors: Vec<TensorInstance>,
142 agents: Vec<AgentInstance>,
143 agent_types: std::collections::HashMap<u16, usize>,
144 pc: usize,
145 code: Vec<u8>,
146 node_id: String,
147 pub sparse_dropped: bool,
148 remote: Option<Arc<dyn RemoteTransport>>,
149 open_files: Vec<Option<std::fs::File>>,
150 _instructions_count: u64,
151 pub print_log: Vec<String>,
152}
153
154impl BetVm {
155 pub fn new(code: Vec<u8>) -> Self {
156 Self {
157 registers: vec![Value::default(); 27],
158 register_stack: Vec::new(),
159 carry_reg: Trit::Tend,
160 stack: Vec::new(),
161 call_stack: Vec::new(),
162 tensors: Vec::new(),
163 agents: Vec::new(),
164 agent_types: std::collections::HashMap::new(),
165 pc: 0,
166 code,
167 node_id: "127.0.0.1".into(),
168 sparse_dropped: false,
169 remote: None,
170 open_files: Vec::new(),
171 _instructions_count: 0,
172 print_log: Vec::new(),
173 }
174 }
175
176
177 pub fn take_output(&mut self) -> Vec<String> {
179 std::mem::take(&mut self.print_log)
180 }
181
182 pub fn set_node_id(&mut self, node_id: String) {
183 self.node_id = node_id;
184 }
185
186 pub fn set_remote(&mut self, transport: Arc<dyn RemoteTransport>) {
187 self.remote = Some(transport);
188 }
189
190 pub fn register_agent_type(&mut self, type_id: u16, handler_addr: usize) {
191 self.agent_types.insert(type_id, handler_addr);
192 }
193
194 pub fn peek_stack(&self) -> Option<Value> {
195 self.stack.last().cloned()
196 }
197
198 pub fn get_registers(&self) -> Vec<Value> {
199 self.registers.clone()
200 }
201
202 pub fn get_register(&self, reg: u8) -> Value {
203 self.registers.get(reg as usize).cloned().unwrap_or_default()
204 }
205
206 pub fn node_id(&self) -> &str {
207 &self.node_id
208 }
209
210 pub fn run(&mut self) -> Result<(), VmError> {
211 loop {
212 if self.pc >= self.code.len() { break; }
213 let opcode = self.code[self.pc];
214 self.pc += 1;
215
216 match opcode {
217 0x01 => { let packed = self.read_u8()?;
219 let trits = unpack_trits(&[packed], 1).map_err(VmError::BetFault)?;
220 self.stack.push(Value::Trit(trits[0]));
221 }
222 0x02 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
224 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
225 match (a.clone(), b.clone()) {
226 (Value::Trit(av), Value::Trit(bv)) => {
227 let (sum, carry) = av + bv;
228 self.stack.push(Value::Trit(sum));
229 self.carry_reg = carry;
230 }
231 (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av + bv)),
232 (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av + bv)),
233 (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av + bv as i64)),
234 (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 + bv)),
235 (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av + (bv as i8 as f64))),
236 (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) + bv)),
237 (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av + (bv as f64))),
238 (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) + bv)),
239 (Value::String(av), Value::String(bv)) => self.stack.push(Value::String(av + &bv)),
241 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
242 }
243 }
244 0x03 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
246 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
247 match (a.clone(), b.clone()) {
248 (Value::Trit(av), Value::Trit(bv)) => self.stack.push(Value::Trit(av * bv)),
249 (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av * bv)),
250 (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av * bv)),
251 (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av * bv as i64)),
252 (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 * bv)),
253 (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av * (bv as i8 as f64))),
254 (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) * bv)),
255 (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av * (bv as f64))),
256 (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) * bv)),
257 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
258 }
259 }
260 0x04 => { let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
262 match a.clone() {
263 Value::Trit(av) => self.stack.push(Value::Trit(-av)),
264 Value::Int(av) => self.stack.push(Value::Int(-av)),
265 Value::Float(av) => self.stack.push(Value::Float(-av)),
266 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", a) }),
267 }
268 }
269 0x05 => { let addr = self.read_u16()?;
271 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
272 let is_pos = match val {
273 Value::Trit(Trit::Affirm) => true,
274 Value::Int(v) => *v > 0,
275 Value::Float(f) => *f > 0.0,
276 _ => false,
277 };
278 if is_pos { self.pc = addr as usize; }
279 }
280 0x06 => { let addr = self.read_u16()?;
282 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
283 let is_zero = match val {
284 Value::Trit(Trit::Tend) => true,
285 Value::Int(v) => *v == 0,
286 Value::Float(f) => *f == 0.0,
287 _ => false,
288 };
289 if is_zero { self.pc = addr as usize; }
290 }
291 0x07 => { let addr = self.read_u16()?;
293 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
294 let is_neg = match val {
295 Value::Trit(Trit::Reject) => true,
296 Value::Int(v) => *v < 0,
297 Value::Float(f) => *f < 0.0,
298 _ => false,
299 };
300 if is_neg { self.pc = addr as usize; }
301 }
302 0x08 => { let reg = self.read_u8()? as usize;
304 let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
305 if reg >= self.registers.len() { self.registers.resize(reg + 1, Value::default()); }
306 self.registers[reg] = val;
307 }
308 0x09 => { let reg = self.read_u8()? as usize;
310 if reg >= self.registers.len() { self.registers.resize(reg + 1, Value::default()); }
311 self.stack.push(self.registers[reg].clone());
312 }
313 0x0a => { let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
315 self.stack.push(val.clone());
316 }
317 0x0b => { let addr = self.read_u16()?;
319 self.pc = addr as usize;
320 }
321 0x0c => { self.stack.pop().ok_or(VmError::StackUnderflow)?;
323 }
324 0x0e => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
326 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
327
328 let a = match a_val {
329 Value::Trit(t) => t,
330 Value::Int(v) if v == 1 => Trit::Affirm,
331 Value::Int(v) if v == 0 => Trit::Tend,
332 Value::Int(v) if v == -1 => Trit::Reject,
333 _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", a_val) }),
334 };
335 let b = match b_val {
336 Value::Trit(t) => t,
337 Value::Int(v) if v == 1 => Trit::Affirm,
338 Value::Int(v) if v == 0 => Trit::Tend,
339 Value::Int(v) if v == -1 => Trit::Reject,
340 _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", b_val) }),
341 };
342
343 let result = match (a, b) {
344 (Trit::Affirm, Trit::Affirm) => Trit::Affirm,
345 (Trit::Reject, Trit::Reject) => Trit::Reject,
346 (Trit::Tend, x) => x,
347 (x, Trit::Tend) => x,
348 _ => Trit::Tend,
349 };
350 self.stack.push(Value::Trit(result));
351 }
352 0x0f => { let rows = self.read_u32()? as usize;
354 let cols = self.read_u32()? as usize;
355 let size = rows * cols;
356 let idx = self.tensors.len();
357 self.tensors.push(TensorInstance {
358 data: TensorData::Trit(vec![Trit::Tend; size]),
359 rows,
360 cols,
361 });
362 self.stack.push(Value::TensorRef(idx));
363 }
364 0x3c => { let rows = self.read_u32()? as usize;
366 let cols = self.read_u32()? as usize;
367 let size = rows * cols;
368 let idx = self.tensors.len();
369 self.tensors.push(TensorInstance {
370 data: TensorData::Int(vec![0i64; size]),
371 rows,
372 cols,
373 });
374 self.stack.push(Value::TensorRef(idx));
375 }
376 0x3d => { let rows = self.read_u32()? as usize;
378 let cols = self.read_u32()? as usize;
379 let size = rows * cols;
380 let idx = self.tensors.len();
381 self.tensors.push(TensorInstance {
382 data: TensorData::Float(vec![0.0f64; size]),
383 rows,
384 cols,
385 });
386 self.stack.push(Value::TensorRef(idx));
387 }
388 0x10 => { if self.call_stack.len() >= MAX_CALL_DEPTH {
390 return Err(VmError::CallStackOverflow);
391 }
392 let addr = self.read_u16()? as usize;
393 self.register_stack.push(self.registers.clone());
394 self.call_stack.push(self.pc);
395 self.pc = addr;
396 }
397 0x11 => { if let Some(prev) = self.register_stack.pop() {
399 self.registers = prev;
400 }
401 match self.call_stack.pop() {
402 Some(ret) => self.pc = ret,
403 None => return Ok(()),
404 }
405 }
406 0x14 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
408 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
409 match (a.clone(), b.clone()) {
410 (Value::Int(x), Value::Int(y)) => {
411 let r = if x < y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
412 self.stack.push(Value::Trit(r));
413 }
414 (Value::Float(x), Value::Float(y)) => {
415 let r = if x < y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
416 self.stack.push(Value::Trit(r));
417 }
418 (Value::Int(x), Value::Trit(y)) => {
419 let bv = y as i64;
420 let r = if x < bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
421 self.stack.push(Value::Trit(r));
422 }
423 (Value::Trit(x), Value::Int(y)) => {
424 let av = x as i64;
425 let r = if av < y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
426 self.stack.push(Value::Trit(r));
427 }
428 (Value::Int(av), Value::Float(bv)) => {
429 let a_val = av as f64;
430 let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
431 self.stack.push(Value::Trit(r));
432 }
433 (Value::Float(av), Value::Int(bv)) => {
434 let b_val = bv as f64;
435 let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
436 self.stack.push(Value::Trit(r));
437 }
438 (Value::Trit(av), Value::Float(bv)) => {
439 let a_val = av as i8 as f64;
440 let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
441 self.stack.push(Value::Trit(r));
442 }
443 (Value::Float(av), Value::Trit(bv)) => {
444 let b_val = bv as i8 as f64;
445 let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
446 self.stack.push(Value::Trit(r));
447 }
448 (Value::Trit(x), Value::Trit(y)) => {
449 let av = x as i64;
450 let bv = y as i64;
451 let r = if av < bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
452 self.stack.push(Value::Trit(r));
453 }
454 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
455 }
456 }
457 0x15 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
459 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
460 match (a.clone(), b.clone()) {
461 (Value::Int(x), Value::Int(y)) => {
462 let r = if x > y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
463 self.stack.push(Value::Trit(r));
464 }
465 (Value::Float(x), Value::Float(y)) => {
466 let r = if x > y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
467 self.stack.push(Value::Trit(r));
468 }
469 (Value::Int(x), Value::Trit(y)) => {
470 let bv = y as i64;
471 let r = if x > bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
472 self.stack.push(Value::Trit(r));
473 }
474 (Value::Trit(x), Value::Int(y)) => {
475 let av = x as i64;
476 let r = if av > y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
477 self.stack.push(Value::Trit(r));
478 }
479 (Value::Int(av), Value::Float(bv)) => {
480 let a_val = av as f64;
481 let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
482 self.stack.push(Value::Trit(r));
483 }
484 (Value::Float(av), Value::Int(bv)) => {
485 let b_val = bv as f64;
486 let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
487 self.stack.push(Value::Trit(r));
488 }
489 (Value::Trit(av), Value::Float(bv)) => {
490 let a_val = av as i8 as f64;
491 let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
492 self.stack.push(Value::Trit(r));
493 }
494 (Value::Float(av), Value::Trit(bv)) => {
495 let b_val = bv as i8 as f64;
496 let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
497 self.stack.push(Value::Trit(r));
498 }
499 (Value::Trit(x), Value::Trit(y)) => {
500 let av = x as i64;
501 let bv = y as i64;
502 let r = if av > bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
503 self.stack.push(Value::Trit(r));
504 }
505 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
506 }
507 }
508 0x16 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
510 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
511 let is_eq = match (a.clone(), b.clone()) {
512 (Value::Int(av), Value::Trit(bv)) => av == bv as i64,
513 (Value::Trit(av), Value::Int(bv)) => av as i64 == bv,
514 (Value::Float(av), Value::Float(bv)) => (av - bv).abs() < f64::EPSILON,
515 (Value::Float(av), Value::Trit(bv)) => (av - (bv as i8 as f64)).abs() < f64::EPSILON,
516 (Value::Trit(av), Value::Float(bv)) => ((av as i8 as f64) - bv).abs() < f64::EPSILON,
517 (Value::Float(av), Value::Int(bv)) => (av - (bv as f64)).abs() < f64::EPSILON,
518 (Value::Int(av), Value::Float(bv)) => ((av as f64) - bv).abs() < f64::EPSILON,
519 _ => a == b,
520 };
521 let r = if is_eq { Trit::Affirm } else { Trit::Reject };
522 self.stack.push(Value::Trit(r));
523 }
524 0x17 => { let mut b = [0u8; 8];
526 for i in 0..8 { b[i] = self.read_u8()?; }
527 self.stack.push(Value::Int(i64::from_le_bytes(b)));
528 }
529 0x18 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
531 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
532 match (a.clone(), b.clone()) {
533 (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x + y)),
534 _ => return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", (a, b)) }),
535 }
536 }
537 0x19 => { let mut b = [0u8; 8];
539 for i in 0..8 { b[i] = self.read_u8()?; }
540 self.stack.push(Value::Float(f64::from_le_bytes(b)));
541 }
542 0x1e => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
544 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
545 match (a_val.clone(), b_val.clone()) {
546 (Value::Int(av), Value::Int(bv)) => {
547 if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
548 self.stack.push(Value::Int(av / bv));
549 }
550 (Value::Float(av), Value::Float(bv)) => {
551 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
552 self.stack.push(Value::Float(av / bv));
553 }
554 (Value::Int(av), Value::Trit(bv)) => {
555 let b = bv as i64;
556 if b == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
557 self.stack.push(Value::Int(av / b));
558 }
559 (Value::Trit(av), Value::Int(bv)) => {
560 if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
561 self.stack.push(Value::Int(av as i64 / bv));
562 }
563 (Value::Float(av), Value::Trit(bv)) => {
564 let b = bv as i8 as f64;
565 if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
566 self.stack.push(Value::Float(av / b));
567 }
568 (Value::Trit(av), Value::Float(bv)) => {
569 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
570 self.stack.push(Value::Float(av as i8 as f64 / bv));
571 }
572 (Value::Float(av), Value::Int(bv)) => {
573 let b = bv as f64;
574 if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
575 self.stack.push(Value::Float(av / b));
576 }
577 (Value::Int(av), Value::Float(bv)) => {
578 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
579 self.stack.push(Value::Float(av as f64 / bv));
580 }
581 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a_val, b_val)) }),
582 }
583 }
584 0x1f => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
586 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
587 match (a_val.clone(), b_val.clone()) {
588 (Value::Int(av), Value::Int(bv)) => {
589 if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
590 self.stack.push(Value::Int(av % bv));
591 }
592 (Value::Int(av), Value::Trit(bv)) => {
593 let b = bv as i64;
594 if b == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
595 self.stack.push(Value::Int(av % b));
596 }
597 (Value::Trit(av), Value::Int(bv)) => {
598 if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
599 self.stack.push(Value::Int(av as i64 % bv));
600 }
601 (Value::Float(av), Value::Float(bv)) => {
602 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
603 self.stack.push(Value::Float(av % bv));
604 }
605 (Value::Float(av), Value::Trit(bv)) => {
606 let b = bv as i8 as f64;
607 if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
608 self.stack.push(Value::Float(av % b));
609 }
610 (Value::Trit(av), Value::Float(bv)) => {
611 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
612 self.stack.push(Value::Float(av as i8 as f64 % bv));
613 }
614 (Value::Float(av), Value::Int(bv)) => {
615 let b = bv as f64;
616 if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
617 self.stack.push(Value::Float(av % b));
618 }
619 (Value::Int(av), Value::Float(bv)) => {
620 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
621 self.stack.push(Value::Float(av as f64 % bv));
622 }
623 _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", (a_val, b_val)) }),
624 }
625 }
626 0x20 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
628 let line = match &val {
629 Value::Trit(t) => format!("{:?}", t),
630 Value::Int(i) => format!("{}", i),
631 Value::Float(f) => format!("{}", f),
632 Value::String(s) => s.clone(),
633 Value::TensorRef(idx) => format!("TensorRef({})", idx),
634 Value::AgentRef(idx, addr) => format!("AgentRef({}, {:?})", idx, addr),
635 Value::Struct(fields) => format!("Struct({:?})", fields),
636 };
637 println!("{}", line);
638 self.print_log.push(line);
639 }
640 0x21 => { let len = self.read_u16()? as usize;
642 let mut bytes = vec![0u8; len];
643 for i in 0..len { bytes[i] = self.read_u8()?; }
644 let s = String::from_utf8(bytes).map_err(|_| VmError::RuntimeError("Invalid UTF-8 string".into()))?;
645 self.stack.push(Value::String(s));
646 }
647 0x22 => { let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
649 let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
650 let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
651 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) }) };
652 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) }) };
653 match rf {
654 Value::TensorRef(idx) => {
655 if idx >= self.tensors.len() {
656 return Err(VmError::TensorNotAllocated(idx));
657 }
658 let tensor = &self.tensors[idx];
659 let data_len = tensor.data.len();
660 let pos = if tensor.cols > 1 && c >= 0 { r as usize * tensor.cols + c as usize } else { r as usize };
661 if pos >= data_len {
662 return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: data_len });
663 }
664 let pushed = match &tensor.data {
665 TensorData::Trit(v) => Value::Trit(v[pos]),
666 TensorData::Float(v) => Value::Float(v[pos]),
667 TensorData::Int(v) => Value::Int(v[pos]),
668 };
669 self.stack.push(pushed);
670 }
671 _ => return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) }),
672 }
673 }
674 0x23 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
676 let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
677 let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
678 let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
679 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) }) };
680 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) }) };
681 if let Value::TensorRef(idx) = rf.clone() {
682 if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
683 let tensor = &mut self.tensors[idx];
684 let data_len = tensor.data.len();
685 let pos = if tensor.cols > 1 && c >= 0 { r as usize * tensor.cols + c as usize } else { r as usize };
686 if pos >= data_len { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: data_len }); }
687 match (&mut tensor.data, val.clone()) {
688 (TensorData::Trit(v), Value::Trit(t)) => v[pos] = t,
689 (TensorData::Trit(v), Value::Int(i)) => v[pos] = if i > 0 { Trit::Affirm } else if i < 0 { Trit::Reject } else { Trit::Tend },
690 (TensorData::Float(v), Value::Float(f)) => v[pos] = f,
691 (TensorData::Float(v), Value::Int(i)) => v[pos] = i as f64,
692 (TensorData::Int(v), Value::Int(i)) => v[pos] = i,
693 (TensorData::Int(v), Value::Float(f)) => v[pos] = f as i64,
694 (TensorData::Int(v), Value::Trit(t)) => v[pos] = t as i64,
695 _ => return Err(VmError::TypeMismatch { expected: "compatible value for tensor type".into(), found: format!("{:?}", val) }),
696 }
697 } else {
698 return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", rf) });
699 }
700 }
701 0x24 => { let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
703 match rf {
704 Value::TensorRef(idx) => {
705 if idx >= self.tensors.len() {
706 return Err(VmError::TensorNotAllocated(idx));
707 }
708 let tensor = &self.tensors[idx];
709 self.stack.push(Value::Int(tensor.rows as i64));
710 self.stack.push(Value::Int(tensor.cols as i64));
711 }
712 Value::String(s) => {
713 let n = s.chars().count() as i64;
715 self.stack.push(Value::Int(n));
716 self.stack.push(Value::Int(1));
717 }
718 _ => return Err(VmError::TypeMismatch { expected: "TensorRef or String".into(), found: format!("{:?}", rf) }),
719 }
720 }
721 0x30 => { let type_id = self.read_u16()?;
723 if let Some(&handler_addr) = self.agent_types.get(&type_id) {
724 let id = self.agents.len();
725 self.agents.push(AgentInstance { handler_addr, mailbox: Default::default() });
726 self.stack.push(Value::AgentRef(id, None));
727 } else {
728 return Err(VmError::AgentTypeNotRegistered(type_id));
729 }
730 }
731 0x31 => { let msg = self.stack.pop().ok_or(VmError::StackUnderflow)?;
733 let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
734 if let Value::AgentRef(id, None) = target {
735 if id < self.agents.len() {
736 self.agents[id].mailbox.push_back(msg);
737 } else {
738 return Err(VmError::AgentIdInvalid(id));
739 }
740 } else {
741 return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
742 }
743 }
744 0x32 => { let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
746 if let Value::AgentRef(id, None) = target {
747 if id < self.agents.len() {
748 if self.call_stack.len() >= MAX_CALL_DEPTH {
749 return Err(VmError::CallStackOverflow);
750 }
751 let handler_addr = self.agents[id].handler_addr;
752 let msg = self.agents[id].mailbox.pop_front().unwrap_or(Value::default());
753 self.register_stack.push(self.registers.clone());
755 self.call_stack.push(self.pc);
756 self.pc = handler_addr;
757 self.stack.push(msg);
758 } else {
759 return Err(VmError::AgentIdInvalid(id));
760 }
761 } else {
762 return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
763 }
764 }
765 0x25 => { let mut b = [0u8; 8];
767 for i in 0..8 { b[i] = self.read_u8()?; }
768 let target_val = i64::from_le_bytes(b);
769 let addr = self.read_u16()?;
770 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
771 let is_eq = match val {
772 Value::Int(v) => *v == target_val,
773 Value::Trit(t) => (*t as i8) as i64 == target_val,
774 _ => false,
775 };
776 if is_eq { self.pc = addr as usize; }
777 }
778 0x26 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
780 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
781 let is_le = match (a.clone(), b.clone()) {
782 (Value::Int(x), Value::Int(y)) => x <= y,
783 (Value::Float(x), Value::Float(y)) => x <= y || (x - y).abs() < f64::EPSILON,
784 (Value::Int(x), Value::Trit(y)) => x <= y as i64,
785 (Value::Trit(x), Value::Int(y)) => (x as i64) <= y,
786 (Value::Trit(x), Value::Trit(y)) => (x as i64) <= (y as i64),
787 _ => false,
788 };
789 self.stack.push(Value::Trit(if is_le { Trit::Affirm } else { Trit::Reject }));
790 }
791 0x27 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
793 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
794 let is_ge = match (a.clone(), b.clone()) {
795 (Value::Int(x), Value::Int(y)) => x >= y,
796 (Value::Float(x), Value::Float(y)) => x >= y || (x - y).abs() < f64::EPSILON,
797 (Value::Int(x), Value::Trit(y)) => x >= y as i64,
798 (Value::Trit(x), Value::Int(y)) => (x as i64) >= y,
799 (Value::Trit(x), Value::Trit(y)) => (x as i64) >= (y as i64),
800 _ => false,
801 };
802 self.stack.push(Value::Trit(if is_ge { Trit::Affirm } else { Trit::Reject }));
803 }
804 0x28 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
806 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
807 let to_trit = |v: Value| -> Result<Trit, VmError> {
808 match v {
809 Value::Trit(t) => Ok(t),
810 Value::Int(n) if n > 0 => Ok(Trit::Affirm),
811 Value::Int(0) => Ok(Trit::Tend),
812 Value::Int(_) => Ok(Trit::Reject),
813 other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
814 }
815 };
816 let ta = to_trit(a)?;
817 let tb = to_trit(b)?;
818 let result = if (ta as i8) <= (tb as i8) { ta } else { tb };
819 self.stack.push(Value::Trit(result));
820 }
821 0x29 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
823 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
824 let to_trit = |v: Value| -> Result<Trit, VmError> {
825 match v {
826 Value::Trit(t) => Ok(t),
827 Value::Int(n) if n > 0 => Ok(Trit::Affirm),
828 Value::Int(0) => Ok(Trit::Tend),
829 Value::Int(_) => Ok(Trit::Reject),
830 other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
831 }
832 };
833 let ta = to_trit(a)?;
834 let tb = to_trit(b)?;
835 let result = if (ta as i8) >= (tb as i8) { ta } else { tb };
836 self.stack.push(Value::Trit(result));
837 }
838 0x2a => { let mut fb = [0u8; 8];
844 for i in 0..8 { fb[i] = self.read_u8()?; }
845 let target_f = f64::from_le_bytes(fb);
846 let addr = self.read_u16()?;
847 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
848 if let Value::Float(f) = val {
849 if (f - target_f).abs() < 1e-9 {
850 self.pc = addr as usize;
851 }
852 }
853 }
854 0x33 => { let mode = self.stack.pop().ok_or(VmError::StackUnderflow)?;
856 let path = self.stack.pop().ok_or(VmError::StackUnderflow)?;
857 if let (Value::String(p), Value::Int(m)) = (path, mode) {
858 use std::fs::OpenOptions;
859 let mut options = OpenOptions::new();
860 match m {
861 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}"))),
865 }
866 let file = options.open(&p).map_err(|e| VmError::FileOpenError(e.to_string()))?;
867 let handle = self.open_files.len();
868 self.open_files.push(Some(file));
869 self.stack.push(Value::Int(handle as i64));
870 } else {
871 return Err(VmError::TypeMismatch { expected: "String, Int".into(), found: "Unknown".into() });
872 }
873 }
874 0x34 => { let handle_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
876 if let Value::Int(h) = handle_val {
877 let h = h as usize;
878 if h >= self.open_files.len() || self.open_files[h].is_none() {
879 return Err(VmError::FileNotOpen(h));
880 }
881 let file = self.open_files[h].as_mut().unwrap();
882 let mut buf = [0u8; 1];
883 use std::io::Read;
884 match file.read_exact(&mut buf) {
885 Ok(_) => {
886 let t = match buf[0] {
887 b'+' | b'1' => Trit::Affirm,
888 b'-' => Trit::Reject,
889 _ => Trit::Tend,
890 };
891 self.stack.push(Value::Trit(t));
892 }
893 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
894 self.stack.push(Value::Trit(Trit::Tend)); }
896 Err(e) => return Err(VmError::FileReadError(e.to_string())),
897 }
898 } else {
899 return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", handle_val) });
900 }
901 }
902 0x35 => { let t_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
904 let h_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
905 if let (Value::Int(h), Value::Trit(t)) = (h_val, t_val) {
906 let h = h as usize;
907 if h >= self.open_files.len() || self.open_files[h].is_none() {
908 return Err(VmError::FileNotOpen(h));
909 }
910 let file = self.open_files[h].as_mut().unwrap();
911 let out = match t {
912 Trit::Affirm => b'+',
913 Trit::Reject => b'-',
914 Trit::Tend => b'0',
915 };
916 use std::io::Write;
917 file.write_all(&[out]).map_err(|e| VmError::FileWriteError(e.to_string()))?;
918 } else {
919 return Err(VmError::TypeMismatch { expected: "Int, Trit".into(), found: "Unknown".into() });
920 }
921 }
922 0x36 => { self.stack.push(Value::String(self.node_id.clone()));
927 }
928 0x37 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
930 let is_affirm = match val {
931 Value::Trit(Trit::Affirm) => true,
932 Value::Int(1) => true,
933 _ => false,
934 };
935 if !is_affirm {
936 return Err(VmError::AssertionFailed);
937 }
938 }
939 0x38 => { let a_rows = self.read_u8()? as usize;
944 let a_cols = self.read_u8()? as usize;
945 let b_cols = self.read_u8()? as usize;
946 let b_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
947 let a_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
948
949 if let (Value::TensorRef(a_idx), Value::TensorRef(b_idx)) = (a_ref, b_ref) {
950 let (a_data, b_data) = {
951 let a = self.tensors.get(a_idx).ok_or(VmError::TensorNotAllocated(a_idx))?;
952 let b = self.tensors.get(b_idx).ok_or(VmError::TensorNotAllocated(b_idx))?;
953
954 let a_data = match &a.data {
955 TensorData::Trit(v) => v,
956 _ => return Err(VmError::TypeMismatch { expected: "TritTensor".into(), found: "Other".into() }),
957 };
958 let b_data = match &b.data {
959 TensorData::Trit(v) => v,
960 _ => return Err(VmError::TypeMismatch { expected: "TritTensor".into(), found: "Other".into() }),
961 };
962 (a_data.clone(), b_data.clone())
963 };
964
965 let mut result = vec![Trit::Tend; a_rows * b_cols];
966 let mut skipped = false;
967
968 for i in 0..a_rows {
969 for k in 0..a_cols {
970 let a_val = a_data[i * a_cols + k];
971 if a_val == Trit::Tend {
972 skipped = true;
973 continue;
974 }
975 for j in 0..b_cols {
976 let b_val = b_data[k * b_cols + j];
977 if b_val == Trit::Tend { continue; }
978 let prod = a_val * b_val;
979 let (sum, _) = result[i * b_cols + j] + prod;
980 result[i * b_cols + j] = sum;
981 }
982 }
983 }
984
985 if skipped { self.sparse_dropped = true; }
986 let res_idx = self.tensors.len();
987 self.tensors.push(TensorInstance {
988 data: TensorData::Trit(result),
989 rows: a_rows,
990 cols: b_cols,
991 });
992 self.stack.push(Value::TensorRef(res_idx));
993 } else {
994 return Err(VmError::TypeMismatch { expected: "TensorRef, TensorRef".into(), found: "Unknown".into() });
995 }
996 }
997 0x40 => { let num_fields = self.read_u8()? as usize;
999 let mut fields = std::collections::HashMap::new();
1000 for _ in 0..num_fields {
1001 let name_len = self.read_u8()? as usize;
1002 let mut name_bytes = vec![0u8; name_len];
1003 for i in 0..name_len { name_bytes[i] = self.read_u8()?; }
1004 let name = String::from_utf8(name_bytes).unwrap();
1005 let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1006 fields.insert(name, val);
1007 }
1008 self.stack.push(Value::Struct(fields));
1009 }
1010 0x41 => { let name_len = self.read_u8()? as usize;
1012 let mut name_bytes = vec![0u8; name_len];
1013 for i in 0..name_len { name_bytes[i] = self.read_u8()?; }
1014 let name = String::from_utf8(name_bytes).unwrap();
1015 let obj = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1016 if let Value::Struct(fields) = obj {
1017 let val = fields.get(&name).cloned().unwrap_or_default();
1018 self.stack.push(val);
1019 } else {
1020 return Err(VmError::TypeMismatch { expected: "Struct".into(), found: format!("{:?}", obj) });
1021 }
1022 }
1023 0x00 => return Ok(()),
1024 _ => return Err(VmError::InvalidOpcode(opcode)),
1025 }
1026 }
1027 Ok(())
1028 }
1029
1030 fn read_u8(&mut self) -> Result<u8, VmError> {
1031 if self.pc >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
1032 let val = self.code[self.pc];
1033 self.pc += 1;
1034 Ok(val)
1035 }
1036
1037 fn read_u16(&mut self) -> Result<u16, VmError> {
1038 if self.pc + 1 >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
1039 let val = u16::from_le_bytes([self.code[self.pc], self.code[self.pc + 1]]);
1040 self.pc += 2;
1041 Ok(val)
1042 }
1043
1044 fn read_u32(&mut self) -> Result<u32, VmError> {
1045 if self.pc + 3 >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
1046 let val = u32::from_le_bytes([
1047 self.code[self.pc], self.code[self.pc + 1],
1048 self.code[self.pc + 2], self.code[self.pc + 3]
1049 ]);
1050 self.pc += 4;
1051 Ok(val)
1052 }
1053}