Skip to main content

virtual_rust/interpreter/
builtins.rs

1//! Built-in function and macro dispatch.
2//!
3//! This module handles:
4//! - **Built-in functions**: `print`, `println`, `String::new`, `Vec::new`, etc.
5//! - **Macros**: `println!`, `format!`, `assert!`, `assert_eq!`, `vec!`, `panic!`, etc.
6
7use crate::ast::Expr;
8use crate::interpreter::error::RuntimeError;
9use crate::interpreter::value::Value;
10use crate::interpreter::Interpreter;
11
12// ── Built-in functions ───────────────────────────────────────────────────
13
14impl Interpreter {
15    /// Tries to call a built-in function by name.
16    /// Returns `Ok(Some(value))` if handled, `Ok(None)` if not a built-in.
17    pub(crate) fn call_builtin(
18        &mut self,
19        name: &str,
20        args: &[Value],
21    ) -> Result<Option<Value>, RuntimeError> {
22        match name {
23            "print" => {
24                for arg in args {
25                    print!("{arg}");
26                }
27                Ok(Some(Value::Unit))
28            }
29            "println" => {
30                for arg in args {
31                    print!("{arg}");
32                }
33                println!();
34                Ok(Some(Value::Unit))
35            }
36            "eprintln" => {
37                for arg in args {
38                    eprint!("{arg}");
39                }
40                eprintln!();
41                Ok(Some(Value::Unit))
42            }
43            "dbg" => {
44                if let Some(arg) = args.first() {
45                    eprintln!("[dbg] = {}", arg.debug_fmt());
46                    Ok(Some(arg.clone()))
47                } else {
48                    Ok(Some(Value::Unit))
49                }
50            }
51            "String::new" => Ok(Some(Value::String(String::new()))),
52            "String::from" => {
53                let s = match args.first() {
54                    Some(Value::String(s)) => s.clone(),
55                    Some(v) => format!("{v}"),
56                    None => String::new(),
57                };
58                Ok(Some(Value::String(s)))
59            }
60            "Vec::new" | "Vec::with_capacity" => Ok(Some(Value::Array(Vec::new()))),
61            "Some" => {
62                let val = args
63                    .first()
64                    .ok_or_else(|| RuntimeError::new("Some() requires one argument"))?;
65                Ok(Some(Value::Option(Some(Box::new(val.clone())))))
66            }
67            "std::io::stdin" | "io::stdin" => Ok(Some(Value::Unit)),
68            _ => Ok(None),
69        }
70    }
71}
72
73// ── Macro dispatch ───────────────────────────────────────────────────────
74
75impl Interpreter {
76    /// Evaluates a macro invocation (e.g. `println!`, `assert_eq!`, `vec!`).
77    pub(crate) fn call_macro(&mut self, name: &str, args: &[Expr]) -> Result<Value, RuntimeError> {
78        match name {
79            "println" => self.macro_print(args, true, false),
80            "print" => self.macro_print(args, false, false),
81            "eprintln" => self.macro_print(args, true, true),
82            "eprint" => self.macro_print(args, false, true),
83            "format" => self.macro_format(args),
84            "dbg" => self.macro_dbg(args),
85            "assert" => self.macro_assert(args),
86            "assert_eq" => self.macro_assert_eq(args),
87            "assert_ne" => self.macro_assert_ne(args),
88            "panic" => self.macro_panic(args),
89            "todo" => Err(RuntimeError::new("not yet implemented")),
90            "unimplemented" => Err(RuntimeError::new("not implemented")),
91            "unreachable" => Err(RuntimeError::new("entered unreachable code")),
92            "vec" => self.macro_vec(args),
93            "include_str" => self.macro_include_str(args),
94            _ => Err(RuntimeError::new(format!("Unknown macro: '{name}!'"))),
95        }
96    }
97
98    // ── Print macros ─────────────────────────────────────────────────
99
100    fn macro_print(
101        &mut self,
102        args: &[Expr],
103        newline: bool,
104        stderr: bool,
105    ) -> Result<Value, RuntimeError> {
106        let output = if args.is_empty() {
107            String::new()
108        } else if let Some(Expr::StringLiteral(fmt)) = args.first() {
109            let evaluated = self.eval_slice(&args[1..])?;
110            self.format_string(fmt, &evaluated)?
111        } else {
112            let val = self.eval(&args[0])?;
113            format!("{val}")
114        };
115
116        if stderr {
117            if newline {
118                eprintln!("{output}");
119            } else {
120                eprint!("{output}");
121            }
122        } else if newline {
123            println!("{output}");
124        } else {
125            print!("{output}");
126        }
127        Ok(Value::Unit)
128    }
129
130    // ── format! ──────────────────────────────────────────────────────
131
132    fn macro_format(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
133        if let Some(Expr::StringLiteral(fmt)) = args.first() {
134            let evaluated = self.eval_slice(&args[1..])?;
135            let formatted = self.format_string(fmt, &evaluated)?;
136            Ok(Value::String(formatted))
137        } else if let Some(arg) = args.first() {
138            let val = self.eval(arg)?;
139            Ok(Value::String(format!("{val}")))
140        } else {
141            Ok(Value::String(String::new()))
142        }
143    }
144
145    // ── dbg! ─────────────────────────────────────────────────────────
146
147    fn macro_dbg(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
148        for arg in args {
149            let val = self.eval(arg)?;
150            eprintln!("[dbg] = {}", val.debug_fmt());
151        }
152        if args.len() == 1 {
153            self.eval(&args[0])
154        } else {
155            Ok(Value::Unit)
156        }
157    }
158
159    // ── Assertion macros ─────────────────────────────────────────────
160
161    fn macro_assert(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
162        if let Some(arg) = args.first() {
163            let val = self.eval(arg)?;
164            if !val.is_truthy() {
165                return Err(RuntimeError::new("Assertion failed"));
166            }
167        }
168        Ok(Value::Unit)
169    }
170
171    fn macro_assert_eq(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
172        if args.len() >= 2 {
173            let left = self.eval(&args[0])?;
174            let right = self.eval(&args[1])?;
175            let equal = self.values_equal(&left, &right);
176            if !equal {
177                let msg = self.optional_message(args, 2)?;
178                return Err(RuntimeError::new(format!(
179                    "Assertion failed: left = {}, right = {}{msg}",
180                    left.debug_fmt(),
181                    right.debug_fmt(),
182                )));
183            }
184        }
185        Ok(Value::Unit)
186    }
187
188    fn macro_assert_ne(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
189        if args.len() >= 2 {
190            let left = self.eval(&args[0])?;
191            let right = self.eval(&args[1])?;
192            let equal = self.values_equal(&left, &right);
193            if equal {
194                return Err(RuntimeError::new(format!(
195                    "Assertion failed (values should not be equal): left = {}, right = {}",
196                    left.debug_fmt(),
197                    right.debug_fmt(),
198                )));
199            }
200        }
201        Ok(Value::Unit)
202    }
203
204    /// Extracts an optional message argument at the given index.
205    fn optional_message(&mut self, args: &[Expr], index: usize) -> Result<String, RuntimeError> {
206        if args.len() > index {
207            if let Ok(Value::String(m)) = self.eval(&args[index]) {
208                return Ok(format!(": {m}"));
209            }
210        }
211        Ok(String::new())
212    }
213
214    // ── panic! / todo! / unreachable! ────────────────────────────────
215
216    fn macro_panic(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
217        if let Some(Expr::StringLiteral(msg)) = args.first() {
218            let evaluated = self.eval_slice(&args[1..])?;
219            let formatted = self.format_string(msg, &evaluated)?;
220            Err(RuntimeError::new(format!("panic: {formatted}")))
221        } else if let Some(arg) = args.first() {
222            let val = self.eval(arg)?;
223            Err(RuntimeError::new(format!("panic: {val}")))
224        } else {
225            Err(RuntimeError::new("explicit panic"))
226        }
227    }
228
229    // ── vec! / include_str! ──────────────────────────────────────────
230
231    fn macro_vec(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
232        let values = self.eval_slice(args)?;
233        Ok(Value::Array(values))
234    }
235
236    fn macro_include_str(&mut self, args: &[Expr]) -> Result<Value, RuntimeError> {
237        if let Some(Expr::StringLiteral(path)) = args.first() {
238            let content = std::fs::read_to_string(path)
239                .map_err(|e| RuntimeError::new(format!("Cannot read file '{path}': {e}")))?;
240            Ok(Value::String(content))
241        } else {
242            Err(RuntimeError::new("include_str! expects a string literal"))
243        }
244    }
245
246    // ── Helpers ──────────────────────────────────────────────────────
247
248    /// Evaluates a slice of expressions into a Vec of values.
249    pub(crate) fn eval_slice(&mut self, exprs: &[Expr]) -> Result<Vec<Value>, RuntimeError> {
250        exprs.iter().map(|e| self.eval(e)).collect()
251    }
252}