Skip to main content

archscript/
interpreter.rs

1//! Tree-walking interpreter for ArchScript.
2
3use std::collections::HashMap;
4use std::fmt;
5
6use crate::ast::*;
7
8// ── Runtime Values ───────────────────────────────────────────────────────────
9
10#[derive(Debug, Clone)]
11pub enum Value {
12    Integer(i64),
13    Float(f64),
14    String(String),
15    Boolean(bool),
16    List(Vec<Value>),
17    Dict(Vec<(Value, Value)>),
18    Tuple(Vec<Value>),
19    Function(FuncValue),
20    BuiltinFn(String),
21    None,
22}
23
24#[derive(Debug, Clone)]
25pub struct FuncValue {
26    pub name: Option<String>,
27    pub params: Vec<Param>,
28    pub body: Expr,
29    pub closure: Environment,
30}
31
32impl fmt::Display for Value {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        match self {
35            Value::Integer(n) => write!(f, "{}", n),
36            Value::Float(n) => write!(f, "{}", n),
37            Value::String(s) => write!(f, "{}", s),
38            Value::Boolean(b) => write!(f, "{}", if *b { "True" } else { "False" }),
39            Value::List(items) => {
40                write!(f, "[")?;
41                for (i, item) in items.iter().enumerate() {
42                    if i > 0 {
43                        write!(f, ", ")?;
44                    }
45                    write!(f, "{}", item)?;
46                }
47                write!(f, "]")
48            }
49            Value::Dict(entries) => {
50                write!(f, "{{")?;
51                for (i, (k, v)) in entries.iter().enumerate() {
52                    if i > 0 {
53                        write!(f, ", ")?;
54                    }
55                    write!(f, "{}: {}", k, v)?;
56                }
57                write!(f, "}}")
58            }
59            Value::Tuple(items) => {
60                write!(f, "(")?;
61                for (i, item) in items.iter().enumerate() {
62                    if i > 0 {
63                        write!(f, ", ")?;
64                    }
65                    write!(f, "{}", item)?;
66                }
67                write!(f, ")")
68            }
69            Value::Function(_) => write!(f, "<function>"),
70            Value::BuiltinFn(name) => write!(f, "<builtin:{}>", name),
71            Value::None => write!(f, "None"),
72        }
73    }
74}
75
76impl PartialEq for Value {
77    fn eq(&self, other: &Self) -> bool {
78        match (self, other) {
79            (Value::Integer(a), Value::Integer(b)) => a == b,
80            (Value::Float(a), Value::Float(b)) => a == b,
81            (Value::Integer(a), Value::Float(b)) => (*a as f64) == *b,
82            (Value::Float(a), Value::Integer(b)) => *a == (*b as f64),
83            (Value::String(a), Value::String(b)) => a == b,
84            (Value::Boolean(a), Value::Boolean(b)) => a == b,
85            (Value::None, Value::None) => true,
86            (Value::List(a), Value::List(b)) => a == b,
87            _ => false,
88        }
89    }
90}
91
92// ── Environment (scoped symbol table) ────────────────────────────────────────
93
94#[derive(Debug, Clone)]
95pub struct Environment {
96    pub scopes: Vec<HashMap<String, Value>>,
97}
98
99impl Default for Environment {
100    fn default() -> Self {
101        Self::new()
102    }
103}
104
105impl Environment {
106    pub fn new() -> Self {
107        let mut global = HashMap::new();
108        // Register built-in functions
109        for name in [
110            "print", "println", "len", "range", "str", "int", "float", "type", "map", "filter",
111            "sum", "append",
112        ] {
113            global.insert(name.to_string(), Value::BuiltinFn(name.to_string()));
114        }
115        let mut env = Self {
116            scopes: vec![global],
117        };
118        // Register stdlib modules (pacman, systemd, aur, fs)
119        crate::stdlib::register_modules(&mut env);
120        env
121    }
122
123    pub fn push_scope(&mut self) {
124        self.scopes.push(HashMap::new());
125    }
126
127    pub fn pop_scope(&mut self) {
128        self.scopes.pop();
129    }
130
131    pub fn get(&self, name: &str) -> Option<&Value> {
132        for scope in self.scopes.iter().rev() {
133            if let Some(val) = scope.get(name) {
134                return Some(val);
135            }
136        }
137        None
138    }
139
140    pub fn set(&mut self, name: String, value: Value) {
141        // Update existing binding if found
142        for scope in self.scopes.iter_mut().rev() {
143            if let std::collections::hash_map::Entry::Occupied(mut e) = scope.entry(name.clone()) {
144                e.insert(value);
145                return;
146            }
147        }
148        // Otherwise create in current scope
149        if let Some(scope) = self.scopes.last_mut() {
150            scope.insert(name, value);
151        }
152    }
153
154    pub fn define(&mut self, name: String, value: Value) {
155        if let Some(scope) = self.scopes.last_mut() {
156            scope.insert(name, value);
157        }
158    }
159}
160
161// ── Runtime Error ────────────────────────────────────────────────────────────
162
163#[derive(Debug, Clone)]
164pub struct RuntimeError(pub String);
165
166impl fmt::Display for RuntimeError {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        write!(f, "Runtime error: {}", self.0)
169    }
170}
171
172impl std::error::Error for RuntimeError {}
173
174/// Signal for early return from functions.
175#[derive(Debug, Clone)]
176pub enum Signal {
177    Value(Value),
178    Return(Value),
179}
180
181// ── Interpreter ──────────────────────────────────────────────────────────────
182
183pub struct Interpreter {
184    pub env: Environment,
185    pub output: Vec<String>,
186}
187
188impl Default for Interpreter {
189    fn default() -> Self {
190        Self::new()
191    }
192}
193
194impl Interpreter {
195    pub fn new() -> Self {
196        Self {
197            env: Environment::new(),
198            output: Vec::new(),
199        }
200    }
201
202    pub fn run(&mut self, program: &Node) -> Result<Value, RuntimeError> {
203        match program {
204            Node::Module(items) => {
205                let mut last = Value::None;
206                for item in items {
207                    match self.exec_node(item)? {
208                        Signal::Return(v) => return Ok(v),
209                        Signal::Value(v) => last = v,
210                    }
211                }
212                Ok(last)
213            }
214            _ => match self.exec_node(program)? {
215                Signal::Return(v) | Signal::Value(v) => Ok(v),
216            },
217        }
218    }
219
220    fn exec_node(&mut self, node: &Node) -> Result<Signal, RuntimeError> {
221        match node {
222            Node::Module(items) => {
223                let mut last = Value::None;
224                for item in items {
225                    match self.exec_node(item)? {
226                        Signal::Return(v) => return Ok(Signal::Return(v)),
227                        Signal::Value(v) => last = v,
228                    }
229                }
230                Ok(Signal::Value(last))
231            }
232            Node::Import(_) => {
233                // Imports are a no-op for now
234                Ok(Signal::Value(Value::None))
235            }
236            Node::VariableDeclaration(name, _, expr) => {
237                let val = self.eval(expr)?;
238                self.env.define(name.clone(), val);
239                Ok(Signal::Value(Value::None))
240            }
241            Node::FunctionDeclaration(decl) => {
242                let func = Value::Function(FuncValue {
243                    name: Some(decl.name.clone()),
244                    params: decl.params.clone(),
245                    body: *decl.body.clone(),
246                    closure: self.env.clone(),
247                });
248                self.env.define(decl.name.clone(), func);
249                Ok(Signal::Value(Value::None))
250            }
251            Node::Expression(expr) => {
252                let val = self.eval(expr)?;
253                Ok(Signal::Value(val))
254            }
255            Node::Return(expr) => {
256                let val = match expr {
257                    Some(e) => self.eval(e)?,
258                    None => Value::None,
259                };
260                Ok(Signal::Return(val))
261            }
262            Node::TypeDefinition(_, _)
263            | Node::DataDefinition(_, _)
264            | Node::TraitDefinition(_, _)
265            | Node::InstanceDefinition(_, _, _) => {
266                // Type system constructs — no-op in interpreter for now
267                Ok(Signal::Value(Value::None))
268            }
269        }
270    }
271
272    pub fn eval(&mut self, expr: &Expr) -> Result<Value, RuntimeError> {
273        match expr {
274            Expr::Integer(n) => Ok(Value::Integer(*n)),
275            Expr::Float(n) => Ok(Value::Float(*n)),
276            Expr::StringLit(s) => Ok(Value::String(s.clone())),
277            Expr::Boolean(b) => Ok(Value::Boolean(*b)),
278            Expr::Identifier(name) => self
279                .env
280                .get(name)
281                .cloned()
282                .ok_or_else(|| RuntimeError(format!("undefined variable: {}", name))),
283
284            Expr::List(items) => {
285                let vals: Vec<Value> = items
286                    .iter()
287                    .map(|e| self.eval(e))
288                    .collect::<Result<_, _>>()?;
289                Ok(Value::List(vals))
290            }
291            Expr::Dict(entries) => {
292                let vals: Vec<(Value, Value)> = entries
293                    .iter()
294                    .map(|(k, v)| Ok((self.eval(k)?, self.eval(v)?)))
295                    .collect::<Result<_, RuntimeError>>()?;
296                Ok(Value::Dict(vals))
297            }
298            Expr::Tuple(items) => {
299                let vals: Vec<Value> = items
300                    .iter()
301                    .map(|e| self.eval(e))
302                    .collect::<Result<_, _>>()?;
303                Ok(Value::Tuple(vals))
304            }
305
306            Expr::BinaryOp(op, left, right) => {
307                let lv = self.eval(left)?;
308                let rv = self.eval(right)?;
309                self.eval_binop(op, &lv, &rv)
310            }
311
312            Expr::UnaryOp(op, expr) => {
313                let val = self.eval(expr)?;
314                match op {
315                    UnaryOp::Neg => match val {
316                        Value::Integer(n) => Ok(Value::Integer(-n)),
317                        Value::Float(n) => Ok(Value::Float(-n)),
318                        _ => Err(RuntimeError("cannot negate non-numeric value".into())),
319                    },
320                    UnaryOp::Pos => Ok(val),
321                    UnaryOp::Not => match val {
322                        Value::Boolean(b) => Ok(Value::Boolean(!b)),
323                        _ => Err(RuntimeError(
324                            "cannot apply 'not' to non-boolean value".into(),
325                        )),
326                    },
327                }
328            }
329
330            Expr::Pipe(left, right) => {
331                let lv = self.eval(left)?;
332                // right should be a function — call it with lv as argument
333                let func = self.eval(right)?;
334                self.call_value(&func, &[lv])
335            }
336
337            Expr::FunctionCall(callee, args) => {
338                let func = self.eval(callee)?;
339                let arg_vals: Vec<Value> = args
340                    .iter()
341                    .map(|a| self.eval(a))
342                    .collect::<Result<_, _>>()?;
343                self.call_value(&func, &arg_vals)
344            }
345
346            Expr::Index(expr, idx) => {
347                let container = self.eval(expr)?;
348                let index = self.eval(idx)?;
349                match (&container, &index) {
350                    (Value::List(items), Value::Integer(i)) => {
351                        let i = if *i < 0 { items.len() as i64 + i } else { *i } as usize;
352                        items
353                            .get(i)
354                            .cloned()
355                            .ok_or_else(|| RuntimeError(format!("index {} out of bounds", i)))
356                    }
357                    (Value::String(s), Value::Integer(i)) => {
358                        let i = if *i < 0 { s.len() as i64 + i } else { *i } as usize;
359                        s.chars()
360                            .nth(i)
361                            .map(|c| Value::String(c.to_string()))
362                            .ok_or_else(|| RuntimeError(format!("index {} out of bounds", i)))
363                    }
364                    (Value::Dict(entries), key) => {
365                        for (k, v) in entries {
366                            if k == key {
367                                return Ok(v.clone());
368                            }
369                        }
370                        Err(RuntimeError(format!("key not found: {}", key)))
371                    }
372                    _ => Err(RuntimeError("cannot index this value".into())),
373                }
374            }
375
376            Expr::MemberAccess(expr, member) => {
377                let val = self.eval(expr)?;
378                match &val {
379                    Value::Dict(entries) => {
380                        for (k, v) in entries {
381                            if let Value::String(s) = k {
382                                if s == member {
383                                    return Ok(v.clone());
384                                }
385                            }
386                        }
387                        Err(RuntimeError(format!("no member '{}' found", member)))
388                    }
389                    _ => Err(RuntimeError(format!(
390                        "member access on unsupported type: {}",
391                        val
392                    ))),
393                }
394            }
395
396            Expr::If(cond, then_body, elif_branches, else_body) => {
397                let cond_val = self.eval(cond)?;
398                if is_truthy(&cond_val) {
399                    self.eval(then_body)
400                } else {
401                    for (elif_cond, elif_body) in elif_branches {
402                        let elif_val = self.eval(elif_cond)?;
403                        if is_truthy(&elif_val) {
404                            return self.eval(elif_body);
405                        }
406                    }
407                    if let Some(else_body) = else_body {
408                        self.eval(else_body)
409                    } else {
410                        Ok(Value::None)
411                    }
412                }
413            }
414
415            Expr::For(var, iterable, body) => {
416                let iter_val = self.eval(iterable)?;
417                let items = match iter_val {
418                    Value::List(items) => items,
419                    _ => return Err(RuntimeError("for loop requires iterable (list)".into())),
420                };
421                self.env.push_scope();
422                let mut last = Value::None;
423                for item in items {
424                    self.env.define(var.clone(), item);
425                    last = self.eval(body)?;
426                }
427                self.env.pop_scope();
428                Ok(last)
429            }
430
431            Expr::While(cond, body) => {
432                let mut last = Value::None;
433                loop {
434                    let cond_val = self.eval(cond)?;
435                    if !is_truthy(&cond_val) {
436                        break;
437                    }
438                    last = self.eval(body)?;
439                }
440                Ok(last)
441            }
442
443            Expr::Match(subject, arms) => {
444                let val = self.eval(subject)?;
445                for arm in arms {
446                    if let Some(bindings) = match_pattern(&arm.pattern, &val) {
447                        self.env.push_scope();
448                        for (name, bound_val) in &bindings {
449                            self.env.define(name.clone(), bound_val.clone());
450                        }
451                        // Check guard
452                        if let Some(guard) = &arm.guard {
453                            let guard_val = self.eval(guard)?;
454                            if !is_truthy(&guard_val) {
455                                self.env.pop_scope();
456                                continue;
457                            }
458                        }
459                        let result = self.eval(&arm.body)?;
460                        self.env.pop_scope();
461                        return Ok(result);
462                    }
463                }
464                Err(RuntimeError(
465                    "no matching pattern in match expression".into(),
466                ))
467            }
468
469            Expr::Lambda(params, body) => Ok(Value::Function(FuncValue {
470                name: None,
471                params: params.clone(),
472                body: *body.clone(),
473                closure: self.env.clone(),
474            })),
475
476            Expr::ListComprehension(expr, var, iterable, filter) => {
477                let iter_val = self.eval(iterable)?;
478                let items = match iter_val {
479                    Value::List(items) => items,
480                    _ => return Err(RuntimeError("list comprehension requires iterable".into())),
481                };
482                let mut result = Vec::new();
483                self.env.push_scope();
484                for item in items {
485                    self.env.define(var.clone(), item);
486                    if let Some(filter_expr) = filter {
487                        let fv = self.eval(filter_expr)?;
488                        if !is_truthy(&fv) {
489                            continue;
490                        }
491                    }
492                    result.push(self.eval(expr)?);
493                }
494                self.env.pop_scope();
495                Ok(Value::List(result))
496            }
497
498            Expr::Block(stmts) => {
499                self.env.push_scope();
500                let mut last = Value::None;
501                for stmt in stmts {
502                    match self.exec_node(stmt)? {
503                        Signal::Return(v) => {
504                            self.env.pop_scope();
505                            return Ok(v); // Propagate return as a value in this context
506                        }
507                        Signal::Value(v) => last = v,
508                    }
509                }
510                self.env.pop_scope();
511                Ok(last)
512            }
513
514            Expr::Assign(target, value) => {
515                let val = self.eval(value)?;
516                match target.as_ref() {
517                    Expr::Identifier(name) => {
518                        self.env.set(name.clone(), val);
519                        Ok(Value::None)
520                    }
521                    _ => Err(RuntimeError("invalid assignment target".into())),
522                }
523            }
524
525            Expr::CompoundAssign(op, target, value) => {
526                let current = self.eval(target)?;
527                let rhs = self.eval(value)?;
528                let result = self.eval_binop(op, &current, &rhs)?;
529                match target.as_ref() {
530                    Expr::Identifier(name) => {
531                        self.env.set(name.clone(), result);
532                        Ok(Value::None)
533                    }
534                    _ => Err(RuntimeError("invalid compound assignment target".into())),
535                }
536            }
537        }
538    }
539
540    fn eval_binop(&self, op: &BinOp, left: &Value, right: &Value) -> Result<Value, RuntimeError> {
541        match op {
542            BinOp::Add => match (left, right) {
543                (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a + b)),
544                (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a + b)),
545                (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(*a as f64 + b)),
546                (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a + *b as f64)),
547                (Value::String(a), Value::String(b)) => Ok(Value::String(format!("{}{}", a, b))),
548                (Value::List(a), Value::List(b)) => {
549                    let mut result = a.clone();
550                    result.extend(b.clone());
551                    Ok(Value::List(result))
552                }
553                _ => Err(RuntimeError(format!("cannot add {} and {}", left, right))),
554            },
555            BinOp::Sub => numeric_op(left, right, |a, b| a - b, |a, b| a - b),
556            BinOp::Mul => match (left, right) {
557                (Value::String(s), Value::Integer(n)) | (Value::Integer(n), Value::String(s)) => {
558                    Ok(Value::String(s.repeat(*n as usize)))
559                }
560                _ => numeric_op(left, right, |a, b| a * b, |a, b| a * b),
561            },
562            BinOp::Div => match (left, right) {
563                (Value::Integer(_), Value::Integer(0)) | (Value::Float(_), Value::Integer(0)) => {
564                    Err(RuntimeError("division by zero".into()))
565                }
566                _ => numeric_op_float(left, right, |a, b| a / b),
567            },
568            BinOp::IntDiv => match (left, right) {
569                (Value::Integer(a), Value::Integer(b)) => {
570                    if *b == 0 {
571                        Err(RuntimeError("division by zero".into()))
572                    } else {
573                        Ok(Value::Integer(a / b))
574                    }
575                }
576                _ => Err(RuntimeError("integer division requires integers".into())),
577            },
578            BinOp::Mod => match (left, right) {
579                (Value::Integer(a), Value::Integer(b)) => {
580                    if *b == 0 {
581                        Err(RuntimeError("modulo by zero".into()))
582                    } else {
583                        Ok(Value::Integer(a % b))
584                    }
585                }
586                _ => Err(RuntimeError("modulo requires integers".into())),
587            },
588            BinOp::Pow => match (left, right) {
589                (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a.pow(*b as u32))),
590                (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.powf(*b))),
591                (Value::Integer(a), Value::Float(b)) => Ok(Value::Float((*a as f64).powf(*b))),
592                (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a.powf(*b as f64))),
593                _ => Err(RuntimeError("power requires numeric operands".into())),
594            },
595            BinOp::Eq => Ok(Value::Boolean(left == right)),
596            BinOp::Neq => Ok(Value::Boolean(left != right)),
597            BinOp::Lt => compare_op(left, right, |ord| ord == std::cmp::Ordering::Less),
598            BinOp::Lte => compare_op(left, right, |ord| {
599                ord == std::cmp::Ordering::Less || ord == std::cmp::Ordering::Equal
600            }),
601            BinOp::Gt => compare_op(left, right, |ord| ord == std::cmp::Ordering::Greater),
602            BinOp::Gte => compare_op(left, right, |ord| {
603                ord == std::cmp::Ordering::Greater || ord == std::cmp::Ordering::Equal
604            }),
605            BinOp::And => Ok(Value::Boolean(is_truthy(left) && is_truthy(right))),
606            BinOp::Or => Ok(Value::Boolean(is_truthy(left) || is_truthy(right))),
607        }
608    }
609
610    fn call_value(&mut self, func: &Value, args: &[Value]) -> Result<Value, RuntimeError> {
611        match func {
612            Value::Function(fv) => {
613                let mut call_env = fv.closure.clone();
614                call_env.push_scope();
615                // Bind the function itself for recursion
616                if let Some(ref name) = fv.name {
617                    call_env.define(name.clone(), func.clone());
618                }
619                for (i, param) in fv.params.iter().enumerate() {
620                    let val = args.get(i).cloned().unwrap_or(Value::None);
621                    call_env.define(param.name.clone(), val);
622                }
623                let prev_env = std::mem::replace(&mut self.env, call_env);
624                let result = self.eval(&fv.body);
625                self.env = prev_env;
626                result
627            }
628            Value::BuiltinFn(name) => self.call_builtin(name, args),
629            _ => Err(RuntimeError(format!("cannot call non-function: {}", func))),
630        }
631    }
632
633    fn call_builtin(&mut self, name: &str, args: &[Value]) -> Result<Value, RuntimeError> {
634        match name {
635            "print" => {
636                let text: Vec<String> = args.iter().map(|a| format!("{}", a)).collect();
637                let output = text.join(" ");
638                self.output.push(output);
639                Ok(Value::None)
640            }
641            "println" => {
642                let text: Vec<String> = args.iter().map(|a| format!("{}", a)).collect();
643                let output = text.join(" ");
644                self.output.push(output);
645                Ok(Value::None)
646            }
647            "len" => match args.first() {
648                Some(Value::List(items)) => Ok(Value::Integer(items.len() as i64)),
649                Some(Value::String(s)) => Ok(Value::Integer(s.len() as i64)),
650                Some(Value::Dict(entries)) => Ok(Value::Integer(entries.len() as i64)),
651                _ => Err(RuntimeError(
652                    "len() requires a list, string, or dict".into(),
653                )),
654            },
655            "range" => {
656                let (start, end, step) = match args.len() {
657                    1 => match &args[0] {
658                        Value::Integer(n) => (0, *n, 1),
659                        _ => return Err(RuntimeError("range() requires integer arguments".into())),
660                    },
661                    2 => match (&args[0], &args[1]) {
662                        (Value::Integer(a), Value::Integer(b)) => (*a, *b, 1),
663                        _ => return Err(RuntimeError("range() requires integer arguments".into())),
664                    },
665                    3 => match (&args[0], &args[1], &args[2]) {
666                        (Value::Integer(a), Value::Integer(b), Value::Integer(c)) => (*a, *b, *c),
667                        _ => return Err(RuntimeError("range() requires integer arguments".into())),
668                    },
669                    _ => return Err(RuntimeError("range() takes 1-3 arguments".into())),
670                };
671                if step == 0 {
672                    return Err(RuntimeError("range() step cannot be zero".into()));
673                }
674                let mut items = Vec::new();
675                let mut i = start;
676                if step > 0 {
677                    while i < end {
678                        items.push(Value::Integer(i));
679                        i += step;
680                    }
681                } else {
682                    while i > end {
683                        items.push(Value::Integer(i));
684                        i += step;
685                    }
686                }
687                Ok(Value::List(items))
688            }
689            "str" => match args.first() {
690                Some(val) => Ok(Value::String(format!("{}", val))),
691                None => Ok(Value::String(String::new())),
692            },
693            "int" => match args.first() {
694                Some(Value::Integer(n)) => Ok(Value::Integer(*n)),
695                Some(Value::Float(n)) => Ok(Value::Integer(*n as i64)),
696                Some(Value::String(s)) => s
697                    .parse::<i64>()
698                    .map(Value::Integer)
699                    .map_err(|_| RuntimeError(format!("cannot convert '{}' to int", s))),
700                Some(Value::Boolean(b)) => Ok(Value::Integer(if *b { 1 } else { 0 })),
701                _ => Err(RuntimeError(
702                    "int() requires a numeric or string argument".into(),
703                )),
704            },
705            "float" => match args.first() {
706                Some(Value::Integer(n)) => Ok(Value::Float(*n as f64)),
707                Some(Value::Float(n)) => Ok(Value::Float(*n)),
708                Some(Value::String(s)) => s
709                    .parse::<f64>()
710                    .map(Value::Float)
711                    .map_err(|_| RuntimeError(format!("cannot convert '{}' to float", s))),
712                _ => Err(RuntimeError(
713                    "float() requires a numeric or string argument".into(),
714                )),
715            },
716            "type" => {
717                let type_name = match args.first() {
718                    Some(Value::Integer(_)) => "Int",
719                    Some(Value::Float(_)) => "Float",
720                    Some(Value::String(_)) => "String",
721                    Some(Value::Boolean(_)) => "Bool",
722                    Some(Value::List(_)) => "List",
723                    Some(Value::Dict(_)) => "Dict",
724                    Some(Value::Tuple(_)) => "Tuple",
725                    Some(Value::Function(_)) => "Function",
726                    Some(Value::BuiltinFn(_)) => "BuiltinFn",
727                    Some(Value::None) | None => "None",
728                };
729                Ok(Value::String(type_name.to_string()))
730            }
731            "map" => {
732                if args.len() != 2 {
733                    return Err(RuntimeError(
734                        "map() takes 2 arguments (function, list)".into(),
735                    ));
736                }
737                let func = &args[0];
738                let items = match &args[1] {
739                    Value::List(items) => items.clone(),
740                    _ => return Err(RuntimeError("map() second argument must be a list".into())),
741                };
742                let mut result = Vec::new();
743                for item in &items {
744                    result.push(self.call_value(func, std::slice::from_ref(item))?);
745                }
746                Ok(Value::List(result))
747            }
748            "filter" => {
749                if args.len() != 2 {
750                    return Err(RuntimeError(
751                        "filter() takes 2 arguments (function, list)".into(),
752                    ));
753                }
754                let func = &args[0];
755                let items = match &args[1] {
756                    Value::List(items) => items.clone(),
757                    _ => {
758                        return Err(RuntimeError(
759                            "filter() second argument must be a list".into(),
760                        ))
761                    }
762                };
763                let mut result = Vec::new();
764                for item in &items {
765                    let v = self.call_value(func, std::slice::from_ref(item))?;
766                    if is_truthy(&v) {
767                        result.push(item.clone());
768                    }
769                }
770                Ok(Value::List(result))
771            }
772            "sum" => match args.first() {
773                Some(Value::List(items)) => {
774                    let mut total = Value::Integer(0);
775                    for item in items {
776                        total = self.eval_binop(&BinOp::Add, &total, item)?;
777                    }
778                    Ok(total)
779                }
780                _ => Err(RuntimeError("sum() requires a list argument".into())),
781            },
782            "append" => {
783                if args.len() != 2 {
784                    return Err(RuntimeError(
785                        "append() takes 2 arguments (list, item)".into(),
786                    ));
787                }
788                match &args[0] {
789                    Value::List(items) => {
790                        let mut new_items = items.clone();
791                        new_items.push(args[1].clone());
792                        Ok(Value::List(new_items))
793                    }
794                    _ => Err(RuntimeError(
795                        "append() first argument must be a list".into(),
796                    )),
797                }
798            }
799            _ => {
800                // Delegate to stdlib modules
801                if let Some(result) = crate::stdlib::call(name, args) {
802                    return result;
803                }
804                Err(RuntimeError(format!("unknown builtin: {}", name)))
805            }
806        }
807    }
808}
809
810// ── Helper Functions ─────────────────────────────────────────────────────────
811
812fn is_truthy(val: &Value) -> bool {
813    match val {
814        Value::Boolean(b) => *b,
815        Value::Integer(n) => *n != 0,
816        Value::Float(n) => *n != 0.0,
817        Value::String(s) => !s.is_empty(),
818        Value::List(items) => !items.is_empty(),
819        Value::None => false,
820        _ => true,
821    }
822}
823
824fn numeric_op(
825    left: &Value,
826    right: &Value,
827    int_op: fn(i64, i64) -> i64,
828    float_op: fn(f64, f64) -> f64,
829) -> Result<Value, RuntimeError> {
830    match (left, right) {
831        (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(int_op(*a, *b))),
832        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(float_op(*a, *b))),
833        (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(float_op(*a as f64, *b))),
834        (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(float_op(*a, *b as f64))),
835        _ => Err(RuntimeError(format!(
836            "arithmetic requires numeric operands, got {} and {}",
837            left, right
838        ))),
839    }
840}
841
842fn numeric_op_float(
843    left: &Value,
844    right: &Value,
845    op: fn(f64, f64) -> f64,
846) -> Result<Value, RuntimeError> {
847    match (left, right) {
848        (Value::Integer(a), Value::Integer(b)) => Ok(Value::Float(op(*a as f64, *b as f64))),
849        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(op(*a, *b))),
850        (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(op(*a as f64, *b))),
851        (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(op(*a, *b as f64))),
852        _ => Err(RuntimeError(format!(
853            "arithmetic requires numeric operands, got {} and {}",
854            left, right
855        ))),
856    }
857}
858
859fn compare_op(
860    left: &Value,
861    right: &Value,
862    pred: fn(std::cmp::Ordering) -> bool,
863) -> Result<Value, RuntimeError> {
864    let ord = match (left, right) {
865        (Value::Integer(a), Value::Integer(b)) => a.cmp(b),
866        (Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal),
867        (Value::Integer(a), Value::Float(b)) => (*a as f64)
868            .partial_cmp(b)
869            .unwrap_or(std::cmp::Ordering::Equal),
870        (Value::Float(a), Value::Integer(b)) => a
871            .partial_cmp(&(*b as f64))
872            .unwrap_or(std::cmp::Ordering::Equal),
873        (Value::String(a), Value::String(b)) => a.cmp(b),
874        _ => {
875            return Err(RuntimeError(format!(
876                "cannot compare {} and {}",
877                left, right
878            )))
879        }
880    };
881    Ok(Value::Boolean(pred(ord)))
882}
883
884fn match_pattern(pattern: &Pattern, value: &Value) -> Option<Vec<(String, Value)>> {
885    match pattern {
886        Pattern::Wildcard => Some(vec![]),
887        Pattern::Literal(lit_expr) => {
888            let lit_val = match lit_expr {
889                Expr::Integer(n) => Value::Integer(*n),
890                Expr::Float(n) => Value::Float(*n),
891                Expr::StringLit(s) => Value::String(s.clone()),
892                Expr::Boolean(b) => Value::Boolean(*b),
893                _ => return None,
894            };
895            if &lit_val == value {
896                Some(vec![])
897            } else {
898                None
899            }
900        }
901        Pattern::Identifier(name) => Some(vec![(name.clone(), value.clone())]),
902        Pattern::Tuple(patterns) => match value {
903            Value::Tuple(items) if items.len() == patterns.len() => {
904                let mut bindings = Vec::new();
905                for (pat, val) in patterns.iter().zip(items.iter()) {
906                    match match_pattern(pat, val) {
907                        Some(b) => bindings.extend(b),
908                        None => return None,
909                    }
910                }
911                Some(bindings)
912            }
913            _ => None,
914        },
915        Pattern::List(patterns, rest) => match value {
916            Value::List(items) => {
917                if rest.is_some() {
918                    if items.len() < patterns.len() {
919                        return None;
920                    }
921                } else if items.len() != patterns.len() {
922                    return None;
923                }
924                let mut bindings = Vec::new();
925                for (pat, val) in patterns.iter().zip(items.iter()) {
926                    match match_pattern(pat, val) {
927                        Some(b) => bindings.extend(b),
928                        None => return None,
929                    }
930                }
931                if let Some(rest_name) = rest {
932                    let rest_items = items[patterns.len()..].to_vec();
933                    bindings.push((rest_name.clone(), Value::List(rest_items)));
934                }
935                Some(bindings)
936            }
937            _ => None,
938        },
939        Pattern::Constructor(_name, _patterns) => {
940            // Constructors are not fully implemented yet
941            None
942        }
943    }
944}
945
946#[cfg(test)]
947mod tests {
948    use super::*;
949    use crate::parser;
950
951    fn eval_str(source: &str) -> Result<Value, String> {
952        let ast = parser::parse(source).map_err(|e| e.to_string())?;
953        let mut interp = Interpreter::new();
954        interp.run(&ast).map_err(|e| e.to_string())
955    }
956
957    fn eval_with_output(source: &str) -> (Result<Value, String>, Vec<String>) {
958        let ast = match parser::parse(source) {
959            Ok(a) => a,
960            Err(e) => return (Err(e.to_string()), vec![]),
961        };
962        let mut interp = Interpreter::new();
963        let result = interp.run(&ast).map_err(|e| e.to_string());
964        (result, interp.output)
965    }
966
967    #[test]
968    fn test_integer_literal() {
969        assert_eq!(eval_str("42").unwrap(), Value::Integer(42));
970    }
971
972    #[test]
973    fn test_float_literal() {
974        match eval_str("3.14").unwrap() {
975            Value::Float(f) => assert!((f - 3.14).abs() < f64::EPSILON),
976            other => panic!("expected float, got {:?}", other),
977        }
978    }
979
980    #[test]
981    fn test_var_float_bug() {
982        // The original bug: `var y = 13.1` should work
983        let source = "var y = 13.1\ny";
984        match eval_str(source).unwrap() {
985            Value::Float(f) => assert!((f - 13.1).abs() < f64::EPSILON),
986            other => panic!("expected float 13.1, got {:?}", other),
987        }
988    }
989
990    #[test]
991    fn test_string_literal() {
992        assert_eq!(
993            eval_str("\"hello\"").unwrap(),
994            Value::String("hello".to_string())
995        );
996    }
997
998    #[test]
999    fn test_boolean() {
1000        assert_eq!(eval_str("True").unwrap(), Value::Boolean(true));
1001        assert_eq!(eval_str("False").unwrap(), Value::Boolean(false));
1002    }
1003
1004    #[test]
1005    fn test_arithmetic() {
1006        assert_eq!(eval_str("2 + 3").unwrap(), Value::Integer(5));
1007        assert_eq!(eval_str("10 - 4").unwrap(), Value::Integer(6));
1008        assert_eq!(eval_str("3 * 7").unwrap(), Value::Integer(21));
1009        assert_eq!(eval_str("10 % 3").unwrap(), Value::Integer(1));
1010    }
1011
1012    #[test]
1013    fn test_operator_precedence() {
1014        assert_eq!(eval_str("2 + 3 * 4").unwrap(), Value::Integer(14));
1015        assert_eq!(eval_str("2 * 3 + 4").unwrap(), Value::Integer(10));
1016    }
1017
1018    #[test]
1019    fn test_variable() {
1020        let source = "var x = 42\nx";
1021        assert_eq!(eval_str(source).unwrap(), Value::Integer(42));
1022    }
1023
1024    #[test]
1025    fn test_comparison() {
1026        assert_eq!(eval_str("3 < 5").unwrap(), Value::Boolean(true));
1027        assert_eq!(eval_str("5 < 3").unwrap(), Value::Boolean(false));
1028        assert_eq!(eval_str("3 == 3").unwrap(), Value::Boolean(true));
1029        assert_eq!(eval_str("3 != 4").unwrap(), Value::Boolean(true));
1030    }
1031
1032    #[test]
1033    fn test_print() {
1034        let (result, output) = eval_with_output("println(\"Hello, ArchScript!\")");
1035        assert!(result.is_ok());
1036        assert_eq!(output, vec!["Hello, ArchScript!"]);
1037    }
1038
1039    #[test]
1040    fn test_len() {
1041        let source = "len(\"hello\")";
1042        assert_eq!(eval_str(source).unwrap(), Value::Integer(5));
1043    }
1044
1045    #[test]
1046    fn test_range() {
1047        let source = "range(5)";
1048        assert_eq!(
1049            eval_str(source).unwrap(),
1050            Value::List(vec![
1051                Value::Integer(0),
1052                Value::Integer(1),
1053                Value::Integer(2),
1054                Value::Integer(3),
1055                Value::Integer(4),
1056            ])
1057        );
1058    }
1059}