aplang_lib/interpreter/
interpreter.rs

1use crate::aplang::ApLang;
2use crate::interpreter::env::{Env, LoopControl};
3use crate::interpreter::errors::{Reports, RuntimeError};
4use crate::interpreter::procedure::FunctionMap;
5use crate::interpreter::procedure::Procedure;
6use crate::interpreter::value::Value;
7use crate::lexer::token::LiteralValue;
8use crate::parser::ast::{Ast, Binary, Expr, Literal, ProcCall, Stmt, Unary};
9use crate::standard_library::Modules;
10use miette::NamedSource;
11use std::cell::RefCell;
12use std::mem;
13use std::ops::Deref;
14use std::path::PathBuf;
15use std::rc::Rc;
16use std::sync::Arc;
17
18// we're using this weird error type because miette! slows down the execution
19// of recursive code by a HUGE amount
20// we profiled and couldn't figure out how to solve the issue
21// we don't know why.
22// we would like to use miette! macro it would
23// make reports better and easier to write
24// increment this counter if you try to solve this and fail
25// COLLECTIVE HOURS WASTED: 20
26#[derive(Clone)]
27pub struct Interpreter {
28    pub(super) venv: Env,
29    ast: Ast,
30
31    file_path: Option<PathBuf>,
32
33    pub(super) return_value: Option<Value>,
34    loop_stack: Vec<LoopControl>,
35
36    modules: Modules,
37}
38
39impl Interpreter {
40    pub fn new(ast: Ast, file_path: Option<PathBuf>) -> Self {
41        let mut interpreter = Self {
42            venv: Env::default(),
43            ast,
44            file_path: file_path.clone(),
45            return_value: None,
46
47            loop_stack: vec![], // *
48            modules: Modules::init(),
49        };
50        //* we start in no loops
51        //* if the stack is empty then we are not in a loop anymore
52
53        // initiate the core std functions
54        interpreter
55            .venv
56            .functions
57            .extend(interpreter.modules.lookup("CORE").unwrap()());
58
59        interpreter
60    }
61
62    pub fn get_return_value(&self) -> &Option<Value> {
63        &self.return_value
64    }
65
66    pub fn get_file_path(&self) -> String {
67        if let Some(file_path) = &self.file_path {
68            file_path.to_string_lossy().into_owned()
69        } else {
70            "stdin".to_string()
71        }
72    }
73
74    pub fn interpret_module(mut self) -> Result<FunctionMap, RuntimeError> {
75        // temporarily take the program to avoid borrow error
76        let program = mem::take(&mut self.ast.program);
77
78        for stmt in &program {
79            match stmt {
80                Stmt::Expr(expr) => {
81                    self.expr(expr.deref())?;
82                }
83                stmt => self.stmt(stmt)?,
84            }
85        }
86
87        self.ast.program = program; // restore program
88        Ok(self.venv.exports)
89    }
90
91    pub fn interpret(&mut self) -> Result<(), RuntimeError> {
92        // temporarily take the program to avoid borrow error
93        let program = mem::take(&mut self.ast.program);
94
95        for stmt in &program {
96            match stmt {
97                Stmt::Expr(expr) => {
98                    self.expr(expr.deref())?;
99                }
100                stmt => self.stmt(stmt)?,
101            }
102        }
103
104        self.ast.program = program; // restore program
105        Ok(())
106    }
107
108    pub fn interpret_debug(&mut self) -> Result<Vec<Value>, RuntimeError> {
109        let mut values = vec![];
110
111        let program = mem::take(&mut self.ast.program); // Temporarily take the program
112
113        for stmt in &program {
114            match stmt {
115                Stmt::Expr(expr) => {
116                    let value = self.expr(expr.deref())?;
117                    values.push(value);
118                }
119                stmt => self.stmt(stmt)?,
120            }
121        }
122
123        self.ast.program = program; // Restore the program
124        Ok(values)
125    }
126
127    // a stmt by definition returns nothing
128    pub(super) fn stmt(&mut self, stmt: &Stmt) -> Result<(), RuntimeError> {
129        match stmt {
130            Stmt::Expr(expr) => self.expr(expr.as_ref()).map(|_| ()),
131            Stmt::If(if_stmt) => {
132                // evaluate the conditional
133                if Self::is_truthy(&self.expr(&if_stmt.condition)?) {
134                    self.stmt(&if_stmt.then_branch)
135                } else if let Some(else_branch) = &if_stmt.else_branch {
136                    self.stmt(else_branch)
137                } else {
138                    Ok(())
139                }
140            }
141            Stmt::RepeatTimes(repeat_times) => {
142                match self.expr(&repeat_times.count)? {
143                    Value::Number(count) => {
144                        // we are now in a loop so keep track of the loop_stack
145                        self.loop_stack.push(LoopControl::default());
146
147                        // floor the value into an int so we can iterate
148                        for _ in 1..=count as usize {
149                            self.stmt(&repeat_times.body)?;
150
151                            // if the CONTINUE stmt was called handle it
152                            if self.loop_stack.last().unwrap().should_continue {
153                                self.loop_stack.last_mut().unwrap().should_continue = false;
154                                continue;
155                            }
156                            
157                            // if the BREAK stmt was called handle it
158                            if self.loop_stack.last().unwrap().should_break {
159                                self.loop_stack.last_mut().unwrap().should_break = false;
160                                break;
161                            }
162                        }
163
164                        // exit the loop
165                        assert!(self.loop_stack.pop().is_some());
166
167                        Ok(())
168                    } // format!("cannot do count for value {value:?}")
169                    value => Err(RuntimeError {
170                        named_source: NamedSource::new(
171                            self.get_file_path(),
172                            repeat_times.count_token.source.clone(),
173                        ),
174                        span: repeat_times.count_token.span,
175                        message: "Invalid Value for nTIMES".to_string(),
176                        help: format!("Make sure `{value:?}` is a NUMBER"),
177                        label: "Invalid Value here".to_string(),
178                    }),
179                }
180            }
181            Stmt::RepeatUntil(repeat_until) => {
182                // enter a loop
183                self.loop_stack.push(LoopControl::default());
184
185                while !Self::is_truthy(&self.expr(&repeat_until.condition)?) {
186                    self.stmt(&repeat_until.body)?;
187                    
188                    // if the BREAK stmt was called handle it
189                    if self.loop_stack.last().unwrap().should_break {
190                        self.loop_stack.last_mut().unwrap().should_break = false;
191                        break;
192                    }
193
194                    // if the CONTINUE stmt was called handle it
195                    if self.loop_stack.last().unwrap().should_continue {
196                        self.loop_stack.last_mut().unwrap().should_continue = false;
197                        continue;
198                    }
199
200                }
201
202                // exit the loop
203                assert!(self.loop_stack.pop().is_some());
204
205                Ok(())
206            }
207            Stmt::ForEach(for_each) => {
208                let values = match self.expr(&for_each.list)? {
209                    Value::List(list) => list,
210                    Value::String(string) => Rc::new(RefCell::new(
211                        string
212                            .chars()
213                            .map(|ch| Value::String(ch.to_string()))
214                            .collect::<Vec<Value>>(),
215                    )),
216                    value => Err(RuntimeError {
217                        named_source: NamedSource::new(
218                            self.get_file_path(),
219                            for_each.list_token.source.clone(),
220                        ),
221                        span: for_each.list_token.span,
222                        message: "Invalid Iterator".to_string(),
223                        help: format!(
224                            "Cannot iterate over {value:?}. This should be a LIST or a STRING"
225                        ),
226                        label: "Invalid Iterator Here".to_string(),
227                    })?,
228                };
229
230                let element = Arc::new(for_each.item.clone());
231
232                // if the variable already exists temperately remove it so doesn't get lost
233                let maybe_cached = self.venv.remove(element.clone());
234
235                // enter into the loop
236                self.loop_stack.push(LoopControl::default());
237
238                let len = values.borrow().len();
239                for i in 0..len {
240                    // inserting temporary value into env
241                    self.venv
242                        .define(element.clone(), values.borrow()[i].clone());
243                    // execute body
244
245                    
246                    self.stmt(&for_each.body)?;
247
248                    // if the BREAK stmt was called handle it
249                    if self.loop_stack.last().unwrap().should_break {
250                        self.loop_stack.last_mut().unwrap().should_break = false;
251                        break;
252                    }
253                    // handle break and continue
254                    // if the CONTINUE stmt was called then we need to deal with that
255                    if self.loop_stack.last().unwrap().should_continue {
256                        self.loop_stack.last_mut().unwrap().should_continue = false;
257                        continue;
258                    }
259
260                    // get temp val out and change it in vec
261                    (*values.borrow_mut())[i] = self.venv.remove(element.clone()).unwrap().0;
262                }
263
264                assert!(self.loop_stack.pop().is_some());
265
266                // put it back if it was originally defined
267                if let Some((cached_value, cached_variable)) = maybe_cached {
268                    self.venv.define(cached_variable, cached_value)
269                }
270
271                Ok(())
272            }
273            Stmt::ProcDeclaration(proc_dec) => {
274                // create a new non-native aplang function
275
276                let procedure = Rc::new(Procedure {
277                    name: proc_dec.name.to_string(),
278                    params: proc_dec.params.clone(),
279                    body: proc_dec.body.clone(),
280                });
281
282                self.venv.functions.insert(
283                    procedure.name.clone(),
284                    (procedure.clone(), Some(proc_dec.clone())),
285                );
286
287                if proc_dec.exported {
288                    self.venv.exports.insert(
289                        procedure.name.clone(),
290                        (procedure.clone(), Some(proc_dec.clone())),
291                    );
292                }
293
294                Ok(())
295            }
296            Stmt::Return(ret_val) => {
297                // deal with the return value inside the procedure
298
299                self.return_value = match &ret_val.data {
300                    None => Some(Value::Null),
301                    Some(expr) => Some(self.expr(expr)?),
302                };
303
304                Ok(())
305            }
306            Stmt::Continue(_cont) => {
307                // we should be in a loop scope here
308                // if not, uh oh
309                // *should* be insured by the parser
310                // todo: write an actual error message instead of panicking here
311                self.loop_stack.last_mut().unwrap().should_continue = true;
312
313                Ok(())
314            }
315            Stmt::Break(_brk) => {
316                // we should be in a loop scope here
317                // if not, uh oh
318                // *should* be insured by the parser
319                // todo: write an actual error message instead of panicking here
320                self.loop_stack.last_mut().unwrap().should_break = true;
321
322                Ok(())
323            }
324            Stmt::Block(block) => {
325                self.venv.create_nested_layer();
326
327                for stmt in block.statements.iter() {
328                    if self
329                        .loop_stack
330                        .last()
331                        .is_some_and(|lc| lc.should_break || lc.should_continue)
332                    {
333                        // if we are in a loop then we need to STOP execution
334                        break;
335                    }
336
337                    self.stmt(stmt)?
338                }
339
340                self.venv.flatten_nested_layer();
341
342                Ok(())
343            }
344            Stmt::Import(import) => {
345                // get a ref to the module name to be imported/activated
346                let Some(LiteralValue::String(module_name)) = import.module_name.literal.as_ref()
347                else {
348                    unreachable!()
349                };
350
351                let mut module = if let Some(injector) = self.modules.lookup(module_name) {
352                    // if the module is a native standard library module, get it
353                    injector()
354                } else {
355                    // the module must be a user module or invalid
356
357                    let Some(mut current_module_path) = self.file_path.clone() else {
358                        return Err(RuntimeError {
359                            named_source: NamedSource::new(
360                                self.get_file_path(),
361                                import.module_name.source.clone(),
362                            ),
363                            span: import.module_name.span,
364                            message: "user modules cannot be called when evaluating from stdin"
365                                .to_string(),
366                            label: "cannot use module".to_string(),
367                            help: "put your code in a file to use user modules".to_string(),
368                        });
369                    };
370
371                    // strip the filename from the path
372                    current_module_path.pop();
373                    // let maybe_path = self
374                    // let maybe_path = current_module_path.join(module_name);
375                    let maybe_path = current_module_path.join(module_name);
376
377                    // check if the file has a dot ap extension.
378                    // if it does then continue
379                    // if not, then try to import an invalid std
380                    if maybe_path
381                        .extension()
382                        .map(|os_str| os_str.to_string_lossy().eq_ignore_ascii_case("ap"))
383                        .is_some_and(|res| res)
384                    {
385                    } else {
386                        Err(RuntimeError {
387                            named_source: NamedSource::new(self.get_file_path(), import.module_name.source.clone()),
388                            span: import.module_name.span,
389                            label: "invalid std module".to_string(),
390                            message: format!("std module not found {}", module_name),
391                            help: "if you meant to import a user module please enter the path to the .ap file in question".to_string()
392                            // maybe do a fuzzy module find?
393                        })?;
394                    }
395
396                    // we need to make sure the file is actually there!
397                    if !maybe_path.is_file() {
398                        Err(RuntimeError {
399                            named_source: NamedSource::new(self.get_file_path(), import.module_name.source.clone()),
400                            span: import.module_name.span,
401                            message: format!("file {} does not exist, or is a directory. could not import user module", module_name),
402                            label: "invalid file path".to_string(),
403                            help: "specify a valid path to '.ap' file to import an std module".to_string(),
404                        })?;
405                    }
406
407                    // TODO: BUG: Only can accept an absolute path. work on relative paths
408                    // // attempt to read module
409                    // let (Ok(module_source_code), Some(file_name)) = (fs::read_to_string(maybe_path), maybe_path.file_name()) else {
410                    //     Err(RuntimeError {
411                    //         named_source: NamedSource::new(self.get_file_path(), import.module_name.source.clone()),
412                    //         span: import.module_name.span,
413                    //         message: format!("user module {} exists but could not read source", module_name),
414                    //         label: "failed to read".to_string(),
415                    //         help: "specify a valid path to '.ap' file to import an std module".to_string(),
416                    //     })?
417                    // };
418
419                    // package source code
420                    // let module_source_code: Arc<str> = module_source_code.into();
421
422                    // convert filename into regular string
423                    // let file_name = file_name.to_string_lossy().into_owned();
424
425                    // init the module interpreter
426                    let aplang =
427                        ApLang::new_from_file(maybe_path.to_path_buf()).map_err(|_err| {
428                            RuntimeError {
429                                named_source: NamedSource::new(
430                                    self.get_file_path(),
431                                    import.module_name.source.clone(),
432                                ),
433                                span: import.module_name.span,
434                                message: format!(
435                                    "user module {} exists but could not read source",
436                                    module_name
437                                ),
438                                label: "failed to read module".to_string(),
439                                help: "specify a valid path to '.ap' file to import an std module"
440                                    .to_string(),
441                            }
442                        })?;
443
444                    // lex
445                    let lexed = aplang.lex().map_err(Reports::from).unwrap();
446                    // parseRun
447                    let parsed = lexed.parse().map_err(Reports::from).unwrap();
448                    // execute the module, get the exports
449                    parsed.execute_as_module()?
450                };
451
452                // before actually adding the function, we might have to trim the module
453                // if we're using IMPORT "x" FROM MOD "y"
454                if let Some(functions) = import.only_functions.clone() {
455                    let mut trimmed_module = FunctionMap::new();
456                    // generated functions need to be removed
457                    // we trim the hashmap down to only specify the specified keys
458                    for function in &functions {
459                        let Some(LiteralValue::String(function_name)) = function.literal.as_ref()
460                        else {
461                            unreachable!()
462                        };
463
464                        let Some(function) = module.remove(function_name) else {
465                            return Err(RuntimeError {
466                                named_source: NamedSource::new("", function.source.clone()),
467                                span: function.span,
468                                message: "Invalid Function".to_string(),
469                                help: format!("Function {function_name} does not exist in module {module_name}"),
470                                label: "Does not exist".to_string(),
471                            });
472                        };
473
474                        trimmed_module.insert(function_name.clone(), function);
475                    }
476
477                    module = trimmed_module;
478                }
479
480                // finally, add it
481                self.venv.functions.extend(module);
482
483                Ok(())
484            }
485        }
486    }
487
488    pub fn interpret_expr_temp(&mut self) -> Result<Vec<Value>, RuntimeError> {
489        let expressions: Vec<Expr> = self
490            .ast
491            .program
492            .iter()
493            .filter_map(|stmt| match stmt {
494                Stmt::Expr(expr) => Some((**expr).clone()), // Dereference Arc and clone Expr
495                _ => None,
496            })
497            .collect(); // Collects into Vec<Expr>
498
499        expressions
500            .iter()
501            .map(|expr| self.expr(expr)) // Directly use Expr reference
502            .collect()
503    }
504    fn expr(&mut self, expr: &Expr) -> Result<Value, RuntimeError> {
505        use crate::parser::ast::Expr::*;
506        use crate::parser::ast::LogicalOp;
507        let value = match expr {
508            Grouping(inside) => self.expr(&inside.expr),
509            Literal(lit) => Ok(Self::literal(&lit.value)),
510            Binary(binary) => self.binary(binary.as_ref()),
511            Unary(unary) => self.unary(unary.as_ref()),
512            ProcCall(proc) => self.call(proc.as_ref()),
513            Access(access) => self.access(access.as_ref()),
514            List(list) => self.list(list.as_ref()),
515            Variable(v) => self
516                .venv
517                .lookup_name(
518                    v.ident.clone().as_str(),
519                    v.token.clone(),
520                    self.get_file_path(),
521                )
522                .cloned()
523                .map(|(value, _)| value),
524            Assign(assignment) => {
525                // execute the expression
526                let result = self.expr(&assignment.value)?;
527                match &result {
528                    Value::List(list) => {
529                        match self
530                            .venv
531                            .lookup_var(&assignment.target.clone(), self.get_file_path())
532                        {
533                            Ok(Value::List(target_list)) => {
534                                target_list.swap(list);
535                            }
536                            _ => self.venv.define(assignment.target.clone(), result.clone()),
537                        }
538                    }
539                    _ => self.venv.define(assignment.target.clone(), result.clone()),
540                }
541
542                Ok(result)
543            }
544            Set(set) => self.set(set.as_ref()),
545            Logical(log) => {
546                let left = self.expr(&log.left)?;
547                let short_circuit = match log.operator {
548                    LogicalOp::Or => Self::is_truthy(&left),
549                    LogicalOp::And => !Self::is_truthy(&left),
550                };
551
552                if short_circuit {
553                    Ok(left)
554                } else {
555                    Ok(self.expr(&log.right)?)
556                }
557            }
558        };
559        value
560    }
561
562    fn call(&mut self, proc: &ProcCall) -> Result<Value, RuntimeError> {
563        // todo: look into callee expr
564
565        let mut argument_evaluations = Vec::new();
566
567        for arg in &proc.arguments {
568            argument_evaluations.push(self.expr(arg)?)
569        }
570
571        let callable = self.venv.lookup_function(
572            proc.ident.clone(),
573            proc.token.clone(),
574            self.get_file_path(),
575        )?;
576
577        if callable.arity() as usize != argument_evaluations.len() {
578            return Err(
579                RuntimeError {
580                    named_source: NamedSource::new(self.get_file_path(), proc.token.source.clone()),
581                    span: (proc.parens.0.span.offset() + proc.parens.0.span.len() .. proc.parens.1.span.offset()).into(),
582                    message: "Incorrect Number Of Args".to_string(),
583                    help: "Make sure the you are passing in the correct number of arguments to the PROCEDURE".to_string(),
584                    label: format!("There should be {} arg{}; Found {}", callable.arity(), if callable.arity() == 1 {""} else {"s"}, argument_evaluations.len())
585                }
586            ); // todo make this error message better -- use source proc pointer
587        }
588
589        callable.call(
590            self,
591            argument_evaluations.as_ref(),
592            proc.arguments_spans.as_ref(),
593            proc.token.source.clone(),
594        )
595    }
596
597    // help: a string can be thought of a list of chars
598    fn list(&mut self, list: &crate::parser::ast::List) -> Result<Value, RuntimeError> {
599        list.items
600            .iter()
601            .map(|expr: &Expr| self.expr(expr))
602            .collect::<Result<Vec<Value>, RuntimeError>>()
603            .map(|x| Value::List(RefCell::new(x).into()))
604    }
605
606    fn access(&mut self, access: &crate::parser::ast::Access) -> Result<Value, RuntimeError> {
607        let list = self.expr(&access.list)?;
608        let idx = self.expr(&access.key)?;
609
610        let Value::Number(idx) = idx else {
611            return Err(RuntimeError {
612                named_source: NamedSource::new(
613                    self.get_file_path(),
614                    access.list_token.source.clone(),
615                ),
616                span: (access.brackets.0.span.offset() + access.brackets.0.span.len()
617                    ..access.brackets.1.span.offset())
618                    .into(),
619                message: "Invalid Index".to_string(),
620                help: format!("Make sure index {idx:?} is a NUMBER!"),
621                label: "Index must be a NUMBER!".to_string(),
622            });
623        };
624
625        let target = match &list {
626            Value::String(string) => string
627                .chars()
628                .nth((idx - 1.0) as usize)
629                .map(|ch| Value::String(ch.to_string()))
630                .ok_or_else(|| RuntimeError {
631                    named_source: NamedSource::new(
632                        self.get_file_path(),
633                        access.brackets.0.source.clone(),
634                    ),
635                    span: (access.brackets.0.span.offset() + access.brackets.0.span.len()
636                        ..access.brackets.1.span.offset())
637                        .into(),
638                    message: "Invalid List Index".to_string(),
639                    help: format!("Make sure index `{idx}` is less than {}", string.len()),
640                    label: "Index must be less than the length of the STRING".to_string(),
641                }),
642            Value::List(list) => {
643                list.borrow()
644                    .get((idx - 1.0) as usize)
645                    .cloned()
646                    .ok_or_else(|| RuntimeError {
647                        named_source: NamedSource::new(
648                            self.get_file_path(),
649                            access.brackets.0.source.clone(),
650                        ),
651                        span: (access.brackets.0.span.offset() + access.brackets.0.span.len()
652                            ..access.brackets.1.span.offset())
653                            .into(),
654                        message: "Invalid List Index".to_string(),
655                        help: format!(
656                            "Make sure index `{idx}` is less than {}",
657                            list.borrow().len()
658                        ),
659                        label: "Index must be less than the length of the LIST".to_string(),
660                    })
661            }
662            _ => Err(RuntimeError {
663                named_source: NamedSource::new(
664                    self.get_file_path(),
665                    access.list_token.source.clone(),
666                ),
667                span: access.list_token.span,
668                message: "Invalid Type".to_string(),
669                help: "You can only access STRINGS and LISTS this way".to_string(),
670                label: "This has the wrong type".to_string(),
671            }),
672        };
673
674        target
675    }
676
677    fn set(&mut self, set: &crate::parser::ast::Set) -> Result<Value, RuntimeError> {
678        let list = self.expr(&set.list)?;
679        let idx = self.expr(&set.idx)?;
680        let value = self.expr(&set.value)?;
681
682        let Value::List(ref list) = list else {
683            return Err(RuntimeError {
684                named_source: NamedSource::new(self.get_file_path(), set.list_token.source.clone()),
685                span: set.list_token.span,
686                message: "Invalid Type".to_string(),
687                help: "You can only SET LISTS this way".to_string(),
688                label: "This should be a LIST".to_string(),
689            });
690        };
691
692        let Value::Number(idx) = idx else {
693            return Err(RuntimeError {
694                named_source: NamedSource::new(self.get_file_path(), set.brackets.0.source.clone()),
695                span: (set.brackets.0.span.offset() + set.brackets.0.span.len()
696                    ..set.brackets.1.span.offset())
697                    .into(),
698                message: "Invalid Index".to_string(),
699                help: format!("Make sure index {idx:?} is a NUMBER!"),
700                label: "Index must be a NUMBER!".to_string(),
701            });
702        };
703
704        let mut list_borrowed = list.borrow_mut();
705        if let Some(target) = list_borrowed.get_mut((idx - 1.0) as usize) {
706            *target = value.clone();
707        } else {
708            return Err(RuntimeError {
709                named_source: NamedSource::new(self.get_file_path(), set.brackets.0.source.clone()),
710                span: (set.brackets.0.span.offset() + set.brackets.0.span.len()
711                    ..set.brackets.1.span.offset())
712                    .into(),
713                message: "Invalid List Index".to_string(),
714                help: format!(
715                    "Make sure index `{idx}` is less than {}",
716                    list_borrowed.len()
717                ),
718                label: "Index must be less than the length of the LIST".to_string(),
719            });
720        }
721
722        Ok(value)
723    }
724
725    fn binary(&mut self, node: &Binary) -> Result<Value, RuntimeError> {
726        let lhs = self.expr(&node.left)?;
727        let rhs = self.expr(&node.right)?;
728
729        use crate::interpreter::value::Value::*;
730        use crate::parser::ast::BinaryOp::*;
731        match (&lhs, &node.operator, &rhs) {
732            (_, EqualEqual, _) => Ok(Bool(Self::equals(&lhs, &rhs))),
733            (_, NotEqual, _) => Ok(Bool(!Self::equals(&lhs, &rhs))),
734            (Number(a), Less, Number(b)) => Ok(Bool(a < b)),
735            (Number(a), LessEqual, Number(b)) => Ok(Bool(a <= b)),
736            (Number(a), Greater, Number(b)) => Ok(Bool(a > b)),
737            (Number(a), GreaterEqual, Number(b)) => Ok(Bool(a >= b)),
738            (Number(a), Plus, Number(b)) => Ok(Number(a + b)),
739            (Number(a), Minus, Number(b)) => Ok(Number(a - b)),
740            (Number(a), Star, Number(b)) => Ok(Number(a * b)),
741            (Number(a), Slash, Number(b)) => {
742                if *b != 0.0 {
743                    Ok(Number(a / b))
744                } else {
745                    Err(RuntimeError {
746                        named_source: NamedSource::new(
747                            self.get_file_path(),
748                            node.token.source.clone(),
749                        ),
750                        span: node.token.span,
751                        message: "Division by Zero".to_string(),
752                        help: "Remember not to divide by zero".to_string(),
753                        label: "Cannot divide by zero".to_string(),
754                    })
755                }
756            }
757            (Number(a), Modulo, Number(b)) => {
758                if *b != 0.0 {
759                    Ok(Number(a % b))
760                } else {
761                    Err(RuntimeError {
762                        named_source: NamedSource::new(
763                            self.get_file_path(),
764                            node.token.source.clone(),
765                        ),
766                        span: node.token.span,
767                        message: "Modulo by Zero".to_string(),
768                        help: "Remember not to take a modulo by zero".to_string(),
769                        label: "Cannot modulo by zero".to_string(),
770                    })
771                }
772            }
773            // if we add to a string implicitly cast the other thing to a string for convenience
774            (String(a), Plus, b) => Ok(String(format!("{a}{b}"))),
775            (List(a), Plus, List(b)) => {
776                // adding two lists
777                // todo: consider using try_borrow?
778                let new_list: Vec<_> = a
779                    .borrow()
780                    .iter()
781                    .cloned()
782                    .chain(b.borrow().iter().cloned())
783                    .collect();
784                Ok(List(RefCell::new(new_list).into()))
785            }
786            _ => Err(RuntimeError {
787                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
788                span: node.token.span,
789                message: "Incomparable Values".to_string(),
790                help: format!("Cannot compare {:?} and {:?}", &lhs, &rhs),
791                label: "Cannot compare these two values".to_string(),
792            }),
793        }
794    }
795
796    fn literal(lit: &Literal) -> Value {
797        match lit {
798            Literal::Number(num) => Value::Number(*num),
799            Literal::String(string) => Value::String(string.clone()),
800            Literal::True => Value::Bool(true),
801            Literal::False => Value::Bool(false),
802            Literal::Null => Value::Null,
803        }
804    }
805    fn unary(&mut self, node: &Unary) -> Result<Value, RuntimeError> {
806        let value = self.expr(&node.right)?;
807
808        use crate::interpreter::value::Value::*;
809        use crate::parser::ast::UnaryOp::*;
810        match (&node.operator, value) {
811            (Minus, Number(num)) => Ok(Number(-num)),
812            (Not, value) => Ok(Bool(!Self::is_truthy(&value))),
813            (op, String(_)) => Err(RuntimeError {
814                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
815                span: node.token.span,
816                message: "Invalid Unary Op".to_string(),
817                help: format!("Invalid application of unary op {op} to String type"),
818                label: "Cannot do operand here".to_string(),
819            }),
820            (op, NativeFunction()) => Err(RuntimeError {
821                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
822                span: node.token.span,
823                message: "Invalid Unary Op".to_string(),
824                help: format!("Invalid application of unary op {op} to NativeFunction type"),
825                label: "Cannot do operand here".to_string(),
826            }),
827            (op, Function()) => Err(RuntimeError {
828                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
829                span: node.token.span,
830                message: "Invalid Unary Op".to_string(),
831                help: format!("Invalid application of unary op {op} to Function type"),
832                label: "Cannot do operand here".to_string(),
833            }),
834            (Minus, Bool(b)) => Err(RuntimeError {
835                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
836                span: node.token.span,
837                message: "Invalid Unary Op".to_string(),
838                help: format!("Invalid application of unary op Minus to Bool type (value) {b}"),
839                label: "Cannot do operand here".to_string(),
840            }),
841            (op, Null) => Err(RuntimeError {
842                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
843                span: node.token.span,
844                message: "Invalid Unary Op".to_string(),
845                help: format!("Invalid application of unary op {op} to Null type"),
846                label: "Cannot do operand here".to_string(),
847            }),
848            (op, List(_l)) => Err(RuntimeError {
849                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
850                span: node.token.span,
851                message: "Invalid Unary Op".to_string(),
852                help: format!("Invalid application of unary op {op} to List type"),
853                label: "Cannot do operand here".to_string(),
854            }),
855            (op, NativeObject(_a)) => Err(RuntimeError {
856                named_source: NamedSource::new(self.get_file_path(), node.token.source.clone()),
857                span: node.token.span,
858                message: "Invalid Unary Op".to_string(),
859                help: format!("Invalid application of unary op {op} to NativeObject type"),
860                label: "Cannot do operand here".to_string(),
861            })
862        }
863    }
864
865    fn equals(lhs: &Value, rhs: &Value) -> bool {
866        match (lhs, rhs) {
867            (Value::Number(n1), Value::Number(n2)) => (n1 - n2).abs() < f64::EPSILON,
868            (Value::String(s1), Value::String(s2)) => s1 == s2,
869            (Value::Bool(b1), Value::Bool(b2)) => b1 == b2,
870            (Value::Null, Value::Null) => true,
871            (_, _) => false,
872        }
873    }
874
875    fn is_truthy(value: &Value) -> bool {
876        match value {
877            Value::Bool(b) => *b,
878            Value::Number(n) if *n == 0.0 => false,
879            Value::Null => false,
880            _ => true,
881        }
882    }
883}