mech_interpreter/
interpreter.rs

1use crate::*;
2use std::rc::Rc;
3use std::collections::HashMap;
4use std::panic::{catch_unwind, AssertUnwindSafe};
5use std::io::{Cursor, Read, Write};
6use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};
7
8// Interpreter 
9// ----------------------------------------------------------------------------
10
11pub struct Interpreter {
12  pub id: u64,
13  ip: usize,  // instruction pointer
14  pub state: Ref<ProgramState>,
15  #[cfg(feature = "functions")]
16  pub stack: Vec<Frame>,
17  registers: Vec<Value>,
18  constants: Vec<Value>,
19  #[cfg(feature = "compiler")]
20  pub context: Option<CompileCtx>,
21  pub code: Vec<MechSourceCode>,
22  pub out: Value,
23  pub out_values: Ref<HashMap<u64, Value>>,
24  pub sub_interpreters: Ref<HashMap<u64, Box<Interpreter>>>,
25}
26
27impl Clone for Interpreter {
28  fn clone(&self) -> Self {
29    Self {
30      id: self.id,
31      ip: self.ip,
32      state: Ref::new(self.state.borrow().clone()),
33      #[cfg(feature = "functions")]
34      stack: self.stack.clone(),
35      registers: self.registers.clone(),
36      constants: self.constants.clone(),
37      #[cfg(feature = "compiler")]
38      context: None,
39      code: self.code.clone(),
40      out: self.out.clone(),
41      out_values: self.out_values.clone(),
42      sub_interpreters: self.sub_interpreters.clone(),
43    }
44  }
45}
46
47impl Interpreter {
48  pub fn new(id: u64) -> Self {
49    let mut state = ProgramState::new();
50    load_stdkinds(&mut state.kinds);
51    #[cfg(feature = "functions")]
52    load_stdlib(&mut state.functions.borrow_mut());
53    Self {
54      id,
55      ip: 0,
56      state: Ref::new(state),
57      #[cfg(feature = "functions")]
58      stack: Vec::new(),
59      registers: Vec::new(),
60      constants: Vec::new(),
61      out: Value::Empty,
62      sub_interpreters: Ref::new(HashMap::new()),
63      out_values: Ref::new(HashMap::new()),
64      code: Vec::new(),
65      #[cfg(feature = "compiler")]
66      context: None,
67    }
68  }
69
70  #[cfg(feature = "symbol_table")]
71  pub fn set_environment(&mut self, env: SymbolTableRef) {
72    self.state.borrow_mut().environment = Some(env);
73  }
74
75  #[cfg(feature = "functions")]
76  pub fn clear_plan(&mut self) {
77    self.state.borrow_mut().plan.borrow_mut().clear();
78  }
79
80  #[cfg(feature = "pretty_print")]
81  pub fn pretty_print(&self) -> String {
82    let mut output = String::new();
83    output.push_str(&format!("Interpreter ID: {}\n", self.id));
84    // print state
85    output.push_str(&self.state.borrow().pretty_print());
86
87    output.push_str("Registers:\n");
88    for (i, reg) in self.registers.iter().enumerate() {
89      output.push_str(&format!("  R{}: {}\n", i, reg));
90    }
91    output.push_str("Constants:\n");
92    for (i, constant) in self.constants.iter().enumerate() {
93      output.push_str(&format!("  C{}: {}\n", i, constant));
94    }
95    output.push_str(&format!("Output Value: {}\n", self.out));
96    output.push_str(&format!(
97      "Number of Sub-Interpreters: {}\n",
98      self.sub_interpreters.borrow().len()
99    ));
100    output.push_str("Output Values:\n");
101    for (key, value) in self.out_values.borrow().iter() {
102      output.push_str(&format!("  {}: {}\n", key, value));
103    }
104    output.push_str(&format!("Code Length: {}\n", self.code.len()));
105    #[cfg(feature = "compiler")]
106    if let Some(context) = &self.context {
107      output.push_str("Context: Exists\n");
108    } else {
109      output.push_str("Context: None\n");
110    }
111    output
112  }
113
114  pub fn clear(&mut self) {
115    let id = self.id;
116    *self = Interpreter::new(id);
117  }
118
119  #[cfg(feature = "pretty_print")]
120  pub fn pretty_print_symbols(&self) -> String {
121    let state_brrw = self.state.borrow();
122    let syms = state_brrw.symbol_table.borrow();
123    syms.pretty_print()
124  }
125
126  #[cfg(feature = "pretty_print")]
127  pub fn pretty_print_plan(&self) -> String {
128    let state_brrw = self.state.borrow();
129    let plan = state_brrw.plan.borrow();
130    let mut result = String::new();
131    for (i, step) in plan.iter().enumerate() {
132      result.push_str(&format!("Step {}:\n", i));
133      result.push_str(&format!("{}\n", step.to_string()));
134    }
135    result
136  }
137
138  #[cfg(feature = "functions")]
139  pub fn plan(&self) -> Plan {
140    self.state.borrow().plan.clone()
141  }
142
143  #[cfg(feature = "symbol_table")]
144  pub fn symbols(&self) -> SymbolTableRef {
145    self.state.borrow().symbol_table.clone()
146  }
147
148  pub fn dictionary(&self) -> Ref<Dictionary> {
149    self.state.borrow().dictionary.clone()
150  }
151
152  #[cfg(feature = "functions")]
153  pub fn functions(&self) -> FunctionsRef {
154    self.state.borrow().functions.clone()
155  }
156
157  #[cfg(feature = "functions")]
158  pub fn set_functions(&mut self, functions: FunctionsRef) {
159    self.state.borrow_mut().functions = functions;
160  }
161
162  #[cfg(feature = "functions")]
163  pub fn step(&mut self, step_id: usize, step_count: u64) -> MResult<Value> {
164    let state_brrw = self.state.borrow();
165    let mut plan_brrw = state_brrw.plan.borrow_mut(); // RefMut<Vec<Box<dyn MechFunction>>>
166
167    if plan_brrw.is_empty() {
168      return Err(MechError2::new(
169          NoStepsInPlanError,
170          None
171        ).with_compiler_loc()
172      );
173    }
174
175    let len = plan_brrw.len();
176
177    // Case 1: step_id == 0, run entire plan step_count times
178    if step_id == 0 {
179      for _ in 0..step_count {
180        for fxn in plan_brrw.iter_mut() {
181          fxn.solve();
182        }
183      }
184      return Ok(plan_brrw[len - 1].out().clone());
185    }
186
187    // Case 2: step a single function by index
188    let idx = step_id as usize;
189    if idx > len {
190      return Err(MechError2::new(
191        StepIndexOutOfBoundsError {
192          step_id,
193          plan_length: len,
194        },
195        None
196      ).with_compiler_loc());
197    }
198
199    let fxn = &mut plan_brrw[idx - 1];
200
201    let fxn_str = fxn.to_string();
202    if fxn_str.lines().count() > 30 {
203      let lines: Vec<&str> = fxn_str.lines().collect();
204      println!("Stepping function:");
205      for line in &lines[0..10] {
206        println!("{}", line);
207      }
208      println!("...");
209      for line in &lines[lines.len() - 10..] {
210        println!("{}", line);
211      }
212    } else {
213      println!("Stepping function:\n{}", fxn_str);
214    }
215
216    for _ in 0..step_count {
217      fxn.solve();
218    }
219
220    Ok(fxn.out().clone())
221  }
222
223
224
225  #[cfg(feature = "functions")]
226  pub fn interpret(&mut self, tree: &Program) -> MResult<Value> {
227    self.code.push(MechSourceCode::Tree(tree.clone()));
228    catch_unwind(AssertUnwindSafe(|| {
229      let result = program(tree, &self);
230      if let Some(last_step) = self.state.borrow().plan.borrow().last() {
231        self.out = last_step.out().clone();
232      } else {
233        self.out = Value::Empty;
234      }
235      result
236    }))
237    .map_err(|err| {
238      if let Some(raw_msg) = err.downcast_ref::<&'static str>() {
239        if raw_msg.contains("Index out of bounds") {
240          MechError2::new(
241            IndexOutOfBoundsError,
242            None,
243          ).with_compiler_loc()
244        } else if raw_msg.contains("attempt to subtract with overflow") {
245          MechError2::new(
246            OverflowSubtractionError,
247            None,
248          ).with_compiler_loc()
249        } else {
250          MechError2::new(
251            UnknownPanicError {
252              details: raw_msg.to_string(),
253            },
254            None,
255          ).with_compiler_loc()
256        }
257      } else {
258        MechError2::new(
259          UnknownPanicError {
260            details: "Non-string panic".to_string(),
261          },
262          None,
263        ).with_compiler_loc()
264      }
265    })?
266}
267
268  
269  #[cfg(feature = "program")]
270  pub fn run_program(&mut self, program: &ParsedProgram) -> MResult<Value> {
271    // Reset the instruction pointer
272    self.ip = 0;
273    // Resize the registers and constant table
274    self.registers = vec![Value::Empty; program.header.reg_count as usize];
275    self.constants = vec![Value::Empty; program.const_entries.len()];
276    // Load the constants
277    self.constants = program.decode_const_entries()?;
278    // Load the symbol table
279    {
280      let mut state_brrw = self.state.borrow_mut();
281      let mut symbol_table = state_brrw.symbol_table.borrow_mut();
282      for (id, reg) in program.symbols.iter() {
283        let constant = self.constants[*reg as usize].clone();
284        self.out = constant.clone();
285        let mutable = program.mutable_symbols.contains(id);
286        symbol_table.insert(*id, constant, mutable);
287      }
288    }
289    // Load the instructions
290    {
291      let state_brrw = self.state.borrow();
292      let functions_table = state_brrw.functions.borrow();
293      while self.ip < program.instrs.len() {
294        let instr = &program.instrs[self.ip];
295        match instr {
296          DecodedInstr::ConstLoad { dst, const_id } => {
297            let value = self.constants[*const_id as usize].clone();
298            self.registers[*dst as usize] = value;
299          },
300          DecodedInstr::NullOp{ fxn_id, dst } => {
301            match functions_table.functions.get(fxn_id) {
302              Some(fxn_factory) => {
303                let out = &self.registers[*dst as usize];
304                let fxn = fxn_factory(FunctionArgs::Nullary(out.clone()))?;
305                self.out = fxn.out().clone();
306                state_brrw.add_plan_step(fxn);
307              },
308              None => {
309                return Err(MechError2::new(
310                  UnknownNullaryFunctionError { fxn_id: *fxn_id },
311                  None
312                ).with_compiler_loc());
313              }
314            }
315          },
316          DecodedInstr::UnOp{ fxn_id, dst, src } => {
317            match functions_table.functions.get(fxn_id) {
318              Some(fxn_factory) => {
319                let src = &self.registers[*src as usize];
320                let out = &self.registers[*dst as usize];
321                let fxn = fxn_factory(FunctionArgs::Unary(out.clone(), src.clone()))?;
322                self.out = fxn.out().clone();
323                state_brrw.add_plan_step(fxn);
324              },
325              None => {
326                return Err(MechError2::new(
327                  UnknownUnaryFunctionError { fxn_id: *fxn_id },
328                  None
329                ).with_compiler_loc());
330              }
331            }
332          },
333          DecodedInstr::BinOp{ fxn_id, dst, lhs, rhs } => {
334            match functions_table.functions.get(fxn_id) {
335              Some(fxn_factory) => {
336                let lhs = &self.registers[*lhs as usize];
337                let rhs = &self.registers[*rhs as usize];
338                let out = &self.registers[*dst as usize];
339                let fxn = fxn_factory(FunctionArgs::Binary(out.clone(), lhs.clone(), rhs.clone()))?;
340                self.out = fxn.out().clone();
341                state_brrw.add_plan_step(fxn);
342              },
343              None => {
344                return Err(MechError2::new(
345                  UnknownBinaryFunctionError { fxn_id: *fxn_id },
346                  None
347                ).with_compiler_loc());
348              }
349            }
350          },
351          DecodedInstr::TernOp{ fxn_id, dst, a, b, c } => {
352            match functions_table.functions.get(fxn_id) {
353              Some(fxn_factory) => {
354                let arg1 = &self.registers[*a as usize];
355                let arg2 = &self.registers[*b as usize];
356                let arg3 = &self.registers[*c as usize];
357                let out = &self.registers[*dst as usize];
358                let fxn = fxn_factory(FunctionArgs::Ternary(out.clone(), arg1.clone(), arg2.clone(), arg3.clone()))?;
359                self.out = fxn.out().clone();
360                state_brrw.add_plan_step(fxn);
361              },
362              None => {
363                return Err(MechError2::new(
364                  UnknownTernaryFunctionError { fxn_id: *fxn_id },
365                  None
366                ).with_compiler_loc());
367              }
368            }
369          },
370          DecodedInstr::QuadOp{ fxn_id, dst, a, b, c, d } => {
371            match functions_table.functions.get(fxn_id) {
372              Some(fxn_factory) => {
373                let arg1 = &self.registers[*a as usize];
374                let arg2 = &self.registers[*b as usize];
375                let arg3 = &self.registers[*c as usize];
376                let arg4 = &self.registers[*d as usize];
377                let out = &self.registers[*dst as usize];
378                let fxn = fxn_factory(FunctionArgs::Quaternary(out.clone(), arg1.clone(), arg2.clone(), arg3.clone(), arg4.clone()))?;
379                self.out = fxn.out().clone();
380                state_brrw.add_plan_step(fxn);
381              },
382              None => {
383                return Err(MechError2::new(
384                  UnknownQuadFunctionError { fxn_id: *fxn_id },
385                  None
386                ).with_compiler_loc());
387              }
388            }
389          },
390          DecodedInstr::VarArg{ fxn_id, dst, args } => {
391            match functions_table.functions.get(fxn_id) {
392              Some(fxn_factory) => {
393                let arg_values: Vec<Value> = args.iter().map(|r| self.registers[*r as usize].clone()).collect();
394                let out = &self.registers[*dst as usize];
395                let fxn = fxn_factory(FunctionArgs::Variadic(out.clone(), arg_values))?;
396                self.out = fxn.out().clone();
397                state_brrw.add_plan_step(fxn);
398              },
399              None => {
400                return Err(MechError2::new(
401                  UnknownVariadicFunctionError { fxn_id: *fxn_id },
402                  None
403                ).with_compiler_loc());
404              }
405            }
406          },
407          DecodedInstr::Ret{ src } => {
408            todo!();
409          },
410          x => {
411            return Err(MechError2::new(
412              UnknownInstructionError { instr: format!("{:?}", x) },
413              None
414            ).with_compiler_loc());
415          }
416        }
417        self.ip += 1;
418      }
419    }
420    // Load the dictionary
421    {
422      let mut state_brrw = self.state.borrow_mut();
423      let mut symbol_table = state_brrw.symbol_table.borrow_mut();
424      for (id, name) in &program.dictionary {
425        symbol_table.dictionary.borrow_mut().insert(*id, name.clone());
426        state_brrw.dictionary.borrow_mut().insert(*id, name.clone());
427      } 
428    }
429    Ok(self.out.clone())
430  }
431
432  #[cfg(feature = "compiler")]
433  pub fn compile(&mut self) -> MResult<Vec<u8>> {
434    let state_brrw = self.state.borrow();
435    let mut plan_brrw = state_brrw.plan.borrow_mut();
436    let mut ctx = CompileCtx::new();
437    for step in plan_brrw.iter() {
438      step.compile(&mut ctx)?;
439    }
440    let bytes = ctx.compile()?;
441    self.context = Some(ctx);
442    Ok(bytes)
443  }
444
445}
446
447#[derive(Debug, Clone)]
448pub struct UnknownInstructionError {
449  pub instr: String,
450}
451impl MechErrorKind2 for UnknownInstructionError {
452  fn name(&self) -> &str {
453    "UnknownInstruction"
454  }
455
456  fn message(&self) -> String {
457    format!("Unknown instruction: {}", self.instr)
458  }
459}
460
461#[derive(Debug, Clone)]
462pub struct UnknownVariadicFunctionError {
463  pub fxn_id: u64,
464}
465
466impl MechErrorKind2 for UnknownVariadicFunctionError {
467  fn name(&self) -> &str {
468    "UnknownVariadicFunction"
469  }
470  fn message(&self) -> String {
471    format!("Unknown variadic function ID: {}", self.fxn_id)
472  }
473}
474
475#[derive(Debug, Clone)]
476pub struct UnknownQuadFunctionError {
477  pub fxn_id: u64,
478}
479impl MechErrorKind2 for UnknownQuadFunctionError {
480  fn name(&self) -> &str {
481    "UnknownQuadFunction"
482  }
483  fn message(&self) -> String {
484    format!("Unknown quad function ID: {}", self.fxn_id)
485  }
486}
487
488#[derive(Debug, Clone)]
489pub struct UnknownTernaryFunctionError {
490  pub fxn_id: u64,
491}
492impl MechErrorKind2 for UnknownTernaryFunctionError {
493  fn name(&self) -> &str {
494    "UnknownTernaryFunction"
495  }
496  fn message(&self) -> String {
497    format!("Unknown ternary function ID: {}", self.fxn_id)
498  }
499}
500
501#[derive(Debug, Clone)]
502pub struct UnknownBinaryFunctionError {
503  pub fxn_id: u64,
504}
505impl MechErrorKind2 for UnknownBinaryFunctionError {
506  fn name(&self) -> &str {
507    "UnknownBinaryFunction"
508  }
509  fn message(&self) -> String {
510    format!("Unknown binary function ID: {}", self.fxn_id)
511  }
512}
513
514#[derive(Debug, Clone)]
515pub struct UnknownUnaryFunctionError {
516  pub fxn_id: u64,
517}
518impl MechErrorKind2 for UnknownUnaryFunctionError {
519  fn name(&self) -> &str {
520    "UnknownUnaryFunction"
521  }
522  fn message(&self) -> String {
523    format!("Unknown unary function ID: {}", self.fxn_id)
524  }
525}
526
527#[derive(Debug, Clone)]
528pub struct UnknownNullaryFunctionError {
529  pub fxn_id: u64,
530}
531impl MechErrorKind2 for UnknownNullaryFunctionError {
532  fn name(&self) -> &str {
533    "UnknownNullaryFunction"
534  }
535  fn message(&self) -> String {
536    format!("Unknown nullary function ID: {}", self.fxn_id)
537  }
538}
539
540#[derive(Debug, Clone)]
541pub struct IndexOutOfBoundsError;
542impl MechErrorKind2 for IndexOutOfBoundsError {
543  fn name(&self) -> &str { "IndexOutOfBounds" }
544  fn message(&self) -> String { "Index out of bounds".to_string() }
545}
546
547#[derive(Debug, Clone)]
548pub struct OverflowSubtractionError;
549impl MechErrorKind2 for OverflowSubtractionError {
550  fn name(&self) -> &str { "OverflowSubtraction" }
551  fn message(&self) -> String { "Attempted subtraction overflow".to_string() }
552}
553
554#[derive(Debug, Clone)]
555pub struct UnknownPanicError {
556  pub details: String
557}
558impl MechErrorKind2 for UnknownPanicError {
559  fn name(&self) -> &str { "UnknownPanic" }
560  fn message(&self) -> String { self.details.clone() }
561}
562
563#[derive(Debug, Clone)]
564struct StepIndexOutOfBoundsError{
565  pub step_id: usize,
566  pub plan_length: usize,
567}
568impl MechErrorKind2 for StepIndexOutOfBoundsError {
569  fn name(&self) -> &str { "StepIndexOutOfBounds" }
570  fn message(&self) -> String {
571    format!("Step id {} out of range (plan has {} steps)", self.step_id, self.plan_length)
572  }
573}
574
575#[derive(Debug, Clone)]
576struct NoStepsInPlanError;
577impl MechErrorKind2 for NoStepsInPlanError {
578  fn name(&self) -> &str { "NoStepsInPlan" }
579  fn message(&self) -> String {
580    "Plan contains no steps. This program doesn't do anything.".to_string()
581  }
582}