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
21const MAX_STEPS: u64 = 10_000_000;
24
25#[derive(Debug, PartialEq, Eq)]
26pub enum VmError {
27 StackUnderflow,
28 BetFault(BetFault),
29 Halt,
30 InvalidOpcode(u8),
31 InvalidRegister(u8),
32 PcOutOfBounds(usize),
33 TypeMismatch { expected: String, found: String },
34 TensorIndexOutOfBounds { tensor_id: usize, index: usize, size: usize },
36 TensorNotAllocated(usize),
37 AgentTypeNotRegistered(u16),
39 AgentIdInvalid(usize),
40 RuntimeError(String),
41 CallStackOverflow,
42 StepLimitExceeded,
43 FileOpenError(String),
45 FileReadError(String),
46 FileWriteError(String),
47 FileNotOpen(usize),
48 AssertionFailed,
49}
50
51impl fmt::Display for VmError {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 VmError::StackUnderflow =>
55 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"),
56 VmError::BetFault(fault) =>
57 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"),
58 VmError::Halt =>
59 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"),
60 VmError::InvalidOpcode(op) =>
61 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"),
62 VmError::InvalidRegister(reg) =>
63 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"),
64 VmError::PcOutOfBounds(pc) =>
65 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"),
66 VmError::TypeMismatch { expected, found } =>
67 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"),
68 VmError::TensorIndexOutOfBounds { tensor_id, index, size } =>
69 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"),
70 VmError::TensorNotAllocated(idx) =>
71 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"),
72 VmError::AgentTypeNotRegistered(type_id) =>
73 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"),
74 VmError::AgentIdInvalid(id) =>
75 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"),
76 VmError::RuntimeError(msg) =>
77 write!(f, "[BET-012] Runtime error: {msg}"),
78 VmError::CallStackOverflow =>
79 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"),
80 VmError::StepLimitExceeded =>
81 write!(f, "[BET-014] Step limit ({MAX_STEPS}) exceeded — program did not halt within the allowed instruction budget. Check for infinite loops.\n → details: stdlib/errors/BET-014.tern | ternlang errors BET-014"),
82 VmError::FileOpenError(e) =>
83 write!(f, "[IO-001] File open error: {e}"),
84 VmError::FileReadError(e) =>
85 write!(f, "[IO-002] File read error: {e}"),
86 VmError::FileWriteError(e) =>
87 write!(f, "[IO-003] File write error: {e}"),
88 VmError::FileNotOpen(id) =>
89 write!(f, "[IO-004] File handle {id} is not open or was closed."),
90 VmError::AssertionFailed =>
91 write!(f, "[ASSERT-001] Assertion failed: an assert() condition evaluated to reject or tend."),
92 }
93 }
94}
95
96#[derive(Debug, Clone, PartialEq)]
97pub enum Value {
98 Trit(Trit),
99 Int(i64),
100 Float(f64),
101 String(String),
102 TensorRef(usize),
103 TensorView {
104 tensor_id: usize,
105 offset: usize,
106 length: usize,
107 stride: usize,
108 },
109 AgentRef(usize, Option<String>),
110 Struct(std::collections::HashMap<String, Value>),
111}
112
113impl Default for Value {
114 fn default() -> Self {
115 Value::Trit(Trit::Tend)
116 }
117}
118
119enum TensorData {
120 Trit(Vec<Trit>),
121 PackedTrit(Vec<u8>, usize),
122 Float(Vec<f64>),
123 Int(Vec<i64>),
124}
125
126impl TensorData {
127 fn len(&self) -> usize {
128 match self {
129 TensorData::Trit(v) => v.len(),
130 TensorData::PackedTrit(_, len) => *len,
131 TensorData::Float(v) => v.len(),
132 TensorData::Int(v) => v.len(),
133 }
134 }
135}
136
137struct TensorInstance {
138 data: TensorData,
139 rows: usize,
140 cols: usize,
141}
142
143struct AgentInstance {
144 handler_addr: usize,
145 mailbox: std::collections::VecDeque<Value>,
146}
147
148pub struct BetVm {
149 registers: Vec<Value>,
152 register_stack: Vec<Vec<Value>>,
153 carry_reg: Trit,
154 stack: Vec<Value>,
155 call_stack: Vec<usize>,
156 tensors: Vec<TensorInstance>,
157 agents: Vec<AgentInstance>,
158 agent_types: std::collections::HashMap<u16, usize>,
159 pc: usize,
160 code: Vec<u8>,
161 node_id: String,
162 pub sparse_dropped: bool,
163 remote: Option<Arc<dyn RemoteTransport>>,
164 open_files: Vec<Option<std::fs::File>>,
165 bindings: std::collections::HashMap<usize, Value>,
166 _instructions_count: u64,
167 pub print_log: Vec<String>,
168 pub trace_log: Vec<String>,
170}
171
172impl BetVm {
173 pub fn new(code: Vec<u8>) -> Self {
174 Self {
175 registers: vec![Value::default(); 27],
176 register_stack: Vec::new(),
177 carry_reg: Trit::Tend,
178 stack: Vec::new(),
179 call_stack: Vec::new(),
180 tensors: Vec::new(),
181 agents: Vec::new(),
182 agent_types: std::collections::HashMap::new(),
183 pc: 0,
184 code,
185 node_id: "127.0.0.1".into(),
186 sparse_dropped: false,
187 remote: None,
188 open_files: Vec::new(),
189 bindings: std::collections::HashMap::new(),
190 _instructions_count: 0,
191 print_log: Vec::new(),
192 trace_log: Vec::new(),
193 }
194 }
195
196 pub fn take_output(&mut self) -> Vec<String> {
198 std::mem::take(&mut self.print_log)
199 }
200
201 pub fn take_trace_log(&mut self) -> Vec<String> {
203 std::mem::take(&mut self.trace_log)
204 }
205
206 pub fn set_node_id(&mut self, node_id: String) {
207 self.node_id = node_id;
208 }
209
210 pub fn set_remote(&mut self, transport: Arc<dyn RemoteTransport>) {
211 self.remote = Some(transport);
212 }
213
214 pub fn register_agent_type(&mut self, type_id: u16, handler_addr: usize) {
215 self.agent_types.insert(type_id, handler_addr);
216 }
217
218 pub fn peek_stack(&self) -> Option<Value> {
219 self.stack.last().cloned()
220 }
221
222 pub fn get_registers(&self) -> Vec<Value> {
223 self.registers.clone()
224 }
225
226 pub fn get_register(&self, reg: u8) -> Value {
227 self.registers.get(reg as usize).cloned().unwrap_or_default()
228 }
229
230 pub fn node_id(&self) -> &str {
231 &self.node_id
232 }
233
234 pub fn run(&mut self) -> Result<(), VmError> {
235 loop {
236 if self.pc >= self.code.len() { break; }
237 self._instructions_count += 1;
238 if self._instructions_count > MAX_STEPS {
239 return Err(VmError::StepLimitExceeded);
240 }
241 let opcode = self.code[self.pc];
242 self.pc += 1;
243
244 match opcode {
245 0x01 => { let packed = self.read_u8()?;
247 let trits = unpack_trits(&[packed], 1).map_err(VmError::BetFault)?;
248 self.stack.push(Value::Trit(trits[0]));
249 }
250 0x02 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
252 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
253 match (a.clone(), b.clone()) {
254 (Value::Trit(av), Value::Trit(bv)) => {
255 let (sum, carry) = av + bv;
256 self.stack.push(Value::Trit(sum));
257 self.carry_reg = carry;
258 }
259 (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av + bv)),
260 (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av + bv)),
261 (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av + bv as i64)),
262 (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 + bv)),
263 (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av + (bv as i8 as f64))),
264 (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) + bv)),
265 (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av + (bv as f64))),
266 (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) + bv)),
267 (Value::String(av), Value::String(bv)) => self.stack.push(Value::String(av + &bv)),
269 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
270 }
271 }
272 0x03 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
274 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
275 match (a.clone(), b.clone()) {
276 (Value::Trit(av), Value::Trit(bv)) => self.stack.push(Value::Trit(av * bv)),
277 (Value::Int(av), Value::Int(bv)) => self.stack.push(Value::Int(av * bv)),
278 (Value::Float(av), Value::Float(bv)) => self.stack.push(Value::Float(av * bv)),
279 (Value::Int(av), Value::Trit(bv)) => self.stack.push(Value::Int(av * bv as i64)),
280 (Value::Trit(av), Value::Int(bv)) => self.stack.push(Value::Int(av as i64 * bv)),
281 (Value::Float(av), Value::Trit(bv)) => self.stack.push(Value::Float(av * (bv as i8 as f64))),
282 (Value::Trit(av), Value::Float(bv)) => self.stack.push(Value::Float((av as i8 as f64) * bv)),
283 (Value::Float(av), Value::Int(bv)) => self.stack.push(Value::Float(av * (bv as f64))),
284 (Value::Int(av), Value::Float(bv)) => self.stack.push(Value::Float((av as f64) * bv)),
285 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
286 }
287 }
288 0x04 => { let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
290 match a.clone() {
291 Value::Trit(av) => self.stack.push(Value::Trit(-av)),
292 Value::Int(av) => self.stack.push(Value::Int(-av)),
293 Value::Float(av) => self.stack.push(Value::Float(-av)),
294 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", a) }),
295 }
296 }
297 0x05 => { let addr = self.read_u16()?;
299 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
300 let is_pos = match val {
301 Value::Trit(Trit::Affirm) => true,
302 Value::Int(v) => *v > 0,
303 Value::Float(f) => *f > 0.0,
304 _ => false,
305 };
306 if is_pos { self.pc = addr as usize; }
307 }
308 0x06 => { let addr = self.read_u16()?;
310 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
311 let is_zero = match val {
312 Value::Trit(Trit::Tend) => true,
313 Value::Int(v) => *v == 0,
314 Value::Float(f) => *f == 0.0,
315 _ => false,
316 };
317 if is_zero { self.pc = addr as usize; }
318 }
319 0x07 => { let addr = self.read_u16()?;
321 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
322 let is_neg = match val {
323 Value::Trit(Trit::Reject) => true,
324 Value::Int(v) => *v < 0,
325 Value::Float(f) => *f < 0.0,
326 _ => false,
327 };
328 if is_neg { self.pc = addr as usize; }
329 }
330 0x08 => { let reg = self.read_u8()? as usize;
332 let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
333 self.bindings.remove(®);
334 if reg >= self.registers.len() { self.registers.resize(reg + 1, Value::default()); }
335 self.registers[reg] = val;
336 }
337 0x09 => { let reg = self.read_u8()? as usize;
339 let val = self.bindings.get(®).cloned().unwrap_or_else(|| {
340 if reg >= self.registers.len() { self.registers.resize(reg + 1, Value::default()); }
341 self.registers[reg].clone()
342 });
343 self.stack.push(val);
344 }
345 0x0a => { let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
347 self.stack.push(val.clone());
348 }
349 0x0b => { let addr = self.read_u16()?;
351 self.pc = addr as usize;
352 }
353 0x0c => { self.stack.pop().ok_or(VmError::StackUnderflow)?;
355 }
356 0x0e => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
358 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
359
360 let a = match a_val {
361 Value::Trit(t) => t,
362 Value::Int(v) if v == 1 => Trit::Affirm,
363 Value::Int(v) if v == 0 => Trit::Tend,
364 Value::Int(v) if v == -1 => Trit::Reject,
365 _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", a_val) }),
366 };
367 let b = match b_val {
368 Value::Trit(t) => t,
369 Value::Int(v) if v == 1 => Trit::Affirm,
370 Value::Int(v) if v == 0 => Trit::Tend,
371 Value::Int(v) if v == -1 => Trit::Reject,
372 _ => return Err(VmError::TypeMismatch { expected: "Trit or Int(-1..1)".into(), found: format!("{:?}", b_val) }),
373 };
374
375 let result = match (a, b) {
376 (Trit::Affirm, Trit::Affirm) => Trit::Affirm,
377 (Trit::Reject, Trit::Reject) => Trit::Reject,
378 (Trit::Tend, x) => x,
379 (x, Trit::Tend) => x,
380 _ => Trit::Tend,
381 };
382 self.stack.push(Value::Trit(result));
383 }
384 0x0f => { let rows = self.read_u32()? as usize;
386 let cols = self.read_u32()? as usize;
387 let size = rows * cols;
388 let idx = self.tensors.len();
389 self.tensors.push(TensorInstance {
390 data: TensorData::Trit(vec![Trit::Tend; size]),
391 rows,
392 cols,
393 });
394 self.stack.push(Value::TensorRef(idx));
395 }
396 0x3c => { let rows = self.read_u32()? as usize;
398 let cols = self.read_u32()? as usize;
399 let size = rows * cols;
400 let idx = self.tensors.len();
401 self.tensors.push(TensorInstance {
402 data: TensorData::Int(vec![0i64; size]),
403 rows,
404 cols,
405 });
406 self.stack.push(Value::TensorRef(idx));
407 }
408 0x3d => { let rows = self.read_u32()? as usize;
410 let cols = self.read_u32()? as usize;
411 let size = rows * cols;
412 let idx = self.tensors.len();
413 self.tensors.push(TensorInstance {
414 data: TensorData::Float(vec![0.0f64; size]),
415 rows,
416 cols,
417 });
418 self.stack.push(Value::TensorRef(idx));
419 }
420 0x10 => { if self.call_stack.len() >= MAX_CALL_DEPTH {
422 return Err(VmError::CallStackOverflow);
423 }
424 let addr = self.read_u16()? as usize;
425 self.register_stack.push(self.registers.clone());
426 self.call_stack.push(self.pc);
427 self.pc = addr;
428 }
429 0x11 => { if let Some(prev) = self.register_stack.pop() {
431 self.registers = prev;
432 }
433 match self.call_stack.pop() {
434 Some(ret) => self.pc = ret,
435 None => return Ok(()),
436 }
437 }
438 0x14 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
440 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
441 match (a.clone(), b.clone()) {
442 (Value::Int(x), Value::Int(y)) => {
443 let r = if x < y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
444 self.stack.push(Value::Trit(r));
445 }
446 (Value::Float(x), Value::Float(y)) => {
447 let r = if x < y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
448 self.stack.push(Value::Trit(r));
449 }
450 (Value::Int(x), Value::Trit(y)) => {
451 let bv = y as i64;
452 let r = if x < bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
453 self.stack.push(Value::Trit(r));
454 }
455 (Value::Trit(x), Value::Int(y)) => {
456 let av = x as i64;
457 let r = if av < y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
458 self.stack.push(Value::Trit(r));
459 }
460 (Value::Int(av), Value::Float(bv)) => {
461 let a_val = av as f64;
462 let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
463 self.stack.push(Value::Trit(r));
464 }
465 (Value::Float(av), Value::Int(bv)) => {
466 let b_val = bv as f64;
467 let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
468 self.stack.push(Value::Trit(r));
469 }
470 (Value::Trit(av), Value::Float(bv)) => {
471 let a_val = av as i8 as f64;
472 let r = if a_val < bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
473 self.stack.push(Value::Trit(r));
474 }
475 (Value::Float(av), Value::Trit(bv)) => {
476 let b_val = bv as i8 as f64;
477 let r = if av < b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
478 self.stack.push(Value::Trit(r));
479 }
480 (Value::Trit(x), Value::Trit(y)) => {
481 let av = x as i64;
482 let bv = y as i64;
483 let r = if av < bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
484 self.stack.push(Value::Trit(r));
485 }
486 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
487 }
488 }
489 0x15 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
491 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
492 match (a.clone(), b.clone()) {
493 (Value::Int(x), Value::Int(y)) => {
494 let r = if x > y { Trit::Affirm } else if x == y { Trit::Tend } else { Trit::Reject };
495 self.stack.push(Value::Trit(r));
496 }
497 (Value::Float(x), Value::Float(y)) => {
498 let r = if x > y { Trit::Affirm } else if (x - y).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
499 self.stack.push(Value::Trit(r));
500 }
501 (Value::Int(x), Value::Trit(y)) => {
502 let bv = y as i64;
503 let r = if x > bv { Trit::Affirm } else if x == bv { Trit::Tend } else { Trit::Reject };
504 self.stack.push(Value::Trit(r));
505 }
506 (Value::Trit(x), Value::Int(y)) => {
507 let av = x as i64;
508 let r = if av > y { Trit::Affirm } else if av == y { Trit::Tend } else { Trit::Reject };
509 self.stack.push(Value::Trit(r));
510 }
511 (Value::Int(av), Value::Float(bv)) => {
512 let a_val = av as f64;
513 let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
514 self.stack.push(Value::Trit(r));
515 }
516 (Value::Float(av), Value::Int(bv)) => {
517 let b_val = bv as f64;
518 let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
519 self.stack.push(Value::Trit(r));
520 }
521 (Value::Trit(av), Value::Float(bv)) => {
522 let a_val = av as i8 as f64;
523 let r = if a_val > bv { Trit::Affirm } else if (a_val - bv).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
524 self.stack.push(Value::Trit(r));
525 }
526 (Value::Float(av), Value::Trit(bv)) => {
527 let b_val = bv as i8 as f64;
528 let r = if av > b_val { Trit::Affirm } else if (av - b_val).abs() < f64::EPSILON { Trit::Tend } else { Trit::Reject };
529 self.stack.push(Value::Trit(r));
530 }
531 (Value::Trit(x), Value::Trit(y)) => {
532 let av = x as i64;
533 let bv = y as i64;
534 let r = if av > bv { Trit::Affirm } else if av == bv { Trit::Tend } else { Trit::Reject };
535 self.stack.push(Value::Trit(r));
536 }
537 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a, b)) }),
538 }
539 }
540 0x16 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
542 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
543 let is_eq = match (a.clone(), b.clone()) {
544 (Value::Int(av), Value::Trit(bv)) => av == bv as i64,
545 (Value::Trit(av), Value::Int(bv)) => av as i64 == bv,
546 (Value::Float(av), Value::Float(bv)) => (av - bv).abs() < f64::EPSILON,
547 (Value::Float(av), Value::Trit(bv)) => (av - (bv as i8 as f64)).abs() < f64::EPSILON,
548 (Value::Trit(av), Value::Float(bv)) => ((av as i8 as f64) - bv).abs() < f64::EPSILON,
549 (Value::Float(av), Value::Int(bv)) => (av - (bv as f64)).abs() < f64::EPSILON,
550 (Value::Int(av), Value::Float(bv)) => ((av as f64) - bv).abs() < f64::EPSILON,
551 _ => a == b,
552 };
553 let r = if is_eq { Trit::Affirm } else { Trit::Reject };
554 self.stack.push(Value::Trit(r));
555 }
556 0x17 => { let mut b = [0u8; 8];
558 for i in 0..8 { b[i] = self.read_u8()?; }
559 self.stack.push(Value::Int(i64::from_le_bytes(b)));
560 }
561 0x18 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
563 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
564 match (a.clone(), b.clone()) {
565 (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x + y)),
566 _ => return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", (a, b)) }),
567 }
568 }
569 0x19 => { let mut b = [0u8; 8];
571 for i in 0..8 { b[i] = self.read_u8()?; }
572 self.stack.push(Value::Float(f64::from_le_bytes(b)));
573 }
574 0x1e => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
576 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
577 match (a_val.clone(), b_val.clone()) {
578 (Value::Int(av), Value::Int(bv)) => {
579 if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
580 self.stack.push(Value::Int(av / bv));
581 }
582 (Value::Float(av), Value::Float(bv)) => {
583 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
584 self.stack.push(Value::Float(av / bv));
585 }
586 (Value::Int(av), Value::Trit(bv)) => {
587 let b = bv as i64;
588 if b == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
589 self.stack.push(Value::Int(av / b));
590 }
591 (Value::Trit(av), Value::Int(bv)) => {
592 if bv == 0 { return Err(VmError::RuntimeError("Division by zero".into())); }
593 self.stack.push(Value::Int(av as i64 / bv));
594 }
595 (Value::Float(av), Value::Trit(bv)) => {
596 let b = bv as i8 as f64;
597 if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
598 self.stack.push(Value::Float(av / b));
599 }
600 (Value::Trit(av), Value::Float(bv)) => {
601 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
602 self.stack.push(Value::Float(av as i8 as f64 / bv));
603 }
604 (Value::Float(av), Value::Int(bv)) => {
605 let b = bv as f64;
606 if b == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
607 self.stack.push(Value::Float(av / b));
608 }
609 (Value::Int(av), Value::Float(bv)) => {
610 if bv == 0.0 { return Err(VmError::RuntimeError("Division by zero".into())); }
611 self.stack.push(Value::Float(av as f64 / bv));
612 }
613 _ => return Err(VmError::TypeMismatch { expected: "Numeric".into(), found: format!("{:?}", (a_val, b_val)) }),
614 }
615 }
616 0x1f => { let b_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
618 let a_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
619 match (a_val.clone(), b_val.clone()) {
620 (Value::Int(av), Value::Int(bv)) => {
621 if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
622 self.stack.push(Value::Int(av % bv));
623 }
624 (Value::Int(av), Value::Trit(bv)) => {
625 let b = bv as i64;
626 if b == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
627 self.stack.push(Value::Int(av % b));
628 }
629 (Value::Trit(av), Value::Int(bv)) => {
630 if bv == 0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
631 self.stack.push(Value::Int(av as i64 % bv));
632 }
633 (Value::Float(av), Value::Float(bv)) => {
634 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
635 self.stack.push(Value::Float(av % bv));
636 }
637 (Value::Float(av), Value::Trit(bv)) => {
638 let b = bv as i8 as f64;
639 if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
640 self.stack.push(Value::Float(av % b));
641 }
642 (Value::Trit(av), Value::Float(bv)) => {
643 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
644 self.stack.push(Value::Float(av as i8 as f64 % bv));
645 }
646 (Value::Float(av), Value::Int(bv)) => {
647 let b = bv as f64;
648 if b == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
649 self.stack.push(Value::Float(av % b));
650 }
651 (Value::Int(av), Value::Float(bv)) => {
652 if bv == 0.0 { return Err(VmError::RuntimeError("Modulo by zero".into())); }
653 self.stack.push(Value::Float(av as f64 % bv));
654 }
655 _ => return Err(VmError::TypeMismatch { expected: "Int or Trit".into(), found: format!("{:?}", (a_val, b_val)) }),
656 }
657 }
658 0x20 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
660 let line = match &val {
661 Value::Trit(t) => format!("{}", t),
662 Value::Int(i) => format!("{}", i),
663 Value::Float(f) => format!("{}", f),
664 Value::String(s) => s.clone(),
665 Value::TensorRef(idx) => format!("TensorRef({})", idx),
666 Value::TensorView { tensor_id, offset, length, .. } => format!("TensorView({}[{}..{}])", tensor_id, offset, offset + length),
667 Value::AgentRef(idx, addr) => format!("AgentRef({}, {:?})", idx, addr),
668 Value::Struct(fields) => format!("Struct({:?})", fields),
669 };
670 println!("{}", line);
671 self.print_log.push(line);
672 }
673 0x21 => { let len = self.read_u16()? as usize;
675 let mut bytes = vec![0u8; len];
676 for i in 0..len { bytes[i] = self.read_u8()?; }
677 let s = String::from_utf8(bytes).map_err(|_| VmError::RuntimeError("Invalid UTF-8 string".into()))?;
678 self.stack.push(Value::String(s));
679 }
680 0x22 => { let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
682 let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
683 let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
684 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) }) };
685 if let Value::String(s) = &rf {
687 let chars: Vec<char> = s.chars().collect();
688 if r < 0 || r as usize >= chars.len() {
689 return Err(VmError::RuntimeError(format!(
690 "[BET-007] String index {} out of bounds (len={}). Use len(s) to guard.",
691 r, chars.len()
692 )));
693 }
694 self.stack.push(Value::String(chars[r as usize].to_string()));
695 } else {
696 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) }) };
697 let (idx, pos) = self.get_pos(&rf, r, c)?;
698 let tensor = &self.tensors[idx];
699 let data_len = tensor.data.len();
700 if pos >= data_len {
701 return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: data_len });
702 }
703 let pushed = match &tensor.data {
704 TensorData::Trit(v) => Value::Trit(v[pos]),
705 TensorData::PackedTrit(v, _) => {
706 let byte_idx = pos / 5;
707 let trit_idx = pos % 5;
708 let trits = crate::trit::unpack_5_trits(v[byte_idx]);
709 Value::Trit(trits[trit_idx])
710 }
711 TensorData::Float(v) => Value::Float(v[pos]),
712 TensorData::Int(v) => Value::Int(v[pos]),
713 };
714 self.stack.push(pushed);
715 }
716 }
717 0x23 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
719 let col = self.stack.pop().ok_or(VmError::StackUnderflow)?;
720 let row = self.stack.pop().ok_or(VmError::StackUnderflow)?;
721 let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
722 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) }) };
723 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) }) };
724
725 let (idx, pos) = self.get_pos(&rf, r, c)?;
726 let tensor = &mut self.tensors[idx];
727 let data_len = tensor.data.len();
728 if pos >= data_len { return Err(VmError::TensorIndexOutOfBounds { tensor_id: idx, index: pos, size: data_len }); }
729 match (&mut tensor.data, val.clone()) {
730 (TensorData::Trit(v), Value::Trit(t)) => v[pos] = t,
731 (TensorData::Trit(v), Value::Int(i)) => v[pos] = if i > 0 { Trit::Affirm } else if i < 0 { Trit::Reject } else { Trit::Tend },
732 (TensorData::PackedTrit(v, _), val_v) => {
733 let byte_idx = pos / 5;
734 let trit_idx = pos % 5;
735 let mut trits = crate::trit::unpack_5_trits(v[byte_idx]);
736 trits[trit_idx] = match val_v {
737 Value::Trit(t) => t,
738 Value::Int(i) => if i > 0 { Trit::Affirm } else if i < 0 { Trit::Reject } else { Trit::Tend },
739 _ => return Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", val_v) }),
740 };
741 v[byte_idx] = crate::trit::pack_5_trits(trits);
742 }
743 (TensorData::Float(v), Value::Float(f)) => v[pos] = f,
744 (TensorData::Float(v), Value::Int(i)) => v[pos] = i as f64,
745 (TensorData::Int(v), Value::Int(i)) => v[pos] = i,
746 (TensorData::Int(v), Value::Float(f)) => v[pos] = f as i64,
747 (TensorData::Int(v), Value::Trit(t)) => v[pos] = t as i64,
748 _ => return Err(VmError::TypeMismatch { expected: "compatible value for tensor type".into(), found: format!("{:?}", val) }),
749 }
750 }
751 0x24 => { let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
753 match rf {
754 Value::TensorRef(idx) => {
755 if idx >= self.tensors.len() { return Err(VmError::TensorNotAllocated(idx)); }
756 let tensor = &self.tensors[idx];
757 self.stack.push(Value::Int(tensor.rows as i64));
758 self.stack.push(Value::Int(tensor.cols as i64));
759 }
760 Value::TensorView { length, .. } => {
761 self.stack.push(Value::Int(length as i64));
762 self.stack.push(Value::Int(1));
763 }
764 Value::String(s) => {
765 let n = s.chars().count() as i64;
766 self.stack.push(Value::Int(n));
767 self.stack.push(Value::Int(1));
768 }
769 _ => return Err(VmError::TypeMismatch { expected: "TensorRef, TensorView, or String".into(), found: format!("{:?}", rf) }),
770 }
771 }
772 0x30 => { let type_id = self.read_u16()?;
774 if let Some(&handler_addr) = self.agent_types.get(&type_id) {
775 let id = self.agents.len();
776 self.agents.push(AgentInstance { handler_addr, mailbox: Default::default() });
777 self.stack.push(Value::AgentRef(id, None));
778 } else {
779 return Err(VmError::AgentTypeNotRegistered(type_id));
780 }
781 }
782 0x31 => { let msg = self.stack.pop().ok_or(VmError::StackUnderflow)?;
784 let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
785 if let Value::AgentRef(id, None) = target {
786 if id < self.agents.len() {
787 self.agents[id].mailbox.push_back(msg);
788 } else {
789 return Err(VmError::AgentIdInvalid(id));
790 }
791 } else {
792 return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
793 }
794 }
795 0x32 => { let target = self.stack.pop().ok_or(VmError::StackUnderflow)?;
797 if let Value::AgentRef(id, None) = target {
798 if id < self.agents.len() {
799 if self.call_stack.len() >= MAX_CALL_DEPTH {
800 return Err(VmError::CallStackOverflow);
801 }
802 let handler_addr = self.agents[id].handler_addr;
803 let msg = self.agents[id].mailbox.pop_front().unwrap_or(Value::default());
804 self.register_stack.push(self.registers.clone());
806 self.call_stack.push(self.pc);
807 self.pc = handler_addr;
808 self.stack.push(msg);
809 } else {
810 return Err(VmError::AgentIdInvalid(id));
811 }
812 } else {
813 return Err(VmError::TypeMismatch { expected: "Local AgentRef".into(), found: format!("{:?}", target) });
814 }
815 }
816 0x25 => { let mut b = [0u8; 8];
818 for i in 0..8 { b[i] = self.read_u8()?; }
819 let target_val = i64::from_le_bytes(b);
820 let addr = self.read_u16()?;
821 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
822 let is_eq = match val {
823 Value::Int(v) => *v == target_val,
824 Value::Trit(t) => (*t as i8) as i64 == target_val,
825 _ => false,
826 };
827 if is_eq { self.pc = addr as usize; }
828 }
829 0x26 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
831 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
832 let is_le = match (a.clone(), b.clone()) {
833 (Value::Int(x), Value::Int(y)) => x <= y,
834 (Value::Float(x), Value::Float(y)) => x <= y || (x - y).abs() < f64::EPSILON,
835 (Value::Int(x), Value::Trit(y)) => x <= y as i64,
836 (Value::Trit(x), Value::Int(y)) => (x as i64) <= y,
837 (Value::Trit(x), Value::Trit(y)) => (x as i64) <= (y as i64),
838 _ => false,
839 };
840 self.stack.push(Value::Trit(if is_le { Trit::Affirm } else { Trit::Reject }));
841 }
842 0x27 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
844 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
845 let is_ge = match (a.clone(), b.clone()) {
846 (Value::Int(x), Value::Int(y)) => x >= y,
847 (Value::Float(x), Value::Float(y)) => x >= y || (x - y).abs() < f64::EPSILON,
848 (Value::Int(x), Value::Trit(y)) => x >= y as i64,
849 (Value::Trit(x), Value::Int(y)) => (x as i64) >= y,
850 (Value::Trit(x), Value::Trit(y)) => (x as i64) >= (y as i64),
851 _ => false,
852 };
853 self.stack.push(Value::Trit(if is_ge { Trit::Affirm } else { Trit::Reject }));
854 }
855 0x28 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
857 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
858 let to_trit = |v: Value| -> Result<Trit, VmError> {
859 match v {
860 Value::Trit(t) => Ok(t),
861 Value::Int(n) if n > 0 => Ok(Trit::Affirm),
862 Value::Int(0) => Ok(Trit::Tend),
863 Value::Int(_) => Ok(Trit::Reject),
864 other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
865 }
866 };
867 let ta = to_trit(a)?;
868 let tb = to_trit(b)?;
869 let result = if (ta as i8) <= (tb as i8) { ta } else { tb };
870 self.stack.push(Value::Trit(result));
871 }
872 0x29 => { let b = self.stack.pop().ok_or(VmError::StackUnderflow)?;
874 let a = self.stack.pop().ok_or(VmError::StackUnderflow)?;
875 let to_trit = |v: Value| -> Result<Trit, VmError> {
876 match v {
877 Value::Trit(t) => Ok(t),
878 Value::Int(n) if n > 0 => Ok(Trit::Affirm),
879 Value::Int(0) => Ok(Trit::Tend),
880 Value::Int(_) => Ok(Trit::Reject),
881 other => Err(VmError::TypeMismatch { expected: "Trit or Int".into(), found: format!("{:?}", other) }),
882 }
883 };
884 let ta = to_trit(a)?;
885 let tb = to_trit(b)?;
886 let result = if (ta as i8) >= (tb as i8) { ta } else { tb };
887 self.stack.push(Value::Trit(result));
888 }
889 0x2a => { let mut fb = [0u8; 8];
895 for i in 0..8 { fb[i] = self.read_u8()?; }
896 let target_f = f64::from_le_bytes(fb);
897 let addr = self.read_u16()?;
898 let val = self.stack.last().ok_or(VmError::StackUnderflow)?;
899 if let Value::Float(f) = val {
900 if (f - target_f).abs() < 1e-9 {
901 self.pc = addr as usize;
902 }
903 }
904 }
905 0x33 => { let mode = self.stack.pop().ok_or(VmError::StackUnderflow)?;
907 let path = self.stack.pop().ok_or(VmError::StackUnderflow)?;
908 if let (Value::String(p), Value::Int(m)) = (path, mode) {
909 use std::fs::OpenOptions;
910 let mut options = OpenOptions::new();
911 match m {
912 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}"))),
916 }
917 let file = options.open(&p).map_err(|e| VmError::FileOpenError(e.to_string()))?;
918 let handle = self.open_files.len();
919 self.open_files.push(Some(file));
920 self.stack.push(Value::Int(handle as i64));
921 } else {
922 return Err(VmError::TypeMismatch { expected: "String, Int".into(), found: "Unknown".into() });
923 }
924 }
925 0x34 => { let handle_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
927 if let Value::Int(h) = handle_val {
928 let h = h as usize;
929 if h >= self.open_files.len() || self.open_files[h].is_none() {
930 return Err(VmError::FileNotOpen(h));
931 }
932 let file = self.open_files[h].as_mut().unwrap();
933 let mut buf = [0u8; 1];
934 use std::io::Read;
935 match file.read_exact(&mut buf) {
936 Ok(_) => {
937 let t = match buf[0] {
938 b'+' | b'1' => Trit::Affirm,
939 b'-' => Trit::Reject,
940 _ => Trit::Tend,
941 };
942 self.stack.push(Value::Trit(t));
943 }
944 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
945 self.stack.push(Value::Trit(Trit::Tend)); }
947 Err(e) => return Err(VmError::FileReadError(e.to_string())),
948 }
949 } else {
950 return Err(VmError::TypeMismatch { expected: "Int".into(), found: format!("{:?}", handle_val) });
951 }
952 }
953 0x35 => { let t_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
955 let h_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
956 if let (Value::Int(h), Value::Trit(t)) = (h_val, t_val) {
957 let h = h as usize;
958 if h >= self.open_files.len() || self.open_files[h].is_none() {
959 return Err(VmError::FileNotOpen(h));
960 }
961 let file = self.open_files[h].as_mut().unwrap();
962 let out = match t {
963 Trit::Affirm => b'+',
964 Trit::Reject => b'-',
965 Trit::Tend => b'0',
966 };
967 use std::io::Write;
968 file.write_all(&[out]).map_err(|e| VmError::FileWriteError(e.to_string()))?;
969 } else {
970 return Err(VmError::TypeMismatch { expected: "Int, Trit".into(), found: "Unknown".into() });
971 }
972 }
973 0x36 => { self.stack.push(Value::String(self.node_id.clone()));
978 }
979 0x37 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
981 let is_affirm = match val {
982 Value::Trit(Trit::Affirm) => true,
983 Value::Int(1) => true,
984 _ => false,
985 };
986 if !is_affirm {
987 return Err(VmError::AssertionFailed);
988 }
989 }
990 0x38 => { let bc_a_rows = self.read_u8()? as usize;
997 let bc_a_cols = self.read_u8()? as usize;
998 let bc_b_cols = self.read_u8()? as usize;
999 let b_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1000 let a_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1001
1002 if let (Value::TensorRef(a_idx), Value::TensorRef(b_idx)) = (a_ref, b_ref) {
1003 let (a_rows, a_cols, b_cols, a_data, b_data) = {
1004 let a = self.tensors.get(a_idx).ok_or(VmError::TensorNotAllocated(a_idx))?;
1005 let b = self.tensors.get(b_idx).ok_or(VmError::TensorNotAllocated(b_idx))?;
1006
1007 let a_data = match &a.data {
1008 TensorData::Trit(v) => v,
1009 _ => return Err(VmError::TypeMismatch { expected: "TritTensor".into(), found: "Other".into() }),
1010 };
1011 let b_data = match &b.data {
1012 TensorData::Trit(v) => v,
1013 _ => return Err(VmError::TypeMismatch { expected: "TritTensor".into(), found: "Other".into() }),
1014 };
1015 let a_rows = if bc_a_rows > 0 { bc_a_rows } else { a.rows };
1017 let a_cols = if bc_a_cols > 0 { bc_a_cols } else { a.cols };
1018 let b_cols = if bc_b_cols > 0 { bc_b_cols } else { b.cols };
1019 (a_rows, a_cols, b_cols, a_data.clone(), b_data.clone())
1020 };
1021
1022 let mut result = vec![Trit::Tend; a_rows * b_cols];
1023 let mut skipped = false;
1024
1025 for i in 0..a_rows {
1026 for k in 0..a_cols {
1027 let a_val = a_data[i * a_cols + k];
1028 if a_val == Trit::Tend {
1029 skipped = true;
1030 continue;
1031 }
1032 for j in 0..b_cols {
1033 let b_val = b_data[k * b_cols + j];
1034 if b_val == Trit::Tend { continue; }
1035 let prod = a_val * b_val;
1036 let (sum, _) = result[i * b_cols + j] + prod;
1037 result[i * b_cols + j] = sum;
1038 }
1039 }
1040 }
1041
1042 if skipped { self.sparse_dropped = true; }
1043 let res_idx = self.tensors.len();
1044 self.tensors.push(TensorInstance {
1045 data: TensorData::Trit(result),
1046 rows: a_rows,
1047 cols: b_cols,
1048 });
1049 self.stack.push(Value::TensorRef(res_idx));
1050 } else {
1051 return Err(VmError::TypeMismatch { expected: "TensorRef, TensorRef".into(), found: "Unknown".into() });
1052 }
1053 }
1054 0x40 => { let num_fields = self.read_u8()? as usize;
1056 let mut fields = std::collections::HashMap::new();
1057 for _ in 0..num_fields {
1058 let name_len = self.read_u8()? as usize;
1059 let mut name_bytes = vec![0u8; name_len];
1060 for i in 0..name_len { name_bytes[i] = self.read_u8()?; }
1061 let name = String::from_utf8(name_bytes).unwrap();
1062 let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1063 fields.insert(name, val);
1064 }
1065 self.stack.push(Value::Struct(fields));
1066 }
1067 0x41 => { let name_len = self.read_u8()? as usize;
1069 let mut name_bytes = vec![0u8; name_len];
1070 for i in 0..name_len { name_bytes[i] = self.read_u8()?; }
1071 let name = String::from_utf8(name_bytes).unwrap();
1072 let obj = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1073 if let Value::Struct(fields) = obj {
1074 let val = fields.get(&name).cloned().unwrap_or_default();
1075 self.stack.push(val);
1076 } else {
1077 return Err(VmError::TypeMismatch { expected: "Struct".into(), found: format!("{:?}", obj) });
1078 }
1079 }
1080 0x42 => { let reg = self.read_u8()? as usize;
1082 let view_val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1083 if let Value::TensorView { .. } = view_val {
1084 self.bindings.insert(reg, view_val);
1085 } else {
1086 return Err(VmError::TypeMismatch { expected: "TensorView".into(), found: format!("{:?}", view_val) });
1087 }
1088 }
1089 0x55 => { let stride = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1091 let length = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1092 let offset = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1093 let rf = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1094
1095 if let (Value::Int(o), Value::Int(l), Value::Int(s)) = (&offset, &length, &stride) {
1096 match rf {
1097 Value::TensorRef(id) => {
1098 self.stack.push(Value::TensorView {
1099 tensor_id: id,
1100 offset: *o as usize,
1101 length: *l as usize,
1102 stride: *s as usize,
1103 });
1104 }
1105 Value::TensorView { tensor_id, offset: v_off, stride: v_stride, .. } => {
1106 self.stack.push(Value::TensorView {
1109 tensor_id,
1110 offset: v_off + (*o as usize * v_stride),
1111 length: *l as usize,
1112 stride: v_stride * (*s as usize),
1113 });
1114 }
1115 _ => return Err(VmError::TypeMismatch { expected: "TensorRef or TensorView".into(), found: format!("{:?}", rf) }),
1116 }
1117 } else {
1118 return Err(VmError::TypeMismatch { expected: "Int, Int, Int".into(), found: format!("{:?}, {:?}, {:?}", offset, length, stride) });
1119 }
1120 }
1121 0x50 => { let mut trits = [Trit::Tend; 5];
1123 for i in (0..5).rev() {
1124 let t = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1125 trits[i] = match t {
1126 Value::Trit(tv) => tv,
1127 _ => return Err(VmError::TypeMismatch { expected: "Trit".into(), found: format!("{:?}", t) }),
1128 };
1129 }
1130 let packed = crate::trit::pack_5_trits(trits);
1131 self.stack.push(Value::Int(packed as i64));
1132 }
1133 0x51 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1135 if let Value::Int(packed) = val {
1136 let trits = crate::trit::unpack_5_trits(packed as u8);
1137 for t in trits {
1138 self.stack.push(Value::Trit(t));
1139 }
1140 } else {
1141 return Err(VmError::TypeMismatch { expected: "Int (packed byte)".into(), found: format!("{:?}", val) });
1142 }
1143 }
1144 0x56 => { let rows = self.read_u32()? as usize;
1146 let cols = self.read_u32()? as usize;
1147 let size = rows * cols;
1148 let num_bytes = (size + 4) / 5;
1149 let idx = self.tensors.len();
1150 self.tensors.push(TensorInstance {
1151 data: TensorData::PackedTrit(vec![0x00; num_bytes], size), rows,
1153 cols,
1154 });
1155 self.stack.push(Value::TensorRef(idx));
1156 }
1157 0x57 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1159 let int_val = match val {
1160 Value::Int(i) => i,
1161 Value::Trit(t) => t as i64,
1162 Value::Float(f) => f as i64,
1163 _ => return Err(VmError::TypeMismatch { expected: "numeric (int/trit/float)".into(), found: format!("{:?}", val) }),
1164 };
1165 self.stack.push(Value::Int(int_val));
1166 }
1167 0x58 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1169 let float_val = match val {
1170 Value::Float(f) => f,
1171 Value::Int(i) => i as f64,
1172 Value::Trit(t) => t as i64 as f64,
1173 _ => return Err(VmError::TypeMismatch { expected: "numeric (int/trit/float)".into(), found: format!("{:?}", val) }),
1174 };
1175 self.stack.push(Value::Float(float_val));
1176 }
1177 0x52 => { let b_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1179 let a_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1180 if let (Value::TensorRef(a_idx), Value::TensorRef(b_idx)) = (a_ref, b_ref) {
1181 let res_idx = self.tensors.len();
1182 let (rows, cols, data) = {
1183 let a = self.tensors.get(a_idx).ok_or(VmError::TensorNotAllocated(a_idx))?;
1184 let b = self.tensors.get(b_idx).ok_or(VmError::TensorNotAllocated(b_idx))?;
1185 if a.rows != b.rows || a.cols != b.cols {
1186 return Err(VmError::RuntimeError("Tensor dimension mismatch in TV_ADD".into()));
1187 }
1188 match (&a.data, &b.data) {
1189 (TensorData::PackedTrit(av, alen), TensorData::PackedTrit(bv, _)) => {
1190 let mut res_v = vec![0u8; av.len()];
1191 for i in 0..av.len() {
1192 res_v[i] = crate::trit::packed_add(av[i], bv[i]);
1193 }
1194 (a.rows, a.cols, TensorData::PackedTrit(res_v, *alen))
1195 }
1196 _ => return Err(VmError::TypeMismatch { expected: "PackedTrit tensors".into(), found: "Other".into() }),
1197 }
1198 };
1199 self.tensors.push(TensorInstance { data, rows, cols });
1200 self.stack.push(Value::TensorRef(res_idx));
1201 } else {
1202 return Err(VmError::TypeMismatch { expected: "TensorRef, TensorRef".into(), found: "Unknown".into() });
1203 }
1204 }
1205 0x53 => { let a_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1207 if let Value::TensorRef(idx) = a_ref {
1208 let res_idx = self.tensors.len();
1209 let (rows, cols, data) = {
1210 let a = self.tensors.get(idx).ok_or(VmError::TensorNotAllocated(idx))?;
1211 match &a.data {
1212 TensorData::PackedTrit(v, len) => {
1213 let mut res_v = vec![0u8; v.len()];
1214 for i in 0..v.len() {
1215 res_v[i] = crate::trit::packed_neg(v[i]);
1216 }
1217 (a.rows, a.cols, TensorData::PackedTrit(res_v, *len))
1218 }
1219 _ => return Err(VmError::TypeMismatch { expected: "PackedTrit tensor".into(), found: "Other".into() }),
1220 }
1221 };
1222 self.tensors.push(TensorInstance { data, rows, cols });
1223 self.stack.push(Value::TensorRef(res_idx));
1224 } else {
1225 return Err(VmError::TypeMismatch { expected: "TensorRef".into(), found: format!("{:?}", a_ref) });
1226 }
1227 }
1228 0x54 => { let b_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1230 let a_ref = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1231 if let (Value::TensorRef(a_idx), Value::TensorRef(b_idx)) = (a_ref, b_ref) {
1232 let res_idx = self.tensors.len();
1233 let (rows, cols, data) = {
1234 let a = self.tensors.get(a_idx).ok_or(VmError::TensorNotAllocated(a_idx))?;
1235 let b = self.tensors.get(b_idx).ok_or(VmError::TensorNotAllocated(b_idx))?;
1236 if a.rows != b.rows || a.cols != b.cols {
1237 return Err(VmError::RuntimeError("Tensor dimension mismatch in TV_CON".into()));
1238 }
1239 match (&a.data, &b.data) {
1240 (TensorData::PackedTrit(av, alen), TensorData::PackedTrit(bv, _)) => {
1241 let mut res_v = vec![0u8; av.len()];
1242 for i in 0..av.len() {
1243 res_v[i] = crate::trit::packed_consensus(av[i], bv[i]);
1244 }
1245 (a.rows, a.cols, TensorData::PackedTrit(res_v, *alen))
1246 }
1247 _ => return Err(VmError::TypeMismatch { expected: "PackedTrit tensors".into(), found: "Other".into() }),
1248 }
1249 };
1250 self.tensors.push(TensorInstance { data, rows, cols });
1251 self.stack.push(Value::TensorRef(res_idx));
1252 } else {
1253 return Err(VmError::TypeMismatch { expected: "TensorRef, TensorRef".into(), found: "Unknown".into() });
1254 }
1255 }
1256 0x60 => { let val = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1262 let label = self.stack.pop().ok_or(VmError::StackUnderflow)?;
1263 let label_str = match label {
1264 Value::String(s) => s,
1265 other => format!("{:?}", other),
1266 };
1267 let val_str = match &val {
1268 Value::Trit(t) => format!("{:?}", t),
1269 Value::Int(i) => format!("{}", i),
1270 Value::Float(f) => format!("{}", f),
1271 Value::String(s) => s.clone(),
1272 other => format!("{:?}", other),
1273 };
1274 self.trace_log.push(format!("{}: {}", label_str, val_str));
1275 }
1276 0x00 => return Ok(()),
1277 _ => return Err(VmError::InvalidOpcode(opcode)),
1278 }
1279 }
1280 Ok(())
1281 }
1282
1283 fn read_u8(&mut self) -> Result<u8, VmError> {
1284 if self.pc >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
1285 let val = self.code[self.pc];
1286 self.pc += 1;
1287 Ok(val)
1288 }
1289
1290 fn read_u16(&mut self) -> Result<u16, VmError> {
1291 if self.pc + 1 >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
1292 let val = u16::from_le_bytes([self.code[self.pc], self.code[self.pc + 1]]);
1293 self.pc += 2;
1294 Ok(val)
1295 }
1296
1297 fn read_u32(&mut self) -> Result<u32, VmError> {
1298 if self.pc + 3 >= self.code.len() { return Err(VmError::PcOutOfBounds(self.pc)); }
1299 let val = u32::from_le_bytes([
1300 self.code[self.pc], self.code[self.pc + 1],
1301 self.code[self.pc + 2], self.code[self.pc + 3]
1302 ]);
1303 self.pc += 4;
1304 Ok(val)
1305 }
1306
1307 fn get_pos(&self, rf: &Value, row: i64, col: i64) -> Result<(usize, usize), VmError> {
1308 match rf {
1309 Value::TensorRef(idx) => {
1310 let tensor = self.tensors.get(*idx).ok_or(VmError::TensorNotAllocated(*idx))?;
1311 let pos = if tensor.cols > 1 && col >= 0 {
1312 row as usize * tensor.cols + col as usize
1313 } else {
1314 row as usize
1315 };
1316 Ok((*idx, pos))
1317 }
1318 Value::TensorView { tensor_id, offset, stride, .. } => {
1319 let pos = *offset + (row as usize * *stride);
1320 Ok((*tensor_id, pos))
1321 }
1322 _ => Err(VmError::TypeMismatch { expected: "TensorRef or TensorView".into(), found: format!("{:?}", rf) }),
1323 }
1324 }
1325}