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