Skip to main content

rl_lang/interpreter/
evaluator.rs

1//! Core evaluator - expression evaluation, function calls, and the runtime state.
2
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::rc::Rc;
6use std::sync::Arc;
7
8use crate::interpreter::stdlib::http::HttpHandle;
9use crate::interpreter::stdlib::net::NetHandle;
10use crate::interpreter::stdlib::random::xoshiro::Xoshiro256;
11use crate::interpreter::values::FunctionData;
12use crate::lexer::tokentypes::TokenType;
13use crate::resolver::Resolver;
14use crate::{
15    ast::{ExprId, nodes::ExpressionKind, statements::TypeAnnotation},
16    interpreter::{
17        native::{IntoNativeFn, Module},
18        stdlib,
19        values::{MapKey, Value},
20    },
21    utils::{
22        errors::{Error, Reason},
23        source::SourceFile,
24        span::Span,
25        suggest::closest_match,
26    },
27};
28
29/// A slot in the environment - holds a value, its declared type, and mutability.
30#[derive(Debug, Clone, PartialEq)]
31pub struct PItem {
32    /// The runtime value stored in this slot.
33    pub value: Value,
34    /// The declared type of this slot, used for assignment type checking.
35    pub type_annotation: TypeAnnotation,
36    /// Whether this slot is immutable (`CONST`).
37    pub is_const: bool,
38}
39
40/// A single environment entry. Currently only [`PItem`] exists;
41/// the enum wrapper leaves room for future variants (e.g. closures, records).
42#[derive(Debug, Clone, PartialEq)]
43pub enum EnvironmentItem {
44    PItem(PItem),
45}
46
47/// The tree-walking interpreter, carrying all runtime state.
48pub struct Evaluator {
49    /// Global scope, addressed at the outermost depth
50    pub globals: Vec<EnvironmentItem>,
51    /// The environment stack - each frame is a scope; innermost is last.
52    /// Holds only local call frames
53    pub environment: Vec<Vec<EnvironmentItem>>,
54    /// Pool of previously-used, now-empty scope frames. `push_scope`/
55    /// `pop_scope` recycle through here instead of allocating a fresh
56    /// `Vec` on every function call and block entry - a hot recursive
57    /// function otherwise pays one malloc+free per call just for its frame.
58    pub scope_pool: Vec<Vec<EnvironmentItem>>,
59    /// Source file for Ariadne error rendering; `None` in embedded/test contexts.
60    pub source_file: Option<SourceFile>,
61    /// The stdlib module tree, used for resolving `std::*` calls.
62    pub root_module: Module,
63    /// Set by a `return` statement; cleared when the enclosing function call collects it.
64    pub return_value: Option<Value>,
65    /// Set by `break`; cleared by the enclosing loop after it exits.
66    pub is_breaking: bool,
67    /// Set by `continue`; cleared by the enclosing loop at the top of the next iteration.
68    pub is_continuing: bool,
69    /// When `Some`, `print`/`println` write here instead of stdout (used by the LSP and REPL).
70    pub output_buffer: Option<String>,
71    /// The Xoshiro256** PRNG instance shared across all `std::random` calls.
72    pub rng: Xoshiro256,
73    /// The resolver, kept alive so import statements can resolve newly loaded files inline.
74    /// Also owns `ast_arena: Ast` - the single expression arena for this session,
75    /// shared by the resolver and evaluator alike. Never construct a second `Ast`
76    /// anywhere else; everything reads/writes through `self.resolver.ast_arena`.
77    pub resolver: Resolver,
78    /// Maps top-level function names to their environment slot for `call_path` shortcut.
79    pub fn_names: HashMap<String, usize>,
80    // for diffrent calls
81    pub user_args_offset: usize,
82    /// Side-table of native networking resources (`std::net`), keyed by handle id.
83    pub net_handles: HashMap<i64, NetHandle>,
84    /// Next handle id to hand out for `std::net` resources; only ever increments.
85    pub net_next_handle: i64,
86    /// Side-table of native HTTP resources (`std::http`), keyed by handle id.
87    pub http_handles: HashMap<i64, HttpHandle>,
88    /// Next handle id to hand out for `std::http` resources; only ever increments.
89    pub http_next_handle: i64,
90    /// Maps `record` type names to their declared `(field name, field type)` list,
91    /// in declaration order. Populated when a `RecordDeclaration` statement runs.
92    pub records: HashMap<String, Vec<(String, TypeAnnotation)>>,
93    /// Maps `tag` (enum) type names to their declared variant name list,
94    /// in declaration order. Populated when a `TagDeclaration` statement runs.
95    pub tags: HashMap<String, Vec<String>>,
96}
97
98impl Default for Evaluator {
99    fn default() -> Self {
100        Self::new()
101    }
102}
103
104impl Evaluator {
105    pub fn new() -> Self {
106        Self {
107            globals: vec![],
108            environment: vec![],
109            scope_pool: vec![],
110            source_file: None,
111            root_module: Module::new(""),
112            return_value: None,
113            is_breaking: false,
114            is_continuing: false,
115            output_buffer: None,
116            rng: Xoshiro256::default(),
117            resolver: Resolver::new(),
118            fn_names: HashMap::new(),
119            user_args_offset: 1,
120            net_handles: HashMap::new(),
121            net_next_handle: 1,
122            http_handles: HashMap::new(),
123            http_next_handle: 1,
124            records: HashMap::new(),
125            tags: HashMap::new(),
126        }
127    }
128
129    /// Attaches a source file for error rendering.
130    pub fn with_source_file(mut self, file: SourceFile) -> Self {
131        self.source_file = Some(file);
132        self
133    }
134
135    /// Attaches a source file for error rendering (mutable reference variant).
136    pub fn set_source_file(&mut self, file: SourceFile) {
137        self.source_file = Some(file);
138    }
139
140    /// Registers a [`Module`] as a submodule of the root module.
141    pub fn with_module(mut self, m: Module) -> Self {
142        self.root_module.submodules.insert(m.name.clone(), m);
143        self
144    }
145
146    /// Registers a typed Rust function directly on the root module.
147    pub fn with_function<F, A>(mut self, name: impl Into<String>, f: F) -> Self
148    where
149        F: IntoNativeFn<A>,
150    {
151        self.root_module
152            .functions
153            .insert(name.into(), f.into_native());
154        self
155    }
156
157    /// Loads the full stdlib into the root module under `std::*`.
158    pub fn with_stdlib(self) -> Self {
159        self.with_module(
160            Module::new("std")
161                .with_module(stdlib::math::module())
162                .with_module(stdlib::io::module())
163                .with_module(stdlib::bitwise::module())
164                .with_module(stdlib::string::module())
165                .with_module(stdlib::types::module())
166                .with_module(stdlib::array::module())
167                .with_module(stdlib::path::module())
168                .with_module(stdlib::fs::module())
169                .with_module(stdlib::random::module())
170                .with_module(stdlib::time::module())
171                .with_module(stdlib::process::module())
172                .with_module(stdlib::result::module())
173                .with_module(stdlib::terminal::module())
174                .with_module(stdlib::rl::module())
175                .with_module(stdlib::debug::module())
176                .with_module(stdlib::net::module())
177                .with_module(stdlib::http::module()),
178        )
179    }
180
181    pub fn with_user_args_offset(mut self, offset: usize) -> Self {
182        self.user_args_offset = offset;
183        self
184    }
185
186    /// Build a [`Reason::Runtime`] error anchored at `span`, with source attached when known.
187    pub fn err(&self, message: impl Into<String>, span: Span) -> Error {
188        let err = Error::at(Reason::Runtime, message, span);
189        match &self.source_file {
190            Some(file) => err.with_source_file(file),
191            None => err,
192        }
193    }
194
195    /// Infers the [`TypeAnnotation`] of a runtime [`Value`].
196    ///
197    /// For arrays, uses the type of the first element; empty arrays infer `Null`.
198    /// `is_const` controls whether the result is the mutable or const variant.
199    pub fn infer_type(value: &Value, is_const: bool) -> TypeAnnotation {
200        match value {
201            Value::Integer(_) => {
202                if is_const {
203                    TypeAnnotation::CInt
204                } else {
205                    TypeAnnotation::Int
206                }
207            }
208            Value::Float(_) => {
209                if is_const {
210                    TypeAnnotation::CFloat
211                } else {
212                    TypeAnnotation::Float
213                }
214            }
215            Value::String(_) => {
216                if is_const {
217                    TypeAnnotation::CString
218                } else {
219                    TypeAnnotation::String
220                }
221            }
222            Value::Bool(_) => {
223                if is_const {
224                    TypeAnnotation::CBool
225                } else {
226                    TypeAnnotation::Bool
227                }
228            }
229            Value::Byte(_) => {
230                if is_const {
231                    TypeAnnotation::CByte
232                } else {
233                    TypeAnnotation::Byte
234                }
235            }
236            Value::Char(_) => {
237                if is_const {
238                    TypeAnnotation::CChar
239                } else {
240                    TypeAnnotation::Char
241                }
242            }
243            Value::Values { items, .. } => {
244                let inner = items
245                    .first()
246                    .map(|v| Self::infer_type(v, false))
247                    .unwrap_or(TypeAnnotation::Null);
248                if is_const {
249                    TypeAnnotation::CArray(Box::new(inner))
250                } else {
251                    TypeAnnotation::Array(Box::new(inner))
252                }
253            }
254            Value::Set { items, .. } => {
255                let inner = items
256                    .first()
257                    .map(|v| Self::infer_type(v, false))
258                    .unwrap_or(TypeAnnotation::Null);
259                if is_const {
260                    TypeAnnotation::CSet(Box::new(inner))
261                } else {
262                    TypeAnnotation::Set(Box::new(inner))
263                }
264            }
265            Value::Map {
266                key_type,
267                value_type,
268                ..
269            } => {
270                if is_const {
271                    TypeAnnotation::CMap(Box::new(key_type.clone()), Box::new(value_type.clone()))
272                } else {
273                    TypeAnnotation::Map(Box::new(key_type.clone()), Box::new(value_type.clone()))
274                }
275            }
276            Value::Struct { name, .. } => {
277                if is_const {
278                    TypeAnnotation::CRecord(name.clone())
279                } else {
280                    TypeAnnotation::Record(name.clone())
281                }
282            }
283            Value::Enum { name, .. } => {
284                if is_const {
285                    TypeAnnotation::CEnum(name.clone())
286                } else {
287                    TypeAnnotation::Enum(name.clone())
288                }
289            }
290            Value::Null => TypeAnnotation::Null,
291            Value::Function { .. } => TypeAnnotation::Fn,
292            Value::Tuple(items) => {
293                let inner: Vec<TypeAnnotation> =
294                    items.iter().map(|v| Self::infer_type(v, false)).collect();
295                if is_const {
296                    TypeAnnotation::CTuple(Rc::new(inner))
297                } else {
298                    TypeAnnotation::Tuple(Rc::new(inner))
299                }
300            }
301            Value::Error(_) => {
302                if is_const {
303                    TypeAnnotation::CError
304                } else {
305                    TypeAnnotation::Error
306                }
307            }
308            Value::Ok(inner) | Value::Err(inner) => {
309                let inner_ty = Self::infer_type(inner, false);
310                if is_const {
311                    TypeAnnotation::CResult(Box::new(inner_ty))
312                } else {
313                    TypeAnnotation::Result(Box::new(inner_ty))
314                }
315            }
316        }
317    }
318
319    /// Returns `true` if `value`'s inferred type is compatible with `expected`.
320    pub fn value_compatible(value: &Value, expected: &TypeAnnotation) -> bool {
321        let actual = Self::infer_type(value, false);
322        Self::types_compatible(&actual, expected)
323    }
324
325    /// Returns `true` if `actual` and `expected` types are assignment-compatible.
326    ///
327    /// Compatibility rules (beyond equality):
328    /// - `Null` is compatible with anything
329    /// - `Byte` widens to `Int` / `CInt`
330    /// - Arrays are compatible if their element types are compatible (recursive)
331    pub fn types_compatible(actual: &TypeAnnotation, expected: &TypeAnnotation) -> bool {
332        if actual == expected {
333            return true;
334        }
335        if *actual == TypeAnnotation::Null {
336            return true;
337        }
338        if *expected == TypeAnnotation::Null {
339            return true;
340        }
341        match (actual, expected) {
342            (
343                TypeAnnotation::Array(a) | TypeAnnotation::CArray(a),
344                TypeAnnotation::Array(b) | TypeAnnotation::CArray(b),
345            ) => Self::types_compatible(a, b),
346            (
347                TypeAnnotation::Tuple(a) | TypeAnnotation::CTuple(a),
348                TypeAnnotation::Tuple(b) | TypeAnnotation::CTuple(b),
349            ) => {
350                a.len() == b.len()
351                    && a.iter()
352                        .zip(b.iter())
353                        .all(|(x, y)| Self::types_compatible(x, y))
354            }
355            (
356                TypeAnnotation::Error | TypeAnnotation::CError,
357                TypeAnnotation::Error | TypeAnnotation::CError,
358            ) => true,
359            (
360                TypeAnnotation::Record(a) | TypeAnnotation::CRecord(a),
361                TypeAnnotation::Record(b) | TypeAnnotation::CRecord(b),
362            ) => a == b,
363            (
364                TypeAnnotation::Result(_) | TypeAnnotation::CResult(_),
365                TypeAnnotation::Result(_) | TypeAnnotation::CResult(_),
366            ) => true,
367            (
368                TypeAnnotation::Enum(a) | TypeAnnotation::CEnum(a),
369                TypeAnnotation::Enum(b) | TypeAnnotation::CEnum(b),
370            ) => a == b,
371            (
372                TypeAnnotation::Map(ak, av) | TypeAnnotation::CMap(ak, av),
373                TypeAnnotation::Map(bk, bv) | TypeAnnotation::CMap(bk, bv),
374            ) => Self::types_compatible(ak, bk) && Self::types_compatible(av, bv),
375            (
376                TypeAnnotation::Set(a) | TypeAnnotation::CSet(a),
377                TypeAnnotation::Set(b) | TypeAnnotation::CSet(b),
378            ) => Self::types_compatible(a, b),
379            _ => false,
380        }
381    }
382
383    /// Return an error if `value` is [`Value::Null`], pointing at `span`.
384    pub fn check_not_null(&self, value: &Value, span: Span) -> Result<(), Error> {
385        if matches!(value, Value::Null) {
386            Err(self.err("value is null", span))
387        } else {
388            Ok(())
389        }
390    }
391
392    pub fn evaluate(&mut self, id: ExprId) -> Result<Value, Error> {
393        let span = self.resolver.ast_arena.exprs.get(id).span;
394
395        #[cfg(feature = "debug")]
396        log::trace!("evaluate {:?} @ {:?}", id, span);
397
398        match &self.resolver.ast_arena.exprs.get(id).kind {
399            ExpressionKind::Null => Ok(Value::Null),
400            ExpressionKind::Integer(i) => Ok(Value::Integer(*i)),
401            ExpressionKind::Byte(b) => Ok(Value::Byte(*b)),
402            ExpressionKind::Bool(b) => Ok(Value::Bool(*b)),
403            ExpressionKind::Float(f) => Ok(Value::Float(*f)),
404            ExpressionKind::Character(c) => Ok(Value::Char(*c)),
405            ExpressionKind::String(s) => {
406                let s = s.clone();
407                Ok(Value::String(s))
408            }
409
410            ExpressionKind::Index { target, index } => {
411                let (target, index) = (*target, *index);
412                let target_span = self.resolver.ast_arena.exprs.get(target).span;
413                let index_span = self.resolver.ast_arena.exprs.get(index).span;
414
415                if let ExpressionKind::ResolvedIdentifier { depth, slot, .. } =
416                    &self.resolver.ast_arena.exprs.get(target).kind
417                {
418                    let (depth, slot) = (*depth, *slot);
419                    let idx = self.evaluate(index)?;
420                    self.check_not_null(&idx, index_span)?;
421                    match idx {
422                        Value::Integer(i) => {
423                            if i < 0 {
424                                return Err(
425                                    self.err(format!("index cannot be negative: {}", i), span)
426                                );
427                            }
428                            return self.index_read(depth, slot, &[i as usize], span);
429                        }
430                        Value::Byte(b) => {
431                            return self.index_read(depth, slot, &[b as usize], span);
432                        }
433                        _ => {
434                            let arr = self.evaluate(target)?;
435                            self.check_not_null(&arr, target_span)?;
436                            return self.index_read_value(
437                                &arr,
438                                &idx,
439                                target_span,
440                                index_span,
441                                span,
442                            );
443                        }
444                    }
445                }
446
447                let arr = self.evaluate(target)?;
448                self.check_not_null(&arr, target_span)?;
449                let idx = self.evaluate(index)?;
450                self.check_not_null(&idx, index_span)?;
451                self.index_read_value(&arr, &idx, target_span, index_span, span)
452            }
453
454            ExpressionKind::ArrayLiteral(items) => {
455                let len = items.len();
456                let mut values = Vec::with_capacity(len);
457                for i in 0..len {
458                    // Re-fetch per element instead of cloning the whole Vec<ExprId>
459                    // up front - each fetch is a cheap bounds-checked index, no alloc.
460                    let item_id = match &self.resolver.ast_arena.exprs.get(id).kind {
461                        ExpressionKind::ArrayLiteral(items) => items[i],
462                        _ => unreachable!(),
463                    };
464                    values.push(self.evaluate(item_id)?);
465                }
466                let items_type = values
467                    .first()
468                    .map(|v| Self::infer_type(v, false))
469                    .unwrap_or(TypeAnnotation::Null);
470
471                if items_type != TypeAnnotation::Null {
472                    for (i, v) in values.iter().enumerate() {
473                        let actual = Self::infer_type(v, false);
474                        if !Self::types_compatible(&actual, &items_type) {
475                            return Err(self.err(
476                                format!(
477                                    "array element type mismatch: element {} is {:?}, expected {:?}",
478                                    i, actual, items_type,
479                                ),
480                                span,
481                            ));
482                        }
483                    }
484                }
485                Ok(Value::Values {
486                    items_type,
487                    items: values,
488                })
489            }
490
491            ExpressionKind::SetLiteral(items) => {
492                let len = items.len();
493                let mut values = Vec::with_capacity(len);
494                for i in 0..len {
495                    let item_id = match &self.resolver.ast_arena.exprs.get(id).kind {
496                        ExpressionKind::SetLiteral(items) => items[i],
497                        _ => unreachable!(),
498                    };
499                    values.push(self.evaluate(item_id)?);
500                }
501                let items_type = values
502                    .first()
503                    .map(|v| Self::infer_type(v, false))
504                    .unwrap_or(TypeAnnotation::Null);
505
506                if items_type != TypeAnnotation::Null {
507                    for (i, v) in values.iter().enumerate() {
508                        let actual = Self::infer_type(v, false);
509                        if !Self::types_compatible(&actual, &items_type) {
510                            return Err(self.err(
511                                format!(
512                                    "set element type mismatch: element {} is {:?}, expected {:?}",
513                                    i, actual, items_type,
514                                ),
515                                span,
516                            ));
517                        }
518                    }
519                }
520                Ok(Value::Set {
521                    items_type,
522                    items: values,
523                })
524            }
525
526            ExpressionKind::MapLiteral(entries) => {
527                let len = entries.len();
528                let mut map = HashMap::with_capacity(len);
529                let mut key_type = TypeAnnotation::Null;
530                let mut value_type = TypeAnnotation::Null;
531
532                for i in 0..len {
533                    let (key_id, value_id) = match &self.resolver.ast_arena.exprs.get(id).kind {
534                        ExpressionKind::MapLiteral(entries) => entries[i],
535                        _ => unreachable!(),
536                    };
537                    let key_val = self.evaluate(key_id)?;
538                    let value_val = self.evaluate(value_id)?;
539
540                    if i == 0 {
541                        key_type = Self::infer_type(&key_val, false);
542                        value_type = Self::infer_type(&value_val, false);
543                    } else {
544                        let actual_key = Self::infer_type(&key_val, false);
545                        if !Self::types_compatible(&actual_key, &key_type) {
546                            return Err(self.err(
547                                format!(
548                                    "map key type mismatch: entry {} key is {:?}, expected {:?}",
549                                    i, actual_key, key_type
550                                ),
551                                span,
552                            ));
553                        }
554                        let actual_value = Self::infer_type(&value_val, false);
555                        if !Self::types_compatible(&actual_value, &value_type) {
556                            return Err(self.err(
557                                            format!("map value type mismatch: entry {} value is {:?}, expected {:?}", i, actual_value, value_type),
558                                            span,
559                                        ));
560                        }
561                    }
562
563                    let map_key = MapKey::from_value(&key_val).ok_or_else(|| {
564                        self.err(
565                            format!("type {} cannot be used as a map key", key_val.type_name()),
566                            span,
567                        )
568                    })?;
569                    map.insert(map_key, value_val);
570                }
571
572                Ok(Value::Map {
573                    key_type,
574                    value_type,
575                    entries: Rc::new(RefCell::new(map)),
576                })
577            }
578
579            ExpressionKind::IndexAssign {
580                target,
581                index,
582                value,
583            } => {
584                let (target, index, value) = (*target, *index, *value);
585                self.index_assign(target, index, value, span)
586            }
587
588            ExpressionKind::Grouping(inner) => {
589                let inner = *inner;
590                self.evaluate(inner)
591            }
592
593            ExpressionKind::Binary {
594                left,
595                operator,
596                right,
597            } => {
598                let (left, operator, right) = (*left, operator.clone(), *right);
599
600                if matches!(operator, TokenType::And) {
601                    let l = self.evaluate(left)?;
602                    if let Value::Bool(false) = l {
603                        return Ok(Value::Bool(false));
604                    }
605                    let r = self.evaluate(right)?;
606                    return Ok(Value::Bool(matches!(r, Value::Bool(true))));
607                }
608
609                if matches!(operator, TokenType::Or) {
610                    let l = self.evaluate(left)?;
611                    if let Value::Bool(true) = l {
612                        return Ok(Value::Bool(true));
613                    }
614                    let r = self.evaluate(right)?;
615                    return Ok(Value::Bool(matches!(r, Value::Bool(true))));
616                }
617
618                let left_span = self.resolver.ast_arena.exprs.get(left).span;
619                let right_span = self.resolver.ast_arena.exprs.get(right).span;
620
621                let left_val = self.evaluate(left)?;
622                let right_val = self.evaluate(right)?;
623                if matches!(operator, TokenType::Compare | TokenType::BangEqual)
624                    && (matches!(left_val, Value::Null) || matches!(right_val, Value::Null))
625                {
626                    let result = matches!((&left_val, &right_val), (Value::Null, Value::Null));
627                    return Ok(if matches!(operator, TokenType::Compare) {
628                        Value::Bool(result)
629                    } else {
630                        Value::Bool(!result)
631                    });
632                }
633                self.check_not_null(&left_val, left_span)?;
634                self.check_not_null(&right_val, right_span)?;
635                self.match_binary_operator(
636                    left_val, left_span, right_val, right_span, &operator, span,
637                )
638            }
639
640            ExpressionKind::Unary { operator, operand } => {
641                let (operator, operand) = (operator.clone(), *operand);
642                let operand_span = self.resolver.ast_arena.exprs.get(operand).span;
643                let operand_val = self.evaluate(operand)?;
644                self.check_not_null(&operand_val, operand_span)?;
645                self.match_unary_operator(operand_val, operand_span, &operator, span)
646            }
647
648            ExpressionKind::ResolvedIdentifier { depth, slot, .. } => {
649                let (depth, slot) = (*depth, *slot);
650                self.get_value(depth, slot, span)
651            }
652
653            ExpressionKind::ResolvedAssign {
654                depth, slot, value, ..
655            } => {
656                let (depth, slot, value) = (*depth, *slot, *value);
657                let val = self.evaluate(value)?;
658                let inferred_type = Self::infer_type(&val, false);
659                self.assign_value(depth, slot, val.clone(), inferred_type, span)?;
660                Ok(val)
661            }
662
663            ExpressionKind::Call { .. } => {
664                let (path, len) = match &self.resolver.ast_arena.exprs.get(id).kind {
665                    ExpressionKind::Call { path, args } => (path.clone(), args.len()),
666                    _ => unreachable!(),
667                };
668                let mut evaluated_args = Vec::with_capacity(len);
669                for i in 0..len {
670                    let arg_id = match &self.resolver.ast_arena.exprs.get(id).kind {
671                        ExpressionKind::Call { args, .. } => args[i],
672                        _ => unreachable!(),
673                    };
674                    evaluated_args.push(self.evaluate(arg_id)?);
675                }
676                self.call_path(&path, evaluated_args, span)
677            }
678
679            ExpressionKind::CallExpr { .. } => {
680                let (callee, len) = match &self.resolver.ast_arena.exprs.get(id).kind {
681                    ExpressionKind::CallExpr { callee, args } => (*callee, args.len()),
682                    _ => unreachable!(),
683                };
684                let func_val = self.evaluate(callee)?;
685                let mut evaluated_args = Vec::with_capacity(len);
686                for i in 0..len {
687                    let arg_id = match &self.resolver.ast_arena.exprs.get(id).kind {
688                        ExpressionKind::CallExpr { args, .. } => args[i],
689                        _ => unreachable!(),
690                    };
691                    evaluated_args.push(self.evaluate(arg_id)?);
692                }
693                self.call_value(func_val, evaluated_args, span)
694            }
695
696            ExpressionKind::MethodCall { .. } => {
697                let (caller, method, len) = match &self.resolver.ast_arena.exprs.get(id).kind {
698                    ExpressionKind::MethodCall {
699                        caller,
700                        method,
701                        args,
702                    } => (*caller, method.clone(), args.len()),
703                    _ => unreachable!(),
704                };
705                let first_arg = self.evaluate(caller)?;
706                let mut evaluated_args = vec![first_arg];
707                for i in 0..len {
708                    let arg_id = match &self.resolver.ast_arena.exprs.get(id).kind {
709                        ExpressionKind::MethodCall { args, .. } => args[i],
710                        _ => unreachable!(),
711                    };
712                    evaluated_args.push(self.evaluate(arg_id)?);
713                }
714                self.call_path(&method, evaluated_args, span)
715            }
716
717            ExpressionKind::ResolvedLambda { .. } => {
718                let (params, body, return_type, capture_depth) =
719                    match &self.resolver.ast_arena.exprs.get(id).kind {
720                        ExpressionKind::ResolvedLambda {
721                            params,
722                            body,
723                            return_type,
724                            capture_depth,
725                        } => (
726                            params.clone(),
727                            body.clone(),
728                            return_type.clone(),
729                            *capture_depth,
730                        ),
731                        _ => unreachable!(),
732                    };
733                let total = self.environment.len();
734                let start = total.saturating_sub(capture_depth);
735                let captured_env: Vec<Vec<EnvironmentItem>> = self.environment[start..].to_vec();
736
737                Ok(Value::Function(Rc::new(FunctionData {
738                    params: Rc::new(params),
739                    body: Rc::new(body),
740                    return_type,
741                    captured_env,
742                })))
743            }
744
745            ExpressionKind::Identifier(name) => {
746                Err(self.err(format!("undefined variable '{}'", name), span))
747            }
748            ExpressionKind::Assign { name, .. } => {
749                Err(self.err(format!("undefined variable '{}'", name), span))
750            }
751
752            ExpressionKind::Cast { value, target_type } => {
753                let (value, target_type) = (*value, target_type.clone());
754                let value_span = self.resolver.ast_arena.exprs.get(value).span;
755                let val = self.evaluate(value)?;
756                self.check_not_null(&val, value_span)?;
757                match (&val, &target_type) {
758                    (Value::Integer(n), TypeAnnotation::Float) => Ok(Value::Float(*n as f64)),
759                    (Value::Integer(n), TypeAnnotation::Byte) => Ok(Value::Byte(*n as u8)),
760                    (Value::Integer(_), TypeAnnotation::Int) => Ok(val),
761                    (Value::Float(f), TypeAnnotation::Int) => Ok(Value::Integer(*f as i64)),
762                    (Value::Float(f), TypeAnnotation::Byte) => Ok(Value::Byte(*f as u8)),
763                    (Value::Float(_), TypeAnnotation::Float) => Ok(val),
764                    (Value::Byte(b), TypeAnnotation::Float) => Ok(Value::Float(*b as f64)),
765                    (Value::Byte(b), TypeAnnotation::Int) => Ok(Value::Integer(*b as i64)),
766                    (Value::Byte(_), TypeAnnotation::Byte) => Ok(val),
767                    _ => Err(self.err(
768                        format!(
769                            "invalid cast: cannot cast {} to {:?}",
770                            val.type_name(),
771                            target_type
772                        ),
773                        span,
774                    )),
775                }
776            }
777
778            ExpressionKind::TupleLiteral(items) => {
779                let len = items.len();
780                let mut values = Vec::with_capacity(len);
781                for i in 0..len {
782                    let item_id = match &self.resolver.ast_arena.exprs.get(id).kind {
783                        ExpressionKind::TupleLiteral(items) => items[i],
784                        _ => unreachable!(),
785                    };
786                    values.push(self.evaluate(item_id)?);
787                }
788                Ok(Value::Tuple(values))
789            }
790
791            ExpressionKind::ErrorLiteral(inner) => {
792                let inner = *inner;
793                let val = self.evaluate(inner)?;
794                if matches!(val, Value::Error(_)) {
795                    return Err(self.err("error cannot wrap another error", span));
796                }
797                Ok(Value::Error(Box::new(val)))
798            }
799            ExpressionKind::OkLiteral(inner) => {
800                let inner = *inner;
801                let val = self.evaluate(inner)?;
802                Ok(Value::Ok(Box::new(val)))
803            }
804            ExpressionKind::ErrLiteral(inner) => {
805                let inner = *inner;
806                let val = self.evaluate(inner)?;
807                Ok(Value::Err(Box::new(val)))
808            }
809
810            ExpressionKind::Propagate(inner) => {
811                let inner = *inner;
812                let val = self.evaluate(inner)?;
813                match val {
814                    Value::Ok(v) => Ok(*v),
815                    Value::Err(_) => {
816                        self.return_value = Some(val);
817                        Ok(Value::Null)
818                    }
819                    other => Ok(other),
820                }
821            }
822
823            ExpressionKind::StructLiteral { .. } => {
824                let (name, fields) = match &self.resolver.ast_arena.exprs.get(id).kind {
825                    ExpressionKind::StructLiteral { name, fields } => {
826                        (name.clone(), fields.clone())
827                    }
828                    _ => unreachable!(),
829                };
830
831                let mut evaluated: Vec<(String, Value)> = Vec::with_capacity(fields.len());
832                for (field_name, value_id) in &fields {
833                    let value = self.evaluate(*value_id)?;
834                    evaluated.push((field_name.clone(), value));
835                }
836
837                if let Some(declared_fields) = self.records.get(&name).cloned() {
838                    if declared_fields.len() != evaluated.len() {
839                        return Err(self.err(
840                            format!(
841                                "record `{}` expects {} field(s), got {}",
842                                name,
843                                declared_fields.len(),
844                                evaluated.len()
845                            ),
846                            span,
847                        ));
848                    }
849
850                    let mut ordered: Vec<(String, Value)> =
851                        Vec::with_capacity(declared_fields.len());
852                    for (field_name, field_type) in &declared_fields {
853                        let Some((_, value)) = evaluated.iter().find(|(n, _)| n == field_name)
854                        else {
855                            return Err(self.err(
856                                format!("record `{}` is missing field `{}`", name, field_name),
857                                span,
858                            ));
859                        };
860                        let value_type = Self::infer_type(value, false);
861                        if !Self::types_compatible(&value_type, field_type)
862                            && value_type != TypeAnnotation::Null
863                        {
864                            return Err(self.err(
865                                format!(
866                                    "field `{}` of record `{}` expects {:?}, got {:?}",
867                                    field_name, name, field_type, value_type
868                                ),
869                                span,
870                            ));
871                        }
872                        ordered.push((field_name.clone(), value.clone()));
873                    }
874                    for (field_name, _) in &evaluated {
875                        if !declared_fields.iter().any(|(n, _)| n == field_name) {
876                            return Err(self.err(
877                                format!("record `{}` has no field `{}`", name, field_name),
878                                span,
879                            ));
880                        }
881                    }
882
883                    Ok(Value::Struct {
884                        name,
885                        fields: Rc::new(std::cell::RefCell::new(ordered)),
886                    })
887                } else {
888                    Ok(Value::Struct {
889                        name,
890                        fields: Rc::new(std::cell::RefCell::new(evaluated)),
891                    })
892                }
893            }
894
895            ExpressionKind::FieldAccess { .. } => {
896                let (target, field) = match &self.resolver.ast_arena.exprs.get(id).kind {
897                    ExpressionKind::FieldAccess { target, field } => (*target, field.clone()),
898                    _ => unreachable!(),
899                };
900                let target_span = self.resolver.ast_arena.exprs.get(target).span;
901                let target_val = self.evaluate(target)?;
902                match target_val {
903                    Value::Struct { name, fields } => {
904                        let fields = fields.borrow();
905                        match fields.iter().find(|(n, _)| *n == field) {
906                            Some((_, value)) => Ok(value.clone()),
907                            None => Err(self
908                                .err(format!("record `{}` has no field `{}`", name, field), span)),
909                        }
910                    }
911                    other => Err(self
912                        .err(
913                            format!("cannot access field `{}` on {}", field, other.type_name()),
914                            span,
915                        )
916                        .with_label(target_span, format!("this is {}", other.type_name()))),
917                }
918            }
919
920            ExpressionKind::FieldAssign { .. } => {
921                let (target, field, value) = match &self.resolver.ast_arena.exprs.get(id).kind {
922                    ExpressionKind::FieldAssign {
923                        target,
924                        field,
925                        value,
926                    } => (*target, field.clone(), *value),
927                    _ => unreachable!(),
928                };
929                let target_span = self.resolver.ast_arena.exprs.get(target).span;
930                let target_val = self.evaluate(target)?;
931                let new_val = self.evaluate(value)?;
932                match target_val {
933                    Value::Struct { name, fields } => {
934                        let mut fields = fields.borrow_mut();
935                        match fields.iter_mut().find(|(n, _)| *n == field) {
936                            Some((_, slot)) => {
937                                *slot = new_val.clone();
938                                Ok(new_val)
939                            }
940                            None => Err(self
941                                .err(format!("record `{}` has no field `{}`", name, field), span)),
942                        }
943                    }
944                    other => Err(self
945                        .err(
946                            format!("cannot assign field `{}` on {}", field, other.type_name()),
947                            span,
948                        )
949                        .with_label(target_span, format!("this is {}", other.type_name()))),
950                }
951            }
952
953            ExpressionKind::EnumVariant { .. } => {
954                let (enum_name, variant) = match &self.resolver.ast_arena.exprs.get(id).kind {
955                    ExpressionKind::EnumVariant { enum_name, variant } => {
956                        (enum_name.clone(), variant.clone())
957                    }
958                    _ => unreachable!(),
959                };
960
961                if let Some(declared_variants) = self.tags.get(&enum_name)
962                    && !declared_variants.contains(&variant)
963                {
964                    return Err(self.err(
965                        format!("tag `{}` has no variant `{}`", enum_name, variant),
966                        span,
967                    ));
968                }
969
970                Ok(Value::Enum {
971                    name: enum_name,
972                    variant,
973                })
974            }
975
976            _ => Ok(Value::Null),
977        }
978    }
979
980    /// Calls a [`Value::Function`], setting up the captured environment, inserting
981    /// arguments into a new scope, running the body, and validating the return type.
982    ///
983    /// Global scope mutations made inside the call are propagated back to the caller.
984    pub fn call_value(
985        &mut self,
986        func: Value,
987        args: Vec<Value>,
988        span: Span,
989    ) -> Result<Value, Error> {
990        if let Value::Function(data) = func {
991            if data.params.len() != args.len() {
992                return Err(self.err(
993                    format!(
994                        "function expects {} argument(s), got {}",
995                        data.params.len(),
996                        args.len()
997                    ),
998                    span,
999                ));
1000            }
1001
1002            let saved_env = std::mem::replace(&mut self.environment, data.captured_env.clone());
1003            let saved_return = self.return_value.take();
1004
1005            self.push_scope();
1006
1007            for (slot, (_, arg)) in data.params.iter().zip(args).enumerate() {
1008                let arg_type = Self::infer_type(&arg, false);
1009                self.insert_value(slot, arg, arg_type, span)?;
1010            }
1011
1012            for statement in &*data.body {
1013                self.evaluate_statement(statement)?;
1014                if self.return_value.is_some() {
1015                    break;
1016                }
1017            }
1018
1019            let result = self.return_value.take().unwrap_or(Value::Null);
1020
1021            self.environment = saved_env;
1022            self.return_value = saved_return;
1023
1024            if let Some(expected) = &data.return_type
1025                && *expected != TypeAnnotation::Null
1026            {
1027                let actual = Self::infer_type(&result, false);
1028                if !Self::types_compatible(&actual, expected) {
1029                    return Err(self.err(
1030                        format!(
1031                            "function declared to return {:?} but returned {:?}",
1032                            expected, actual
1033                        ),
1034                        span,
1035                    ));
1036                }
1037            }
1038
1039            return Ok(result);
1040        }
1041
1042        Err(self.err("value is not callable", span))
1043    }
1044
1045    /// Resolves a call path and dispatches to either a stdlib [`NativeFn`] or a
1046    /// user-defined function looked up via [`fn_names`].
1047    ///
1048    /// Resolution order:
1049    /// 1. Full stdlib path via [`root_module.resolve`]
1050    /// 2. Single-name shorthand via [`fn_names`]
1051    /// 3. Error with "did you mean?" suggestion from stdlib keywords
1052    pub fn call_path(
1053        &mut self,
1054        path: &[String],
1055        args: Vec<Value>,
1056        span: Span,
1057    ) -> Result<Value, Error> {
1058        if let Some(f) = self.root_module.resolve(path) {
1059            let f = Arc::clone(f);
1060            return match f(self, args, span) {
1061                Ok(v) => Ok(v),
1062                Err(e) if e.span().is_some() => Err(match &self.source_file {
1063                    Some(file) => e.with_source_file(file),
1064                    None => e,
1065                }),
1066                Err(e) => Err(self.err(e.message(), span)),
1067            };
1068        }
1069        if path.len() == 1
1070            && let Some(&slot) = self.fn_names.get(&path[0])
1071        {
1072            let func = self.get_value(0, slot, span)?;
1073            return self.call_value(func, args, span);
1074        }
1075        let mut err = self.err(format!("undefined function {}", path.join("::")), span);
1076        // suggest a stdlib leaf name if the last segment is a close typo
1077        if let Some(last) = path.last() {
1078            let candidates = stdlib::math::KEYWORDS
1079                .iter()
1080                .chain(stdlib::math::constants::KEYWORDS)
1081                .chain(stdlib::bitwise::KEYWORDS)
1082                .chain(stdlib::io::KEYWORDS)
1083                .chain(stdlib::string::KEYWORDS)
1084                .chain(stdlib::types::KEYWORDS)
1085                .chain(stdlib::array::KEYWORDS)
1086                .chain(stdlib::path::KEYWORDS)
1087                .chain(stdlib::fs::KEYWORDS)
1088                .chain(stdlib::random::KEYWORDS)
1089                .chain(stdlib::time::KEYWORDS)
1090                .chain(stdlib::process::KEYWORDS)
1091                .chain(stdlib::result::KEYWORDS)
1092                .chain(stdlib::terminal::KEYWORDS)
1093                .chain(stdlib::rl::KEYWORDS)
1094                .chain(stdlib::debug::KEYWORDS)
1095                .chain(stdlib::net::KEYWORDS)
1096                .chain(stdlib::http::KEYWORDS)
1097                .copied();
1098            if let Some(suggestion) = closest_match(last, candidates) {
1099                err = err.with_help(format!("did you mean `{}`?", suggestion));
1100            }
1101        }
1102        Err(err)
1103    }
1104}