1use crate::ast::BinOp;
7use crate::interpreter::error::RuntimeError;
8use crate::interpreter::value::Value;
9use crate::interpreter::Interpreter;
10
11impl Interpreter {
12 pub(crate) fn call_method(
14 &mut self,
15 object: Value,
16 method: &str,
17 args: Vec<Value>,
18 ) -> Result<Value, RuntimeError> {
19 match &object {
20 Value::String(s) => self.string_method(s.clone(), method, args),
21 Value::Array(arr) => self.array_method(arr.clone(), method, args),
22 Value::Int(n) => self.int_method(*n, method, &args),
23 Value::Float(n) => self.float_method(*n, method, &args),
24 Value::Bool(b) => self.bool_method(*b, method),
25 Value::Char(c) => self.char_method(*c, method),
26 Value::Option(opt) => self.option_method(opt.clone(), method, args),
27 _ => {
28 match method {
30 "to_string" => Ok(Value::String(format!("{object}"))),
31 "clone" => Ok(object.clone()),
32 _ => Err(RuntimeError::new(format!(
33 "Unknown method '{method}' on type '{}'",
34 object.type_name()
35 ))),
36 }
37 }
38 }
39 }
40}
41
42impl Interpreter {
45 fn string_method(
46 &mut self,
47 s: String,
48 method: &str,
49 args: Vec<Value>,
50 ) -> Result<Value, RuntimeError> {
51 match method {
52 "len" => Ok(Value::Int(s.len() as i64)),
53 "is_empty" => Ok(Value::Bool(s.is_empty())),
54 "contains" => {
55 let substr = expect_string_arg(&args, "contains")?;
56 Ok(Value::Bool(s.contains(substr.as_str())))
57 }
58 "starts_with" => {
59 let prefix = expect_string_arg(&args, "starts_with")?;
60 Ok(Value::Bool(s.starts_with(prefix.as_str())))
61 }
62 "ends_with" => {
63 let suffix = expect_string_arg(&args, "ends_with")?;
64 Ok(Value::Bool(s.ends_with(suffix.as_str())))
65 }
66 "trim" => Ok(Value::String(s.trim().to_string())),
67 "trim_start" => Ok(Value::String(s.trim_start().to_string())),
68 "trim_end" => Ok(Value::String(s.trim_end().to_string())),
69 "to_uppercase" => Ok(Value::String(s.to_uppercase())),
70 "to_lowercase" => Ok(Value::String(s.to_lowercase())),
71 "replace" => {
72 if args.len() < 2 {
73 return Err(RuntimeError::new("replace() expects two arguments"));
74 }
75 match (&args[0], &args[1]) {
76 (Value::String(from), Value::String(to)) => {
77 Ok(Value::String(s.replace(from.as_str(), to.as_str())))
78 }
79 _ => Err(RuntimeError::new(
80 "replace() expects two string arguments",
81 )),
82 }
83 }
84 "split" => {
85 let delim = expect_string_arg(&args, "split")?;
86 let parts = s
87 .split(delim.as_str())
88 .map(|p| Value::String(p.to_string()))
89 .collect();
90 Ok(Value::Array(parts))
91 }
92 "chars" => Ok(Value::Array(s.chars().map(Value::Char).collect())),
93 "bytes" => Ok(Value::Array(
94 s.bytes().map(|b| Value::Int(b as i64)).collect(),
95 )),
96 "to_string" => Ok(Value::String(s)),
97 "parse" => {
98 if let Ok(n) = s.parse::<i64>() {
99 Ok(Value::Option(Some(Box::new(Value::Int(n)))))
100 } else if let Ok(n) = s.parse::<f64>() {
101 Ok(Value::Option(Some(Box::new(Value::Float(n)))))
102 } else {
103 Ok(Value::Option(None))
104 }
105 }
106 "push_str" => {
107 let extra = expect_string_arg(&args, "push_str")?;
108 Ok(Value::String(format!("{s}{extra}")))
109 }
110 "push" => {
111 let c = expect_char_arg(&args, "push")?;
112 let mut new_s = s;
113 new_s.push(c);
114 Ok(Value::String(new_s))
115 }
116 "repeat" => {
117 let n = expect_int_arg(&args, "repeat")?;
118 Ok(Value::String(s.repeat(n as usize)))
119 }
120 "lines" => {
121 let lines = s.lines().map(|l| Value::String(l.to_string())).collect();
122 Ok(Value::Array(lines))
123 }
124 "clone" => Ok(Value::String(s)),
125 _ => Err(RuntimeError::new(format!(
126 "Unknown method '{method}' on String"
127 ))),
128 }
129 }
130}
131
132impl Interpreter {
135 fn array_method(
136 &mut self,
137 arr: Vec<Value>,
138 method: &str,
139 args: Vec<Value>,
140 ) -> Result<Value, RuntimeError> {
141 match method {
142 "len" | "count" => Ok(Value::Int(arr.len() as i64)),
144 "is_empty" => Ok(Value::Bool(arr.is_empty())),
145 "first" => Ok(Value::Option(arr.first().map(|v| Box::new(v.clone())))),
146 "last" => Ok(Value::Option(arr.last().map(|v| Box::new(v.clone())))),
147
148 "push" => {
150 let mut new_arr = arr;
151 if let Some(val) = args.into_iter().next() {
152 new_arr.push(val);
153 }
154 Ok(Value::Array(new_arr))
155 }
156 "pop" => {
157 let mut new_arr = arr;
158 let popped = new_arr.pop();
159 Ok(Value::Option(popped.map(Box::new)))
160 }
161 "reverse" => {
162 let mut new_arr = arr;
163 new_arr.reverse();
164 Ok(Value::Array(new_arr))
165 }
166
167 "contains" => {
169 if let Some(val) = args.first() {
170 let found = arr
171 .iter()
172 .any(|v| format!("{v}") == format!("{val}"));
173 Ok(Value::Bool(found))
174 } else {
175 Ok(Value::Bool(false))
176 }
177 }
178
179 "iter" | "into_iter" | "collect" => Ok(Value::Array(arr)),
181
182 "map" => self.array_hof_map(arr, args),
184 "filter" => self.array_hof_filter(arr, args),
185 "fold" => self.array_hof_fold(arr, args),
186 "for_each" => self.array_hof_for_each(arr, args),
187 "any" => self.array_hof_any(arr, args),
188 "all" => self.array_hof_all(arr, args),
189 "find" => self.array_hof_find(arr, args),
190 "position" => self.array_hof_position(arr, args),
191 "flat_map" => self.array_hof_flat_map(arr, args),
192
193 "enumerate" => {
195 let enumerated = arr
196 .iter()
197 .enumerate()
198 .map(|(i, v)| Value::Tuple(vec![Value::Int(i as i64), v.clone()]))
199 .collect();
200 Ok(Value::Array(enumerated))
201 }
202 "zip" => {
203 let other = match args.first() {
204 Some(Value::Array(a)) => a,
205 _ => return Err(RuntimeError::new("zip() expects an array argument")),
206 };
207 let zipped = arr
208 .iter()
209 .zip(other.iter())
210 .map(|(a, b)| Value::Tuple(vec![a.clone(), b.clone()]))
211 .collect();
212 Ok(Value::Array(zipped))
213 }
214 "skip" => {
215 let n = expect_int_arg(&args, "skip")? as usize;
216 Ok(Value::Array(arr.into_iter().skip(n).collect()))
217 }
218 "take" => {
219 let n = expect_int_arg(&args, "take")? as usize;
220 Ok(Value::Array(arr.into_iter().take(n).collect()))
221 }
222
223 "sum" => {
225 let mut acc = Value::Int(0);
226 for item in &arr {
227 acc = self.eval_binary_op(&acc, &BinOp::Add, item)?;
228 }
229 Ok(acc)
230 }
231 "product" => {
232 let mut acc = Value::Int(1);
233 for item in &arr {
234 acc = self.eval_binary_op(&acc, &BinOp::Mul, item)?;
235 }
236 Ok(acc)
237 }
238 "min" => self.array_min_max(&arr, true),
239 "max" => self.array_min_max(&arr, false),
240 "join" => {
241 let sep = match args.first() {
242 Some(Value::String(s)) => s.as_str(),
243 _ => "",
244 };
245 let parts: Vec<String> = arr.iter().map(|v| format!("{v}")).collect();
246 Ok(Value::String(parts.join(sep)))
247 }
248
249 _ => Err(RuntimeError::new(format!(
250 "Unknown method '{method}' on array"
251 ))),
252 }
253 }
254
255 fn array_hof_map(&mut self, arr: Vec<Value>, args: Vec<Value>) -> Result<Value, RuntimeError> {
258 let func = expect_callable(args, "map")?;
259 let mut results = Vec::with_capacity(arr.len());
260 for item in arr {
261 results.push(self.call_function(func.clone(), vec![item])?);
262 }
263 Ok(Value::Array(results))
264 }
265
266 fn array_hof_filter(
267 &mut self,
268 arr: Vec<Value>,
269 args: Vec<Value>,
270 ) -> Result<Value, RuntimeError> {
271 let func = expect_callable(args, "filter")?;
272 let mut results = Vec::new();
273 for item in arr {
274 let keep = self.call_function(func.clone(), vec![item.clone()])?;
275 if keep.is_truthy() {
276 results.push(item);
277 }
278 }
279 Ok(Value::Array(results))
280 }
281
282 fn array_hof_fold(
283 &mut self,
284 arr: Vec<Value>,
285 args: Vec<Value>,
286 ) -> Result<Value, RuntimeError> {
287 if args.len() < 2 {
288 return Err(RuntimeError::new(
289 "fold() expects an initial value and a closure",
290 ));
291 }
292 let mut acc = args[0].clone();
293 let func = args[1].clone();
294 for item in arr {
295 acc = self.call_function(func.clone(), vec![acc, item])?;
296 }
297 Ok(acc)
298 }
299
300 fn array_hof_for_each(
301 &mut self,
302 arr: Vec<Value>,
303 args: Vec<Value>,
304 ) -> Result<Value, RuntimeError> {
305 let func = expect_callable(args, "for_each")?;
306 for item in arr {
307 self.call_function(func.clone(), vec![item])?;
308 }
309 Ok(Value::Unit)
310 }
311
312 fn array_hof_any(&mut self, arr: Vec<Value>, args: Vec<Value>) -> Result<Value, RuntimeError> {
313 let func = expect_callable(args, "any")?;
314 for item in arr {
315 if self.call_function(func.clone(), vec![item])?.is_truthy() {
316 return Ok(Value::Bool(true));
317 }
318 }
319 Ok(Value::Bool(false))
320 }
321
322 fn array_hof_all(&mut self, arr: Vec<Value>, args: Vec<Value>) -> Result<Value, RuntimeError> {
323 let func = expect_callable(args, "all")?;
324 for item in arr {
325 if !self.call_function(func.clone(), vec![item])?.is_truthy() {
326 return Ok(Value::Bool(false));
327 }
328 }
329 Ok(Value::Bool(true))
330 }
331
332 fn array_hof_find(
333 &mut self,
334 arr: Vec<Value>,
335 args: Vec<Value>,
336 ) -> Result<Value, RuntimeError> {
337 let func = expect_callable(args, "find")?;
338 for item in arr {
339 if self
340 .call_function(func.clone(), vec![item.clone()])?
341 .is_truthy()
342 {
343 return Ok(Value::Option(Some(Box::new(item))));
344 }
345 }
346 Ok(Value::Option(None))
347 }
348
349 fn array_hof_position(
350 &mut self,
351 arr: Vec<Value>,
352 args: Vec<Value>,
353 ) -> Result<Value, RuntimeError> {
354 let func = expect_callable(args, "position")?;
355 for (i, item) in arr.iter().enumerate() {
356 if self
357 .call_function(func.clone(), vec![item.clone()])?
358 .is_truthy()
359 {
360 return Ok(Value::Option(Some(Box::new(Value::Int(i as i64)))));
361 }
362 }
363 Ok(Value::Option(None))
364 }
365
366 fn array_hof_flat_map(
367 &mut self,
368 arr: Vec<Value>,
369 args: Vec<Value>,
370 ) -> Result<Value, RuntimeError> {
371 let func = expect_callable(args, "flat_map")?;
372 let mut results = Vec::new();
373 for item in arr {
374 let result = self.call_function(func.clone(), vec![item])?;
375 match result {
376 Value::Array(inner) => results.extend(inner),
377 other => results.push(other),
378 }
379 }
380 Ok(Value::Array(results))
381 }
382
383 fn array_min_max(&self, arr: &[Value], is_min: bool) -> Result<Value, RuntimeError> {
384 if arr.is_empty() {
385 return Ok(Value::Option(None));
386 }
387 let cmp_op = if is_min { BinOp::Lt } else { BinOp::Gt };
388 let mut best = arr[0].clone();
389 for item in arr.iter().skip(1) {
390 if let Value::Bool(true) = self.eval_binary_op(item, &cmp_op, &best)? {
391 best = item.clone();
392 }
393 }
394 Ok(Value::Option(Some(Box::new(best))))
395 }
396}
397
398impl Interpreter {
401 fn int_method(
402 &self,
403 n: i64,
404 method: &str,
405 args: &[Value],
406 ) -> Result<Value, RuntimeError> {
407 match method {
408 "abs" => Ok(Value::Int(n.abs())),
409 "pow" => {
410 let exp = expect_int_arg(args, "pow")?;
411 Ok(Value::Int(n.pow(exp as u32)))
412 }
413 "to_string" => Ok(Value::String(n.to_string())),
414 "min" => {
415 let other = expect_int_arg(args, "min")?;
416 Ok(Value::Int(n.min(other)))
417 }
418 "max" => {
419 let other = expect_int_arg(args, "max")?;
420 Ok(Value::Int(n.max(other)))
421 }
422 "clamp" => {
423 if args.len() < 2 {
424 return Err(RuntimeError::new("clamp() expects two arguments"));
425 }
426 match (&args[0], &args[1]) {
427 (Value::Int(min), Value::Int(max)) => Ok(Value::Int(n.clamp(*min, *max))),
428 _ => Err(RuntimeError::new("clamp() expects integer arguments")),
429 }
430 }
431 _ => Err(RuntimeError::new(format!(
432 "Unknown method '{method}' on i64"
433 ))),
434 }
435 }
436}
437
438impl Interpreter {
441 fn float_method(
442 &self,
443 n: f64,
444 method: &str,
445 args: &[Value],
446 ) -> Result<Value, RuntimeError> {
447 match method {
448 "abs" => Ok(Value::Float(n.abs())),
449 "sqrt" => Ok(Value::Float(n.sqrt())),
450 "floor" => Ok(Value::Float(n.floor())),
451 "ceil" => Ok(Value::Float(n.ceil())),
452 "round" => Ok(Value::Float(n.round())),
453 "sin" => Ok(Value::Float(n.sin())),
454 "cos" => Ok(Value::Float(n.cos())),
455 "tan" => Ok(Value::Float(n.tan())),
456 "log" => {
457 if let Some(Value::Float(base)) = args.first() {
458 Ok(Value::Float(n.log(*base)))
459 } else {
460 Ok(Value::Float(n.ln()))
461 }
462 }
463 "ln" => Ok(Value::Float(n.ln())),
464 "log2" => Ok(Value::Float(n.log2())),
465 "log10" => Ok(Value::Float(n.log10())),
466 "powi" => {
467 let exp = expect_int_arg(args, "powi")?;
468 Ok(Value::Float(n.powi(exp as i32)))
469 }
470 "powf" => {
471 if let Some(Value::Float(exp)) = args.first() {
472 Ok(Value::Float(n.powf(*exp)))
473 } else {
474 Err(RuntimeError::new("powf() expects a float argument"))
475 }
476 }
477 "is_nan" => Ok(Value::Bool(n.is_nan())),
478 "is_infinite" => Ok(Value::Bool(n.is_infinite())),
479 "is_finite" => Ok(Value::Bool(n.is_finite())),
480 "to_string" => Ok(Value::String(n.to_string())),
481 _ => Err(RuntimeError::new(format!(
482 "Unknown method '{method}' on f64"
483 ))),
484 }
485 }
486}
487
488impl Interpreter {
491 fn bool_method(&self, b: bool, method: &str) -> Result<Value, RuntimeError> {
492 match method {
493 "to_string" => Ok(Value::String(b.to_string())),
494 _ => Err(RuntimeError::new(format!(
495 "Unknown method '{method}' on bool"
496 ))),
497 }
498 }
499}
500
501impl Interpreter {
504 fn char_method(&self, c: char, method: &str) -> Result<Value, RuntimeError> {
505 match method {
506 "is_alphabetic" => Ok(Value::Bool(c.is_alphabetic())),
507 "is_numeric" => Ok(Value::Bool(c.is_numeric())),
508 "is_alphanumeric" => Ok(Value::Bool(c.is_alphanumeric())),
509 "is_whitespace" => Ok(Value::Bool(c.is_whitespace())),
510 "is_uppercase" => Ok(Value::Bool(c.is_uppercase())),
511 "is_lowercase" => Ok(Value::Bool(c.is_lowercase())),
512 "to_uppercase" => Ok(Value::String(c.to_uppercase().to_string())),
513 "to_lowercase" => Ok(Value::String(c.to_lowercase().to_string())),
514 "to_string" => Ok(Value::String(c.to_string())),
515 _ => Err(RuntimeError::new(format!(
516 "Unknown method '{method}' on char"
517 ))),
518 }
519 }
520}
521
522impl Interpreter {
525 fn option_method(
526 &mut self,
527 opt: Option<Box<Value>>,
528 method: &str,
529 args: Vec<Value>,
530 ) -> Result<Value, RuntimeError> {
531 match method {
532 "unwrap" => match opt {
533 Some(v) => Ok(*v),
534 None => Err(RuntimeError::new("Called unwrap() on a None value")),
535 },
536 "unwrap_or" => match opt {
537 Some(v) => Ok(*v),
538 None => args
539 .into_iter()
540 .next()
541 .ok_or_else(|| RuntimeError::new("unwrap_or() expects a default value")),
542 },
543 "is_some" => Ok(Value::Bool(opt.is_some())),
544 "is_none" => Ok(Value::Bool(opt.is_none())),
545 "map" => {
546 let func = expect_callable(args, "map")?;
547 match opt {
548 Some(v) => {
549 let result = self.call_function(func, vec![*v])?;
550 Ok(Value::Option(Some(Box::new(result))))
551 }
552 None => Ok(Value::Option(None)),
553 }
554 }
555 _ => Err(RuntimeError::new(format!(
556 "Unknown method '{method}' on Option"
557 ))),
558 }
559 }
560}
561
562fn expect_string_arg(args: &[Value], method_name: &str) -> Result<String, RuntimeError> {
565 match args.first() {
566 Some(Value::String(s)) => Ok(s.clone()),
567 _ => Err(RuntimeError::new(format!(
568 "{method_name}() expects a string argument"
569 ))),
570 }
571}
572
573fn expect_int_arg(args: &[Value], method_name: &str) -> Result<i64, RuntimeError> {
574 match args.first() {
575 Some(Value::Int(n)) => Ok(*n),
576 _ => Err(RuntimeError::new(format!(
577 "{method_name}() expects an integer argument"
578 ))),
579 }
580}
581
582fn expect_char_arg(args: &[Value], method_name: &str) -> Result<char, RuntimeError> {
583 match args.first() {
584 Some(Value::Char(c)) => Ok(*c),
585 _ => Err(RuntimeError::new(format!(
586 "{method_name}() expects a char argument"
587 ))),
588 }
589}
590
591fn expect_callable(args: Vec<Value>, method_name: &str) -> Result<Value, RuntimeError> {
592 args.into_iter().next().ok_or_else(|| {
593 RuntimeError::new(format!("{method_name}() expects a closure argument"))
594 })
595}