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