1use crate::{
2 ast::{BinaryOp, DoStatement, Expr, PostfixOp, RecordEntry, RecordKey, UnaryOp},
3 functions::{
4 BuiltInFunction, get_built_in_function_def_by_ident, get_function_def, is_built_in_function,
5 },
6 heap::{Heap, HeapPointer, HeapValue, IterablePointer, RecordPointer},
7 parser::Rule,
8 values::{
9 LambdaArg, LambdaDef,
10 Value::{self, Bool, List, Number, Spread},
11 },
12};
13use anyhow::{Result, anyhow};
14use indexmap::IndexMap;
15use pest::{
16 iterators::Pairs,
17 pratt_parser::{Assoc, Op, PrattParser},
18};
19use std::{
20 cell::RefCell,
21 collections::{HashMap, HashSet},
22 rc::Rc,
23 sync::LazyLock,
24};
25
26static PRATT: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
27 PrattParser::new()
28 .op(Op::infix(Rule::and, Assoc::Left)
29 | Op::infix(Rule::natural_and, Assoc::Left)
30 | Op::infix(Rule::or, Assoc::Left)
31 | Op::infix(Rule::natural_or, Assoc::Left)
32 | Op::infix(Rule::via, Assoc::Left)
33 | Op::infix(Rule::into, Assoc::Left))
34 .op(Op::infix(Rule::equal, Assoc::Left)
35 | Op::infix(Rule::not_equal, Assoc::Left)
36 | Op::infix(Rule::less, Assoc::Left)
37 | Op::infix(Rule::less_eq, Assoc::Left)
38 | Op::infix(Rule::greater, Assoc::Left)
39 | Op::infix(Rule::greater_eq, Assoc::Left)
40 | Op::infix(Rule::dot_equal, Assoc::Left)
41 | Op::infix(Rule::dot_not_equal, Assoc::Left)
42 | Op::infix(Rule::dot_less, Assoc::Left)
43 | Op::infix(Rule::dot_less_eq, Assoc::Left)
44 | Op::infix(Rule::dot_greater, Assoc::Left)
45 | Op::infix(Rule::dot_greater_eq, Assoc::Left))
46 .op(Op::infix(Rule::add, Assoc::Left) | Op::infix(Rule::subtract, Assoc::Left))
47 .op(Op::infix(Rule::multiply, Assoc::Left)
48 | Op::infix(Rule::divide, Assoc::Left)
49 | Op::infix(Rule::modulo, Assoc::Left))
50 .op(Op::infix(Rule::power, Assoc::Right) | Op::infix(Rule::coalesce, Assoc::Left))
51 .op(Op::prefix(Rule::negation)
52 | Op::prefix(Rule::spread_operator)
53 | Op::prefix(Rule::invert)
54 | Op::prefix(Rule::natural_not))
55 .op(Op::postfix(Rule::factorial))
56 .op(Op::postfix(Rule::access)
57 | Op::postfix(Rule::dot_access)
58 | Op::postfix(Rule::call_list))
59});
60
61pub fn evaluate_pairs(
63 pairs: Pairs<Rule>,
64 heap: Rc<RefCell<Heap>>,
65 bindings: Rc<RefCell<HashMap<String, Value>>>,
66 call_depth: usize,
67) -> Result<Value> {
68 let ast = pairs_to_expr(pairs)?;
70
71 evaluate_ast(&ast, heap, bindings, call_depth)
73}
74
75fn flatten_spread_value(
78 spread_ptr: &IterablePointer,
79 heap: &Rc<RefCell<Heap>>,
80) -> Result<Vec<Value>> {
81 match spread_ptr {
82 IterablePointer::List(list_ptr) => {
83 let borrowed_heap = heap.borrow();
84 Ok(list_ptr.reify(&borrowed_heap).as_list()?.clone())
85 }
86 IterablePointer::String(string_ptr) => {
87 let string = {
88 let borrowed_heap = heap.borrow();
89 string_ptr.reify(&borrowed_heap).as_string()?.to_string()
90 };
91 Ok(string
93 .chars()
94 .map(|c| heap.borrow_mut().insert_string(c.to_string()))
95 .collect())
96 }
97 IterablePointer::Record(record_ptr) => {
98 let entries = {
99 let borrowed_heap = heap.borrow();
100 record_ptr.reify(&borrowed_heap).as_record()?.clone()
101 };
102 Ok(entries
104 .into_iter()
105 .map(|(k, v)| {
106 let key = heap.borrow_mut().insert_string(k);
107 heap.borrow_mut().insert_list(vec![key, v])
108 })
109 .collect())
110 }
111 }
112}
113
114fn evaluate_do_block_expr(
116 expr: &Expr,
117 heap: Rc<RefCell<Heap>>,
118 bindings: Rc<RefCell<HashMap<String, Value>>>,
119 call_depth: usize,
120) -> Result<Value> {
121 if let Expr::Assignment { ident, value } = expr {
123 if matches!(
125 ident.as_str(),
126 "return" | "if" | "then" | "else" | "do" | "true" | "false" | "null" | "output"
127 ) {
128 return Err(anyhow!("{} is a keyword, and cannot be reassigned", ident));
129 }
130
131 let val = evaluate_ast(value, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
133
134 if let Value::Lambda(lambda_ptr) = val {
136 let mut borrowed_heap = heap.borrow_mut();
137 if let Some(HeapValue::Lambda(lambda_def)) = borrowed_heap.get_mut(lambda_ptr.index()) {
138 lambda_def.name = Some(ident.clone());
139 }
140 }
141
142 bindings.borrow_mut().insert(ident.clone(), val);
143 return Ok(val);
144 }
145
146 evaluate_ast(expr, heap, bindings, call_depth)
148}
149
150pub fn evaluate_ast(
151 expr: &Expr,
152 heap: Rc<RefCell<Heap>>,
153 bindings: Rc<RefCell<HashMap<String, Value>>>,
154 call_depth: usize,
155) -> Result<Value> {
156 match expr {
157 Expr::Number(n) => Ok(Number(*n)),
158 Expr::String(s) => Ok(heap.borrow_mut().insert_string(s.clone())),
159 Expr::Bool(b) => Ok(Bool(*b)),
160 Expr::Null => Ok(Value::Null),
161 Expr::Identifier(ident) => match ident.as_str() {
162 "infinity" => Ok(Number(f64::INFINITY)),
163 "inf" => Ok(Number(f64::INFINITY)),
164 "constants" => Ok(Value::Record(RecordPointer::new(0))),
165 _ => bindings
166 .borrow()
167 .get(ident)
168 .copied()
169 .ok_or(anyhow!("unknown identifier: {}", ident)),
170 },
171 Expr::InputReference(field) => {
172 let inputs_value = bindings
174 .borrow()
175 .get("inputs")
176 .copied()
177 .ok_or(anyhow!("inputs not found (required for #{} syntax)", field))?;
178
179 match inputs_value {
180 Value::Record(record_ptr) => {
181 let borrowed_heap = heap.borrow();
182 let record = record_ptr.reify(&borrowed_heap).as_record()?;
183 Ok(record.get(field).copied().unwrap_or(Value::Null))
185 }
186 _ => Err(anyhow!("inputs must be a record to use #{} syntax", field)),
187 }
188 }
189 Expr::BuiltIn(built_in) => Ok(Value::BuiltIn(*built_in)),
190 Expr::List(exprs) => {
191 let values = exprs
192 .iter()
193 .map(|e| evaluate_ast(e, Rc::clone(&heap), Rc::clone(&bindings), call_depth))
194 .collect::<Result<Vec<Value>>>()?;
195
196 let mut flattened = Vec::new();
198
199 for value in values {
200 match value {
201 Value::Spread(spread_ptr) => {
202 let spread_values = flatten_spread_value(&spread_ptr, &heap)?;
203 flattened.extend(spread_values);
204 }
205 _ => flattened.push(value),
206 }
207 }
208
209 Ok(heap.borrow_mut().insert_list(flattened))
210 }
211 Expr::Record(entries) => {
212 let mut record = IndexMap::new();
213
214 for entry in entries {
215 match &entry.key {
216 RecordKey::Static(key) => {
217 let value = evaluate_ast(
218 &entry.value,
219 Rc::clone(&heap),
220 Rc::clone(&bindings),
221 call_depth,
222 )?;
223 record.insert(key.clone(), value);
224 }
225 RecordKey::Dynamic(key_expr) => {
226 let key_value = evaluate_ast(
227 key_expr,
228 Rc::clone(&heap),
229 Rc::clone(&bindings),
230 call_depth,
231 )?;
232 let key = key_value.as_string(&heap.borrow())?.to_string();
233 let value = evaluate_ast(
234 &entry.value,
235 Rc::clone(&heap),
236 Rc::clone(&bindings),
237 call_depth,
238 )?;
239 record.insert(key, value);
240 }
241 RecordKey::Shorthand(ident) => {
242 let value = bindings
243 .borrow()
244 .get(ident)
245 .copied()
246 .ok_or(anyhow!("unknown identifier: {}", ident))?;
247 record.insert(ident.clone(), value);
248 }
249 RecordKey::Spread(spread_expr) => {
250 let spread_value = evaluate_ast(
251 spread_expr,
252 Rc::clone(&heap),
253 Rc::clone(&bindings),
254 call_depth,
255 )?;
256
257 if let Spread(iterable) = spread_value {
258 match iterable {
259 IterablePointer::List(pointer) => {
260 let borrowed_heap = &heap.borrow();
261 pointer
262 .reify(borrowed_heap)
263 .as_list()?
264 .iter()
265 .enumerate()
266 .for_each(|(i, value)| {
267 record.insert(i.to_string(), *value);
268 });
269 }
270 IterablePointer::String(pointer) => {
271 let s = {
272 let borrowed_heap = &heap.borrow();
273 pointer.reify(borrowed_heap).as_string()?.to_string()
274 };
275
276 s.chars().enumerate().for_each(|(i, c)| {
277 record.insert(
278 i.to_string(),
279 heap.borrow_mut().insert_string(c.to_string()),
280 );
281 });
282 }
283 IterablePointer::Record(pointer) => {
284 let borrowed_heap = &heap.borrow();
285 let spread_record = pointer.reify(borrowed_heap).as_record()?;
286
287 for (k, v) in spread_record {
288 record.insert(k.clone(), *v);
289 }
290 }
291 }
292 }
293 }
294 }
295 }
296
297 Ok(heap.borrow_mut().insert_record(record))
298 }
299 Expr::Lambda { args, body } => {
300 let mut captured_scope = HashMap::new();
302 let mut referenced_vars = Vec::new();
303 collect_free_variables(body, &mut referenced_vars, &mut HashSet::new());
304
305 let current_bindings = bindings.borrow();
306 for var in referenced_vars {
307 if current_bindings.contains_key(&var) && !is_built_in_function(&var) {
308 captured_scope.insert(var.clone(), current_bindings[&var]);
309 }
310 }
311
312 let lambda = heap.borrow_mut().insert_lambda(LambdaDef {
313 name: None,
314 args: args.clone(),
315 body: (**body).clone(),
316 scope: captured_scope,
317 });
318
319 Ok(lambda)
320 }
321 Expr::Assignment { ident, value } => {
322 if is_built_in_function(ident) {
323 return Err(anyhow!(
324 "{} is the name of a built-in function, and cannot be reassigned",
325 ident
326 ));
327 }
328
329 if ident == "constants"
330 || ident == "if"
331 || ident == "then"
332 || ident == "else"
333 || ident == "true"
334 || ident == "false"
335 || ident == "null"
336 || ident == "inputs"
337 || ident == "and"
338 || ident == "or"
339 {
340 return Err(anyhow!("{} is a keyword, and cannot be reassigned", ident));
341 }
342
343 if bindings.borrow().contains_key(ident) {
345 return Err(anyhow!(
346 "{} is already defined, and cannot be reassigned",
347 ident
348 ));
349 }
350
351 let val = evaluate_ast(value, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
352
353 if let Value::Lambda(lambda_ptr) = val {
355 let mut borrowed_heap = heap.borrow_mut();
356 if let Some(HeapValue::Lambda(lambda_def)) =
357 borrowed_heap.get_mut(lambda_ptr.index())
358 {
359 lambda_def.name = Some(ident.clone());
360 }
361 }
362
363 bindings.borrow_mut().insert(ident.clone(), val);
364 Ok(val)
365 }
366 Expr::Conditional {
367 condition,
368 then_expr,
369 else_expr,
370 } => {
371 let cond_val = evaluate_ast(
372 condition,
373 Rc::clone(&heap),
374 Rc::clone(&bindings),
375 call_depth,
376 )?;
377
378 if cond_val.as_bool()? {
379 evaluate_ast(then_expr, heap, bindings, call_depth)
380 } else {
381 evaluate_ast(else_expr, heap, bindings, call_depth)
382 }
383 }
384 Expr::DoBlock {
385 statements,
386 return_expr,
387 } => {
388 let new_bindings = bindings.borrow().clone();
390 let block_bindings = Rc::new(RefCell::new(new_bindings));
391
392 for stmt in statements {
394 match stmt {
395 DoStatement::Expression(expr) => {
396 evaluate_do_block_expr(
397 expr,
398 Rc::clone(&heap),
399 Rc::clone(&block_bindings),
400 call_depth,
401 )?;
402 }
403 DoStatement::Comment(_) => {} }
405 }
406
407 evaluate_do_block_expr(return_expr, heap, block_bindings, call_depth)
409 }
410 Expr::Call { func, args } => {
411 let func_val = evaluate_ast(func, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
412 let arg_vals_raw = args
413 .iter()
414 .map(|arg| evaluate_ast(arg, Rc::clone(&heap), Rc::clone(&bindings), call_depth))
415 .collect::<Result<Vec<_>>>()?;
416
417 let mut arg_vals = Vec::new();
419
420 for value in arg_vals_raw {
421 match value {
422 Value::Spread(spread_ptr) => {
423 let spread_values = flatten_spread_value(&spread_ptr, &heap)?;
424 arg_vals.extend(spread_values);
425 }
426 _ => arg_vals.push(value),
427 }
428 }
429
430 if !func_val.is_lambda() && !func_val.is_built_in() {
431 return Err(anyhow!(
432 "can't call a non-function: {}",
433 func_val.stringify_internal(&heap.borrow())
434 ));
435 }
436
437 let def = {
438 let borrowed_heap = &heap.borrow();
439 get_function_def(&func_val, borrowed_heap).ok_or_else(|| {
440 anyhow!(
441 "unknown function: {}",
442 func_val.stringify_internal(borrowed_heap)
443 )
444 })?
445 };
446
447 def.call(func_val, arg_vals, heap, bindings, call_depth)
448 }
449 Expr::Access { expr, index } => {
450 let val = evaluate_ast(expr, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
451 let idx_val = evaluate_ast(index, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
452
453 match val {
454 Value::Record(record) => {
455 let borrowed_heap = &heap.borrow();
456 let record = record.reify(borrowed_heap).as_record()?;
457 let key = idx_val.as_string(borrowed_heap)?;
458 Ok(record.get(key).copied().unwrap_or(Value::Null))
459 }
460 Value::List(list) => {
461 let borrowed_heap = &heap.borrow();
462 let list = list.reify(borrowed_heap).as_list()?;
463 let index = usize::try_from(idx_val.as_number()? as u64)?;
464 Ok(list.get(index).copied().unwrap_or(Value::Null))
465 }
466 Value::String(string) => {
467 let string = string.reify(&heap.borrow()).as_string()?.to_string();
468 let index = usize::try_from(idx_val.as_number()? as u64)?;
469
470 Ok(string
471 .chars()
472 .nth(index)
473 .map(|c| heap.borrow_mut().insert_string(c.to_string()))
474 .unwrap_or(Value::Null))
475 }
476 _ => Err(anyhow!(
477 "expected a record, list, string, but got a {}",
478 val.get_type()
479 )),
480 }
481 }
482 Expr::DotAccess { expr, field } => {
483 let val = evaluate_ast(expr, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
484 let borrowed_heap = &heap.borrow();
485
486 match val {
487 Value::Record(record) => {
488 let record = record.reify(borrowed_heap).as_record()?;
489 Ok(record.get(field).copied().unwrap_or(Value::Null))
490 }
491 _ => Err(anyhow!("expected a record, but got a {}", val.get_type())),
492 }
493 }
494 Expr::BinaryOp { op, left, right } => {
495 evaluate_binary_op_ast(*op, left, right, heap, bindings, call_depth)
496 }
497 Expr::UnaryOp { op, expr } => {
498 let val = evaluate_ast(expr, heap, bindings, call_depth)?;
499
500 match op {
501 UnaryOp::Negate => Ok(Number(-val.as_number()?)),
502 UnaryOp::Not | UnaryOp::Invert => Ok(Bool(!val.as_bool()?)),
503 }
504 }
505 Expr::PostfixOp { op, expr } => {
506 let val = evaluate_ast(expr, heap, bindings, call_depth)?;
507
508 match op {
509 PostfixOp::Factorial => {
510 let n = val.as_number()?;
511 if n >= 0.0 && n == (n as u64) as f64 {
512 Ok(Number(
513 (1..(n as u64) + 1).map(|x| x as f64).product::<f64>(),
514 ))
515 } else {
516 Err(anyhow!("factorial only works on non-negative integers"))
517 }
518 }
519 }
520 }
521 Expr::Spread(expr) => {
522 let val = evaluate_ast(expr, heap, bindings, call_depth)?;
523
524 match val {
525 List(pointer) => Ok(Spread(IterablePointer::List(pointer))),
526 Value::String(pointer) => Ok(Spread(IterablePointer::String(pointer))),
527 Value::Record(pointer) => Ok(Spread(IterablePointer::Record(pointer))),
528 _ => Err(anyhow!("expected a list, record, or string")),
529 }
530 }
531 }
532}
533
534fn collect_free_variables(expr: &Expr, vars: &mut Vec<String>, bound: &mut HashSet<String>) {
536 match expr {
537 Expr::Identifier(name) => {
538 if !bound.contains(name) && name != "infinity" && name != "inf" && name != "constants" {
539 vars.push(name.clone());
540 }
541 }
542 Expr::Lambda { args, body } => {
543 let mut new_bound = bound.clone();
544 for arg in args {
545 new_bound.insert(arg.get_name().to_string());
546 }
547 collect_free_variables(body, vars, &mut new_bound);
548 }
549 Expr::BinaryOp { left, right, .. } => {
550 collect_free_variables(left, vars, bound);
551 collect_free_variables(right, vars, bound);
552 }
553 Expr::UnaryOp { expr, .. } | Expr::PostfixOp { expr, .. } | Expr::Spread(expr) => {
554 collect_free_variables(expr, vars, bound);
555 }
556 Expr::Call { func, args } => {
557 collect_free_variables(func, vars, bound);
558 for arg in args {
559 collect_free_variables(arg, vars, bound);
560 }
561 }
562 Expr::Access { expr, index } => {
563 collect_free_variables(expr, vars, bound);
564 collect_free_variables(index, vars, bound);
565 }
566 Expr::DotAccess { expr, .. } => {
567 collect_free_variables(expr, vars, bound);
568 }
569 Expr::Conditional {
570 condition,
571 then_expr,
572 else_expr,
573 } => {
574 collect_free_variables(condition, vars, bound);
575 collect_free_variables(then_expr, vars, bound);
576 collect_free_variables(else_expr, vars, bound);
577 }
578 Expr::Assignment { value, .. } => {
579 collect_free_variables(value, vars, bound);
580 }
581 Expr::List(exprs) => {
582 for expr in exprs {
583 collect_free_variables(expr, vars, bound);
584 }
585 }
586 Expr::Record(entries) => {
587 for entry in entries {
588 match &entry.key {
589 RecordKey::Dynamic(expr) | RecordKey::Spread(expr) => {
590 collect_free_variables(expr, vars, bound);
591 }
592 _ => {}
593 }
594 if !matches!(entry.key, RecordKey::Shorthand(_) | RecordKey::Spread(_)) {
595 collect_free_variables(&entry.value, vars, bound);
596 }
597 }
598 }
599 Expr::DoBlock {
600 statements,
601 return_expr,
602 } => {
603 let mut block_bound = bound.clone();
605
606 for stmt in statements {
607 if let DoStatement::Expression(expr) = stmt {
608 if let Expr::Assignment { ident, value } = expr {
610 collect_free_variables(value, vars, &mut block_bound);
612 block_bound.insert(ident.clone());
614 } else {
615 collect_free_variables(expr, vars, &mut block_bound);
616 }
617 }
618 }
619 collect_free_variables(return_expr, vars, &mut block_bound);
620 }
621 _ => {}
622 }
623}
624
625pub fn validate_portable_value(
627 value: &Value,
628 heap: &Heap,
629 bindings: &HashMap<String, Value>,
630) -> Result<()> {
631 match value {
632 Value::Lambda(lambda_ptr) => {
633 if let Some(HeapValue::Lambda(lambda_def)) = heap.get(lambda_ptr.index()) {
635 let mut free_vars = Vec::new();
637 let mut bound_vars = HashSet::new();
638
639 for arg in &lambda_def.args {
641 bound_vars.insert(arg.get_name().to_string());
642 }
643
644 for key in lambda_def.scope.keys() {
646 bound_vars.insert(key.clone());
647 }
648
649 collect_free_variables(&lambda_def.body, &mut free_vars, &mut bound_vars);
650
651 for var in &free_vars {
657 let is_self_reference = lambda_def.name.as_ref() == Some(var);
658
659 if !lambda_def.scope.contains_key(var)
660 && !is_built_in_function(var)
661 && !is_self_reference
662 && !bindings.contains_key(var)
663 {
664 return Err(anyhow!(
665 "Function contains unbound variable \"{}\". Output functions must be self-contained.",
666 var
667 ));
668 }
669 }
670 }
671 Ok(())
672 }
673 Value::List(list_ptr) => {
674 let list = list_ptr.reify(heap).as_list()?;
676 for item in list {
677 validate_portable_value(item, heap, bindings)?;
678 }
679 Ok(())
680 }
681 Value::Record(record_ptr) => {
682 let record = record_ptr.reify(heap).as_record()?;
684 for value in record.values() {
685 validate_portable_value(value, heap, bindings)?;
686 }
687 Ok(())
688 }
689 _ => Ok(()),
691 }
692}
693
694fn evaluate_binary_op_ast(
696 op: BinaryOp,
697 left: &Expr,
698 right: &Expr,
699 heap: Rc<RefCell<Heap>>,
700 bindings: Rc<RefCell<HashMap<String, Value>>>,
701 call_depth: usize,
702) -> Result<Value> {
703 let lhs = evaluate_ast(left, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
704 let rhs = evaluate_ast(right, Rc::clone(&heap), Rc::clone(&bindings), call_depth)?;
705
706 match op {
708 BinaryOp::DotEqual => return Ok(Bool(lhs.equals(&rhs, &heap.borrow())?)),
709 BinaryOp::DotNotEqual => return Ok(Bool(!lhs.equals(&rhs, &heap.borrow())?)),
710 BinaryOp::DotLess => {
711 return match lhs.compare(&rhs, &heap.borrow())? {
712 Some(std::cmp::Ordering::Less) => Ok(Bool(true)),
713 _ => Ok(Bool(false)),
714 };
715 }
716 BinaryOp::DotLessEq => {
717 return match lhs.compare(&rhs, &heap.borrow())? {
718 Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) => Ok(Bool(true)),
719 _ => Ok(Bool(false)),
720 };
721 }
722 BinaryOp::DotGreater => {
723 return match lhs.compare(&rhs, &heap.borrow())? {
724 Some(std::cmp::Ordering::Greater) => Ok(Bool(true)),
725 _ => Ok(Bool(false)),
726 };
727 }
728 BinaryOp::DotGreaterEq => {
729 return match lhs.compare(&rhs, &heap.borrow())? {
730 Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) => {
731 Ok(Bool(true))
732 }
733 _ => Ok(Bool(false)),
734 };
735 }
736 _ => {} }
738
739 match (lhs, rhs) {
740 (_, Value::List(_)) if op == BinaryOp::Into => Err(anyhow!(
741 "'into' operator requires a function on the right side, not a list"
742 )),
743 (Value::List(list_l), Value::List(list_r)) => {
744 let (l_vec, r_vec) = {
745 let borrowed_heap = &heap.borrow();
746 (
747 list_l.reify(borrowed_heap).as_list()?.clone(),
748 list_r.reify(borrowed_heap).as_list()?.clone(),
749 )
750 };
751
752 if l_vec.len() != r_vec.len() {
753 return Err(anyhow!(
754 "left- and right-hand-side lists must be the same length"
755 ));
756 }
757
758 match op {
759 BinaryOp::Equal => {
760 let mapped_list = l_vec
761 .iter()
762 .zip(&r_vec)
763 .map(|(l, r)| Ok(Bool(l.equals(r, &heap.borrow())?)))
764 .collect::<Result<Vec<Value>>>()?;
765 Ok(heap.borrow_mut().insert_list(mapped_list))
766 }
767 BinaryOp::NotEqual => {
768 let mapped_list = l_vec
769 .iter()
770 .zip(&r_vec)
771 .map(|(l, r)| Ok(Bool(!l.equals(r, &heap.borrow())?)))
772 .collect::<Result<Vec<Value>>>()?;
773 Ok(heap.borrow_mut().insert_list(mapped_list))
774 }
775 BinaryOp::Less => {
776 let mapped_list = l_vec
777 .iter()
778 .zip(&r_vec)
779 .map(|(l, r)| match l.compare(r, &heap.borrow())? {
780 Some(std::cmp::Ordering::Less) => Ok(Bool(true)),
781 _ => Ok(Bool(false)),
782 })
783 .collect::<Result<Vec<Value>>>()?;
784 Ok(heap.borrow_mut().insert_list(mapped_list))
785 }
786 BinaryOp::LessEq => {
787 let mapped_list = l_vec
788 .iter()
789 .zip(&r_vec)
790 .map(|(l, r)| match l.compare(r, &heap.borrow())? {
791 Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) => {
792 Ok(Bool(true))
793 }
794 _ => Ok(Bool(false)),
795 })
796 .collect::<Result<Vec<Value>>>()?;
797 Ok(heap.borrow_mut().insert_list(mapped_list))
798 }
799 BinaryOp::Greater => {
800 let mapped_list = l_vec
801 .iter()
802 .zip(&r_vec)
803 .map(|(l, r)| match l.compare(r, &heap.borrow())? {
804 Some(std::cmp::Ordering::Greater) => Ok(Bool(true)),
805 _ => Ok(Bool(false)),
806 })
807 .collect::<Result<Vec<Value>>>()?;
808 Ok(heap.borrow_mut().insert_list(mapped_list))
809 }
810 BinaryOp::GreaterEq => {
811 let mapped_list = l_vec
812 .iter()
813 .zip(&r_vec)
814 .map(|(l, r)| match l.compare(r, &heap.borrow())? {
815 Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) => {
816 Ok(Bool(true))
817 }
818 _ => Ok(Bool(false)),
819 })
820 .collect::<Result<Vec<Value>>>()?;
821 Ok(heap.borrow_mut().insert_list(mapped_list))
822 }
823 BinaryOp::And | BinaryOp::NaturalAnd => {
824 let mapped_list = l_vec
825 .iter()
826 .zip(&r_vec)
827 .map(|(l, r)| Ok(Bool(l.as_bool()? && r.as_bool()?)))
828 .collect::<Result<Vec<Value>>>()?;
829 Ok(heap.borrow_mut().insert_list(mapped_list))
830 }
831 BinaryOp::Or | BinaryOp::NaturalOr => {
832 let mapped_list = l_vec
833 .iter()
834 .zip(&r_vec)
835 .map(|(l, r)| Ok(Bool(l.as_bool()? || r.as_bool()?)))
836 .collect::<Result<Vec<Value>>>()?;
837 Ok(heap.borrow_mut().insert_list(mapped_list))
838 }
839 BinaryOp::Add => {
840 let mapped_list = l_vec
841 .iter()
842 .zip(&r_vec)
843 .map(|(l, r)| match (l, r) {
844 (Value::String(_), Value::String(_)) => {
845 let (l_str, r_str) = {
846 (
847 l.as_string(&heap.borrow())?.to_string(),
848 r.as_string(&heap.borrow())?.to_string(),
849 )
850 };
851 Ok(heap
852 .borrow_mut()
853 .insert_string(format!("{}{}", l_str, r_str)))
854 }
855 (Value::Number(_), Value::Number(_)) => {
856 Ok(Number(l.as_number()? + r.as_number()?))
857 }
858 _ => Err(anyhow!("can't add {} and {}", l.get_type(), r.get_type())),
859 })
860 .collect::<Result<Vec<Value>>>()?;
861 Ok(heap.borrow_mut().insert_list(mapped_list))
862 }
863 BinaryOp::Subtract => {
864 let mapped_list = l_vec
865 .iter()
866 .zip(&r_vec)
867 .map(|(l, r)| Ok(Number(l.as_number()? - r.as_number()?)))
868 .collect::<Result<Vec<Value>>>()?;
869 Ok(heap.borrow_mut().insert_list(mapped_list))
870 }
871 BinaryOp::Multiply => {
872 let mapped_list = l_vec
873 .iter()
874 .zip(&r_vec)
875 .map(|(l, r)| Ok(Number(l.as_number()? * r.as_number()?)))
876 .collect::<Result<Vec<Value>>>()?;
877 Ok(heap.borrow_mut().insert_list(mapped_list))
878 }
879 BinaryOp::Divide => {
880 let mapped_list = l_vec
881 .iter()
882 .zip(&r_vec)
883 .map(|(l, r)| Ok(Number(l.as_number()? / r.as_number()?)))
884 .collect::<Result<Vec<Value>>>()?;
885 Ok(heap.borrow_mut().insert_list(mapped_list))
886 }
887 BinaryOp::Modulo => {
888 let mapped_list = l_vec
889 .iter()
890 .zip(&r_vec)
891 .map(|(l, r)| Ok(Number(l.as_number()? % r.as_number()?)))
892 .collect::<Result<Vec<Value>>>()?;
893 Ok(heap.borrow_mut().insert_list(mapped_list))
894 }
895 BinaryOp::Power => {
896 let mapped_list = l_vec
897 .iter()
898 .zip(&r_vec)
899 .map(|(l, r)| Ok(Number(l.as_number()?.powf(r.as_number()?))))
900 .collect::<Result<Vec<Value>>>()?;
901 Ok(heap.borrow_mut().insert_list(mapped_list))
902 }
903 BinaryOp::Coalesce => {
904 let mapped_list = l_vec
905 .iter()
906 .zip(&r_vec)
907 .map(|(l, r)| if *l == Value::Null { Ok(*r) } else { Ok(*l) })
908 .collect::<Result<Vec<Value>>>()?;
909 Ok(heap.borrow_mut().insert_list(mapped_list))
910 }
911 BinaryOp::Via => {
912 let mapped_list = l_vec
913 .iter()
914 .zip(&r_vec)
915 .map(|(l, r)| {
916 if !r.is_lambda() && !r.is_built_in() {
917 return Err(anyhow!(
918 "right-hand iterable contains non-function {}",
919 r.stringify_internal(&heap.borrow())
920 ));
921 }
922
923 let def = {
924 let borrowed_heap = &heap.borrow();
925 get_function_def(r, borrowed_heap).ok_or_else(|| {
926 anyhow!(
927 "unknown function: {}",
928 r.stringify_internal(borrowed_heap)
929 )
930 })?
931 };
932
933 def.call(
934 *r,
935 vec![*l],
936 Rc::clone(&heap),
937 Rc::clone(&bindings),
938 call_depth,
939 )
940 })
941 .collect::<Result<Vec<Value>>>()?;
942 Ok(heap.borrow_mut().insert_list(mapped_list))
943 }
944 BinaryOp::Into => {
945 unreachable!("Into operator should not reach list-to-list evaluation")
947 }
948 BinaryOp::DotEqual
949 | BinaryOp::DotNotEqual
950 | BinaryOp::DotLess
951 | BinaryOp::DotLessEq
952 | BinaryOp::DotGreater
953 | BinaryOp::DotGreaterEq => {
954 unreachable!("Dot operators should be handled before list broadcasting")
956 }
957 }
958 }
959 (Value::List(list), scalar) | (scalar, Value::List(list)) => {
960 let (l_vec, is_list_first) = {
961 let borrowed_heap = &heap.borrow();
962 if matches!(lhs, Value::List(_)) {
963 (list.reify(borrowed_heap).as_list()?.clone(), true)
964 } else {
965 (list.reify(borrowed_heap).as_list()?.clone(), false)
966 }
967 };
968
969 match op {
970 BinaryOp::Equal => {
971 let mapped_list = l_vec
972 .iter()
973 .map(|v| Ok(Bool(v.equals(&scalar, &heap.borrow())?)))
974 .collect::<Result<Vec<Value>>>()?;
975 Ok(heap.borrow_mut().insert_list(mapped_list))
976 }
977 BinaryOp::NotEqual => {
978 let mapped_list = l_vec
979 .iter()
980 .map(|v| Ok(Bool(!v.equals(&scalar, &heap.borrow())?)))
981 .collect::<Result<Vec<Value>>>()?;
982 Ok(heap.borrow_mut().insert_list(mapped_list))
983 }
984 BinaryOp::Less => {
985 let mapped_list = l_vec
986 .iter()
987 .map(|v| {
988 let ordering = if is_list_first {
989 v.compare(&scalar, &heap.borrow())?
990 } else {
991 scalar.compare(v, &heap.borrow())?
992 };
993 match ordering {
994 Some(std::cmp::Ordering::Less) => Ok(Bool(true)),
995 _ => Ok(Bool(false)),
996 }
997 })
998 .collect::<Result<Vec<Value>>>()?;
999 Ok(heap.borrow_mut().insert_list(mapped_list))
1000 }
1001 BinaryOp::LessEq => {
1002 let mapped_list = l_vec
1003 .iter()
1004 .map(|v| {
1005 let ordering = if is_list_first {
1006 v.compare(&scalar, &heap.borrow())?
1007 } else {
1008 scalar.compare(v, &heap.borrow())?
1009 };
1010 match ordering {
1011 Some(std::cmp::Ordering::Less)
1012 | Some(std::cmp::Ordering::Equal) => Ok(Bool(true)),
1013 _ => Ok(Bool(false)),
1014 }
1015 })
1016 .collect::<Result<Vec<Value>>>()?;
1017 Ok(heap.borrow_mut().insert_list(mapped_list))
1018 }
1019 BinaryOp::Greater => {
1020 let mapped_list = l_vec
1021 .iter()
1022 .map(|v| {
1023 let ordering = if is_list_first {
1024 v.compare(&scalar, &heap.borrow())?
1025 } else {
1026 scalar.compare(v, &heap.borrow())?
1027 };
1028 match ordering {
1029 Some(std::cmp::Ordering::Greater) => Ok(Bool(true)),
1030 _ => Ok(Bool(false)),
1031 }
1032 })
1033 .collect::<Result<Vec<Value>>>()?;
1034 Ok(heap.borrow_mut().insert_list(mapped_list))
1035 }
1036 BinaryOp::GreaterEq => {
1037 let mapped_list = l_vec
1038 .iter()
1039 .map(|v| {
1040 let ordering = if is_list_first {
1041 v.compare(&scalar, &heap.borrow())?
1042 } else {
1043 scalar.compare(v, &heap.borrow())?
1044 };
1045 match ordering {
1046 Some(std::cmp::Ordering::Greater)
1047 | Some(std::cmp::Ordering::Equal) => Ok(Bool(true)),
1048 _ => Ok(Bool(false)),
1049 }
1050 })
1051 .collect::<Result<Vec<Value>>>()?;
1052 Ok(heap.borrow_mut().insert_list(mapped_list))
1053 }
1054 BinaryOp::And | BinaryOp::NaturalAnd => {
1055 let mapped_list = if is_list_first {
1056 l_vec
1057 .iter()
1058 .map(|v| Ok(Bool(v.as_bool()? && scalar.as_bool()?)))
1059 .collect::<Result<Vec<Value>>>()?
1060 } else {
1061 l_vec
1062 .iter()
1063 .map(|v| Ok(Bool(scalar.as_bool()? && v.as_bool()?)))
1064 .collect::<Result<Vec<Value>>>()?
1065 };
1066 Ok(heap.borrow_mut().insert_list(mapped_list))
1067 }
1068 BinaryOp::Or | BinaryOp::NaturalOr => {
1069 let mapped_list = if is_list_first {
1070 l_vec
1071 .iter()
1072 .map(|v| Ok(Bool(v.as_bool()? || scalar.as_bool()?)))
1073 .collect::<Result<Vec<Value>>>()?
1074 } else {
1075 l_vec
1076 .iter()
1077 .map(|v| Ok(Bool(scalar.as_bool()? || v.as_bool()?)))
1078 .collect::<Result<Vec<Value>>>()?
1079 };
1080 Ok(heap.borrow_mut().insert_list(mapped_list))
1081 }
1082 BinaryOp::Add => {
1083 let mapped_list = if is_list_first {
1084 l_vec
1085 .iter()
1086 .map(|v| match (v, &scalar) {
1087 (Value::String(_), Value::String(_)) => {
1088 let (v_str, s_str) = {
1089 (
1090 v.as_string(&heap.borrow())?.to_string(),
1091 scalar.as_string(&heap.borrow())?.to_string(),
1092 )
1093 };
1094 Ok(heap
1095 .borrow_mut()
1096 .insert_string(format!("{}{}", v_str, s_str)))
1097 }
1098 (Value::Number(_), Value::Number(_)) => {
1099 Ok(Number(v.as_number()? + scalar.as_number()?))
1100 }
1101 _ => Err(anyhow!(
1102 "can't add {} and {}",
1103 v.get_type(),
1104 scalar.get_type()
1105 )),
1106 })
1107 .collect::<Result<Vec<Value>>>()?
1108 } else {
1109 l_vec
1110 .iter()
1111 .map(|v| match (&scalar, v) {
1112 (Value::String(_), Value::String(_)) => {
1113 let (s_str, v_str) = {
1114 (
1115 scalar.as_string(&heap.borrow())?.to_string(),
1116 v.as_string(&heap.borrow())?.to_string(),
1117 )
1118 };
1119 Ok(heap
1120 .borrow_mut()
1121 .insert_string(format!("{}{}", s_str, v_str)))
1122 }
1123 (Value::Number(_), Value::Number(_)) => {
1124 Ok(Number(scalar.as_number()? + v.as_number()?))
1125 }
1126 _ => Err(anyhow!(
1127 "can't add {} and {}",
1128 scalar.get_type(),
1129 v.get_type()
1130 )),
1131 })
1132 .collect::<Result<Vec<Value>>>()?
1133 };
1134 Ok(heap.borrow_mut().insert_list(mapped_list))
1135 }
1136 BinaryOp::Subtract => {
1137 let mapped_list = if is_list_first {
1138 l_vec
1139 .iter()
1140 .map(|v| Ok(Number(v.as_number()? - scalar.as_number()?)))
1141 .collect::<Result<Vec<Value>>>()?
1142 } else {
1143 l_vec
1144 .iter()
1145 .map(|v| Ok(Number(scalar.as_number()? - v.as_number()?)))
1146 .collect::<Result<Vec<Value>>>()?
1147 };
1148 Ok(heap.borrow_mut().insert_list(mapped_list))
1149 }
1150 BinaryOp::Multiply => {
1151 let mapped_list = l_vec
1152 .iter()
1153 .map(|v| Ok(Number(v.as_number()? * scalar.as_number()?)))
1154 .collect::<Result<Vec<Value>>>()?;
1155 Ok(heap.borrow_mut().insert_list(mapped_list))
1156 }
1157 BinaryOp::Divide => {
1158 let mapped_list = if is_list_first {
1159 l_vec
1160 .iter()
1161 .map(|v| Ok(Number(v.as_number()? / scalar.as_number()?)))
1162 .collect::<Result<Vec<Value>>>()?
1163 } else {
1164 l_vec
1165 .iter()
1166 .map(|v| Ok(Number(scalar.as_number()? / v.as_number()?)))
1167 .collect::<Result<Vec<Value>>>()?
1168 };
1169 Ok(heap.borrow_mut().insert_list(mapped_list))
1170 }
1171 BinaryOp::Modulo => {
1172 let mapped_list = if is_list_first {
1173 l_vec
1174 .iter()
1175 .map(|v| Ok(Number(v.as_number()? % scalar.as_number()?)))
1176 .collect::<Result<Vec<Value>>>()?
1177 } else {
1178 l_vec
1179 .iter()
1180 .map(|v| Ok(Number(scalar.as_number()? % v.as_number()?)))
1181 .collect::<Result<Vec<Value>>>()?
1182 };
1183 Ok(heap.borrow_mut().insert_list(mapped_list))
1184 }
1185 BinaryOp::Power => {
1186 let mapped_list = if is_list_first {
1187 l_vec
1188 .iter()
1189 .map(|v| Ok(Number(v.as_number()?.powf(scalar.as_number()?))))
1190 .collect::<Result<Vec<Value>>>()?
1191 } else {
1192 l_vec
1193 .iter()
1194 .map(|v| Ok(Number(scalar.as_number()?.powf(v.as_number()?))))
1195 .collect::<Result<Vec<Value>>>()?
1196 };
1197 Ok(heap.borrow_mut().insert_list(mapped_list))
1198 }
1199 BinaryOp::Coalesce => {
1200 let mapped_list = if is_list_first {
1201 l_vec
1202 .iter()
1203 .map(|v| {
1204 if *v == Value::Null {
1205 Ok(scalar)
1206 } else {
1207 Ok(*v)
1208 }
1209 })
1210 .collect::<Result<Vec<Value>>>()?
1211 } else {
1212 l_vec
1213 .iter()
1214 .map(|v| {
1215 if scalar == Value::Null {
1216 Ok(*v)
1217 } else {
1218 Ok(scalar)
1219 }
1220 })
1221 .collect::<Result<Vec<Value>>>()?
1222 };
1223 Ok(heap.borrow_mut().insert_list(mapped_list))
1224 }
1225 BinaryOp::Via => {
1226 if is_list_first {
1227 if !scalar.is_callable() {
1228 return Err(anyhow!(
1229 "can't call a non-function: {}",
1230 scalar.stringify_internal(&heap.borrow())
1231 ));
1232 }
1233
1234 let list = heap.borrow_mut().insert_list(l_vec.clone());
1235
1236 let call_result = get_built_in_function_def_by_ident("map").unwrap().call(
1237 scalar,
1238 vec![list, scalar],
1239 Rc::clone(&heap),
1240 Rc::clone(&bindings),
1241 call_depth,
1242 )?;
1243
1244 let mapped_list = { call_result.as_list(&heap.borrow())?.clone() };
1245
1246 Ok(heap.borrow_mut().insert_list(mapped_list))
1247 } else {
1248 Err(anyhow!("map operator requires function on right side"))
1249 }
1250 }
1251 BinaryOp::Into => {
1252 if is_list_first {
1253 if !scalar.is_callable() {
1254 return Err(anyhow!(
1255 "can't call a non-function: {}",
1256 scalar.stringify_internal(&heap.borrow())
1257 ));
1258 }
1259
1260 let list = heap.borrow_mut().insert_list(l_vec.clone());
1261
1262 let def = {
1263 let borrowed_heap = &heap.borrow();
1264 get_function_def(&scalar, borrowed_heap).ok_or_else(|| {
1265 anyhow!(
1266 "unknown function: {}",
1267 scalar.stringify_internal(borrowed_heap)
1268 )
1269 })?
1270 };
1271
1272 def.call(
1273 scalar,
1274 vec![list],
1275 Rc::clone(&heap),
1276 Rc::clone(&bindings),
1277 call_depth,
1278 )
1279 } else {
1280 Err(anyhow!("'into' operator requires function on right side"))
1281 }
1282 }
1283 BinaryOp::DotEqual
1284 | BinaryOp::DotNotEqual
1285 | BinaryOp::DotLess
1286 | BinaryOp::DotLessEq
1287 | BinaryOp::DotGreater
1288 | BinaryOp::DotGreaterEq => {
1289 unreachable!("Dot operators should be handled before list broadcasting")
1291 }
1292 }
1293 }
1294 (lhs, rhs) => match op {
1295 BinaryOp::Equal => Ok(Bool(lhs.equals(&rhs, &heap.borrow())?)),
1296 BinaryOp::NotEqual => Ok(Bool(!lhs.equals(&rhs, &heap.borrow())?)),
1297 BinaryOp::Less => match lhs.compare(&rhs, &heap.borrow())? {
1298 Some(std::cmp::Ordering::Less) => Ok(Bool(true)),
1299 _ => Ok(Bool(false)),
1300 },
1301 BinaryOp::LessEq => match lhs.compare(&rhs, &heap.borrow())? {
1302 Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) => Ok(Bool(true)),
1303 _ => Ok(Bool(false)),
1304 },
1305 BinaryOp::Greater => match lhs.compare(&rhs, &heap.borrow())? {
1306 Some(std::cmp::Ordering::Greater) => Ok(Bool(true)),
1307 _ => Ok(Bool(false)),
1308 },
1309 BinaryOp::GreaterEq => match lhs.compare(&rhs, &heap.borrow())? {
1310 Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) => {
1311 Ok(Bool(true))
1312 }
1313 _ => Ok(Bool(false)),
1314 },
1315 BinaryOp::And | BinaryOp::NaturalAnd => Ok(Bool(lhs.as_bool()? && rhs.as_bool()?)),
1316 BinaryOp::Or | BinaryOp::NaturalOr => Ok(Bool(lhs.as_bool()? || rhs.as_bool()?)),
1317 BinaryOp::Add => {
1318 if lhs.is_string() {
1319 let (l_str, r_str) = {
1320 (
1321 lhs.as_string(&heap.borrow())?.to_string(),
1322 rhs.as_string(&heap.borrow())?.to_string(),
1323 )
1324 };
1325
1326 return Ok(heap
1327 .borrow_mut()
1328 .insert_string(format!("{}{}", l_str, r_str)));
1329 }
1330
1331 Ok(Number(lhs.as_number()? + rhs.as_number()?))
1332 }
1333 BinaryOp::Subtract => Ok(Number(lhs.as_number()? - rhs.as_number()?)),
1334 BinaryOp::Multiply => Ok(Number(lhs.as_number()? * rhs.as_number()?)),
1335 BinaryOp::Divide => Ok(Number(lhs.as_number()? / rhs.as_number()?)),
1336 BinaryOp::Modulo => Ok(Number(lhs.as_number()? % rhs.as_number()?)),
1337 BinaryOp::Power => Ok(Number(lhs.as_number()?.powf(rhs.as_number()?))),
1338 BinaryOp::Coalesce => {
1339 if lhs == Value::Null {
1340 Ok(rhs)
1341 } else {
1342 Ok(lhs)
1343 }
1344 }
1345 BinaryOp::Via => {
1346 if !rhs.is_callable() {
1347 return Err(anyhow!(
1348 "can't call a non-function ({} is of type {})",
1349 rhs.stringify_internal(&heap.borrow()),
1350 rhs.get_type()
1351 ));
1352 }
1353
1354 let def = { get_function_def(&rhs, &heap.borrow()) };
1355
1356 if def.is_none() {
1357 return Err(anyhow!(
1358 "unknown function: {}",
1359 rhs.stringify_internal(&heap.borrow())
1360 ));
1361 }
1362
1363 def.unwrap().call(
1364 rhs,
1365 vec![lhs],
1366 Rc::clone(&heap),
1367 Rc::clone(&bindings),
1368 call_depth,
1369 )
1370 }
1371 BinaryOp::Into => {
1372 if !rhs.is_callable() {
1373 return Err(anyhow!(
1374 "can't call a non-function ({} is of type {})",
1375 rhs.stringify_internal(&heap.borrow()),
1376 rhs.get_type()
1377 ));
1378 }
1379
1380 let def = { get_function_def(&rhs, &heap.borrow()) };
1381
1382 if def.is_none() {
1383 return Err(anyhow!(
1384 "unknown function: {}",
1385 rhs.stringify_internal(&heap.borrow())
1386 ));
1387 }
1388
1389 def.unwrap().call(
1390 rhs,
1391 vec![lhs],
1392 Rc::clone(&heap),
1393 Rc::clone(&bindings),
1394 call_depth,
1395 )
1396 }
1397 BinaryOp::DotEqual
1398 | BinaryOp::DotNotEqual
1399 | BinaryOp::DotLess
1400 | BinaryOp::DotLessEq
1401 | BinaryOp::DotGreater
1402 | BinaryOp::DotGreaterEq => {
1403 unreachable!("Dot operators should be handled before generic value matching")
1405 }
1406 },
1407 }
1408}
1409
1410pub fn pairs_to_expr(pairs: Pairs<Rule>) -> Result<Expr> {
1412 PRATT
1413 .map_primary(|primary| match primary.as_rule() {
1414 Rule::number => Ok(Expr::Number(
1415 primary
1416 .as_str()
1417 .replace("_", "")
1418 .parse::<f64>()
1419 .map_err(anyhow::Error::from)?,
1420 )),
1421 Rule::list => {
1422 let list_pairs = primary.into_inner();
1423 let exprs = list_pairs
1424 .into_iter()
1425 .map(|pair| pairs_to_expr(pair.into_inner()))
1426 .collect::<Result<Vec<Expr>>>()?;
1427 Ok(Expr::List(exprs))
1428 }
1429 Rule::record => {
1430 let record_pairs = primary.into_inner();
1431 let mut entries = Vec::new();
1432
1433 for pair in record_pairs {
1434 match pair.as_rule() {
1435 Rule::record_pair => {
1436 let mut inner_pairs = pair.into_inner();
1437 let key_pair = inner_pairs.next().unwrap();
1438 let key = match key_pair.as_rule() {
1439 Rule::record_key_static => {
1440 let inner_key_pair = key_pair.into_inner().next().unwrap();
1441 match inner_key_pair.as_rule() {
1442 Rule::identifier => {
1443 RecordKey::Static(inner_key_pair.as_str().to_string())
1444 }
1445 Rule::string => RecordKey::Static(
1446 inner_key_pair.into_inner().as_str().to_string(),
1447 ),
1448 _ => unreachable!(),
1449 }
1450 }
1451 Rule::record_key_dynamic => RecordKey::Dynamic(Box::new(
1452 pairs_to_expr(key_pair.into_inner())?,
1453 )),
1454 _ => unreachable!(),
1455 };
1456
1457 let value = pairs_to_expr(inner_pairs.next().unwrap().into_inner())?;
1458 entries.push(RecordEntry { key, value });
1459 }
1460 Rule::record_shorthand => {
1461 let ident = pair.into_inner().next().unwrap().as_str().to_string();
1462 entries.push(RecordEntry {
1463 key: RecordKey::Shorthand(ident),
1464 value: Expr::Null, });
1466 }
1467 Rule::spread_expression => {
1468 let spread_expr = pairs_to_expr(pair.into_inner())?;
1469 entries.push(RecordEntry {
1470 key: RecordKey::Spread(Box::new(spread_expr)),
1471 value: Expr::Null, });
1473 }
1474 _ => {}
1475 }
1476 }
1477
1478 Ok(Expr::Record(entries))
1479 }
1480 Rule::bool => {
1481 let bool_str = primary.as_str();
1482 match bool_str {
1483 "true" => Ok(Expr::Bool(true)),
1484 "false" => Ok(Expr::Bool(false)),
1485 _ => unreachable!(),
1486 }
1487 }
1488 Rule::null => Ok(Expr::Null),
1489 Rule::string => {
1490 let contents = primary.into_inner().as_str().to_string();
1491 Ok(Expr::String(contents))
1492 }
1493 Rule::assignment => {
1494 let mut inner_pairs = primary.into_inner();
1495 let ident = inner_pairs.next().unwrap().as_str().to_string();
1496 let value = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1497 Ok(Expr::Assignment { ident, value })
1498 }
1499 Rule::lambda => {
1500 let mut inner_pairs = primary.into_inner();
1501 let arg_list = inner_pairs.next().unwrap();
1502 let body_pairs = inner_pairs.next().unwrap();
1503
1504 let mut args = Vec::new();
1505 for arg_pair in arg_list.into_inner() {
1506 match arg_pair.as_rule() {
1507 Rule::required_arg => {
1508 args.push(LambdaArg::Required(
1509 arg_pair.into_inner().as_str().to_string(),
1510 ));
1511 }
1512 Rule::optional_arg => {
1513 args.push(LambdaArg::Optional(
1514 arg_pair.into_inner().as_str().to_string(),
1515 ));
1516 }
1517 Rule::rest_arg => {
1518 args.push(LambdaArg::Rest(arg_pair.into_inner().as_str().to_string()));
1519 }
1520 _ => {}
1521 }
1522 }
1523
1524 let body = Box::new(pairs_to_expr(body_pairs.into_inner())?);
1525 Ok(Expr::Lambda { args, body })
1526 }
1527 Rule::conditional => {
1528 let mut inner_pairs = primary.into_inner();
1529 let condition = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1530 let then_expr = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1531 let else_expr = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1532 Ok(Expr::Conditional {
1533 condition,
1534 then_expr,
1535 else_expr,
1536 })
1537 }
1538 Rule::do_block => {
1539 let inner_pairs = primary.into_inner();
1540 let mut statements = Vec::new();
1541 let mut return_expr = Box::new(Expr::Null);
1542
1543 for pair in inner_pairs {
1544 match pair.as_rule() {
1545 Rule::do_statement => {
1546 if let Some(inner) = pair.into_inner().next() {
1547 if inner.as_rule() == Rule::expression {
1548 statements.push(DoStatement::Expression(pairs_to_expr(
1549 inner.into_inner(),
1550 )?));
1551 } else if inner.as_rule() == Rule::comment {
1552 statements
1553 .push(DoStatement::Comment(inner.as_str().to_string()));
1554 }
1555 }
1556 }
1557 Rule::return_statement => {
1558 let return_expr_pair = pair.into_inner().next().unwrap();
1559 return_expr = Box::new(pairs_to_expr(return_expr_pair.into_inner())?);
1560 }
1561 _ => {}
1562 }
1563 }
1564
1565 Ok(Expr::DoBlock {
1566 statements,
1567 return_expr,
1568 })
1569 }
1570 Rule::identifier => {
1571 let ident = primary.as_str();
1572
1573 if let Some(built_in) = BuiltInFunction::from_ident(ident) {
1575 Ok(Expr::BuiltIn(built_in))
1576 } else {
1577 Ok(Expr::Identifier(ident.to_string()))
1578 }
1579 }
1580 Rule::input_reference => {
1581 let field = primary.as_str()[1..].to_string();
1583 Ok(Expr::InputReference(field))
1584 }
1585 Rule::expression => pairs_to_expr(primary.into_inner()),
1586 _ => unreachable!("{}", primary.as_str()),
1587 })
1588 .map_prefix(|op, rhs| match op.as_rule() {
1589 Rule::negation => Ok(Expr::UnaryOp {
1590 op: UnaryOp::Negate,
1591 expr: Box::new(rhs?),
1592 }),
1593 Rule::spread_operator => Ok(Expr::Spread(Box::new(rhs?))),
1594 Rule::invert | Rule::natural_not => Ok(Expr::UnaryOp {
1595 op: UnaryOp::Not,
1596 expr: Box::new(rhs?),
1597 }),
1598 _ => unreachable!(),
1599 })
1600 .map_postfix(|lhs, op| match op.as_rule() {
1601 Rule::factorial => Ok(Expr::PostfixOp {
1602 op: PostfixOp::Factorial,
1603 expr: Box::new(lhs?),
1604 }),
1605 Rule::access => {
1606 let index_expr = pairs_to_expr(op.into_inner())?;
1607 Ok(Expr::Access {
1608 expr: Box::new(lhs?),
1609 index: Box::new(index_expr),
1610 })
1611 }
1612 Rule::dot_access => {
1613 let field = op.into_inner().as_str().to_string();
1614 Ok(Expr::DotAccess {
1615 expr: Box::new(lhs?),
1616 field,
1617 })
1618 }
1619 Rule::call_list => {
1620 let call_list = op.into_inner();
1621 let args = call_list
1622 .into_iter()
1623 .map(|arg| pairs_to_expr(arg.into_inner()))
1624 .collect::<Result<Vec<Expr>>>()?;
1625 Ok(Expr::Call {
1626 func: Box::new(lhs?),
1627 args,
1628 })
1629 }
1630 _ => unreachable!(),
1631 })
1632 .map_infix(|lhs, op, rhs| {
1633 let op = match op.as_rule() {
1634 Rule::add => BinaryOp::Add,
1635 Rule::subtract => BinaryOp::Subtract,
1636 Rule::multiply => BinaryOp::Multiply,
1637 Rule::divide => BinaryOp::Divide,
1638 Rule::modulo => BinaryOp::Modulo,
1639 Rule::power => BinaryOp::Power,
1640 Rule::equal => BinaryOp::Equal,
1641 Rule::not_equal => BinaryOp::NotEqual,
1642 Rule::less => BinaryOp::Less,
1643 Rule::less_eq => BinaryOp::LessEq,
1644 Rule::greater => BinaryOp::Greater,
1645 Rule::greater_eq => BinaryOp::GreaterEq,
1646 Rule::dot_equal => BinaryOp::DotEqual,
1647 Rule::dot_not_equal => BinaryOp::DotNotEqual,
1648 Rule::dot_less => BinaryOp::DotLess,
1649 Rule::dot_less_eq => BinaryOp::DotLessEq,
1650 Rule::dot_greater => BinaryOp::DotGreater,
1651 Rule::dot_greater_eq => BinaryOp::DotGreaterEq,
1652 Rule::and => BinaryOp::And,
1653 Rule::natural_and => BinaryOp::NaturalAnd,
1654 Rule::or => BinaryOp::Or,
1655 Rule::natural_or => BinaryOp::NaturalOr,
1656 Rule::via => BinaryOp::Via,
1657 Rule::into => BinaryOp::Into,
1658 Rule::coalesce => BinaryOp::Coalesce,
1659 _ => unreachable!(),
1660 };
1661 Ok(Expr::BinaryOp {
1662 op,
1663 left: Box::new(lhs?),
1664 right: Box::new(rhs?),
1665 })
1666 })
1667 .parse(pairs)
1668}
1669
1670#[cfg(test)]
1671mod tests {
1672 use super::*;
1673 use crate::{heap::LambdaPointer, parser::get_pairs};
1674
1675 fn parse_and_evaluate(
1676 input: &str,
1677 heap: Option<Rc<RefCell<Heap>>>,
1678 bindings: Option<Rc<RefCell<HashMap<String, Value>>>>,
1679 ) -> Result<Value> {
1680 let binding = input.to_string();
1681 let mut pairs = get_pairs(&binding).unwrap();
1682 let expr = pairs.next().unwrap().into_inner();
1683 evaluate_pairs(
1684 expr,
1685 heap.unwrap_or(Rc::new(RefCell::new(Heap::new()))),
1686 bindings.unwrap_or(Rc::new(RefCell::new(HashMap::new()))),
1687 0,
1688 )
1689 }
1690
1691 #[test]
1692 fn addition_of_integers() {
1693 let result = parse_and_evaluate("5 + 2", None, None).unwrap();
1694 assert_eq!(result, Value::Number(7.0));
1695 }
1696
1697 #[test]
1698 fn exponentiation_of_two_integers() {
1699 let result = parse_and_evaluate("2 ^ 3", None, None).unwrap();
1700 assert_eq!(result, Value::Number(8.0));
1701 }
1702
1703 #[test]
1704 fn multiplication_of_integers() {
1705 let result = parse_and_evaluate("8 * 4", None, None).unwrap();
1706 assert_eq!(result, Value::Number(32.0));
1707 }
1708
1709 #[test]
1710 fn division_with_integer_resulting_in_decimal() {
1711 let result = parse_and_evaluate("9 / 2", None, None).unwrap();
1712 assert_eq!(result, Value::Number(4.5));
1713 }
1714
1715 #[test]
1716 fn addition_with_nested_expression() {
1717 let result = parse_and_evaluate("5 + (2 * 4)", None, None).unwrap();
1718 assert_eq!(result, Value::Number(13.0));
1719 }
1720
1721 #[test]
1722 fn grouping_and_multiplication_in_expression() {
1723 let result = parse_and_evaluate("(3 + 2) * 2", None, None).unwrap();
1724 assert_eq!(result, Value::Number(10.0));
1725 }
1726
1727 #[test]
1728 fn mixed_operations_with_decimal_and_precedence() {
1729 let result = parse_and_evaluate("6.5 / 2 + 4 * 2", None, None).unwrap();
1730 assert_eq!(result, Value::Number(11.25));
1731 }
1732
1733 #[test]
1734 fn exponentiation_with_nested_expression() {
1735 let result = parse_and_evaluate("2 ^ (1 + 2)", None, None).unwrap();
1736 assert_eq!(result, Value::Number(8.0));
1737 }
1738
1739 #[test]
1740 fn complex_expression_with_decimals() {
1741 let result = parse_and_evaluate("7.5 - 3.25 + 2 * (8 / 4)", None, None).unwrap();
1742 assert_eq!(result, Value::Number(8.25));
1743 }
1744
1745 #[test]
1746 fn subtraction_with_decimal_result() {
1747 let result = parse_and_evaluate("10.75 - 3.5", None, None).unwrap();
1748 assert_eq!(result, Value::Number(7.25));
1749 }
1750
1751 #[test]
1752 fn multiplication_of_two_decimals() {
1753 let result = parse_and_evaluate("3.5 * 2.0", None, None).unwrap();
1754 assert_eq!(result, Value::Number(7.0));
1755 }
1756
1757 #[test]
1758 fn division_of_two_decimals() {
1759 let result = parse_and_evaluate("7.5 / 2.5", None, None).unwrap();
1760 assert_eq!(result, Value::Number(3.0));
1761 }
1762
1763 #[test]
1764 fn boolean_and() {
1765 let result = parse_and_evaluate("true and false", None, None).unwrap();
1766 assert_eq!(result, Value::Bool(false));
1767 }
1768
1769 #[test]
1770 fn boolean_and_alt() {
1771 let result = parse_and_evaluate("true && false", None, None).unwrap();
1772 assert_eq!(result, Value::Bool(false));
1773 }
1774
1775 #[test]
1776 fn boolean_or() {
1777 let result = parse_and_evaluate("true or false", None, None).unwrap();
1778 assert_eq!(result, Value::Bool(true));
1779 }
1780
1781 #[test]
1782 fn boolean_or_alt() {
1783 let result = parse_and_evaluate("true || false", None, None).unwrap();
1784 assert_eq!(result, Value::Bool(true));
1785 }
1786
1787 #[test]
1788 fn boolean_and_with_nested_expression() {
1789 let result = parse_and_evaluate("true and (false or true)", None, None).unwrap();
1790 assert_eq!(result, Value::Bool(true));
1791 }
1792
1793 #[test]
1794 fn boolean_and_with_nested_expression_alt() {
1795 let result = parse_and_evaluate("true && (false || true)", None, None).unwrap();
1796 assert_eq!(result, Value::Bool(true));
1797 }
1798
1799 #[test]
1800 fn boolean_or_with_nested_expression() {
1801 let result = parse_and_evaluate("true or (false and true)", None, None).unwrap();
1802 assert_eq!(result, Value::Bool(true));
1803 }
1804
1805 #[test]
1806 fn boolean_or_with_nested_expression_alt() {
1807 let result = parse_and_evaluate("true || (false && true)", None, None).unwrap();
1808 assert_eq!(result, Value::Bool(true));
1809 }
1810
1811 #[test]
1812 fn logical_not() {
1813 let result = parse_and_evaluate("!true", None, None).unwrap();
1814 assert_eq!(result, Value::Bool(false));
1815 }
1816
1817 #[test]
1818 fn logical_not_with_nested_expression() {
1819 let result = parse_and_evaluate("!(true and false)", None, None).unwrap();
1820 assert_eq!(result, Value::Bool(true));
1821 }
1822
1823 #[test]
1824 fn equality_of_two_integers() {
1825 let result = parse_and_evaluate("5 == 5", None, None).unwrap();
1826 assert_eq!(result, Value::Bool(true));
1827 }
1828
1829 #[test]
1830 fn inequality_of_two_integers() {
1831 let result = parse_and_evaluate("5 != 5", None, None).unwrap();
1832 assert_eq!(result, Value::Bool(false));
1833 }
1834
1835 #[test]
1836 fn less_than_comparison() {
1837 let result = parse_and_evaluate("5 < 10", None, None).unwrap();
1838 assert_eq!(result, Value::Bool(true));
1839 }
1840
1841 #[test]
1842 fn less_than_or_equal_comparison() {
1843 let result = parse_and_evaluate("5 <= 5", None, None).unwrap();
1844 assert_eq!(result, Value::Bool(true));
1845 }
1846
1847 #[test]
1848 fn greater_than_comparison() {
1849 let result = parse_and_evaluate("10 > 5", None, None).unwrap();
1850 assert_eq!(result, Value::Bool(true));
1851 }
1852
1853 #[test]
1854 fn greater_than_or_equal_comparison() {
1855 let result = parse_and_evaluate("5 >= 5", None, None).unwrap();
1856 assert_eq!(result, Value::Bool(true));
1857 }
1858
1859 #[test]
1860 fn equality_of_two_lists() {
1861 let heap = Rc::new(RefCell::new(Heap::new()));
1863 let result =
1864 parse_and_evaluate("[1, 2, 3] == [1, 2, 3]", Some(heap.clone()), None).unwrap();
1865 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(true)];
1866 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
1867 }
1868
1869 #[test]
1870 fn inequality_of_two_lists() {
1871 let heap = Rc::new(RefCell::new(Heap::new()));
1873 let result =
1874 parse_and_evaluate("[1, 2, 3] != [2, 3, 4]", Some(heap.clone()), None).unwrap();
1875 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(true)];
1876 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
1877 }
1878
1879 #[test]
1880 fn conditional_expression_with_true_condition() {
1881 let result = parse_and_evaluate("if true then 5 else 10", None, None).unwrap();
1882 assert_eq!(result, Value::Number(5.0));
1883 }
1884
1885 #[test]
1886 fn conditional_expression_with_false_condition() {
1887 let result = parse_and_evaluate("if false then 5 else 10", None, None).unwrap();
1888 assert_eq!(result, Value::Number(10.0));
1889 }
1890
1891 #[test]
1892 fn factorial_of_integer() {
1893 let result = parse_and_evaluate("5!", None, None).unwrap();
1894 assert_eq!(result, Value::Number(120.0));
1895 }
1896
1897 #[test]
1898 fn factorial_of_zero() {
1899 let result = parse_and_evaluate("0!", None, None).unwrap();
1900 assert_eq!(result, Value::Number(1.0));
1901 }
1902
1903 #[test]
1904 fn factorial_of_negative_integer() {
1905 let result = parse_and_evaluate("(-5)!", None, None);
1906 assert!(result.is_err());
1907 }
1908
1909 #[test]
1910 fn factorial_of_decimal() {
1911 let result = parse_and_evaluate("5.5!", None, None);
1912 assert!(result.is_err());
1913 }
1914
1915 #[test]
1916 fn string_concatenation() {
1917 let heap = Rc::new(RefCell::new(Heap::new()));
1918 let result =
1919 parse_and_evaluate("\"hello\" + \"world\"", Some(Rc::clone(&heap)), None).unwrap();
1920
1921 assert!(matches!(result, Value::String(_)));
1922 assert_eq!(result.as_string(&heap.borrow()).unwrap(), "helloworld");
1923 }
1924
1925 #[test]
1926 fn string_concatenation_with_integer() {
1927 let result = parse_and_evaluate("\"hello\" + 5", None, None);
1928 assert!(result.is_err());
1929 }
1930
1931 #[test]
1932 fn variable_assignment() {
1933 let bindings = Rc::new(RefCell::new(HashMap::new()));
1934 let result = parse_and_evaluate("x = 5", None, Some(Rc::clone(&bindings))).unwrap();
1935
1936 assert_eq!(result, Value::Number(5.0));
1937 assert_eq!(bindings.borrow().get("x").unwrap(), &Value::Number(5.0));
1938 }
1939
1940 #[test]
1941 fn variable_assignment_with_expression() {
1942 let bindings = Rc::new(RefCell::new(HashMap::new()));
1943 let result = parse_and_evaluate("x = 5 + 2", None, Some(Rc::clone(&bindings))).unwrap();
1944 assert_eq!(result, Value::Number(7.0));
1945 assert_eq!(bindings.borrow().get("x").unwrap(), &Value::Number(7.0));
1946 }
1947
1948 #[test]
1949 fn variable_assignment_with_lambda() {
1950 let heap = Rc::new(RefCell::new(Heap::new()));
1951 let bindings = Rc::new(RefCell::new(HashMap::new()));
1952 let result = parse_and_evaluate(
1953 "f = x => x + 1",
1954 Some(Rc::clone(&heap)),
1955 Some(Rc::clone(&bindings)),
1956 )
1957 .unwrap();
1958
1959 {
1960 let heap_borrow = heap.borrow();
1961 let lambda_def = result.as_lambda(&heap_borrow).unwrap();
1962 assert_eq!(lambda_def.name, Some("f".to_string()));
1963 assert_eq!(lambda_def.args, vec![LambdaArg::Required("x".to_string())]);
1964 assert_eq!(lambda_def.scope, HashMap::new());
1965 match &lambda_def.body {
1967 Expr::BinaryOp {
1968 op: BinaryOp::Add,
1969 left,
1970 right,
1971 } => match (left.as_ref(), right.as_ref()) {
1972 (Expr::Identifier(x), Expr::Number(n)) => {
1973 assert_eq!(x, "x");
1974 assert_eq!(*n, 1.0);
1975 }
1976 _ => panic!("Expected Identifier('x') + Number(1)"),
1977 },
1978 _ => panic!("Expected BinaryOp(Add)"),
1979 }
1980 }
1981 assert_eq!(
1982 bindings.borrow().get("f").unwrap(),
1983 &Value::Lambda(LambdaPointer::new(1))
1984 );
1985 }
1986
1987 #[test]
1988 fn variable_assignment_with_lambda_and_call() {
1989 let heap = Rc::new(RefCell::new(Heap::new()));
1990 let bindings = Rc::new(RefCell::new(HashMap::new()));
1991 let _ = parse_and_evaluate(
1992 "f = x => x + 1",
1993 Some(Rc::clone(&heap)),
1994 Some(Rc::clone(&bindings)),
1995 )
1996 .unwrap();
1997 let result =
1998 parse_and_evaluate("f(5)", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings))).unwrap();
1999
2000 assert_eq!(result, Value::Number(6.0));
2001 }
2002
2003 #[test]
2004 fn variable_assignment_with_lambda_and_call_with_multiple_args() {
2005 let heap = Rc::new(RefCell::new(Heap::new()));
2006 let bindings = Rc::new(RefCell::new(HashMap::new()));
2007 let _ = parse_and_evaluate(
2008 "f = (x, y) => x + y",
2009 Some(Rc::clone(&heap)),
2010 Some(Rc::clone(&bindings)),
2011 )
2012 .unwrap();
2013 let result = parse_and_evaluate(
2014 "f(5, 2)",
2015 Some(Rc::clone(&heap)),
2016 Some(Rc::clone(&bindings)),
2017 )
2018 .unwrap();
2019
2020 assert_eq!(result, Value::Number(7.0));
2021 }
2022
2023 #[test]
2024 fn variable_assignment_with_lambda_and_call_with_multiple_args_and_expression() {
2025 let heap = Rc::new(RefCell::new(Heap::new()));
2026 let bindings = Rc::new(RefCell::new(HashMap::new()));
2027 let _ = parse_and_evaluate(
2028 "f = (x, y) => x + y",
2029 Some(Rc::clone(&heap)),
2030 Some(Rc::clone(&bindings)),
2031 )
2032 .unwrap();
2033 let result = parse_and_evaluate(
2034 "f(5, 2) + 3",
2035 Some(Rc::clone(&heap)),
2036 Some(Rc::clone(&bindings)),
2037 )
2038 .unwrap();
2039
2040 assert_eq!(result, Value::Number(10.0));
2041 }
2042
2043 #[test]
2044 fn coalesce_operator_with_null() {
2045 let result = parse_and_evaluate("null ?? 5", None, None).unwrap();
2046 assert_eq!(result, Value::Number(5.0));
2047 }
2048
2049 #[test]
2050 fn coalesce_operator_with_non_null() {
2051 let result = parse_and_evaluate("3 ?? 10", None, None).unwrap();
2052 assert_eq!(result, Value::Number(3.0));
2053 }
2054
2055 #[test]
2057 fn list_elementwise_addition() {
2058 let heap = Rc::new(RefCell::new(Heap::new()));
2059 let result =
2060 parse_and_evaluate("[1, 2, 3] + [4, 5, 6]", Some(Rc::clone(&heap)), None).unwrap();
2061 let expected = vec![Value::Number(5.0), Value::Number(7.0), Value::Number(9.0)];
2062 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2063 }
2064
2065 #[test]
2066 fn list_elementwise_subtraction() {
2067 let heap = Rc::new(RefCell::new(Heap::new()));
2068 let result =
2069 parse_and_evaluate("[5, 7, 9] - [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
2070 let expected = vec![Value::Number(4.0), Value::Number(5.0), Value::Number(6.0)];
2071 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2072 }
2073
2074 #[test]
2075 fn list_elementwise_multiplication() {
2076 let heap = Rc::new(RefCell::new(Heap::new()));
2077 let result =
2078 parse_and_evaluate("[2, 3, 4] * [5, 6, 7]", Some(Rc::clone(&heap)), None).unwrap();
2079 let expected = vec![
2080 Value::Number(10.0),
2081 Value::Number(18.0),
2082 Value::Number(28.0),
2083 ];
2084 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2085 }
2086
2087 #[test]
2088 fn list_elementwise_division() {
2089 let heap = Rc::new(RefCell::new(Heap::new()));
2090 let result =
2091 parse_and_evaluate("[10, 20, 30] / [2, 4, 5]", Some(Rc::clone(&heap)), None).unwrap();
2092 let expected = vec![Value::Number(5.0), Value::Number(5.0), Value::Number(6.0)];
2093 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2094 }
2095
2096 #[test]
2097 fn list_elementwise_power() {
2098 let heap = Rc::new(RefCell::new(Heap::new()));
2099 let result =
2100 parse_and_evaluate("[2, 3, 4] ^ [2, 2, 2]", Some(Rc::clone(&heap)), None).unwrap();
2101 let expected = vec![Value::Number(4.0), Value::Number(9.0), Value::Number(16.0)];
2102 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2103 }
2104
2105 #[test]
2106 fn list_elementwise_modulo() {
2107 let heap = Rc::new(RefCell::new(Heap::new()));
2108 let result =
2109 parse_and_evaluate("[10, 11, 12] % [3, 3, 3]", Some(Rc::clone(&heap)), None).unwrap();
2110 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(0.0)];
2111 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2112 }
2113
2114 #[test]
2115 fn list_elementwise_different_lengths_error() {
2116 let result = parse_and_evaluate("[1, 2, 3] + [4, 5]", None, None);
2117 assert!(result.is_err());
2118 assert!(
2119 result
2120 .unwrap_err()
2121 .to_string()
2122 .contains("left- and right-hand-side lists must be the same length")
2123 );
2124 }
2125
2126 #[test]
2128 fn list_scalar_addition() {
2129 let heap = Rc::new(RefCell::new(Heap::new()));
2130 let result = parse_and_evaluate("[1, 2, 3] + 10", Some(Rc::clone(&heap)), None).unwrap();
2131 let expected = vec![
2132 Value::Number(11.0),
2133 Value::Number(12.0),
2134 Value::Number(13.0),
2135 ];
2136 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2137 }
2138
2139 #[test]
2140 fn list_scalar_subtraction() {
2141 let heap = Rc::new(RefCell::new(Heap::new()));
2142 let result = parse_and_evaluate("[10, 20, 30] - 5", Some(Rc::clone(&heap)), None).unwrap();
2143 let expected = vec![Value::Number(5.0), Value::Number(15.0), Value::Number(25.0)];
2144 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2145 }
2146
2147 #[test]
2148 fn list_scalar_multiplication() {
2149 let heap = Rc::new(RefCell::new(Heap::new()));
2150 let result = parse_and_evaluate("[2, 3, 4] * 2", Some(Rc::clone(&heap)), None).unwrap();
2151 let expected = vec![Value::Number(4.0), Value::Number(6.0), Value::Number(8.0)];
2152 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2153 }
2154
2155 #[test]
2156 fn list_scalar_division() {
2157 let heap = Rc::new(RefCell::new(Heap::new()));
2158 let result = parse_and_evaluate("[10, 20, 30] / 10", Some(Rc::clone(&heap)), None).unwrap();
2159 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(3.0)];
2160 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2161 }
2162
2163 #[test]
2164 fn list_scalar_power() {
2165 let heap = Rc::new(RefCell::new(Heap::new()));
2166 let result = parse_and_evaluate("[2, 3, 4] ^ 2", Some(Rc::clone(&heap)), None).unwrap();
2167 let expected = vec![Value::Number(4.0), Value::Number(9.0), Value::Number(16.0)];
2168 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2169 }
2170
2171 #[test]
2172 fn list_scalar_modulo() {
2173 let heap = Rc::new(RefCell::new(Heap::new()));
2174 let result = parse_and_evaluate("[10, 11, 12] % 3", Some(Rc::clone(&heap)), None).unwrap();
2175 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(0.0)];
2176 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2177 }
2178
2179 #[test]
2180 fn list_with_operator() {
2181 let heap = Rc::new(RefCell::new(Heap::new()));
2182 let result =
2183 parse_and_evaluate("[1, 2, 3] via (x => x * x)", Some(Rc::clone(&heap)), None).unwrap();
2184 let expected = vec![Value::Number(1.0), Value::Number(4.0), Value::Number(9.0)];
2185 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2186 }
2187
2188 #[test]
2189 fn list_with_builtin_function() {
2190 let heap = Rc::new(RefCell::new(Heap::new()));
2191 let result =
2192 parse_and_evaluate("[4, 9, 16] via sqrt", Some(Rc::clone(&heap)), None).unwrap();
2193 let expected = vec![Value::Number(2.0), Value::Number(3.0), Value::Number(4.0)];
2194 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2195 }
2196
2197 #[test]
2198 fn into_operator_with_list() {
2199 let heap = Rc::new(RefCell::new(Heap::new()));
2200 let result =
2201 parse_and_evaluate("['hello', 'world'] into head", Some(Rc::clone(&heap)), None)
2202 .unwrap();
2203 assert_eq!(result.as_string(&heap.borrow()).unwrap(), "hello");
2204 }
2205
2206 #[test]
2207 fn into_operator_with_string() {
2208 let heap = Rc::new(RefCell::new(Heap::new()));
2209 let result = parse_and_evaluate("'hello' into head", Some(Rc::clone(&heap)), None).unwrap();
2210 assert_eq!(result.as_string(&heap.borrow()).unwrap(), "h");
2211 }
2212
2213 #[test]
2214 fn into_vs_via_difference() {
2215 let heap = Rc::new(RefCell::new(Heap::new()));
2216
2217 let via_result =
2219 parse_and_evaluate("['hello', 'world'] via head", Some(Rc::clone(&heap)), None)
2220 .unwrap();
2221 let borrowed_heap = heap.borrow();
2222 let via_list = via_result.as_list(&borrowed_heap).unwrap();
2223 assert_eq!(via_list.len(), 2);
2224 assert_eq!(via_list[0].as_string(&borrowed_heap).unwrap(), "h");
2225 assert_eq!(via_list[1].as_string(&borrowed_heap).unwrap(), "w");
2226 drop(borrowed_heap);
2227
2228 let into_result =
2230 parse_and_evaluate("['hello', 'world'] into head", Some(Rc::clone(&heap)), None)
2231 .unwrap();
2232 assert_eq!(into_result.as_string(&heap.borrow()).unwrap(), "hello");
2233 }
2234
2235 #[test]
2236 fn into_operator_with_aggregation() {
2237 let heap = Rc::new(RefCell::new(Heap::new()));
2238 let result =
2239 parse_and_evaluate("[1, 2, 3, 4, 5] into sum", Some(Rc::clone(&heap)), None).unwrap();
2240 assert_eq!(result.as_number().unwrap(), 15.0);
2241 }
2242
2243 #[test]
2244 fn into_operator_rejects_lists() {
2245 let heap = Rc::new(RefCell::new(Heap::new()));
2246
2247 let result = parse_and_evaluate(
2249 "[1, 2, 3] into [sqrt, sqrt, sqrt]",
2250 Some(Rc::clone(&heap)),
2251 None,
2252 );
2253 assert!(result.is_err());
2254 assert!(
2255 result
2256 .unwrap_err()
2257 .to_string()
2258 .contains("'into' operator requires a function on the right side, not a list")
2259 );
2260
2261 let result = parse_and_evaluate("[1, 2, 3] into [sqrt]", Some(Rc::clone(&heap)), None);
2263 assert!(result.is_err());
2264 assert!(
2265 result
2266 .unwrap_err()
2267 .to_string()
2268 .contains("'into' operator requires a function on the right side, not a list")
2269 );
2270 }
2271
2272 #[test]
2273 fn list_elementwise_boolean_and() {
2274 let heap = Rc::new(RefCell::new(Heap::new()));
2275 let result = parse_and_evaluate(
2276 "[true, true, false] && [true, false, true]",
2277 Some(Rc::clone(&heap)),
2278 None,
2279 )
2280 .unwrap();
2281 let expected = vec![Value::Bool(true), Value::Bool(false), Value::Bool(false)];
2282 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2283 }
2284
2285 #[test]
2286 fn list_elementwise_boolean_or() {
2287 let heap = Rc::new(RefCell::new(Heap::new()));
2288 let result = parse_and_evaluate(
2289 "[true, false, false] || [false, true, false]",
2290 Some(Rc::clone(&heap)),
2291 None,
2292 )
2293 .unwrap();
2294 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(false)];
2295 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2296 }
2297
2298 #[test]
2299 fn list_elementwise_coalesce() {
2300 let heap = Rc::new(RefCell::new(Heap::new()));
2301 let result = parse_and_evaluate(
2302 "[null, 2, null] ?? [1, null, 3]",
2303 Some(Rc::clone(&heap)),
2304 None,
2305 )
2306 .unwrap();
2307 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(3.0)];
2308 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2309 }
2310
2311 #[test]
2312 fn list_scalar_coalesce() {
2313 let heap = Rc::new(RefCell::new(Heap::new()));
2314 let result =
2315 parse_and_evaluate("[null, 2, null] ?? 5", Some(Rc::clone(&heap)), None).unwrap();
2316 let expected = vec![Value::Number(5.0), Value::Number(2.0), Value::Number(5.0)];
2317 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2318 }
2319
2320 #[test]
2321 fn list_elementwise_string_concat() {
2322 let heap = Rc::new(RefCell::new(Heap::new()));
2323 let result = parse_and_evaluate(
2324 "[\"a\", \"b\", \"c\"] + [\"1\", \"2\", \"3\"]",
2325 Some(Rc::clone(&heap)),
2326 None,
2327 )
2328 .unwrap();
2329 let borrowed_heap = heap.borrow();
2330 let result_list = result.as_list(&borrowed_heap).unwrap();
2331 assert_eq!(result_list.len(), 3);
2332 assert_eq!(result_list[0].as_string(&borrowed_heap).unwrap(), "a1");
2333 assert_eq!(result_list[1].as_string(&borrowed_heap).unwrap(), "b2");
2334 assert_eq!(result_list[2].as_string(&borrowed_heap).unwrap(), "c3");
2335 }
2336
2337 #[test]
2338 fn list_scalar_string_concat() {
2339 let heap = Rc::new(RefCell::new(Heap::new()));
2340 let result = parse_and_evaluate(
2341 "[\"a\", \"b\", \"c\"] + \"!\"",
2342 Some(Rc::clone(&heap)),
2343 None,
2344 )
2345 .unwrap();
2346 let borrowed_heap = heap.borrow();
2347 let result_list = result.as_list(&borrowed_heap).unwrap();
2348 assert_eq!(result_list.len(), 3);
2349 assert_eq!(result_list[0].as_string(&borrowed_heap).unwrap(), "a!");
2350 assert_eq!(result_list[1].as_string(&borrowed_heap).unwrap(), "b!");
2351 assert_eq!(result_list[2].as_string(&borrowed_heap).unwrap(), "c!");
2352 }
2353
2354 #[test]
2355 fn nested_list_operations() {
2356 let heap = Rc::new(RefCell::new(Heap::new()));
2357 let result =
2358 parse_and_evaluate("([1, 2, 3] + [4, 5, 6]) * 2", Some(Rc::clone(&heap)), None)
2359 .unwrap();
2360 let expected = vec![
2361 Value::Number(10.0),
2362 Value::Number(14.0),
2363 Value::Number(18.0),
2364 ];
2365 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2366 }
2367
2368 #[test]
2369 fn list_comparison_all_equal() {
2370 let heap = Rc::new(RefCell::new(Heap::new()));
2371 let result = parse_and_evaluate("[1, 1, 1] == 1", Some(heap.clone()), None).unwrap();
2372 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(true)];
2373 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2374 }
2375
2376 #[test]
2377 fn list_comparison_not_all_equal() {
2378 let heap = Rc::new(RefCell::new(Heap::new()));
2379 let result = parse_and_evaluate("[1, 2, 1] == 1", Some(heap.clone()), None).unwrap();
2380 let expected = vec![Value::Bool(true), Value::Bool(false), Value::Bool(true)];
2381 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2382 }
2383
2384 #[test]
2385 fn list_comparison_all_less() {
2386 let heap = Rc::new(RefCell::new(Heap::new()));
2387 let result = parse_and_evaluate("[1, 2, 3] < 5", Some(heap.clone()), None).unwrap();
2388 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(true)];
2389 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2390 }
2391
2392 #[test]
2393 fn list_comparison_not_all_less() {
2394 let heap = Rc::new(RefCell::new(Heap::new()));
2395 let result = parse_and_evaluate("[1, 6, 3] < 5", Some(heap.clone()), None).unwrap();
2396 let expected = vec![Value::Bool(true), Value::Bool(false), Value::Bool(true)];
2397 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2398 }
2399
2400 #[test]
2401 fn not_operator_basic() {
2402 let result = parse_and_evaluate("not true", None, None).unwrap();
2403 assert_eq!(result, Value::Bool(false));
2404 }
2405
2406 #[test]
2407 fn not_operator_with_false() {
2408 let result = parse_and_evaluate("not false", None, None).unwrap();
2409 assert_eq!(result, Value::Bool(true));
2410 }
2411
2412 #[test]
2413 fn not_operator_with_expression() {
2414 let result = parse_and_evaluate("not (5 > 10)", None, None).unwrap();
2415 assert_eq!(result, Value::Bool(true));
2416 }
2417
2418 #[test]
2419 fn not_operator_double_negation() {
2420 let result = parse_and_evaluate("not not true", None, None).unwrap();
2421 assert_eq!(result, Value::Bool(true));
2422 }
2423
2424 #[test]
2425 fn not_operator_with_and() {
2426 let result = parse_and_evaluate("not (true and false)", None, None).unwrap();
2427 assert_eq!(result, Value::Bool(true));
2428 }
2429
2430 #[test]
2431 fn not_operator_with_or() {
2432 let result = parse_and_evaluate("not (false or false)", None, None).unwrap();
2433 assert_eq!(result, Value::Bool(true));
2434 }
2435
2436 #[test]
2437 fn not_operator_precedence() {
2438 let result = parse_and_evaluate("not true and false", None, None).unwrap();
2439 assert_eq!(result, Value::Bool(false));
2440 }
2441
2442 #[test]
2443 fn not_operator_comparison_with_invert() {
2444 let not_result = parse_and_evaluate("not true", None, None).unwrap();
2445 let invert_result = parse_and_evaluate("!true", None, None).unwrap();
2446 assert_eq!(not_result, invert_result);
2447 }
2448
2449 #[test]
2450 fn variable_immutability_prevents_reassignment() {
2451 let heap = Rc::new(RefCell::new(Heap::new()));
2452 let bindings = Rc::new(RefCell::new(HashMap::new()));
2453
2454 let result1 =
2456 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2457 assert!(result1.is_ok());
2458 assert_eq!(result1.unwrap(), Value::Number(5.0));
2459
2460 let result2 =
2462 parse_and_evaluate("x = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2463 assert!(result2.is_err());
2464 assert!(
2465 result2
2466 .unwrap_err()
2467 .to_string()
2468 .contains("x is already defined, and cannot be reassigned")
2469 );
2470
2471 let result3 = parse_and_evaluate("x", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2473 assert!(result3.is_ok());
2474 assert_eq!(result3.unwrap(), Value::Number(5.0));
2475 }
2476
2477 #[test]
2478 fn variable_immutability_allows_shadowing_in_nested_scopes() {
2479 let heap = Rc::new(RefCell::new(Heap::new()));
2480 let bindings = Rc::new(RefCell::new(HashMap::new()));
2481
2482 let result1 =
2484 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2485 assert!(result1.is_ok());
2486
2487 let result2 = parse_and_evaluate(
2489 "f = (x) => x * 2",
2490 Some(Rc::clone(&heap)),
2491 Some(Rc::clone(&bindings)),
2492 );
2493 assert!(result2.is_ok());
2494
2495 let result3 =
2497 parse_and_evaluate("f(10)", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2498 assert!(result3.is_ok());
2499 assert_eq!(result3.unwrap(), Value::Number(20.0));
2500
2501 let result4 = parse_and_evaluate("x", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2503 assert!(result4.is_ok());
2504 assert_eq!(result4.unwrap(), Value::Number(5.0));
2505 }
2506
2507 #[test]
2508 fn variable_immutability_in_do_blocks() {
2509 let heap = Rc::new(RefCell::new(Heap::new()));
2510 let bindings = Rc::new(RefCell::new(HashMap::new()));
2511
2512 let result1 =
2514 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2515 assert!(result1.is_ok());
2516
2517 let do_block = r#"do {
2519 x = 10
2520 y = x * 2
2521 return y
2522 }"#;
2523 let result2 =
2524 parse_and_evaluate(do_block, Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2525 assert!(result2.is_ok());
2526 assert_eq!(result2.unwrap(), Value::Number(20.0)); let do_block2 = r#"do {
2530 z = x * 3
2531 return z
2532 }"#;
2533 let result3 = parse_and_evaluate(
2534 do_block2,
2535 Some(Rc::clone(&heap)),
2536 Some(Rc::clone(&bindings)),
2537 );
2538 assert!(result3.is_ok());
2539 assert_eq!(result3.unwrap(), Value::Number(15.0));
2540
2541 let result4 = parse_and_evaluate("x", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2543 assert!(result4.is_ok());
2544 assert_eq!(result4.unwrap(), Value::Number(5.0));
2545 }
2546
2547 #[test]
2548 fn variable_immutability_different_variables() {
2549 let heap = Rc::new(RefCell::new(Heap::new()));
2550 let bindings = Rc::new(RefCell::new(HashMap::new()));
2551
2552 let result1 =
2554 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2555 assert!(result1.is_ok());
2556
2557 let result2 =
2558 parse_and_evaluate("y = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2559 assert!(result2.is_ok());
2560
2561 let result3 = parse_and_evaluate(
2562 "z = x + y",
2563 Some(Rc::clone(&heap)),
2564 Some(Rc::clone(&bindings)),
2565 );
2566 assert!(result3.is_ok());
2567 assert_eq!(result3.unwrap(), Value::Number(15.0));
2568 }
2569
2570 #[test]
2571 fn variable_immutability_with_complex_types() {
2572 let heap = Rc::new(RefCell::new(Heap::new()));
2573 let bindings = Rc::new(RefCell::new(HashMap::new()));
2574
2575 let result1 = parse_and_evaluate(
2577 "list = [1, 2, 3]",
2578 Some(Rc::clone(&heap)),
2579 Some(Rc::clone(&bindings)),
2580 );
2581 assert!(result1.is_ok());
2582
2583 let result2 = parse_and_evaluate(
2585 "list = [4, 5, 6]",
2586 Some(Rc::clone(&heap)),
2587 Some(Rc::clone(&bindings)),
2588 );
2589 assert!(result2.is_err());
2590 assert!(
2591 result2
2592 .unwrap_err()
2593 .to_string()
2594 .contains("list is already defined, and cannot be reassigned")
2595 );
2596
2597 let result3 = parse_and_evaluate(
2599 "rec = {x: 1, y: 2}",
2600 Some(Rc::clone(&heap)),
2601 Some(Rc::clone(&bindings)),
2602 );
2603 assert!(result3.is_ok());
2604
2605 let result4 = parse_and_evaluate(
2607 "rec = {x: 3, y: 4}",
2608 Some(Rc::clone(&heap)),
2609 Some(Rc::clone(&bindings)),
2610 );
2611 assert!(result4.is_err());
2612 assert!(
2613 result4
2614 .unwrap_err()
2615 .to_string()
2616 .contains("rec is already defined, and cannot be reassigned")
2617 );
2618 }
2619
2620 #[test]
2621 fn equality_comparison_numbers() {
2622 let result = parse_and_evaluate("5e2 == 5e2", None, None).unwrap();
2623 assert_eq!(result, Value::Bool(true));
2624
2625 let result = parse_and_evaluate("42 == 42", None, None).unwrap();
2626 assert_eq!(result, Value::Bool(true));
2627
2628 let result = parse_and_evaluate("42 == 43", None, None).unwrap();
2629 assert_eq!(result, Value::Bool(false));
2630 }
2631
2632 #[test]
2633 fn equality_comparison_strings() {
2634 let result = parse_and_evaluate(r#""hey" == "hey""#, None, None).unwrap();
2635 assert_eq!(result, Value::Bool(true));
2636
2637 let result = parse_and_evaluate(r#""hello" == "world""#, None, None).unwrap();
2638 assert_eq!(result, Value::Bool(false));
2639
2640 let result = parse_and_evaluate(r#""" == """#, None, None).unwrap();
2641 assert_eq!(result, Value::Bool(true));
2642 }
2643
2644 #[test]
2645 fn equality_comparison_lists() {
2646 let heap = Rc::new(RefCell::new(Heap::new()));
2647 let result = parse_and_evaluate("[1,2,3] == [1,2,3]", Some(heap.clone()), None).unwrap();
2648 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(true)];
2649 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2650
2651 let heap2 = Rc::new(RefCell::new(Heap::new()));
2652 let result = parse_and_evaluate("[1,2,3] == [1,2,4]", Some(heap2.clone()), None).unwrap();
2653 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(false)];
2654 assert_eq!(result.as_list(&heap2.borrow()).unwrap(), &expected);
2655
2656 let heap3 = Rc::new(RefCell::new(Heap::new()));
2661 let result =
2662 parse_and_evaluate(r#"["a", "b"] == ["a", "b"]"#, Some(heap3.clone()), None).unwrap();
2663 let expected = vec![Value::Bool(true), Value::Bool(true)];
2664 assert_eq!(result.as_list(&heap3.borrow()).unwrap(), &expected);
2665
2666 let heap4 = Rc::new(RefCell::new(Heap::new()));
2668 let result =
2669 parse_and_evaluate("[[1,2,3]] == [[1,2,3]]", Some(heap4.clone()), None).unwrap();
2670 let expected = vec![Value::Bool(true)];
2671 assert_eq!(result.as_list(&heap4.borrow()).unwrap(), &expected);
2672
2673 let heap5 = Rc::new(RefCell::new(Heap::new()));
2674 let result = parse_and_evaluate(
2675 "[[1,2,3], [4,5]] == [[1,2,3], [4,5]]",
2676 Some(heap5.clone()),
2677 None,
2678 )
2679 .unwrap();
2680 let expected = vec![Value::Bool(true), Value::Bool(true)];
2681 assert_eq!(result.as_list(&heap5.borrow()).unwrap(), &expected);
2682 }
2683
2684 #[test]
2685 fn equality_comparison_records() {
2686 let result = parse_and_evaluate("{ hey: 1 } == { hey: 1 }", None, None).unwrap();
2687 assert_eq!(result, Value::Bool(true));
2688
2689 let result = parse_and_evaluate("{ hey: 1 } == { hey: 2 }", None, None).unwrap();
2690 assert_eq!(result, Value::Bool(false));
2691
2692 let result = parse_and_evaluate("{ hey: 1 } == { hello: 1 }", None, None).unwrap();
2693 assert_eq!(result, Value::Bool(false));
2694
2695 let result = parse_and_evaluate("{ a: 1, b: 2 } == { a: 1, b: 2 }", None, None).unwrap();
2697 assert_eq!(result, Value::Bool(true));
2698
2699 let result = parse_and_evaluate("{ a: 1, b: 2 } == { b: 2, a: 1 }", None, None).unwrap();
2701 assert_eq!(result, Value::Bool(true));
2702
2703 let result = parse_and_evaluate("{ x: { y: 1 } } == { x: { y: 1 } }", None, None).unwrap();
2705 assert_eq!(result, Value::Bool(true));
2706 }
2707
2708 #[test]
2709 fn equality_comparison_lambdas() {
2710 let heap = Rc::new(RefCell::new(Heap::new()));
2711 let bindings = Rc::new(RefCell::new(HashMap::new()));
2712
2713 parse_and_evaluate(
2715 "f1 = (x) => x + 2",
2716 Some(Rc::clone(&heap)),
2717 Some(Rc::clone(&bindings)),
2718 )
2719 .unwrap();
2720 parse_and_evaluate(
2721 "f2 = (x) => x + 2",
2722 Some(Rc::clone(&heap)),
2723 Some(Rc::clone(&bindings)),
2724 )
2725 .unwrap();
2726 let result = parse_and_evaluate(
2727 "f1 == f2",
2728 Some(Rc::clone(&heap)),
2729 Some(Rc::clone(&bindings)),
2730 )
2731 .unwrap();
2732 assert_eq!(result, Value::Bool(true));
2733
2734 let result = parse_and_evaluate(
2736 "f1 == f1",
2737 Some(Rc::clone(&heap)),
2738 Some(Rc::clone(&bindings)),
2739 )
2740 .unwrap();
2741 assert_eq!(result, Value::Bool(true));
2742
2743 parse_and_evaluate(
2745 "f3 = f1",
2746 Some(Rc::clone(&heap)),
2747 Some(Rc::clone(&bindings)),
2748 )
2749 .unwrap();
2750 let result = parse_and_evaluate(
2751 "f1 == f3",
2752 Some(Rc::clone(&heap)),
2753 Some(Rc::clone(&bindings)),
2754 )
2755 .unwrap();
2756 assert_eq!(result, Value::Bool(true));
2757
2758 parse_and_evaluate(
2760 "f4 = (x) => x + 3",
2761 Some(Rc::clone(&heap)),
2762 Some(Rc::clone(&bindings)),
2763 )
2764 .unwrap();
2765 let result = parse_and_evaluate(
2766 "f1 == f4",
2767 Some(Rc::clone(&heap)),
2768 Some(Rc::clone(&bindings)),
2769 )
2770 .unwrap();
2771 assert_eq!(result, Value::Bool(false));
2772
2773 parse_and_evaluate(
2775 "f5 = (y) => y + 2",
2776 Some(Rc::clone(&heap)),
2777 Some(Rc::clone(&bindings)),
2778 )
2779 .unwrap();
2780 let result = parse_and_evaluate(
2781 "f1 == f5",
2782 Some(Rc::clone(&heap)),
2783 Some(Rc::clone(&bindings)),
2784 )
2785 .unwrap();
2786 assert_eq!(result, Value::Bool(false));
2787
2788 parse_and_evaluate(
2790 "f6 = (x, y) => x + y",
2791 Some(Rc::clone(&heap)),
2792 Some(Rc::clone(&bindings)),
2793 )
2794 .unwrap();
2795 let result = parse_and_evaluate(
2796 "f1 == f6",
2797 Some(Rc::clone(&heap)),
2798 Some(Rc::clone(&bindings)),
2799 )
2800 .unwrap();
2801 assert_eq!(result, Value::Bool(false));
2802 }
2803
2804 #[test]
2805 fn equality_comparison_mixed_types() {
2806 let result = parse_and_evaluate("1 == \"1\"", None, None).unwrap();
2808 assert_eq!(result, Value::Bool(false));
2809
2810 let result = parse_and_evaluate("true == 1", None, None).unwrap();
2811 assert_eq!(result, Value::Bool(false));
2812
2813 let heap = Rc::new(RefCell::new(Heap::new()));
2815 let result = parse_and_evaluate("[1] == 1", Some(heap.clone()), None).unwrap();
2816 let expected = vec![Value::Bool(true)];
2817 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2818
2819 let result = parse_and_evaluate("null == 0", None, None).unwrap();
2820 assert_eq!(result, Value::Bool(false));
2821 }
2822
2823 #[test]
2824 fn comparison_operators_strings() {
2825 let result = parse_and_evaluate(r#""apple" < "banana""#, None, None).unwrap();
2827 assert_eq!(result, Value::Bool(true));
2828
2829 let result = parse_and_evaluate(r#""zebra" > "apple""#, None, None).unwrap();
2830 assert_eq!(result, Value::Bool(true));
2831
2832 let result = parse_and_evaluate(r#""hello" <= "hello""#, None, None).unwrap();
2833 assert_eq!(result, Value::Bool(true));
2834 }
2835
2836 #[test]
2837 fn comparison_operators_lists() {
2838 let heap = Rc::new(RefCell::new(Heap::new()));
2841 let result = parse_and_evaluate("[1, 2] < [2, 3]", Some(heap.clone()), None).unwrap();
2842 let expected = vec![Value::Bool(true), Value::Bool(true)];
2843 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2844
2845 let heap2 = Rc::new(RefCell::new(Heap::new()));
2847 let result = parse_and_evaluate("[1, 2] < [1, 3]", Some(heap2.clone()), None).unwrap();
2848 let expected = vec![Value::Bool(false), Value::Bool(true)];
2849 assert_eq!(result.as_list(&heap2.borrow()).unwrap(), &expected);
2850
2851 let heap3 = Rc::new(RefCell::new(Heap::new()));
2853 let result = parse_and_evaluate("[2, 1] > [1, 0]", Some(heap3.clone()), None).unwrap();
2854 let expected = vec![Value::Bool(true), Value::Bool(true)];
2855 assert_eq!(result.as_list(&heap3.borrow()).unwrap(), &expected);
2856 }
2857
2858 #[test]
2859 fn late_binding_unbound_variable_succeeds() {
2860 let heap = Rc::new(RefCell::new(Heap::new()));
2862 let bindings = Rc::new(RefCell::new(HashMap::new()));
2863 let result = parse_and_evaluate("f = x => x + y", Some(heap), Some(bindings));
2864 assert!(result.is_ok());
2866 }
2867
2868 #[test]
2869 fn early_binding_bound_variable_succeeds() {
2870 let heap = Rc::new(RefCell::new(Heap::new()));
2872 let bindings = Rc::new(RefCell::new(HashMap::new()));
2873
2874 let _ = parse_and_evaluate("y = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
2876 .unwrap();
2877
2878 let result = parse_and_evaluate(
2880 "g = x => x + y",
2881 Some(Rc::clone(&heap)),
2882 Some(Rc::clone(&bindings)),
2883 );
2884 assert!(result.is_ok());
2885
2886 let call_result = parse_and_evaluate("g(2)", Some(heap), Some(bindings)).unwrap();
2888 assert_eq!(call_result, Value::Number(7.0));
2889 }
2890
2891 #[test]
2892 fn early_binding_builtin_function_succeeds() {
2893 let heap = Rc::new(RefCell::new(Heap::new()));
2895 let bindings = Rc::new(RefCell::new(HashMap::new()));
2896 let result = parse_and_evaluate(
2897 "h = x => sin(x)",
2898 Some(Rc::clone(&heap)),
2899 Some(Rc::clone(&bindings)),
2900 );
2901 assert!(result.is_ok());
2902
2903 let call_result = parse_and_evaluate("h(0)", Some(heap), Some(bindings)).unwrap();
2905 assert_eq!(call_result, Value::Number(0.0));
2906 }
2907
2908 #[test]
2909 fn late_binding_nested_function_succeeds() {
2910 let heap = Rc::new(RefCell::new(Heap::new()));
2912 let bindings = Rc::new(RefCell::new(HashMap::new()));
2913
2914 let result = parse_and_evaluate(
2916 "outer = x => do { inner = y => y + z; return inner(x) }",
2917 Some(Rc::clone(&heap)),
2918 Some(Rc::clone(&bindings)),
2919 );
2920 assert!(result.is_ok());
2921
2922 let _ = parse_and_evaluate(
2924 "z = 100",
2925 Some(Rc::clone(&heap)),
2926 Some(Rc::clone(&bindings)),
2927 )
2928 .unwrap();
2929
2930 let call_result = parse_and_evaluate("outer(5)", Some(heap), Some(bindings)).unwrap();
2932 assert_eq!(call_result, Value::Number(105.0));
2933 }
2934
2935 #[test]
2936 fn early_binding_all_variables_bound() {
2937 let heap = Rc::new(RefCell::new(Heap::new()));
2939 let bindings = Rc::new(RefCell::new(HashMap::new()));
2940
2941 let _ = parse_and_evaluate("a = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
2943 .unwrap();
2944 let _ = parse_and_evaluate("b = 20", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
2945 .unwrap();
2946
2947 let result = parse_and_evaluate(
2949 "func = x => (x + a) * b",
2950 Some(Rc::clone(&heap)),
2951 Some(Rc::clone(&bindings)),
2952 );
2953 assert!(result.is_ok());
2954
2955 let call_result = parse_and_evaluate("func(5)", Some(heap), Some(bindings)).unwrap();
2957 assert_eq!(call_result, Value::Number(300.0));
2958 }
2959
2960 #[test]
2961 fn early_binding_parameter_shadows_outer() {
2962 let heap = Rc::new(RefCell::new(Heap::new()));
2964 let bindings = Rc::new(RefCell::new(HashMap::new()));
2965
2966 let _ = parse_and_evaluate(
2968 "x = 100",
2969 Some(Rc::clone(&heap)),
2970 Some(Rc::clone(&bindings)),
2971 )
2972 .unwrap();
2973
2974 let result = parse_and_evaluate(
2976 "shadow = x => x * 2",
2977 Some(Rc::clone(&heap)),
2978 Some(Rc::clone(&bindings)),
2979 );
2980 assert!(result.is_ok());
2981
2982 let call_result = parse_and_evaluate("shadow(5)", Some(heap), Some(bindings)).unwrap();
2984 assert_eq!(call_result, Value::Number(10.0));
2985 }
2986
2987 #[test]
2988 fn early_binding_do_block_internal_binding() {
2989 let heap = Rc::new(RefCell::new(Heap::new()));
2991 let bindings = Rc::new(RefCell::new(HashMap::new()));
2992
2993 let result = parse_and_evaluate(
2995 "f = x => do { y = 5; return x + y }",
2996 Some(Rc::clone(&heap)),
2997 Some(Rc::clone(&bindings)),
2998 );
2999 assert!(result.is_ok());
3000
3001 let call_result = parse_and_evaluate("f(10)", Some(heap), Some(bindings)).unwrap();
3003 assert_eq!(call_result, Value::Number(15.0));
3004 }
3005
3006 #[test]
3007 fn early_binding_do_block_nested_scope() {
3008 let heap = Rc::new(RefCell::new(Heap::new()));
3010 let bindings = Rc::new(RefCell::new(HashMap::new()));
3011
3012 let result = parse_and_evaluate(
3013 "later_func = do { c = 30; f = x => x + c; return f(10) }",
3014 Some(Rc::clone(&heap)),
3015 Some(Rc::clone(&bindings)),
3016 );
3017 assert!(result.is_ok());
3018
3019 let later_func_result =
3021 parse_and_evaluate("later_func", Some(heap), Some(bindings)).unwrap();
3022 assert_eq!(later_func_result, Value::Number(40.0));
3023 }
3024
3025 #[test]
3026 fn late_binding_do_block_forward_reference_succeeds() {
3027 let heap = Rc::new(RefCell::new(Heap::new()));
3029 let bindings = Rc::new(RefCell::new(HashMap::new()));
3030
3031 let result = parse_and_evaluate(
3032 "g = x => do { f = y => y + z; z = 10; return f(x) }",
3033 Some(Rc::clone(&heap)),
3034 Some(Rc::clone(&bindings)),
3035 );
3036 assert!(result.is_ok());
3037
3038 let call_result = parse_and_evaluate("g(5)", Some(heap), Some(bindings)).unwrap();
3040 assert_eq!(call_result, Value::Number(15.0));
3041 }
3042
3043 #[test]
3044 fn early_binding_do_block_multiple_assignments() {
3045 let heap = Rc::new(RefCell::new(Heap::new()));
3047 let bindings = Rc::new(RefCell::new(HashMap::new()));
3048
3049 let result = parse_and_evaluate(
3050 "calc = x => do { a = 2; b = 3; c = 4; return x * a + b * c }",
3051 Some(Rc::clone(&heap)),
3052 Some(Rc::clone(&bindings)),
3053 );
3054 assert!(result.is_ok());
3055
3056 let call_result = parse_and_evaluate("calc(5)", Some(heap), Some(bindings)).unwrap();
3058 assert_eq!(call_result, Value::Number(22.0));
3059 }
3060
3061 #[test]
3062 fn late_binding_multiple_unbound_variables_succeeds() {
3063 let heap = Rc::new(RefCell::new(Heap::new()));
3065 let bindings = Rc::new(RefCell::new(HashMap::new()));
3066
3067 let result = parse_and_evaluate(
3068 "f = x => x + y + z",
3069 Some(Rc::clone(&heap)),
3070 Some(Rc::clone(&bindings)),
3071 );
3072 assert!(result.is_ok());
3073
3074 let _ = parse_and_evaluate("y = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
3076 .unwrap();
3077 let _ = parse_and_evaluate("z = 20", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
3078 .unwrap();
3079
3080 let call_result = parse_and_evaluate("f(5)", Some(heap), Some(bindings)).unwrap();
3082 assert_eq!(call_result, Value::Number(35.0));
3083 }
3084
3085 #[test]
3086 fn late_binding_with_optional_args_succeeds() {
3087 let heap = Rc::new(RefCell::new(Heap::new()));
3089 let bindings = Rc::new(RefCell::new(HashMap::new()));
3090
3091 let result = parse_and_evaluate(
3092 "f = (x, y?) => x + z",
3093 Some(Rc::clone(&heap)),
3094 Some(Rc::clone(&bindings)),
3095 );
3096 assert!(result.is_ok());
3097
3098 let _ = parse_and_evaluate(
3100 "z = 100",
3101 Some(Rc::clone(&heap)),
3102 Some(Rc::clone(&bindings)),
3103 )
3104 .unwrap();
3105
3106 let call_result = parse_and_evaluate("f(5)", Some(heap), Some(bindings)).unwrap();
3108 assert_eq!(call_result, Value::Number(105.0));
3109 }
3110
3111 #[test]
3112 fn late_binding_with_rest_args_succeeds() {
3113 let heap = Rc::new(RefCell::new(Heap::new()));
3115 let bindings = Rc::new(RefCell::new(HashMap::new()));
3116
3117 let result = parse_and_evaluate(
3118 "f = (x, ...rest) => x + y",
3119 Some(Rc::clone(&heap)),
3120 Some(Rc::clone(&bindings)),
3121 );
3122 assert!(result.is_ok());
3123
3124 let _ = parse_and_evaluate("y = 50", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
3126 .unwrap();
3127
3128 let call_result = parse_and_evaluate("f(5)", Some(heap), Some(bindings)).unwrap();
3130 assert_eq!(call_result, Value::Number(55.0));
3131 }
3132
3133 #[test]
3134 fn recursion_self_reference_allowed() {
3135 let heap = Rc::new(RefCell::new(Heap::new()));
3137 let bindings = Rc::new(RefCell::new(HashMap::new()));
3138
3139 let result = parse_and_evaluate(
3141 "factorial = n => if n <= 1 then 1 else n * factorial(n - 1)",
3142 Some(Rc::clone(&heap)),
3143 Some(Rc::clone(&bindings)),
3144 );
3145 assert!(result.is_ok());
3146
3147 let call_result = parse_and_evaluate("factorial(5)", Some(heap), Some(bindings)).unwrap();
3149 assert_eq!(call_result, Value::Number(120.0));
3150 }
3151
3152 #[test]
3153 fn recursion_fibonacci() {
3154 let heap = Rc::new(RefCell::new(Heap::new()));
3156 let bindings = Rc::new(RefCell::new(HashMap::new()));
3157
3158 let result = parse_and_evaluate(
3160 "fib = n => if n <= 1 then n else fib(n - 1) + fib(n - 2)",
3161 Some(Rc::clone(&heap)),
3162 Some(Rc::clone(&bindings)),
3163 );
3164 assert!(result.is_ok());
3165
3166 let call_result = parse_and_evaluate("fib(6)", Some(heap), Some(bindings)).unwrap();
3168 assert_eq!(call_result, Value::Number(8.0));
3169 }
3170
3171 #[test]
3172 fn recursion_in_do_block() {
3173 let heap = Rc::new(RefCell::new(Heap::new()));
3175 let bindings = Rc::new(RefCell::new(HashMap::new()));
3176
3177 let result = parse_and_evaluate(
3178 "result = do { factorial = n => if n <= 1 then 1 else n * factorial(n - 1); return factorial(4) }",
3179 Some(Rc::clone(&heap)),
3180 Some(Rc::clone(&bindings)),
3181 );
3182 assert!(result.is_ok());
3183
3184 let result_val = parse_and_evaluate("result", Some(heap), Some(bindings)).unwrap();
3186 assert_eq!(result_val, Value::Number(24.0));
3187 }
3188
3189 #[test]
3190 fn mutual_recursion_succeeds() {
3191 let heap = Rc::new(RefCell::new(Heap::new()));
3193 let bindings = Rc::new(RefCell::new(HashMap::new()));
3194
3195 let result = parse_and_evaluate(
3197 "isEven = n => if n == 0 then true else isOdd(n - 1)",
3198 Some(Rc::clone(&heap)),
3199 Some(Rc::clone(&bindings)),
3200 );
3201 assert!(result.is_ok());
3202
3203 let _ = parse_and_evaluate(
3205 "isOdd = n => if n == 0 then false else isEven(n - 1)",
3206 Some(Rc::clone(&heap)),
3207 Some(Rc::clone(&bindings)),
3208 )
3209 .unwrap();
3210
3211 let result1 = parse_and_evaluate(
3213 "isEven(4)",
3214 Some(Rc::clone(&heap)),
3215 Some(Rc::clone(&bindings)),
3216 )
3217 .unwrap();
3218 assert_eq!(result1, Value::Bool(true));
3219
3220 let result2 = parse_and_evaluate(
3221 "isEven(5)",
3222 Some(Rc::clone(&heap)),
3223 Some(Rc::clone(&bindings)),
3224 )
3225 .unwrap();
3226 assert_eq!(result2, Value::Bool(false));
3227
3228 let result3 = parse_and_evaluate(
3229 "isOdd(3)",
3230 Some(Rc::clone(&heap)),
3231 Some(Rc::clone(&bindings)),
3232 )
3233 .unwrap();
3234 assert_eq!(result3, Value::Bool(true));
3235
3236 let result4 = parse_and_evaluate("isOdd(6)", Some(heap), Some(bindings)).unwrap();
3237 assert_eq!(result4, Value::Bool(false));
3238 }
3239
3240 #[test]
3241 fn recursion_only_for_lambdas() {
3242 let heap = Rc::new(RefCell::new(Heap::new()));
3244 let bindings = Rc::new(RefCell::new(HashMap::new()));
3245
3246 let result = parse_and_evaluate("y = x + 1", Some(heap), Some(bindings));
3248 assert!(result.is_err());
3249 }
3250
3251 #[test]
3253 fn dot_equal_lists() {
3254 let heap = Rc::new(RefCell::new(Heap::new()));
3255
3256 let result =
3258 parse_and_evaluate("[1, 2, 3] .== [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3259 assert_eq!(result, Value::Bool(true));
3260
3261 let result =
3263 parse_and_evaluate("[1, 2, 3] .== [1, 2, 4]", Some(Rc::clone(&heap)), None).unwrap();
3264 assert_eq!(result, Value::Bool(false));
3265
3266 let result =
3268 parse_and_evaluate("[1, 2] .== [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3269 assert_eq!(result, Value::Bool(false));
3270
3271 let result = parse_and_evaluate("[1, 2, 3] .== 1", Some(Rc::clone(&heap)), None).unwrap();
3273 assert_eq!(result, Value::Bool(false));
3274
3275 let result = parse_and_evaluate("[] .== []", Some(Rc::clone(&heap)), None).unwrap();
3277 assert_eq!(result, Value::Bool(true));
3278
3279 let result =
3281 parse_and_evaluate("[[1, 2], [3, 4]] .== [[1, 2], [3, 4]]", Some(heap), None).unwrap();
3282 assert_eq!(result, Value::Bool(true));
3283 }
3284
3285 #[test]
3286 fn dot_not_equal_lists() {
3287 let heap = Rc::new(RefCell::new(Heap::new()));
3288
3289 let result =
3290 parse_and_evaluate("[1, 2, 3] .!= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3291 assert_eq!(result, Value::Bool(false));
3292
3293 let result =
3294 parse_and_evaluate("[1, 2, 3] .!= [1, 2, 4]", Some(Rc::clone(&heap)), None).unwrap();
3295 assert_eq!(result, Value::Bool(true));
3296
3297 let result = parse_and_evaluate("[1, 2, 3] .!= 1", Some(heap), None).unwrap();
3298 assert_eq!(result, Value::Bool(true));
3299 }
3300
3301 #[test]
3302 fn dot_less_lists() {
3303 let heap = Rc::new(RefCell::new(Heap::new()));
3304
3305 let result =
3307 parse_and_evaluate("[1, 2, 2] .< [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3308 assert_eq!(result, Value::Bool(true));
3309
3310 let result =
3311 parse_and_evaluate("[1, 2] .< [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3312 assert_eq!(result, Value::Bool(true));
3313
3314 let result = parse_and_evaluate("[] .< [1]", Some(Rc::clone(&heap)), None).unwrap();
3315 assert_eq!(result, Value::Bool(true));
3316
3317 let result = parse_and_evaluate("[2] .< [1, 9, 9]", Some(Rc::clone(&heap)), None).unwrap();
3318 assert_eq!(result, Value::Bool(false));
3319
3320 let result = parse_and_evaluate("[1, 2, 3] .< [1, 2, 3]", Some(heap), None).unwrap();
3321 assert_eq!(result, Value::Bool(false));
3322 }
3323
3324 #[test]
3325 fn dot_less_eq_lists() {
3326 let heap = Rc::new(RefCell::new(Heap::new()));
3327
3328 let result =
3329 parse_and_evaluate("[1, 2, 2] .<= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3330 assert_eq!(result, Value::Bool(true));
3331
3332 let result =
3333 parse_and_evaluate("[1, 2, 3] .<= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3334 assert_eq!(result, Value::Bool(true));
3335
3336 let result = parse_and_evaluate("[1, 2, 4] .<= [1, 2, 3]", Some(heap), None).unwrap();
3337 assert_eq!(result, Value::Bool(false));
3338 }
3339
3340 #[test]
3341 fn dot_greater_lists() {
3342 let heap = Rc::new(RefCell::new(Heap::new()));
3343
3344 let result =
3345 parse_and_evaluate("[1, 2, 3] .> [1, 2, 2]", Some(Rc::clone(&heap)), None).unwrap();
3346 assert_eq!(result, Value::Bool(true));
3347
3348 let result = parse_and_evaluate("[2] .> [1, 9, 9]", Some(Rc::clone(&heap)), None).unwrap();
3349 assert_eq!(result, Value::Bool(true));
3350
3351 let result = parse_and_evaluate("[1] .> []", Some(Rc::clone(&heap)), None).unwrap();
3352 assert_eq!(result, Value::Bool(true));
3353
3354 let result = parse_and_evaluate("[1, 2, 3] .> [1, 2, 3]", Some(heap), None).unwrap();
3355 assert_eq!(result, Value::Bool(false));
3356 }
3357
3358 #[test]
3359 fn dot_greater_eq_lists() {
3360 let heap = Rc::new(RefCell::new(Heap::new()));
3361
3362 let result =
3363 parse_and_evaluate("[1, 2, 3] .>= [1, 2, 2]", Some(Rc::clone(&heap)), None).unwrap();
3364 assert_eq!(result, Value::Bool(true));
3365
3366 let result =
3367 parse_and_evaluate("[1, 2, 3] .>= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3368 assert_eq!(result, Value::Bool(true));
3369
3370 let result = parse_and_evaluate("[1, 2, 2] .>= [1, 2, 3]", Some(heap), None).unwrap();
3371 assert_eq!(result, Value::Bool(false));
3372 }
3373
3374 #[test]
3375 fn dot_operators_with_scalars() {
3376 let result = parse_and_evaluate("5 .== 5", None, None).unwrap();
3378 assert_eq!(result, Value::Bool(true));
3379
3380 let result = parse_and_evaluate("5 .!= 3", None, None).unwrap();
3381 assert_eq!(result, Value::Bool(true));
3382
3383 let result = parse_and_evaluate("3 .< 5", None, None).unwrap();
3384 assert_eq!(result, Value::Bool(true));
3385
3386 let result = parse_and_evaluate("5 .> 3", None, None).unwrap();
3387 assert_eq!(result, Value::Bool(true));
3388 }
3389
3390 #[test]
3391 fn dot_equal_vs_regular_equal_with_broadcasting() {
3392 let heap = Rc::new(RefCell::new(Heap::new()));
3393
3394 let result =
3396 parse_and_evaluate("[true, true, true] == true", Some(Rc::clone(&heap)), None).unwrap();
3397 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(true)];
3398 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
3399
3400 let result =
3402 parse_and_evaluate("[true, true, true] .== true", Some(Rc::clone(&heap)), None)
3403 .unwrap();
3404 assert_eq!(result, Value::Bool(false));
3405
3406 let result = parse_and_evaluate(
3408 "[true, true, true] .== [true, true, true]",
3409 Some(heap),
3410 None,
3411 )
3412 .unwrap();
3413 assert_eq!(result, Value::Bool(true));
3414 }
3415
3416 #[test]
3417 fn dot_operators_mixed_types() {
3418 let heap = Rc::new(RefCell::new(Heap::new()));
3419
3420 let result =
3422 parse_and_evaluate("\"hello\" .== [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3423 assert_eq!(result, Value::Bool(false));
3424
3425 let result = parse_and_evaluate("5 .< [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3427 assert_eq!(result, Value::Bool(false));
3428
3429 let result = parse_and_evaluate("\"abc\" .< \"def\"", Some(heap), None).unwrap();
3431 assert_eq!(result, Value::Bool(true));
3432 }
3433}