unitdc/interpreter/
mod.rs1use std::{
2 collections::HashMap,
3 io::{BufReader, Read},
4};
5
6use crate::{
7 quantity::{
8 units::{UnitCombo, UnitSystem},
9 Quantity, QuantityError,
10 },
11 tokenizer::{token::Token, ReaderCursor, Tokenizer, TokenizerError},
12};
13
14use thiserror::Error;
15
16pub mod ops;
18pub mod ops_macros;
20pub mod ops_variables;
22
23pub struct Interpreter<'a> {
24 variables: HashMap<String, Quantity>,
25 unit_system: UnitSystem,
26 stack: Vec<Quantity>,
27 output: Box<dyn Fn(Output) + 'a>,
28}
29
30#[derive(Debug, Clone, PartialEq)]
31pub enum Output {
32 Quantity(Quantity),
33 QuantityList(Vec<Quantity>),
34 Message(String),
35}
36
37#[derive(Debug, Error)]
38pub enum InterpreterError {
39 #[error("Tokenizer error: {1} at {0}")]
40 TokenizerError(ReaderCursor, TokenizerError),
41 #[error("Quantity error: {0}")]
42 QuantityError(QuantityError),
43 #[error("Stack underflow")]
44 StackUnderflow,
45 #[error("Undefined unit: {0}")]
46 UndefinedUnit(String),
47 #[error("Undefined macro: {0}")]
48 UndefinedMacro(String),
49 #[error("Undefined variable: {0}")]
50 UndefinedVariable(String),
51 #[error("Incompatible units: {0}")]
52 IncompatibleUnits(UnitCombo),
53 #[error("No solution: {0}")]
54 NoSolution(String),
55 #[error("Already defined: {0}")]
56 AlreadyDefined(String),
57}
58
59pub type InterpreterResult<T> = Result<T, InterpreterError>;
60
61impl<'a> Interpreter<'a> {
62 pub fn new(output: Box<dyn Fn(Output) + 'a>) -> Self {
63 Self {
64 variables: HashMap::new(),
65 unit_system: UnitSystem::new(),
66 stack: Vec::new(),
67 output,
68 }
69 }
70 pub fn process_tokens<R: Read>(
72 &mut self,
73 tokenizer: &mut Tokenizer<R>,
74 ) -> InterpreterResult<()> {
75 while let Some(token) = tokenizer
76 .parse_next_token()
77 .map_err(|e| InterpreterError::TokenizerError(tokenizer.get_cursor(), e))?
78 {
79 match token {
80 Token::Number(n) => self.op_number(n)?,
81 Token::Unit(u) => self.op_unit(&u)?,
82 Token::Add => self.op_add()?,
83 Token::Sub => self.op_sub()?,
84 Token::Mul => self.op_mul()?,
85 Token::Div => self.op_div()?,
86 Token::Operator('p') => self.op_p()?,
87 Token::Operator('n') => self.op_n()?,
88 Token::Operator('f') => self.op_f()?,
89 Token::Operator('c') => self.op_c()?,
90 Token::Operator('d') => self.op_d()?,
91 Token::Operator('r') => self.op_r()?,
92 Token::Operator('s') => self.op_s()?,
93 Token::Operator('U') => self.op_upper_u()?,
94 Token::VarRecall(name) => self.op_recall(&name)?,
95 Token::VarStore(name) => self.op_store(&name)?,
96 Token::MacroInvoke((name, args)) => match name.as_str() {
97 "base" => self.op_macro_baseunit(&args)?,
98 "derived" => self.op_macro_derivedunit(&args)?,
99 _ => return Err(InterpreterError::UndefinedMacro(name)),
100 },
101 Token::Comment(_) => {}
102 _ => eprintln!("Unhandled token: {:?}", token),
103 }
104 }
105
106 Ok(())
107 }
108 pub fn run_str(&mut self, input: &str) -> InterpreterResult<()> {
109 let mut tokenizer = Tokenizer::new(BufReader::new(input.as_bytes()));
110 self.process_tokens(&mut tokenizer)?;
111
112 Ok(())
113 }
114}