Skip to main content

virtual_rust/interpreter/
mod.rs

1//! Tree-walking interpreter for the Virtual Rust VM.
2//!
3//! # Architecture
4//!
5//! The interpreter is split into focused sub-modules:
6//!
7//! | Module          | Responsibility                                    |
8//! |-----------------|---------------------------------------------------|
9//! | [`value`]       | Runtime value types (`Value` enum)                 |
10//! | [`environment`] | Variable scoping (scope stack)                     |
11//! | [`error`]       | `RuntimeError` definition                          |
12//! | [`builtins`]    | Built-in functions & macro dispatch                |
13//! | [`methods`]     | Method call dispatch (String, Array, Int, …)       |
14//! | [`format`]      | Format-string processing (`{}`, `{:?}`, `{:.2}`)  |
15//! | [`pattern`]     | Pattern matching for `match` expressions           |
16//! | [`cast`]        | Type casting (`as` expressions)                    |
17
18pub mod builtins;
19pub mod cast;
20pub mod environment;
21pub mod error;
22pub mod format;
23pub mod methods;
24pub mod pattern;
25pub mod value;
26
27pub use environment::Environment;
28pub use error::RuntimeError;
29pub use value::Value;
30
31use std::collections::HashMap;
32
33use crate::ast::*;
34
35/// The tree-walking interpreter that evaluates an AST.
36///
37/// Maintains an [`Environment`] for variable storage and a registry
38/// of struct definitions encountered during execution.
39pub struct Interpreter {
40    pub env: Environment,
41    struct_defs: HashMap<String, Vec<(String, Type)>>,
42}
43
44impl Default for Interpreter {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl Interpreter {
51    /// Creates a new interpreter with a fresh environment.
52    pub fn new() -> Self {
53        let mut interp = Interpreter {
54            env: Environment::new(),
55            struct_defs: HashMap::new(),
56        };
57        // Register built-in constants
58        interp
59            .env
60            .define("None".to_string(), Value::Option(None), false);
61        interp
62    }
63
64    /// Runs a complete program (list of top-level statements).
65    pub fn run(&mut self, program: Vec<Expr>) -> Result<Value, RuntimeError> {
66        let mut result = Value::Unit;
67        for expr in program {
68            result = self.eval(&expr)?;
69            if let Value::Return(val) = result {
70                return Ok(val.map(|v| *v).unwrap_or(Value::Unit));
71            }
72        }
73        Ok(result)
74    }
75
76    // ── Core evaluation ──────────────────────────────────────────────
77
78    /// Evaluates a single expression / statement.
79    pub fn eval(&mut self, expr: &Expr) -> Result<Value, RuntimeError> {
80        match expr {
81            // ── Literals ─────────────────────────────────────────────
82            Expr::IntLiteral(n) => Ok(Value::Int(*n)),
83            Expr::FloatLiteral(n) => Ok(Value::Float(*n)),
84            Expr::StringLiteral(s) => Ok(Value::String(s.clone())),
85            Expr::CharLiteral(c) => Ok(Value::Char(*c)),
86            Expr::BoolLiteral(b) => Ok(Value::Bool(*b)),
87            Expr::Unit => Ok(Value::Unit),
88
89            // ── Identifiers ──────────────────────────────────────────
90            Expr::Ident(name) => self.eval_ident(name),
91
92            // ── Operators ────────────────────────────────────────────
93            Expr::BinaryOp { left, op, right } => {
94                let lv = self.eval(left)?;
95                let rv = self.eval(right)?;
96                self.eval_binary_op(&lv, op, &rv)
97            }
98            Expr::UnaryOp { op, expr } => {
99                let val = self.eval(expr)?;
100                self.eval_unary_op(op, &val)
101            }
102
103            // ── Bindings & assignment ────────────────────────────────
104            Expr::Let {
105                name,
106                mutable,
107                value,
108                ..
109            } => self.eval_let(name, *mutable, value.as_deref()),
110
111            Expr::Assign { target, value } => {
112                let val = self.eval(value)?;
113                self.assign_to(target, val)?;
114                Ok(Value::Unit)
115            }
116            Expr::CompoundAssign { target, op, value } => {
117                let current = self.eval(target)?;
118                let rhs = self.eval(value)?;
119                let result = self.eval_binary_op(&current, op, &rhs)?;
120                self.assign_to(target, result)?;
121                Ok(Value::Unit)
122            }
123
124            // ── Control flow ─────────────────────────────────────────
125            Expr::Block(stmts) => self.eval_block(stmts),
126            Expr::If {
127                condition,
128                then_block,
129                else_block,
130            } => self.eval_if(condition, then_block, else_block.as_deref()),
131            Expr::While { condition, body } => self.eval_while(condition, body),
132            Expr::Loop { body } => self.eval_loop(body),
133            Expr::For {
134                var,
135                iterator,
136                body,
137            } => self.eval_for(var, iterator, body),
138            Expr::Range {
139                start,
140                end,
141                inclusive,
142            } => self.eval_range(start.as_deref(), end.as_deref(), *inclusive),
143            Expr::Break(val) => {
144                let v = val.as_ref().map(|e| self.eval(e)).transpose()?;
145                Ok(Value::Break(v.map(Box::new)))
146            }
147            Expr::Continue => Ok(Value::Continue),
148            Expr::Return(val) => {
149                let v = val.as_ref().map(|e| self.eval(e)).transpose()?;
150                Ok(Value::Return(v.map(Box::new)))
151            }
152
153            // ── Functions & calls ────────────────────────────────────
154            Expr::FnDef {
155                name, params, body, ..
156            } => self.eval_fn_def(name, params, body),
157
158            Expr::FnCall { name, args } => self.eval_fn_call(name, args),
159
160            Expr::MethodCall {
161                object,
162                method,
163                args,
164            } => {
165                let obj = self.eval(object)?;
166                let evaluated_args = self.eval_slice(args)?;
167                self.call_method(obj, method, evaluated_args)
168            }
169            Expr::MacroCall { name, args } => self.call_macro(name, args),
170
171            // ── Data structures ──────────────────────────────────────
172            Expr::ArrayLiteral(elements) => {
173                let values = self.eval_slice(elements)?;
174                Ok(Value::Array(values))
175            }
176            Expr::ArrayRepeat { value, count } => self.eval_array_repeat(value, count),
177            Expr::TupleLiteral(elements) => {
178                let values = self.eval_slice(elements)?;
179                Ok(Value::Tuple(values))
180            }
181            Expr::VecMacro(elements) => {
182                let values = self.eval_slice(elements)?;
183                Ok(Value::Array(values))
184            }
185
186            // ── Indexing & field access ──────────────────────────────
187            Expr::Index { object, index } => self.eval_index(object, index),
188            Expr::FieldAccess { object, field } => self.eval_field_access(object, field),
189
190            // ── Structs ──────────────────────────────────────────────
191            Expr::StructDef { name, fields } => {
192                self.struct_defs.insert(name.clone(), fields.clone());
193                Ok(Value::Unit)
194            }
195            Expr::StructInit { name, fields } => self.eval_struct_init(name, fields),
196
197            // ── Match ────────────────────────────────────────────────
198            Expr::Match { expr, arms } => self.eval_match(expr, arms),
199
200            // ── Type cast ────────────────────────────────────────────
201            Expr::TypeCast { expr, target_type } => {
202                let val = self.eval(expr)?;
203                cast::type_cast(val, target_type)
204            }
205
206            // ── Closures & references ────────────────────────────────
207            Expr::Closure { params, body } => Ok(Value::Closure {
208                params: params.clone(),
209                body: body.clone(),
210                env: self.env.clone(),
211            }),
212            Expr::Ref { expr, .. } | Expr::Deref(expr) => self.eval(expr),
213        }
214    }
215
216    // ── Evaluation helpers ───────────────────────────────────────────
217
218    fn eval_ident(&self, name: &str) -> Result<Value, RuntimeError> {
219        if name == "Some" {
220            return Ok(Value::Function {
221                name: "Some".to_string(),
222                params: vec![("value".to_string(), Type::Inferred)],
223                body: Box::new(Expr::Ident("value".to_string())),
224                closure_env: None,
225            });
226        }
227        self.env
228            .get(name)
229            .cloned()
230            .ok_or_else(|| RuntimeError::new(format!("Undefined variable: '{name}'")))
231    }
232
233    fn eval_let(
234        &mut self,
235        name: &str,
236        mutable: bool,
237        value: Option<&Expr>,
238    ) -> Result<Value, RuntimeError> {
239        let val = match value {
240            Some(expr) => {
241                let v = self.eval(expr)?;
242                if let Value::Return(_) = &v {
243                    return Ok(v);
244                }
245                v
246            }
247            None => Value::Unit,
248        };
249        self.env.define(name.to_string(), val, mutable);
250        Ok(Value::Unit)
251    }
252
253    fn eval_block(&mut self, stmts: &[Expr]) -> Result<Value, RuntimeError> {
254        self.env.push_scope();
255        let mut result = Value::Unit;
256        for stmt in stmts {
257            result = self.eval(stmt)?;
258            if matches!(&result, Value::Return(_) | Value::Break(_) | Value::Continue) {
259                self.env.pop_scope();
260                return Ok(result);
261            }
262        }
263        self.env.pop_scope();
264        Ok(result)
265    }
266
267    fn eval_if(
268        &mut self,
269        condition: &Expr,
270        then_block: &Expr,
271        else_block: Option<&Expr>,
272    ) -> Result<Value, RuntimeError> {
273        let cond = self.eval(condition)?;
274        if cond.is_truthy() {
275            self.eval(then_block)
276        } else if let Some(else_b) = else_block {
277            self.eval(else_b)
278        } else {
279            Ok(Value::Unit)
280        }
281    }
282
283    fn eval_while(&mut self, condition: &Expr, body: &Expr) -> Result<Value, RuntimeError> {
284        loop {
285            if !self.eval(condition)?.is_truthy() {
286                break;
287            }
288            match self.eval(body)? {
289                Value::Break(v) => return Ok(v.map(|v| *v).unwrap_or(Value::Unit)),
290                Value::Continue => continue,
291                Value::Return(v) => return Ok(Value::Return(v)),
292                _ => {}
293            }
294        }
295        Ok(Value::Unit)
296    }
297
298    fn eval_loop(&mut self, body: &Expr) -> Result<Value, RuntimeError> {
299        loop {
300            match self.eval(body)? {
301                Value::Break(v) => return Ok(v.map(|v| *v).unwrap_or(Value::Unit)),
302                Value::Continue => continue,
303                Value::Return(v) => return Ok(Value::Return(v)),
304                _ => {}
305            }
306        }
307    }
308
309    fn eval_for(
310        &mut self,
311        var: &str,
312        iterator: &Expr,
313        body: &Expr,
314    ) -> Result<Value, RuntimeError> {
315        let iter_val = self.eval(iterator)?;
316        let items = value_to_iterator(iter_val)?;
317        for item in items {
318            self.env.push_scope();
319            self.env.define(var.to_string(), item, true);
320            let result = self.eval(body)?;
321            self.env.pop_scope();
322            match result {
323                Value::Break(v) => return Ok(v.map(|v| *v).unwrap_or(Value::Unit)),
324                Value::Continue => continue,
325                Value::Return(v) => return Ok(Value::Return(v)),
326                _ => {}
327            }
328        }
329        Ok(Value::Unit)
330    }
331
332    fn eval_range(
333        &mut self,
334        start: Option<&Expr>,
335        end: Option<&Expr>,
336        inclusive: bool,
337    ) -> Result<Value, RuntimeError> {
338        let start_val = match start {
339            Some(e) => expect_int(self.eval(e)?, "Range start")?,
340            None => 0,
341        };
342        match end {
343            Some(e) => {
344                let end_val = expect_int(self.eval(e)?, "Range end")?;
345                let items: Vec<Value> = if inclusive {
346                    (start_val..=end_val).map(Value::Int).collect()
347                } else {
348                    (start_val..end_val).map(Value::Int).collect()
349                };
350                Ok(Value::Array(items))
351            }
352            None => Ok(Value::Array(Vec::new())),
353        }
354    }
355
356    // ── Function definitions & calls ─────────────────────────────────
357
358    fn eval_fn_def(
359        &mut self,
360        name: &str,
361        params: &[(String, Type)],
362        body: &Expr,
363    ) -> Result<Value, RuntimeError> {
364        let func = Value::Function {
365            name: name.to_string(),
366            params: params.to_vec(),
367            body: Box::new(body.clone()),
368            closure_env: None,
369        };
370        self.env.define(name.to_string(), func, false);
371        Ok(Value::Unit)
372    }
373
374    fn eval_fn_call(&mut self, name: &str, args: &[Expr]) -> Result<Value, RuntimeError> {
375        let evaluated_args = self.eval_slice(args)?;
376
377        // Try built-ins first
378        if let Some(result) = self.call_builtin(name, &evaluated_args)? {
379            return Ok(result);
380        }
381
382        let func = self
383            .env
384            .get(name)
385            .cloned()
386            .ok_or_else(|| RuntimeError::new(format!("Undefined function: '{name}'")))?;
387
388        self.call_function(func, evaluated_args)
389    }
390
391    /// Calls a function or closure value with the given arguments.
392    pub(crate) fn call_function(
393        &mut self,
394        func: Value,
395        args: Vec<Value>,
396    ) -> Result<Value, RuntimeError> {
397        match func {
398            Value::Function {
399                params,
400                body,
401                closure_env,
402                ..
403            } => {
404                let saved_env = self.env.clone();
405                if let Some(env) = closure_env {
406                    self.env = env;
407                }
408                self.env.push_scope();
409                for (i, (param_name, _)) in params.iter().enumerate() {
410                    let val = args.get(i).cloned().unwrap_or(Value::Unit);
411                    self.env.define(param_name.clone(), val, true);
412                }
413                let result = self.eval(&body)?;
414                self.env.pop_scope();
415                self.env = saved_env;
416                unwrap_return(result)
417            }
418            Value::Closure {
419                params, body, env, ..
420            } => {
421                let saved_env = self.env.clone();
422                self.env = env;
423                self.env.push_scope();
424                for (i, (param_name, _)) in params.iter().enumerate() {
425                    let val = args.get(i).cloned().unwrap_or(Value::Unit);
426                    self.env.define(param_name.clone(), val, true);
427                }
428                let result = self.eval(&body)?;
429                self.env.pop_scope();
430                self.env = saved_env;
431                unwrap_return(result)
432            }
433            _ => Err(RuntimeError::new(format!(
434                "'{}' is not callable",
435                func.type_name()
436            ))),
437        }
438    }
439
440    // ── Data structure evaluation ────────────────────────────────────
441
442    fn eval_array_repeat(
443        &mut self,
444        value: &Expr,
445        count: &Expr,
446    ) -> Result<Value, RuntimeError> {
447        let val = self.eval(value)?;
448        let cnt = expect_int(self.eval(count)?, "Array repeat count")? as usize;
449        Ok(Value::Array(vec![val; cnt]))
450    }
451
452    fn eval_index(&mut self, object: &Expr, index: &Expr) -> Result<Value, RuntimeError> {
453        let obj = self.eval(object)?;
454        let idx = self.eval(index)?;
455
456        match (&obj, &idx) {
457            (Value::Array(arr), Value::Int(i)) => {
458                let index = normalize_index(*i, arr.len());
459                arr.get(index).cloned().ok_or_else(|| {
460                    RuntimeError::new(format!(
461                        "Index {i} out of bounds for array of length {}",
462                        arr.len()
463                    ))
464                })
465            }
466            (Value::String(s), Value::Int(i)) => {
467                let index = normalize_index(*i, s.len());
468                s.chars().nth(index).map(Value::Char).ok_or_else(|| {
469                    RuntimeError::new(format!(
470                        "Index {i} out of bounds for string of length {}",
471                        s.len()
472                    ))
473                })
474            }
475            (Value::Tuple(elems), Value::Int(i)) => {
476                elems.get(*i as usize).cloned().ok_or_else(|| {
477                    RuntimeError::new(format!(
478                        "Index {i} out of bounds for tuple of length {}",
479                        elems.len()
480                    ))
481                })
482            }
483            _ => Err(RuntimeError::new(format!(
484                "Cannot index {} with {}",
485                obj.type_name(),
486                idx.type_name()
487            ))),
488        }
489    }
490
491    fn eval_field_access(&mut self, object: &Expr, field: &str) -> Result<Value, RuntimeError> {
492        let obj = self.eval(object)?;
493        match &obj {
494            Value::Struct { fields, .. } => {
495                fields.get(field).cloned().ok_or_else(|| {
496                    RuntimeError::new(format!("No field '{field}' on struct"))
497                })
498            }
499            Value::Tuple(elements) => {
500                let idx: usize = field.parse().map_err(|_| {
501                    RuntimeError::new(format!("Invalid tuple field: {field}"))
502                })?;
503                elements.get(idx).cloned().ok_or_else(|| {
504                    RuntimeError::new(format!("Tuple index {idx} out of bounds"))
505                })
506            }
507            _ => Err(RuntimeError::new(format!(
508                "Cannot access field '{field}' on {}",
509                obj.type_name()
510            ))),
511        }
512    }
513
514    fn eval_struct_init(
515        &mut self,
516        name: &str,
517        fields: &[(String, Expr)],
518    ) -> Result<Value, RuntimeError> {
519        let mut field_values = HashMap::new();
520        for (fname, fexpr) in fields {
521            field_values.insert(fname.clone(), self.eval(fexpr)?);
522        }
523        Ok(Value::Struct {
524            name: name.to_string(),
525            fields: field_values,
526        })
527    }
528
529    fn eval_match(&mut self, expr: &Expr, arms: &[MatchArm]) -> Result<Value, RuntimeError> {
530        let val = self.eval(expr)?;
531        for arm in arms {
532            if self.match_pattern(&arm.pattern, &val)? {
533                self.env.push_scope();
534                self.bind_pattern(&arm.pattern, &val)?;
535                let result = self.eval(&arm.body)?;
536                self.env.pop_scope();
537                return Ok(result);
538            }
539        }
540        Err(RuntimeError::new("Non-exhaustive match"))
541    }
542
543    // ── Assignment targets ───────────────────────────────────────────
544
545    fn assign_to(&mut self, target: &Expr, value: Value) -> Result<(), RuntimeError> {
546        match target {
547            Expr::Ident(name) => self.env.set(name, value),
548            Expr::Index { object, index } => self.assign_to_index(object, index, value),
549            Expr::FieldAccess { object, field } => self.assign_to_field(object, field, value),
550            _ => Err(RuntimeError::new("Invalid assignment target")),
551        }
552    }
553
554    fn assign_to_index(
555        &mut self,
556        object: &Expr,
557        index: &Expr,
558        value: Value,
559    ) -> Result<(), RuntimeError> {
560        let Expr::Ident(name) = object else {
561            return Err(RuntimeError::new("Complex index assignment not supported"));
562        };
563        let idx = expect_int(self.eval(index)?, "Index")? as usize;
564        let mut arr = self
565            .env
566            .get(name)
567            .cloned()
568            .ok_or_else(|| RuntimeError::new(format!("Undefined variable: '{name}'")))?;
569        let Value::Array(ref mut elements) = arr else {
570            return Err(RuntimeError::new("Cannot index non-array"));
571        };
572        if idx >= elements.len() {
573            return Err(RuntimeError::new(format!("Index {idx} out of bounds")));
574        }
575        elements[idx] = value;
576        self.env.set(name, arr)
577    }
578
579    fn assign_to_field(
580        &mut self,
581        object: &Expr,
582        field: &str,
583        value: Value,
584    ) -> Result<(), RuntimeError> {
585        let Expr::Ident(name) = object else {
586            return Err(RuntimeError::new("Complex field assignment not supported"));
587        };
588        let mut obj = self
589            .env
590            .get(name)
591            .cloned()
592            .ok_or_else(|| RuntimeError::new(format!("Undefined variable: '{name}'")))?;
593        let Value::Struct { ref mut fields, .. } = obj else {
594            return Err(RuntimeError::new("Cannot set field on non-struct"));
595        };
596        fields.insert(field.to_string(), value);
597        self.env.set(name, obj)
598    }
599
600    // ── Binary / unary operators ─────────────────────────────────────
601
602    pub(crate) fn eval_binary_op(
603        &self,
604        left: &Value,
605        op: &BinOp,
606        right: &Value,
607    ) -> Result<Value, RuntimeError> {
608        // String concatenation
609        if let (Value::String(a), BinOp::Add, Value::String(b)) = (left, op, right) {
610            return Ok(Value::String(format!("{a}{b}")));
611        }
612
613        match (left, right) {
614            (Value::Int(a), Value::Int(b)) => eval_int_op(*a, op, *b),
615            (Value::Float(a), Value::Float(b)) => eval_float_op(*a, op, *b),
616            (Value::Int(a), Value::Float(b)) => eval_float_op(*a as f64, op, *b),
617            (Value::Float(a), Value::Int(b)) => eval_float_op(*a, op, *b as f64),
618            (Value::Bool(a), Value::Bool(b)) => eval_bool_op(*a, op, *b),
619            (Value::String(a), Value::String(b)) => eval_string_cmp(a, op, b),
620            _ => Err(RuntimeError::new(format!(
621                "Cannot apply {op:?} to {} and {}",
622                left.type_name(),
623                right.type_name()
624            ))),
625        }
626    }
627
628    fn eval_unary_op(&self, op: &UnaryOp, val: &Value) -> Result<Value, RuntimeError> {
629        match (op, val) {
630            (UnaryOp::Neg, Value::Int(n)) => Ok(Value::Int(-n)),
631            (UnaryOp::Neg, Value::Float(n)) => Ok(Value::Float(-n)),
632            (UnaryOp::Not, Value::Bool(b)) => Ok(Value::Bool(!b)),
633            (UnaryOp::Not, Value::Int(n)) => Ok(Value::Int(!n)),
634            _ => Err(RuntimeError::new(format!(
635                "Cannot apply {op:?} to {}",
636                val.type_name()
637            ))),
638        }
639    }
640
641    /// Checks value equality using the `==` binary operator.
642    pub(crate) fn values_equal(&self, left: &Value, right: &Value) -> bool {
643        matches!(
644            self.eval_binary_op(left, &BinOp::Eq, right),
645            Ok(Value::Bool(true))
646        )
647    }
648
649    /// Processes a format string; delegates to [`format::format_string`].
650    pub(crate) fn format_string(
651        &self,
652        fmt: &str,
653        args: &[Value],
654    ) -> Result<String, RuntimeError> {
655        format::format_string(fmt, args)
656    }
657}
658
659// ── Free-standing helpers ────────────────────────────────────────────────
660
661/// Converts a value into an iterable list of values.
662fn value_to_iterator(val: Value) -> Result<Vec<Value>, RuntimeError> {
663    match val {
664        Value::Array(items) => Ok(items),
665        Value::String(s) => Ok(s.chars().map(Value::Char).collect()),
666        _ => Err(RuntimeError::new(format!(
667            "Cannot iterate over {}",
668            val.type_name()
669        ))),
670    }
671}
672
673/// Unwraps a `Value::Return` into its inner value.
674fn unwrap_return(result: Value) -> Result<Value, RuntimeError> {
675    match result {
676        Value::Return(Some(v)) => Ok(*v),
677        Value::Return(None) => Ok(Value::Unit),
678        other => Ok(other),
679    }
680}
681
682/// Extracts an `i64` from a `Value::Int`, or returns an error.
683fn expect_int(val: Value, context: &str) -> Result<i64, RuntimeError> {
684    match val {
685        Value::Int(n) => Ok(n),
686        other => Err(RuntimeError::new(format!(
687            "{context} must be integer, got {}",
688            other.type_name()
689        ))),
690    }
691}
692
693/// Normalizes a potentially-negative index into a valid `usize`.
694fn normalize_index(i: i64, len: usize) -> usize {
695    if i < 0 {
696        (len as i64 + i) as usize
697    } else {
698        i as usize
699    }
700}
701
702// ── Operator evaluation (pure functions) ─────────────────────────────────
703
704fn eval_int_op(a: i64, op: &BinOp, b: i64) -> Result<Value, RuntimeError> {
705    match op {
706        BinOp::Add => Ok(Value::Int(a.wrapping_add(b))),
707        BinOp::Sub => Ok(Value::Int(a.wrapping_sub(b))),
708        BinOp::Mul => Ok(Value::Int(a.wrapping_mul(b))),
709        BinOp::Div => {
710            if b == 0 {
711                Err(RuntimeError::new("Division by zero"))
712            } else {
713                Ok(Value::Int(a / b))
714            }
715        }
716        BinOp::Mod => {
717            if b == 0 {
718                Err(RuntimeError::new("Modulo by zero"))
719            } else {
720                Ok(Value::Int(a % b))
721            }
722        }
723        BinOp::Eq => Ok(Value::Bool(a == b)),
724        BinOp::NotEq => Ok(Value::Bool(a != b)),
725        BinOp::Lt => Ok(Value::Bool(a < b)),
726        BinOp::LtEq => Ok(Value::Bool(a <= b)),
727        BinOp::Gt => Ok(Value::Bool(a > b)),
728        BinOp::GtEq => Ok(Value::Bool(a >= b)),
729        BinOp::BitAnd => Ok(Value::Int(a & b)),
730        BinOp::BitOr => Ok(Value::Int(a | b)),
731        BinOp::BitXor => Ok(Value::Int(a ^ b)),
732        BinOp::Shl => Ok(Value::Int(a << b)),
733        BinOp::Shr => Ok(Value::Int(a >> b)),
734        _ => Err(RuntimeError::new(format!(
735            "Unsupported operation {op:?} on integers"
736        ))),
737    }
738}
739
740fn eval_float_op(a: f64, op: &BinOp, b: f64) -> Result<Value, RuntimeError> {
741    match op {
742        BinOp::Add => Ok(Value::Float(a + b)),
743        BinOp::Sub => Ok(Value::Float(a - b)),
744        BinOp::Mul => Ok(Value::Float(a * b)),
745        BinOp::Div => Ok(Value::Float(a / b)),
746        BinOp::Mod => Ok(Value::Float(a % b)),
747        BinOp::Eq => Ok(Value::Bool(a == b)),
748        BinOp::NotEq => Ok(Value::Bool(a != b)),
749        BinOp::Lt => Ok(Value::Bool(a < b)),
750        BinOp::LtEq => Ok(Value::Bool(a <= b)),
751        BinOp::Gt => Ok(Value::Bool(a > b)),
752        BinOp::GtEq => Ok(Value::Bool(a >= b)),
753        _ => Err(RuntimeError::new(format!(
754            "Unsupported operation {op:?} on floats"
755        ))),
756    }
757}
758
759fn eval_bool_op(a: bool, op: &BinOp, b: bool) -> Result<Value, RuntimeError> {
760    match op {
761        BinOp::And => Ok(Value::Bool(a && b)),
762        BinOp::Or => Ok(Value::Bool(a || b)),
763        BinOp::Eq => Ok(Value::Bool(a == b)),
764        BinOp::NotEq => Ok(Value::Bool(a != b)),
765        _ => Err(RuntimeError::new(format!(
766            "Unsupported operation {op:?} on booleans"
767        ))),
768    }
769}
770
771fn eval_string_cmp(a: &str, op: &BinOp, b: &str) -> Result<Value, RuntimeError> {
772    match op {
773        BinOp::Eq => Ok(Value::Bool(a == b)),
774        BinOp::NotEq => Ok(Value::Bool(a != b)),
775        BinOp::Lt => Ok(Value::Bool(a < b)),
776        BinOp::LtEq => Ok(Value::Bool(a <= b)),
777        BinOp::Gt => Ok(Value::Bool(a > b)),
778        BinOp::GtEq => Ok(Value::Bool(a >= b)),
779        _ => Err(RuntimeError::new(format!(
780            "Unsupported operation {op:?} on strings"
781        ))),
782    }
783}