stackr_rs/interpreter/
mod.rs

1/// Addresses used to identify words in the interpreter.
2mod address;
3/// Addresses used to identify words in the interpreter.
4mod address_cache;
5/// Built-in words registered at runtime.
6mod built_ins;
7/// Contains logic for loading and executing a program.
8mod evaluate;
9/// Instructions that can be executed by the interpreter.
10mod instruction;
11/// Locations of the program instructions. Used for debugging.
12mod location;
13/// Values stored in the RAM.
14mod ram_value;
15/// Values stored on the stack.
16mod stack_value;
17/// Stringifies the program.
18mod stringify;
19
20pub(crate) use address_cache::*;
21pub(crate) use instruction::*;
22pub(crate) use ram_value::*;
23pub use stack_value::*;
24
25pub use address::*;
26pub use built_ins::*;
27pub use location::*;
28
29use std::{collections::HashMap, io::Write, path::PathBuf};
30
31/// A type alias for an error.
32pub type Err = (String, Location);
33/// A type alias for a number.
34pub type Number = f32;
35
36/// A value that is stored in RAM or on the stack.
37#[derive(Debug, PartialEq, Clone)]
38pub enum Value {
39    Number(Number),
40    String(String),
41}
42
43/// The mode of the interpreter.
44/// Read mode determines if words should be read as addresses or evaluated.
45#[derive(Debug, Copy, Clone, PartialEq)]
46pub(crate) enum ReadMode {
47    On,
48    Off,
49    SingleWord,
50}
51
52/// The core interpreter object.
53/// Takes in a custom defined state that can be modified by built-ins.
54pub struct Interpreter<State> {
55    /// Custom state for each application.
56    /// Allows users to register built-ins that modify this state.
57    #[allow(unused)]
58    pub state: State,
59    /// Address cache. Used to remove need to lookup addresses every time.
60    address_cache: AddressCache,
61    /// Whether the program should break out of the current loop.
62    break_loop: bool,
63    /// Program counter.
64    program_counter: usize,
65    /// Program to execute.
66    program: Vec<Instruction>,
67    /// Program counter stack. Used for loops/control flow.
68    program_counter_stack: Vec<usize>,
69    /// Whether the interpreter is in compile mode.
70    compiling: bool,
71    /// Locations of the program instructions. Used for debugging.
72    program_debug_locations: Vec<Location>,
73    /// Whether the interpreter should quit.
74    exit: bool,
75    /// Read mode. Determines if words should be read as addresses or evaluated.
76    read_mode: ReadMode,
77    /// Whether the interpreter should run a REPL.
78    repl_mode: bool,
79    /// Next address to use.
80    next_address: Address,
81    /// RAM. Stores values and words.
82    ram: HashMap<Address, RamValue<State>>,
83    /// Stack.
84    stack: Vec<StackValue>,
85    /// Documentation table. Maps addresses to documentation.
86    documentation_table: HashMap<Address, String>,
87    /// Name table. Maps names to addresses.
88    name_table: HashMap<String, Address>,
89}
90
91impl<State> Interpreter<State> {
92    /// Create a new interpreter.
93    /// Pass in the initial custom state for the interpreter.
94    pub fn new(state: State) -> Self {
95        let mut interpreter = Self {
96            state,
97            compiling: false,
98            break_loop: false,
99            address_cache: AddressCache::uninitalized(),
100            program_counter: 0,
101            program: vec![],
102            program_counter_stack: vec![],
103            program_debug_locations: vec![],
104            exit: false,
105            read_mode: ReadMode::Off,
106            repl_mode: false,
107            ram: HashMap::new(),
108            stack: vec![],
109            next_address: Address::default(),
110            documentation_table: HashMap::new(),
111            name_table: HashMap::new(),
112        };
113
114        interpreter.register_builtins();
115
116        AddressCache::initialize(&mut interpreter);
117
118        interpreter
119    }
120
121    /// Returns whether the interpreter should exit.
122    pub fn exit(&self) -> bool {
123        self.exit
124    }
125
126    /// Evaluate a program.
127    pub fn evaluate(&mut self, code: &str, path: Option<PathBuf>) -> Result<(), Err> {
128        self.load_program(code, path)?;
129        self.execute()?;
130        Ok(())
131    }
132
133    /// Get the name of an address if present.
134    pub fn get_name(&self, address: Address) -> String {
135        // Check if the address is in the name table
136        for (name, addr) in &self.name_table {
137            if *addr == address {
138                return name.clone();
139            }
140        }
141
142        // Didn't find it, so if we have something in ram that contains the address, use that
143        for (k, value) in &self.ram {
144            if let Some(addr) = value.address() {
145                if addr == address {
146                    return format!("@{}", self.get_name(*k));
147                }
148            }
149        }
150
151        // Didn't find it, so return an unknown name
152        format!("@UNKNOWN-{:?}", address)
153    }
154
155    /// Pop a value from the stack.
156    pub fn pop(&mut self) -> Result<StackValue, Err> {
157        self.stack
158            .pop()
159            .ok_or(("Stack is empty".to_string(), self.location()))
160    }
161
162    /// Pop a boolean from the stack.
163    pub fn pop_bool(&mut self) -> Result<bool, Err> {
164        match self.pop()? {
165            StackValue::Value(Value::Number(number)) => Ok(number != 0.0),
166            _ => Err(("Expected a boolean/number".to_string(), self.location())),
167        }
168    }
169
170    /// Pop a number from the stack.
171    pub fn pop_number(&mut self) -> Result<f32, Err> {
172        match self.pop()? {
173            StackValue::Value(Value::Number(number)) => Ok(number),
174            _ => Err(("Expected a number".to_string(), self.location())),
175        }
176    }
177
178    /// Push a number onto the stack.
179    pub fn push_number(&mut self, number: f32) {
180        self.stack.push(StackValue::Value(Value::Number(number)));
181    }
182
183    /// Push an address onto the stack.
184    pub fn push_address(&mut self, address: Address) {
185        self.stack.push(StackValue::Address(address));
186    }
187
188    /// Pop an address from the stack.
189    pub fn pop_address(&mut self) -> Result<Address, Err> {
190        match self.pop()? {
191            StackValue::Address(address) => Ok(address),
192            _ => Err(("Expected an address".to_string(), self.location())),
193        }
194    }
195
196    /// Push a string onto the stack.
197    pub fn push_string(&mut self, string: String) {
198        self.stack.push(StackValue::Value(Value::String(string)));
199    }
200
201    /// Pop a string from the stack.
202    pub fn pop_string(&mut self) -> Result<String, Err> {
203        match self.pop()? {
204            StackValue::Value(Value::String(string)) => Ok(string),
205            _ => Err(("Expected a string".to_string(), self.location())),
206        }
207    }
208
209    /// Start a REPL.
210    pub fn start_repl(&mut self) -> Result<(), Err> {
211        self.repl_mode = true;
212        println!("Use 'repl-exit' to exit REPL mode.");
213
214        while !self.exit && self.repl_mode {
215            // Read input from stdin
216            let mut input = String::new();
217            print!("> ");
218            std::io::stdout().flush().unwrap();
219            std::io::stdin().read_line(&mut input).unwrap();
220
221            let input = format!("{} print-stack", input.trim());
222
223            // Evaluate input
224            match self.evaluate(&input, None) {
225                Ok(_) => (),
226                Err((e, location)) => println!("{}: {}", location, e),
227            }
228        }
229        Ok(())
230    }
231
232    /// Register a built-in function to be used in the interpreter.
233    pub fn register_builtin(
234        &mut self,
235        name: &str,
236        stack_modification: &str,
237        documentation: &str,
238        example: &str,
239        func: BuiltIn<State>,
240    ) {
241        let address = self.get_address(name);
242        self.register_documentation(address, stack_modification, documentation, example);
243        self.ram.insert(address, RamValue::BuiltIn(func));
244    }
245
246    /// Register documentation for a word.
247    pub(crate) fn register_documentation(
248        &mut self,
249        address: Address,
250        stack_modification: &str,
251        documentation: &str,
252        example: &str,
253    ) {
254        let stack_modification = if stack_modification.is_empty() {
255            "".to_string()
256        } else {
257            format!("\t( {} )", stack_modification.replace("...", "..").trim())
258        };
259
260        let example = if example.is_empty() {
261            "".to_string()
262        } else {
263            format!("\n\tExample '{}'", example)
264        };
265        let documentation = documentation.trim();
266        let documentation = format!("{stack_modification}\n\t{}{}", documentation, example);
267
268        self.documentation_table.insert(address, documentation);
269    }
270
271    /// Print the documentation for all words.
272    pub fn print_documentation(&self) {
273        println!("Documentation:");
274        let mut names = self.name_table.keys().cloned().collect::<Vec<_>>();
275        names.sort();
276        for name in names {
277            let address = self.name_table[&name];
278            if let Some(documentation) = self.documentation_table.get(&address) {
279                println!("{}  {}\n", name, documentation);
280            }
281        }
282        println!();
283    }
284
285    /// Get the address of a name.
286    pub(crate) fn get_address(&mut self, name: &str) -> Address {
287        if let Some(address) = self.name_table.get(name) {
288            address.clone()
289        } else {
290            let address = self.next_address;
291            self.next_address = self.next_address.next();
292            self.name_table.insert(name.to_string(), address);
293            address
294        }
295    }
296
297    /// Get the next instruction from the program.
298    pub(crate) fn chomp_instruction(&mut self) -> Result<Instruction, Err> {
299        if self.program_counter >= self.program.len() {
300            return Err(("No more instructions".to_string(), self.location()));
301        }
302
303        let instruction = self.program[self.program_counter].clone();
304        self.program_counter += 1;
305        Ok(instruction)
306    }
307
308    /// Returns the location of the current instruction.
309    pub fn location(&self) -> Location {
310        if self.program_debug_locations.is_empty()
311            || self.program_counter >= self.program_debug_locations.len()
312        {
313            return Location::default();
314        }
315        self.program_debug_locations[self.program_counter].clone()
316    }
317}
318
319#[cfg(test)]
320mod tests {
321    use super::*;
322
323    #[test]
324    fn test_get_address() {
325        let mut interpreter = Interpreter::new(());
326        let expected = interpreter.next_address;
327        let actual = interpreter.get_address("test");
328        assert_eq!(expected, actual);
329    }
330
331    #[test]
332    fn pop_returns_err_if_stack_is_empty() {
333        let mut interpreter = Interpreter::new(());
334        let err = interpreter.pop().unwrap_err();
335        assert_eq!(err, ("Stack is empty".to_string(), Location::default()));
336    }
337
338    #[test]
339    fn pop_number_returns_err_if_not_number() {
340        let mut interpreter = Interpreter::new(());
341        interpreter.push_address(Address::default());
342        let err = interpreter.pop_number().unwrap_err();
343        assert_eq!(err, ("Expected a number".to_string(), Location::default()));
344    }
345
346    #[test]
347    fn pop_bool_returns_err_if_not_bool() {
348        let mut interpreter = Interpreter::new(());
349        interpreter.push_string("hello".to_string());
350        let err = interpreter.pop_bool().unwrap_err();
351        assert_eq!(
352            err,
353            ("Expected a boolean/number".to_string(), Location::default())
354        );
355    }
356
357    #[test]
358    fn pop_bool_returns_true() {
359        let mut interpreter = Interpreter::new(());
360        interpreter.push_number(0.1);
361        let value = interpreter.pop_bool().unwrap();
362        assert_eq!(value, true);
363    }
364
365    #[test]
366    fn pop_bool_returns_false() {
367        let mut interpreter = Interpreter::new(());
368        interpreter.push_number(0.0);
369        let value = interpreter.pop_bool().unwrap();
370        assert_eq!(value, false);
371    }
372
373    #[test]
374    fn pop_number_returns_value() {
375        let mut interpreter = Interpreter::new(());
376        interpreter.evaluate("1", None).unwrap();
377        let value = interpreter.pop_number().unwrap();
378        assert_eq!(value, 1.0);
379    }
380
381    #[test]
382    fn pop_string_returns_err_if_not_string() {
383        let mut interpreter = Interpreter::new(());
384        interpreter.evaluate("1", None).unwrap();
385        let err = interpreter.pop_string().unwrap_err();
386        assert_eq!(err, ("Expected a string".to_string(), Location::default()));
387    }
388
389    #[test]
390    fn pop_string_returns_value() {
391        let mut interpreter = Interpreter::new(());
392        interpreter.push_string("hello".to_string());
393        let value = interpreter.pop_string().unwrap();
394        assert_eq!(value, "hello");
395    }
396
397    #[test]
398    fn pop_address_returns_err_if_not_address() {
399        let mut interpreter = Interpreter::new(());
400        interpreter.evaluate("1", None).unwrap();
401
402        let err = interpreter.pop_address().unwrap_err();
403        assert_eq!(
404            err,
405            ("Expected an address".to_string(), Location::default())
406        );
407    }
408
409    #[test]
410    fn pop_address_returns_value() {
411        let mut interpreter = Interpreter::new(());
412        let address = interpreter.next_address;
413        interpreter.push_address(address.clone());
414        let value = interpreter.pop_address().unwrap();
415        assert_eq!(value, address);
416    }
417
418    #[test]
419    fn parse_string_returns_err_if_not_closed() {
420        let code = r#""hello"#;
421        let mut interpreter = Interpreter::new(());
422        let result = interpreter.evaluate(code, None);
423        assert!(result.is_err());
424        assert_eq!(result.unwrap_err().0, "Unclosed string");
425    }
426
427    #[test]
428    fn parse_string_puts_string_on_stack() {
429        let code = r#""hello""#;
430
431        let mut interpreter = Interpreter::new(());
432        interpreter.evaluate(code, None).unwrap();
433        let value = interpreter.pop_string().unwrap();
434        assert_eq!(value, "hello");
435    }
436
437    #[test]
438    fn var_only_creates_if_not_already_in_ram() {
439        let mut interpreter = Interpreter::new(());
440        let address = interpreter.next_address;
441        interpreter.evaluate("var test", None).unwrap();
442
443        let first_call = interpreter.ram.get(&address).unwrap().clone();
444
445        interpreter.evaluate("var test", None).unwrap();
446
447        let second_call = interpreter.ram.get(&address).unwrap().clone();
448        assert_eq!(first_call, second_call);
449    }
450
451    // #[test]
452    // fn parse_string_puts_escaped_string_on_stack() {
453    //     let mut interpreter = Interpreter::new(());
454    //     let code = "\"hello\n \\\" \"";
455    //     interpreter.evaluate(code, None).unwrap();
456    //     let value = interpreter.pop_string().unwrap();
457    //     assert_eq!(value.as_str(), "hello\n \" ");
458    // }
459}