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#[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![], modules: Modules::init(),
49 };
50 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 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; Ok(self.venv.exports)
89 }
90
91 pub fn interpret(&mut self) -> Result<(), RuntimeError> {
92 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; 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); 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; Ok(values)
125 }
126
127 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 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 self.loop_stack.push(LoopControl::default());
146
147 for _ in 1..=count as usize {
149 self.stmt(&repeat_times.body)?;
150
151 if self.loop_stack.last().unwrap().should_continue {
153 self.loop_stack.last_mut().unwrap().should_continue = false;
154 continue;
155 }
156
157 if self.loop_stack.last().unwrap().should_break {
159 self.loop_stack.last_mut().unwrap().should_break = false;
160 break;
161 }
162 }
163
164 assert!(self.loop_stack.pop().is_some());
166
167 Ok(())
168 } 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 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 self.loop_stack.last().unwrap().should_break {
190 self.loop_stack.last_mut().unwrap().should_break = false;
191 break;
192 }
193
194 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 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 let maybe_cached = self.venv.remove(element.clone());
234
235 self.loop_stack.push(LoopControl::default());
237
238 let len = values.borrow().len();
239 for i in 0..len {
240 self.venv
242 .define(element.clone(), values.borrow()[i].clone());
243 self.stmt(&for_each.body)?;
247
248 if self.loop_stack.last().unwrap().should_break {
250 self.loop_stack.last_mut().unwrap().should_break = false;
251 break;
252 }
253 if self.loop_stack.last().unwrap().should_continue {
256 self.loop_stack.last_mut().unwrap().should_continue = false;
257 continue;
258 }
259
260 (*values.borrow_mut())[i] = self.venv.remove(element.clone()).unwrap().0;
262 }
263
264 assert!(self.loop_stack.pop().is_some());
265
266 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 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 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 self.loop_stack.last_mut().unwrap().should_continue = true;
312
313 Ok(())
314 }
315 Stmt::Break(_brk) => {
316 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 break;
335 }
336
337 self.stmt(stmt)?
338 }
339
340 self.venv.flatten_nested_layer();
341
342 Ok(())
343 }
344 Stmt::Import(import) => {
345 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 injector()
354 } else {
355 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 current_module_path.pop();
373 let maybe_path = current_module_path.join(module_name);
376
377 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 })?;
394 }
395
396 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 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 let lexed = aplang.lex().map_err(Reports::from).unwrap();
446 let parsed = lexed.parse().map_err(Reports::from).unwrap();
448 parsed.execute_as_module()?
450 };
451
452 if let Some(functions) = import.only_functions.clone() {
455 let mut trimmed_module = FunctionMap::new();
456 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 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()), _ => None,
496 })
497 .collect(); expressions
500 .iter()
501 .map(|expr| self.expr(expr)) .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 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 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 ); }
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 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 (String(a), Plus, b) => Ok(String(format!("{a}{b}"))),
775 (List(a), Plus, List(b)) => {
776 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}