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