virtual_rust/interpreter/
builtins.rs1use crate::ast::Expr;
8use crate::interpreter::error::RuntimeError;
9use crate::interpreter::value::Value;
10use crate::interpreter::Interpreter;
11
12impl Interpreter {
15 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
73impl Interpreter {
76 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 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 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 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 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 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 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 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 pub(crate) fn eval_slice(&mut self, exprs: &[Expr]) -> Result<Vec<Value>, RuntimeError> {
250 exprs.iter().map(|e| self.eval(e)).collect()
251 }
252}