1use crate::*;
2use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
3use std::collections::HashMap;
4use std::io::{Cursor, Read, Write};
5use std::panic::{catch_unwind, AssertUnwindSafe};
6use std::rc::Rc;
7use std::time::Duration;
8use std::time::Instant;
9
10pub struct Interpreter {
14 pub id: u64,
15 pub profile: bool,
16 pub max_steps: usize,
17 #[cfg(feature = "trace")]
18 pub trace: bool,
19 #[cfg(feature = "trace")]
20 pub trace_to_stdout: bool,
21 #[cfg(feature = "trace")]
22 pub trace_events: Ref<Vec<TraceEvent>>,
23 ip: usize, pub state: Ref<ProgramState>,
25 #[cfg(feature = "functions")]
26 pub stack: Vec<Frame>,
27 registers: Vec<Value>,
28 constants: Vec<Value>,
29 #[cfg(feature = "compiler")]
30 pub context: Option<CompileCtx>,
31 pub code: Vec<MechSourceCode>,
32 pub out: Value,
33 pub out_values: Ref<HashMap<u64, Value>>,
34 #[cfg(feature = "state_machines")]
35 pub user_state_machines: Ref<HashMap<u64, FsmImplementation>>,
36 pub sub_interpreters: Ref<HashMap<u64, Box<Interpreter>>>,
37}
38
39impl Clone for Interpreter {
40 fn clone(&self) -> Self {
41 Self {
42 id: self.id,
43 ip: self.ip,
44 profile: false,
45 max_steps: self.max_steps,
46 #[cfg(feature = "trace")]
47 trace: self.trace,
48 #[cfg(feature = "trace")]
49 trace_to_stdout: self.trace_to_stdout,
50 #[cfg(feature = "trace")]
51 trace_events: self.trace_events.clone(),
52 state: Ref::new(self.state.borrow().clone()),
53 #[cfg(feature = "functions")]
54 stack: self.stack.clone(),
55 registers: self.registers.clone(),
56 constants: self.constants.clone(),
57 #[cfg(feature = "compiler")]
58 context: None,
59 code: self.code.clone(),
60 out: self.out.clone(),
61 out_values: self.out_values.clone(),
62 #[cfg(feature = "state_machines")]
63 user_state_machines: self.user_state_machines.clone(),
64 sub_interpreters: self.sub_interpreters.clone(),
65 }
66 }
67}
68
69impl Interpreter {
70 pub fn new(id: u64) -> Self {
71 let mut state = ProgramState::new();
72 load_stdkinds(&mut state.kinds);
73 #[cfg(feature = "functions")]
74 load_stdlib(&mut state.functions.borrow_mut());
75 Self {
76 id,
77 ip: 0,
78 profile: false,
79 max_steps: 10_00000, #[cfg(feature = "trace")]
81 trace: false,
82 #[cfg(feature = "trace")]
83 trace_to_stdout: true,
84 #[cfg(feature = "trace")]
85 trace_events: Ref::new(Vec::new()),
86 state: Ref::new(state),
87 #[cfg(feature = "functions")]
88 stack: Vec::new(),
89 registers: Vec::new(),
90 constants: Vec::new(),
91 out: Value::Empty,
92 sub_interpreters: Ref::new(HashMap::new()),
93 out_values: Ref::new(HashMap::new()),
94 #[cfg(feature = "state_machines")]
95 user_state_machines: Ref::new(HashMap::new()),
96 code: Vec::new(),
97 #[cfg(feature = "compiler")]
98 context: None,
99 }
100 }
101
102 #[cfg(feature = "symbol_table")]
103 pub fn set_environment(&mut self, env: SymbolTableRef) {
104 self.state.borrow_mut().environment = Some(env);
105 }
106
107 #[cfg(feature = "functions")]
108 pub fn clear_plan(&mut self) {
109 self.state.borrow_mut().plan.borrow_mut().clear();
110 }
111
112 #[cfg(feature = "pretty_print")]
113 pub fn pretty_print(&self) -> String {
114 let mut output = String::new();
115 output.push_str(&format!("Interpreter ID: {}\n", self.id));
116 output.push_str(&self.state.borrow().pretty_print());
118
119 output.push_str("Registers:\n");
120 for (i, reg) in self.registers.iter().enumerate() {
121 output.push_str(&format!(" R{}: {}\n", i, reg));
122 }
123 output.push_str("Constants:\n");
124 for (i, constant) in self.constants.iter().enumerate() {
125 output.push_str(&format!(" C{}: {}\n", i, constant));
126 }
127 output.push_str(&format!("Output Value: {}\n", self.out));
128 output.push_str(&format!(
129 "Number of Sub-Interpreters: {}\n",
130 self.sub_interpreters.borrow().len()
131 ));
132 output.push_str("Output Values:\n");
133 for (key, value) in self.out_values.borrow().iter() {
134 output.push_str(&format!(" {}: {}\n", key, value));
135 }
136 output.push_str(&format!("Code Length: {}\n", self.code.len()));
137 #[cfg(feature = "compiler")]
138 if let Some(context) = &self.context {
139 output.push_str("Context: Exists\n");
140 } else {
141 output.push_str("Context: None\n");
142 }
143 output
144 }
145
146 pub fn clear(&mut self) {
147 let id = self.id;
148 *self = Interpreter::new(id);
149 }
150
151 pub fn set_trace_enabled(&mut self, enabled: bool) {
152 #[cfg(feature = "trace")]
153 {
154 self.trace = enabled;
155 }
156 #[cfg(not(feature = "trace"))]
157 {
158 let _ = enabled;
159 }
160 }
161
162 #[cfg(feature = "trace")]
163 pub fn set_trace_to_stdout(&mut self, enabled: bool) {
164 self.trace_to_stdout = enabled;
165 }
166
167 #[cfg(feature = "trace")]
168 pub fn clear_trace_events(&self) {
169 self.trace_events.borrow_mut().clear();
170 }
171
172 #[cfg(feature = "trace")]
173 pub fn trace_events(&self) -> Vec<TraceEvent> {
174 self.trace_events.borrow().clone()
175 }
176
177 #[cfg(feature = "trace")]
178 pub fn trace_events_to_json(&self) -> String {
179 let trace_events = self.trace_events.borrow();
180 trace_events_to_json(trace_events.as_slice())
181 }
182
183 #[cfg(feature = "trace")]
184 pub fn push_trace_line(&self, rendered: String) {
185 let (channel, label, message) = parse_trace_line(&rendered);
186 let mut trace_events = self.trace_events.borrow_mut();
187 let index = trace_events.len();
188 trace_events.push(TraceEvent {
189 index,
190 channel,
191 label,
192 message,
193 rendered,
194 });
195 }
196
197 #[cfg(all(feature = "trace", feature = "state_machines"))]
198 pub fn formatted_fsm_trace(&self) -> String {
199 format_fsm_trace_report(&self.trace_events())
200 }
201
202 #[cfg(feature = "pretty_print")]
203 pub fn pretty_print_symbols(&self) -> String {
204 let state_brrw = self.state.borrow();
205 let syms = state_brrw.symbol_table.borrow();
206 syms.pretty_print()
207 }
208
209 #[cfg(feature = "pretty_print")]
210 pub fn pretty_print_plan(&self) -> String {
211 let state_brrw = self.state.borrow();
212 let plan = state_brrw.plan.borrow();
213 let mut result = String::new();
214 for (i, step) in plan.iter().enumerate() {
215 result.push_str(&format!("Step {}:\n", i));
216 result.push_str(&format!("{}\n", step.to_string()));
217 }
218 result
219 }
220
221 #[cfg(feature = "functions")]
222 pub fn plan(&self) -> Plan {
223 self.state.borrow().plan.clone()
224 }
225
226 #[cfg(feature = "symbol_table")]
227 pub fn symbols(&self) -> SymbolTableRef {
228 self.state.borrow().symbol_table.clone()
229 }
230
231 pub fn dictionary(&self) -> Ref<Dictionary> {
232 self.state.borrow().dictionary.clone()
233 }
234
235 #[cfg(feature = "functions")]
236 pub fn functions(&self) -> FunctionsRef {
237 self.state.borrow().functions.clone()
238 }
239
240 #[cfg(feature = "functions")]
241 pub fn set_functions(&mut self, functions: FunctionsRef) {
242 self.state.borrow_mut().functions = functions;
243 }
244
245 #[cfg(feature = "functions")]
246 pub fn step(&mut self, step_id: usize, step_count: u64) -> MResult<Value> {
247 let state_brrw = self.state.borrow();
248 let mut plan_brrw = state_brrw.plan.borrow_mut(); if plan_brrw.is_empty() {
251 return Err(MechError::new(NoStepsInPlanError, None).with_compiler_loc());
252 }
253
254 let len = plan_brrw.len();
255
256 if step_id == 0 {
258 if self.profile {
259 let mut total_durations = vec![Duration::ZERO; len];
261 for _ in 0..step_count {
262 for (idx, fxn) in plan_brrw.iter_mut().enumerate() {
263 let start = Instant::now();
264 fxn.solve();
265 total_durations[idx] += start.elapsed();
266 }
267 }
268 if self.profile {
270 println!("\nStep timing summary and histogram:");
271 print_histogram(&total_durations);
272 }
273 return Ok(plan_brrw[len - 1].out().clone());
274 } else {
275 for _ in 0..step_count {
276 for (idx, fxn) in plan_brrw.iter_mut().enumerate() {
277 trace_println!(self, "{}", {
278 let fxn_header = fxn
279 .to_string()
280 .lines()
281 .next()
282 .unwrap_or("<unknown-step>")
283 .to_string();
284 format!("[trace][plan] step[{idx}] {fxn_header}")
285 });
286 fxn.solve();
287 trace_println!(self, "{}", {
288 let output = fxn.out().to_string();
289 let output = if output.chars().count() > 96 {
290 format!("{}…", output.chars().take(96).collect::<String>())
291 } else {
292 output
293 };
294 format!("[trace][plan] step[{idx}] out={output}")
295 });
296 }
297 }
298 return Ok(plan_brrw[len - 1].out().clone());
299 }
300 }
301
302 let idx = step_id as usize;
304 if idx > len {
305 return Err(MechError::new(
306 StepIndexOutOfBoundsError {
307 step_id,
308 plan_length: len,
309 },
310 None,
311 )
312 .with_compiler_loc());
313 }
314
315 let fxn = &mut plan_brrw[idx - 1];
316
317 let fxn_str = fxn.to_string();
318 if fxn_str.lines().count() > 30 {
319 let lines: Vec<&str> = fxn_str.lines().collect();
320 println!("Stepping function:");
321 for line in &lines[0..10] {
322 println!("{}", line);
323 }
324 println!("...");
325 for line in &lines[lines.len() - 10..] {
326 println!("{}", line);
327 }
328 } else {
329 println!("Stepping function:\n{}", fxn_str);
330 }
331
332 for _ in 0..step_count {
333 fxn.solve();
334 }
335
336 Ok(fxn.out().clone())
337 }
338
339 #[cfg(feature = "functions")]
340 pub fn interpret(&mut self, tree: &Program) -> MResult<Value> {
341 self.code.push(MechSourceCode::Tree(tree.clone()));
342 catch_unwind(AssertUnwindSafe(|| {
343 let result = program(tree, &self);
344 match self.state.borrow().plan.borrow().last() {
345 Some(last_step) => self.out = last_step.out().clone(),
346 None => self.out = Value::Empty,
347 }
348 result
349 }))
350 .map_err(|err| {
351 match err.downcast_ref::<&'static str>() {
352 Some(raw_msg) => {
353 if raw_msg.contains("Index out of bounds") {
354 MechError::new(IndexOutOfBoundsError, None).with_compiler_loc()
355 } else if raw_msg.contains("attempt to subtract with overflow") {
356 MechError::new(OverflowSubtractionError, None).with_compiler_loc()
357 } else {
358 MechError::new(
359 UnknownPanicError {
360 details: raw_msg.to_string(),
361 },
362 None,
363 )
364 .with_compiler_loc()
365 }
366 }
367 None => {
368 MechError::new(
369 UnknownPanicError {
370 details: "Non-string panic".to_string(),
371 },
372 None,
373 )
374 .with_compiler_loc()
375 }
376 }
377 })?
378 }
379
380
381 #[cfg(feature = "program")]
382 pub fn run_program(&mut self, program: &ParsedProgram) -> MResult<Value> {
383 self.ip = 0;
385 self.registers = vec![Value::Empty; program.header.reg_count as usize];
387 self.constants = vec![Value::Empty; program.const_entries.len()];
388 self.constants = program.decode_const_entries()?;
390 {
392 let mut state_brrw = self.state.borrow_mut();
393 let mut symbol_table = state_brrw.symbol_table.borrow_mut();
394 for (id, reg) in program.symbols.iter() {
395 let constant = self.constants[*reg as usize].clone();
396 self.out = constant.clone();
397 let mutable = program.mutable_symbols.contains(id);
398 symbol_table.insert(*id, constant, mutable);
399 }
400 }
401 {
403 let state_brrw = self.state.borrow();
404 let functions_table = state_brrw.functions.borrow();
405 while self.ip < program.instrs.len() {
406 let instr = &program.instrs[self.ip];
407 match instr {
408 DecodedInstr::ConstLoad { dst, const_id } => {
409 let value = self.constants[*const_id as usize].clone();
410 self.registers[*dst as usize] = value;
411 }
412 DecodedInstr::NullOp { fxn_id, dst } => {
413 match functions_table.functions.get(fxn_id) {
414 Some(fxn_factory) => {
415 let out = &self.registers[*dst as usize];
416 let fxn = fxn_factory(FunctionArgs::Nullary(out.clone()))?;
417 self.out = fxn.out().clone();
418 state_brrw.add_plan_step(fxn);
419 }
420 None => {
421 return Err(MechError::new(
422 UnknownNullaryFunctionError { fxn_id: *fxn_id },
423 None,
424 )
425 .with_compiler_loc());
426 }
427 }
428 }
429 DecodedInstr::UnOp { fxn_id, dst, src } => {
430 match functions_table.functions.get(fxn_id) {
431 Some(fxn_factory) => {
432 let src = &self.registers[*src as usize];
433 let out = &self.registers[*dst as usize];
434 let fxn =
435 fxn_factory(FunctionArgs::Unary(out.clone(), src.clone()))?;
436 self.out = fxn.out().clone();
437 state_brrw.add_plan_step(fxn);
438 }
439 None => {
440 return Err(MechError::new(
441 UnknownUnaryFunctionError { fxn_id: *fxn_id },
442 None,
443 )
444 .with_compiler_loc());
445 }
446 }
447 }
448 DecodedInstr::BinOp { fxn_id, dst, lhs, rhs } =>
449 match functions_table.functions.get(fxn_id) {
450 Some(fxn_factory) => {
451 let lhs = &self.registers[*lhs as usize];
452 let rhs = &self.registers[*rhs as usize];
453 let out = &self.registers[*dst as usize];
454 let fxn = fxn_factory(FunctionArgs::Binary(out.clone(),lhs.clone(),rhs.clone()))?;
455 self.out = fxn.out().clone();
456 state_brrw.add_plan_step(fxn);
457 }
458 None => {
459 return Err(MechError::new(
460 UnknownBinaryFunctionError { fxn_id: *fxn_id },
461 None,
462 )
463 .with_compiler_loc());
464 }
465 },
466 DecodedInstr::TernOp {fxn_id,dst,a,b,c} =>
467 match functions_table.functions.get(fxn_id) {
468 Some(fxn_factory) => {
469 let arg1 = &self.registers[*a as usize];
470 let arg2 = &self.registers[*b as usize];
471 let arg3 = &self.registers[*c as usize];
472 let out = &self.registers[*dst as usize];
473 let fxn = fxn_factory(FunctionArgs::Ternary(
474 out.clone(),
475 arg1.clone(),
476 arg2.clone(),
477 arg3.clone(),
478 ))?;
479 self.out = fxn.out().clone();
480 state_brrw.add_plan_step(fxn);
481 }
482 None => {
483 return Err(MechError::new(
484 UnknownTernaryFunctionError { fxn_id: *fxn_id },
485 None,
486 )
487 .with_compiler_loc());
488 }
489 },
490 DecodedInstr::QuadOp {fxn_id,dst,a,b,c,d } =>
491 match functions_table.functions.get(fxn_id) {
492 Some(fxn_factory) => {
493 let arg1 = &self.registers[*a as usize];
494 let arg2 = &self.registers[*b as usize];
495 let arg3 = &self.registers[*c as usize];
496 let arg4 = &self.registers[*d as usize];
497 let out = &self.registers[*dst as usize];
498 let fxn = fxn_factory(FunctionArgs::Quaternary(
499 out.clone(),
500 arg1.clone(),
501 arg2.clone(),
502 arg3.clone(),
503 arg4.clone(),
504 ))?;
505 self.out = fxn.out().clone();
506 state_brrw.add_plan_step(fxn);
507 }
508 None => {
509 return Err(MechError::new(
510 UnknownQuadFunctionError { fxn_id: *fxn_id },
511 None,
512 )
513 .with_compiler_loc());
514 }
515 },
516 DecodedInstr::VarArg { fxn_id, dst, args } => {
517 match functions_table.functions.get(fxn_id) {
518 Some(fxn_factory) => {
519 let arg_values: Vec<Value> = args
520 .iter()
521 .map(|r| self.registers[*r as usize].clone())
522 .collect();
523 let out = &self.registers[*dst as usize];
524 let fxn = fxn_factory(FunctionArgs::Variadic(out.clone(), arg_values))?;
525 self.out = fxn.out().clone();
526 state_brrw.add_plan_step(fxn);
527 }
528 None => {
529 return Err(MechError::new(
530 UnknownVariadicFunctionError { fxn_id: *fxn_id },
531 None,
532 )
533 .with_compiler_loc());
534 }
535 }
536 }
537 DecodedInstr::Ret { src } => {
538 todo!();
539 }
540 x => {
541 return Err(MechError::new(
542 UnknownInstructionError {
543 instr: format!("{:?}", x),
544 },
545 None,
546 )
547 .with_compiler_loc());
548 }
549 }
550 self.ip += 1;
551 }
552 }
553 {
555 let mut state_brrw = self.state.borrow_mut();
556 let mut symbol_table = state_brrw.symbol_table.borrow_mut();
557 for (id, name) in &program.dictionary {
558 symbol_table
559 .dictionary
560 .borrow_mut()
561 .insert(*id, name.clone());
562 state_brrw.dictionary.borrow_mut().insert(*id, name.clone());
563 }
564 }
565 Ok(self.out.clone())
566 }
567
568 #[cfg(feature = "compiler")]
569 pub fn compile(&mut self) -> MResult<Vec<u8>> {
570 let state_brrw = self.state.borrow();
571 let mut plan_brrw = state_brrw.plan.borrow_mut();
572 let mut ctx = CompileCtx::new();
573 for step in plan_brrw.iter() {
574 step.compile(&mut ctx)?;
575 }
576 let bytes = ctx.compile()?;
577 self.context = Some(ctx);
578 Ok(bytes)
579 }
580}
581
582#[derive(Debug, Clone)]
586pub struct UnknownInstructionError {
587 pub instr: String,
588}
589impl MechErrorKind for UnknownInstructionError {
590 fn name(&self) -> &str {
591 "UnknownInstruction"
592 }
593
594 fn message(&self) -> String {
595 format!("Unknown instruction: {}", self.instr)
596 }
597}
598
599#[derive(Debug, Clone)]
600pub struct UnknownVariadicFunctionError {
601 pub fxn_id: u64,
602}
603
604impl MechErrorKind for UnknownVariadicFunctionError {
605 fn name(&self) -> &str {
606 "UnknownVariadicFunction"
607 }
608 fn message(&self) -> String {
609 format!("Unknown variadic function ID: {}", self.fxn_id)
610 }
611}
612
613#[derive(Debug, Clone)]
614pub struct UnknownQuadFunctionError {
615 pub fxn_id: u64,
616}
617impl MechErrorKind for UnknownQuadFunctionError {
618 fn name(&self) -> &str {
619 "UnknownQuadFunction"
620 }
621 fn message(&self) -> String {
622 format!("Unknown quad function ID: {}", self.fxn_id)
623 }
624}
625
626#[derive(Debug, Clone)]
627pub struct UnknownTernaryFunctionError {
628 pub fxn_id: u64,
629}
630impl MechErrorKind for UnknownTernaryFunctionError {
631 fn name(&self) -> &str {
632 "UnknownTernaryFunction"
633 }
634 fn message(&self) -> String {
635 format!("Unknown ternary function ID: {}", self.fxn_id)
636 }
637}
638
639#[derive(Debug, Clone)]
640pub struct UnknownBinaryFunctionError {
641 pub fxn_id: u64,
642}
643impl MechErrorKind for UnknownBinaryFunctionError {
644 fn name(&self) -> &str {
645 "UnknownBinaryFunction"
646 }
647 fn message(&self) -> String {
648 format!("Unknown binary function ID: {}", self.fxn_id)
649 }
650}
651
652#[derive(Debug, Clone)]
653pub struct UnknownUnaryFunctionError {
654 pub fxn_id: u64,
655}
656impl MechErrorKind for UnknownUnaryFunctionError {
657 fn name(&self) -> &str {
658 "UnknownUnaryFunction"
659 }
660 fn message(&self) -> String {
661 format!("Unknown unary function ID: {}", self.fxn_id)
662 }
663}
664
665#[derive(Debug, Clone)]
666pub struct UnknownNullaryFunctionError {
667 pub fxn_id: u64,
668}
669impl MechErrorKind for UnknownNullaryFunctionError {
670 fn name(&self) -> &str {
671 "UnknownNullaryFunction"
672 }
673 fn message(&self) -> String {
674 format!("Unknown nullary function ID: {}", self.fxn_id)
675 }
676}
677
678#[derive(Debug, Clone)]
679pub struct IndexOutOfBoundsError;
680impl MechErrorKind for IndexOutOfBoundsError {
681 fn name(&self) -> &str {
682 "IndexOutOfBounds"
683 }
684 fn message(&self) -> String {
685 "Index out of bounds".to_string()
686 }
687}
688
689#[derive(Debug, Clone)]
690pub struct OverflowSubtractionError;
691impl MechErrorKind for OverflowSubtractionError {
692 fn name(&self) -> &str {
693 "OverflowSubtraction"
694 }
695 fn message(&self) -> String {
696 "Attempted subtraction overflow".to_string()
697 }
698}
699
700#[derive(Debug, Clone)]
701pub struct UnknownPanicError {
702 pub details: String,
703}
704impl MechErrorKind for UnknownPanicError {
705 fn name(&self) -> &str {
706 "UnknownPanic"
707 }
708 fn message(&self) -> String {
709 self.details.clone()
710 }
711}
712
713#[derive(Debug, Clone)]
714struct StepIndexOutOfBoundsError {
715 pub step_id: usize,
716 pub plan_length: usize,
717}
718impl MechErrorKind for StepIndexOutOfBoundsError {
719 fn name(&self) -> &str {
720 "StepIndexOutOfBounds"
721 }
722 fn message(&self) -> String {
723 format!(
724 "Step id {} out of range (plan has {} steps)",
725 self.step_id, self.plan_length
726 )
727 }
728}
729
730#[derive(Debug, Clone)]
731struct NoStepsInPlanError;
732impl MechErrorKind for NoStepsInPlanError {
733 fn name(&self) -> &str {
734 "NoStepsInPlan"
735 }
736 fn message(&self) -> String {
737 "Plan contains no steps. This program doesn't do anything.".to_string()
738 }
739}