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 borrowed_heap = heap.borrow();
743 let mut all_equal = true;
744 for (l, r) in l_vec.iter().zip(&r_vec) {
745 if !l.equals(r, &borrowed_heap)? {
746 all_equal = false;
747 break;
748 }
749 }
750 Ok(Bool(all_equal))
751 }
752 BinaryOp::NotEqual => {
753 let borrowed_heap = heap.borrow();
754 let mut all_not_equal = true;
755 for (l, r) in l_vec.iter().zip(&r_vec) {
756 if l.equals(r, &borrowed_heap)? {
757 all_not_equal = false;
758 break;
759 }
760 }
761 Ok(Bool(all_not_equal))
762 }
763 BinaryOp::Less => {
764 let borrowed_heap = heap.borrow();
765 let mut all_less = true;
766 for (l, r) in l_vec.iter().zip(&r_vec) {
767 match l.compare(r, &borrowed_heap)? {
768 Some(std::cmp::Ordering::Less) => continue,
769 _ => {
770 all_less = false;
771 break;
772 }
773 }
774 }
775 Ok(Bool(all_less))
776 }
777 BinaryOp::LessEq => {
778 let borrowed_heap = heap.borrow();
779 let mut all_less_eq = true;
780 for (l, r) in l_vec.iter().zip(&r_vec) {
781 match l.compare(r, &borrowed_heap)? {
782 Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) => {
783 continue;
784 }
785 _ => {
786 all_less_eq = false;
787 break;
788 }
789 }
790 }
791 Ok(Bool(all_less_eq))
792 }
793 BinaryOp::Greater => {
794 let borrowed_heap = heap.borrow();
795 let mut all_greater = true;
796 for (l, r) in l_vec.iter().zip(&r_vec) {
797 match l.compare(r, &borrowed_heap)? {
798 Some(std::cmp::Ordering::Greater) => continue,
799 _ => {
800 all_greater = false;
801 break;
802 }
803 }
804 }
805 Ok(Bool(all_greater))
806 }
807 BinaryOp::GreaterEq => {
808 let borrowed_heap = heap.borrow();
809 let mut all_greater_eq = true;
810 for (l, r) in l_vec.iter().zip(&r_vec) {
811 match l.compare(r, &borrowed_heap)? {
812 Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) => {
813 continue;
814 }
815 _ => {
816 all_greater_eq = false;
817 break;
818 }
819 }
820 }
821 Ok(Bool(all_greater_eq))
822 }
823 BinaryOp::And | BinaryOp::NaturalAnd => {
824 let mapped_list = l_vec
825 .iter()
826 .zip(&r_vec)
827 .map(|(l, r)| Ok(Bool(l.as_bool()? && r.as_bool()?)))
828 .collect::<Result<Vec<Value>>>()?;
829 Ok(heap.borrow_mut().insert_list(mapped_list))
830 }
831 BinaryOp::Or | BinaryOp::NaturalOr => {
832 let mapped_list = l_vec
833 .iter()
834 .zip(&r_vec)
835 .map(|(l, r)| Ok(Bool(l.as_bool()? || r.as_bool()?)))
836 .collect::<Result<Vec<Value>>>()?;
837 Ok(heap.borrow_mut().insert_list(mapped_list))
838 }
839 BinaryOp::Add => {
840 let mapped_list = l_vec
841 .iter()
842 .zip(&r_vec)
843 .map(|(l, r)| match (l, r) {
844 (Value::String(_), Value::String(_)) => {
845 let (l_str, r_str) = {
846 (
847 l.as_string(&heap.borrow())?.to_string(),
848 r.as_string(&heap.borrow())?.to_string(),
849 )
850 };
851 Ok(heap
852 .borrow_mut()
853 .insert_string(format!("{}{}", l_str, r_str)))
854 }
855 (Value::Number(_), Value::Number(_)) => {
856 Ok(Number(l.as_number()? + r.as_number()?))
857 }
858 _ => Err(anyhow!("can't add {} and {}", l.get_type(), r.get_type())),
859 })
860 .collect::<Result<Vec<Value>>>()?;
861 Ok(heap.borrow_mut().insert_list(mapped_list))
862 }
863 BinaryOp::Subtract => {
864 let mapped_list = l_vec
865 .iter()
866 .zip(&r_vec)
867 .map(|(l, r)| Ok(Number(l.as_number()? - r.as_number()?)))
868 .collect::<Result<Vec<Value>>>()?;
869 Ok(heap.borrow_mut().insert_list(mapped_list))
870 }
871 BinaryOp::Multiply => {
872 let mapped_list = l_vec
873 .iter()
874 .zip(&r_vec)
875 .map(|(l, r)| Ok(Number(l.as_number()? * r.as_number()?)))
876 .collect::<Result<Vec<Value>>>()?;
877 Ok(heap.borrow_mut().insert_list(mapped_list))
878 }
879 BinaryOp::Divide => {
880 let mapped_list = l_vec
881 .iter()
882 .zip(&r_vec)
883 .map(|(l, r)| Ok(Number(l.as_number()? / r.as_number()?)))
884 .collect::<Result<Vec<Value>>>()?;
885 Ok(heap.borrow_mut().insert_list(mapped_list))
886 }
887 BinaryOp::Modulo => {
888 let mapped_list = l_vec
889 .iter()
890 .zip(&r_vec)
891 .map(|(l, r)| Ok(Number(l.as_number()? % r.as_number()?)))
892 .collect::<Result<Vec<Value>>>()?;
893 Ok(heap.borrow_mut().insert_list(mapped_list))
894 }
895 BinaryOp::Power => {
896 let mapped_list = l_vec
897 .iter()
898 .zip(&r_vec)
899 .map(|(l, r)| Ok(Number(l.as_number()?.powf(r.as_number()?))))
900 .collect::<Result<Vec<Value>>>()?;
901 Ok(heap.borrow_mut().insert_list(mapped_list))
902 }
903 BinaryOp::Coalesce => {
904 let mapped_list = l_vec
905 .iter()
906 .zip(&r_vec)
907 .map(|(l, r)| if *l == Value::Null { Ok(*r) } else { Ok(*l) })
908 .collect::<Result<Vec<Value>>>()?;
909 Ok(heap.borrow_mut().insert_list(mapped_list))
910 }
911 BinaryOp::Via => {
912 let mapped_list = l_vec
913 .iter()
914 .zip(&r_vec)
915 .map(|(l, r)| {
916 if !r.is_lambda() && !r.is_built_in() {
917 return Err(anyhow!(
918 "right-hand iterable contains non-function {}",
919 r.stringify_internal(&heap.borrow())
920 ));
921 }
922
923 let def = {
924 let borrowed_heap = &heap.borrow();
925 get_function_def(r, borrowed_heap).ok_or_else(|| {
926 anyhow!(
927 "unknown function: {}",
928 r.stringify_internal(borrowed_heap)
929 )
930 })?
931 };
932
933 def.call(
934 *r,
935 vec![*l],
936 Rc::clone(&heap),
937 Rc::clone(&bindings),
938 call_depth,
939 )
940 })
941 .collect::<Result<Vec<Value>>>()?;
942 Ok(heap.borrow_mut().insert_list(mapped_list))
943 }
944 BinaryOp::Into => {
945 unreachable!("Into operator should not reach list-to-list evaluation")
947 }
948 BinaryOp::DotEqual
949 | BinaryOp::DotNotEqual
950 | BinaryOp::DotLess
951 | BinaryOp::DotLessEq
952 | BinaryOp::DotGreater
953 | BinaryOp::DotGreaterEq => {
954 unreachable!("Dot operators should be handled before list broadcasting")
956 }
957 }
958 }
959 (Value::List(list), scalar) | (scalar, Value::List(list)) => {
960 let (l_vec, is_list_first) = {
961 let borrowed_heap = &heap.borrow();
962 if matches!(lhs, Value::List(_)) {
963 (list.reify(borrowed_heap).as_list()?.clone(), true)
964 } else {
965 (list.reify(borrowed_heap).as_list()?.clone(), false)
966 }
967 };
968
969 match op {
970 BinaryOp::Equal => {
971 let borrowed_heap = heap.borrow();
972 let mut all_equal = true;
973 for v in l_vec.iter() {
974 if !v.equals(&scalar, &borrowed_heap)? {
975 all_equal = false;
976 break;
977 }
978 }
979 Ok(Bool(all_equal))
980 }
981 BinaryOp::NotEqual => {
982 let borrowed_heap = heap.borrow();
983 let mut all_not_equal = true;
984 for v in l_vec.iter() {
985 if v.equals(&scalar, &borrowed_heap)? {
986 all_not_equal = false;
987 break;
988 }
989 }
990 Ok(Bool(all_not_equal))
991 }
992 BinaryOp::Less => {
993 let borrowed_heap = heap.borrow();
994 let mut all_less = true;
995 for v in l_vec.iter() {
996 let ordering = if is_list_first {
997 v.compare(&scalar, &borrowed_heap)?
998 } else {
999 scalar.compare(v, &borrowed_heap)?
1000 };
1001 match ordering {
1002 Some(std::cmp::Ordering::Less) => continue,
1003 _ => {
1004 all_less = false;
1005 break;
1006 }
1007 }
1008 }
1009 Ok(Bool(all_less))
1010 }
1011 BinaryOp::LessEq => {
1012 let borrowed_heap = heap.borrow();
1013 let mut all_less_eq = true;
1014 for v in l_vec.iter() {
1015 let ordering = if is_list_first {
1016 v.compare(&scalar, &borrowed_heap)?
1017 } else {
1018 scalar.compare(v, &borrowed_heap)?
1019 };
1020 match ordering {
1021 Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) => {
1022 continue;
1023 }
1024 _ => {
1025 all_less_eq = false;
1026 break;
1027 }
1028 }
1029 }
1030 Ok(Bool(all_less_eq))
1031 }
1032 BinaryOp::Greater => {
1033 let borrowed_heap = heap.borrow();
1034 let mut all_greater = true;
1035 for v in l_vec.iter() {
1036 let ordering = if is_list_first {
1037 v.compare(&scalar, &borrowed_heap)?
1038 } else {
1039 scalar.compare(v, &borrowed_heap)?
1040 };
1041 match ordering {
1042 Some(std::cmp::Ordering::Greater) => continue,
1043 _ => {
1044 all_greater = false;
1045 break;
1046 }
1047 }
1048 }
1049 Ok(Bool(all_greater))
1050 }
1051 BinaryOp::GreaterEq => {
1052 let borrowed_heap = heap.borrow();
1053 let mut all_greater_eq = true;
1054 for v in l_vec.iter() {
1055 let ordering = if is_list_first {
1056 v.compare(&scalar, &borrowed_heap)?
1057 } else {
1058 scalar.compare(v, &borrowed_heap)?
1059 };
1060 match ordering {
1061 Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) => {
1062 continue;
1063 }
1064 _ => {
1065 all_greater_eq = false;
1066 break;
1067 }
1068 }
1069 }
1070 Ok(Bool(all_greater_eq))
1071 }
1072 BinaryOp::And | BinaryOp::NaturalAnd => {
1073 let mapped_list = if is_list_first {
1074 l_vec
1075 .iter()
1076 .map(|v| Ok(Bool(v.as_bool()? && scalar.as_bool()?)))
1077 .collect::<Result<Vec<Value>>>()?
1078 } else {
1079 l_vec
1080 .iter()
1081 .map(|v| Ok(Bool(scalar.as_bool()? && v.as_bool()?)))
1082 .collect::<Result<Vec<Value>>>()?
1083 };
1084 Ok(heap.borrow_mut().insert_list(mapped_list))
1085 }
1086 BinaryOp::Or | BinaryOp::NaturalOr => {
1087 let mapped_list = if is_list_first {
1088 l_vec
1089 .iter()
1090 .map(|v| Ok(Bool(v.as_bool()? || scalar.as_bool()?)))
1091 .collect::<Result<Vec<Value>>>()?
1092 } else {
1093 l_vec
1094 .iter()
1095 .map(|v| Ok(Bool(scalar.as_bool()? || v.as_bool()?)))
1096 .collect::<Result<Vec<Value>>>()?
1097 };
1098 Ok(heap.borrow_mut().insert_list(mapped_list))
1099 }
1100 BinaryOp::Add => {
1101 let mapped_list = if is_list_first {
1102 l_vec
1103 .iter()
1104 .map(|v| match (v, &scalar) {
1105 (Value::String(_), Value::String(_)) => {
1106 let (v_str, s_str) = {
1107 (
1108 v.as_string(&heap.borrow())?.to_string(),
1109 scalar.as_string(&heap.borrow())?.to_string(),
1110 )
1111 };
1112 Ok(heap
1113 .borrow_mut()
1114 .insert_string(format!("{}{}", v_str, s_str)))
1115 }
1116 (Value::Number(_), Value::Number(_)) => {
1117 Ok(Number(v.as_number()? + scalar.as_number()?))
1118 }
1119 _ => Err(anyhow!(
1120 "can't add {} and {}",
1121 v.get_type(),
1122 scalar.get_type()
1123 )),
1124 })
1125 .collect::<Result<Vec<Value>>>()?
1126 } else {
1127 l_vec
1128 .iter()
1129 .map(|v| match (&scalar, v) {
1130 (Value::String(_), Value::String(_)) => {
1131 let (s_str, v_str) = {
1132 (
1133 scalar.as_string(&heap.borrow())?.to_string(),
1134 v.as_string(&heap.borrow())?.to_string(),
1135 )
1136 };
1137 Ok(heap
1138 .borrow_mut()
1139 .insert_string(format!("{}{}", s_str, v_str)))
1140 }
1141 (Value::Number(_), Value::Number(_)) => {
1142 Ok(Number(scalar.as_number()? + v.as_number()?))
1143 }
1144 _ => Err(anyhow!(
1145 "can't add {} and {}",
1146 scalar.get_type(),
1147 v.get_type()
1148 )),
1149 })
1150 .collect::<Result<Vec<Value>>>()?
1151 };
1152 Ok(heap.borrow_mut().insert_list(mapped_list))
1153 }
1154 BinaryOp::Subtract => {
1155 let mapped_list = if is_list_first {
1156 l_vec
1157 .iter()
1158 .map(|v| Ok(Number(v.as_number()? - scalar.as_number()?)))
1159 .collect::<Result<Vec<Value>>>()?
1160 } else {
1161 l_vec
1162 .iter()
1163 .map(|v| Ok(Number(scalar.as_number()? - v.as_number()?)))
1164 .collect::<Result<Vec<Value>>>()?
1165 };
1166 Ok(heap.borrow_mut().insert_list(mapped_list))
1167 }
1168 BinaryOp::Multiply => {
1169 let mapped_list = l_vec
1170 .iter()
1171 .map(|v| Ok(Number(v.as_number()? * scalar.as_number()?)))
1172 .collect::<Result<Vec<Value>>>()?;
1173 Ok(heap.borrow_mut().insert_list(mapped_list))
1174 }
1175 BinaryOp::Divide => {
1176 let mapped_list = if is_list_first {
1177 l_vec
1178 .iter()
1179 .map(|v| Ok(Number(v.as_number()? / scalar.as_number()?)))
1180 .collect::<Result<Vec<Value>>>()?
1181 } else {
1182 l_vec
1183 .iter()
1184 .map(|v| Ok(Number(scalar.as_number()? / v.as_number()?)))
1185 .collect::<Result<Vec<Value>>>()?
1186 };
1187 Ok(heap.borrow_mut().insert_list(mapped_list))
1188 }
1189 BinaryOp::Modulo => {
1190 let mapped_list = if is_list_first {
1191 l_vec
1192 .iter()
1193 .map(|v| Ok(Number(v.as_number()? % scalar.as_number()?)))
1194 .collect::<Result<Vec<Value>>>()?
1195 } else {
1196 l_vec
1197 .iter()
1198 .map(|v| Ok(Number(scalar.as_number()? % v.as_number()?)))
1199 .collect::<Result<Vec<Value>>>()?
1200 };
1201 Ok(heap.borrow_mut().insert_list(mapped_list))
1202 }
1203 BinaryOp::Power => {
1204 let mapped_list = if is_list_first {
1205 l_vec
1206 .iter()
1207 .map(|v| Ok(Number(v.as_number()?.powf(scalar.as_number()?))))
1208 .collect::<Result<Vec<Value>>>()?
1209 } else {
1210 l_vec
1211 .iter()
1212 .map(|v| Ok(Number(scalar.as_number()?.powf(v.as_number()?))))
1213 .collect::<Result<Vec<Value>>>()?
1214 };
1215 Ok(heap.borrow_mut().insert_list(mapped_list))
1216 }
1217 BinaryOp::Coalesce => {
1218 let mapped_list = if is_list_first {
1219 l_vec
1220 .iter()
1221 .map(|v| {
1222 if *v == Value::Null {
1223 Ok(scalar)
1224 } else {
1225 Ok(*v)
1226 }
1227 })
1228 .collect::<Result<Vec<Value>>>()?
1229 } else {
1230 l_vec
1231 .iter()
1232 .map(|v| {
1233 if scalar == Value::Null {
1234 Ok(*v)
1235 } else {
1236 Ok(scalar)
1237 }
1238 })
1239 .collect::<Result<Vec<Value>>>()?
1240 };
1241 Ok(heap.borrow_mut().insert_list(mapped_list))
1242 }
1243 BinaryOp::Via => {
1244 if is_list_first {
1245 if !scalar.is_callable() {
1246 return Err(anyhow!(
1247 "can't call a non-function: {}",
1248 scalar.stringify_internal(&heap.borrow())
1249 ));
1250 }
1251
1252 let list = heap.borrow_mut().insert_list(l_vec.clone());
1253
1254 let call_result = get_built_in_function_def_by_ident("map").unwrap().call(
1255 scalar,
1256 vec![list, scalar],
1257 Rc::clone(&heap),
1258 Rc::clone(&bindings),
1259 call_depth,
1260 )?;
1261
1262 let mapped_list = { call_result.as_list(&heap.borrow())?.clone() };
1263
1264 Ok(heap.borrow_mut().insert_list(mapped_list))
1265 } else {
1266 Err(anyhow!("map operator requires function on right side"))
1267 }
1268 }
1269 BinaryOp::Into => {
1270 if is_list_first {
1271 if !scalar.is_callable() {
1272 return Err(anyhow!(
1273 "can't call a non-function: {}",
1274 scalar.stringify_internal(&heap.borrow())
1275 ));
1276 }
1277
1278 let list = heap.borrow_mut().insert_list(l_vec.clone());
1279
1280 let def = {
1281 let borrowed_heap = &heap.borrow();
1282 get_function_def(&scalar, borrowed_heap).ok_or_else(|| {
1283 anyhow!(
1284 "unknown function: {}",
1285 scalar.stringify_internal(borrowed_heap)
1286 )
1287 })?
1288 };
1289
1290 def.call(
1291 scalar,
1292 vec![list],
1293 Rc::clone(&heap),
1294 Rc::clone(&bindings),
1295 call_depth,
1296 )
1297 } else {
1298 Err(anyhow!("'into' operator requires function on right side"))
1299 }
1300 }
1301 BinaryOp::DotEqual
1302 | BinaryOp::DotNotEqual
1303 | BinaryOp::DotLess
1304 | BinaryOp::DotLessEq
1305 | BinaryOp::DotGreater
1306 | BinaryOp::DotGreaterEq => {
1307 unreachable!("Dot operators should be handled before list broadcasting")
1309 }
1310 }
1311 }
1312 (lhs, rhs) => match op {
1313 BinaryOp::Equal => Ok(Bool(lhs.equals(&rhs, &heap.borrow())?)),
1314 BinaryOp::NotEqual => Ok(Bool(!lhs.equals(&rhs, &heap.borrow())?)),
1315 BinaryOp::Less => match lhs.compare(&rhs, &heap.borrow())? {
1316 Some(std::cmp::Ordering::Less) => Ok(Bool(true)),
1317 _ => Ok(Bool(false)),
1318 },
1319 BinaryOp::LessEq => match lhs.compare(&rhs, &heap.borrow())? {
1320 Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) => Ok(Bool(true)),
1321 _ => Ok(Bool(false)),
1322 },
1323 BinaryOp::Greater => match lhs.compare(&rhs, &heap.borrow())? {
1324 Some(std::cmp::Ordering::Greater) => Ok(Bool(true)),
1325 _ => Ok(Bool(false)),
1326 },
1327 BinaryOp::GreaterEq => match lhs.compare(&rhs, &heap.borrow())? {
1328 Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) => {
1329 Ok(Bool(true))
1330 }
1331 _ => Ok(Bool(false)),
1332 },
1333 BinaryOp::And | BinaryOp::NaturalAnd => Ok(Bool(lhs.as_bool()? && rhs.as_bool()?)),
1334 BinaryOp::Or | BinaryOp::NaturalOr => Ok(Bool(lhs.as_bool()? || rhs.as_bool()?)),
1335 BinaryOp::Add => {
1336 if lhs.is_string() {
1337 let (l_str, r_str) = {
1338 (
1339 lhs.as_string(&heap.borrow())?.to_string(),
1340 rhs.as_string(&heap.borrow())?.to_string(),
1341 )
1342 };
1343
1344 return Ok(heap
1345 .borrow_mut()
1346 .insert_string(format!("{}{}", l_str, r_str)));
1347 }
1348
1349 Ok(Number(lhs.as_number()? + rhs.as_number()?))
1350 }
1351 BinaryOp::Subtract => Ok(Number(lhs.as_number()? - rhs.as_number()?)),
1352 BinaryOp::Multiply => Ok(Number(lhs.as_number()? * rhs.as_number()?)),
1353 BinaryOp::Divide => Ok(Number(lhs.as_number()? / rhs.as_number()?)),
1354 BinaryOp::Modulo => Ok(Number(lhs.as_number()? % rhs.as_number()?)),
1355 BinaryOp::Power => Ok(Number(lhs.as_number()?.powf(rhs.as_number()?))),
1356 BinaryOp::Coalesce => {
1357 if lhs == Value::Null {
1358 Ok(rhs)
1359 } else {
1360 Ok(lhs)
1361 }
1362 }
1363 BinaryOp::Via => {
1364 if !rhs.is_callable() {
1365 return Err(anyhow!(
1366 "can't call a non-function ({} is of type {})",
1367 rhs.stringify_internal(&heap.borrow()),
1368 rhs.get_type()
1369 ));
1370 }
1371
1372 let def = { get_function_def(&rhs, &heap.borrow()) };
1373
1374 if def.is_none() {
1375 return Err(anyhow!(
1376 "unknown function: {}",
1377 rhs.stringify_internal(&heap.borrow())
1378 ));
1379 }
1380
1381 def.unwrap().call(
1382 rhs,
1383 vec![lhs],
1384 Rc::clone(&heap),
1385 Rc::clone(&bindings),
1386 call_depth,
1387 )
1388 }
1389 BinaryOp::Into => {
1390 if !rhs.is_callable() {
1391 return Err(anyhow!(
1392 "can't call a non-function ({} is of type {})",
1393 rhs.stringify_internal(&heap.borrow()),
1394 rhs.get_type()
1395 ));
1396 }
1397
1398 let def = { get_function_def(&rhs, &heap.borrow()) };
1399
1400 if def.is_none() {
1401 return Err(anyhow!(
1402 "unknown function: {}",
1403 rhs.stringify_internal(&heap.borrow())
1404 ));
1405 }
1406
1407 def.unwrap().call(
1408 rhs,
1409 vec![lhs],
1410 Rc::clone(&heap),
1411 Rc::clone(&bindings),
1412 call_depth,
1413 )
1414 }
1415 BinaryOp::DotEqual
1416 | BinaryOp::DotNotEqual
1417 | BinaryOp::DotLess
1418 | BinaryOp::DotLessEq
1419 | BinaryOp::DotGreater
1420 | BinaryOp::DotGreaterEq => {
1421 unreachable!("Dot operators should be handled before generic value matching")
1423 }
1424 },
1425 }
1426}
1427
1428pub fn pairs_to_expr(pairs: Pairs<Rule>) -> Result<Expr> {
1430 PRATT
1431 .map_primary(|primary| match primary.as_rule() {
1432 Rule::number => Ok(Expr::Number(
1433 primary
1434 .as_str()
1435 .replace("_", "")
1436 .parse::<f64>()
1437 .map_err(anyhow::Error::from)?,
1438 )),
1439 Rule::list => {
1440 let list_pairs = primary.into_inner();
1441 let exprs = list_pairs
1442 .into_iter()
1443 .map(|pair| pairs_to_expr(pair.into_inner()))
1444 .collect::<Result<Vec<Expr>>>()?;
1445 Ok(Expr::List(exprs))
1446 }
1447 Rule::record => {
1448 let record_pairs = primary.into_inner();
1449 let mut entries = Vec::new();
1450
1451 for pair in record_pairs {
1452 match pair.as_rule() {
1453 Rule::record_pair => {
1454 let mut inner_pairs = pair.into_inner();
1455 let key_pair = inner_pairs.next().unwrap();
1456 let key = match key_pair.as_rule() {
1457 Rule::record_key_static => {
1458 let inner_key_pair = key_pair.into_inner().next().unwrap();
1459 match inner_key_pair.as_rule() {
1460 Rule::identifier => {
1461 RecordKey::Static(inner_key_pair.as_str().to_string())
1462 }
1463 Rule::string => RecordKey::Static(
1464 inner_key_pair.into_inner().as_str().to_string(),
1465 ),
1466 _ => unreachable!(),
1467 }
1468 }
1469 Rule::record_key_dynamic => RecordKey::Dynamic(Box::new(
1470 pairs_to_expr(key_pair.into_inner())?,
1471 )),
1472 _ => unreachable!(),
1473 };
1474
1475 let value = pairs_to_expr(inner_pairs.next().unwrap().into_inner())?;
1476 entries.push(RecordEntry { key, value });
1477 }
1478 Rule::record_shorthand => {
1479 let ident = pair.into_inner().next().unwrap().as_str().to_string();
1480 entries.push(RecordEntry {
1481 key: RecordKey::Shorthand(ident),
1482 value: Expr::Null, });
1484 }
1485 Rule::spread_expression => {
1486 let spread_expr = pairs_to_expr(pair.into_inner())?;
1487 entries.push(RecordEntry {
1488 key: RecordKey::Spread(Box::new(spread_expr)),
1489 value: Expr::Null, });
1491 }
1492 _ => {}
1493 }
1494 }
1495
1496 Ok(Expr::Record(entries))
1497 }
1498 Rule::bool => {
1499 let bool_str = primary.as_str();
1500 match bool_str {
1501 "true" => Ok(Expr::Bool(true)),
1502 "false" => Ok(Expr::Bool(false)),
1503 _ => unreachable!(),
1504 }
1505 }
1506 Rule::null => Ok(Expr::Null),
1507 Rule::string => {
1508 let contents = primary.into_inner().as_str().to_string();
1509 Ok(Expr::String(contents))
1510 }
1511 Rule::assignment => {
1512 let mut inner_pairs = primary.into_inner();
1513 let ident = inner_pairs.next().unwrap().as_str().to_string();
1514 let value = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1515 Ok(Expr::Assignment { ident, value })
1516 }
1517 Rule::lambda => {
1518 let mut inner_pairs = primary.into_inner();
1519 let arg_list = inner_pairs.next().unwrap();
1520 let body_pairs = inner_pairs.next().unwrap();
1521
1522 let mut args = Vec::new();
1523 for arg_pair in arg_list.into_inner() {
1524 match arg_pair.as_rule() {
1525 Rule::required_arg => {
1526 args.push(LambdaArg::Required(
1527 arg_pair.into_inner().as_str().to_string(),
1528 ));
1529 }
1530 Rule::optional_arg => {
1531 args.push(LambdaArg::Optional(
1532 arg_pair.into_inner().as_str().to_string(),
1533 ));
1534 }
1535 Rule::rest_arg => {
1536 args.push(LambdaArg::Rest(arg_pair.into_inner().as_str().to_string()));
1537 }
1538 _ => {}
1539 }
1540 }
1541
1542 let body = Box::new(pairs_to_expr(body_pairs.into_inner())?);
1543 Ok(Expr::Lambda { args, body })
1544 }
1545 Rule::conditional => {
1546 let mut inner_pairs = primary.into_inner();
1547 let condition = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1548 let then_expr = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1549 let else_expr = Box::new(pairs_to_expr(inner_pairs.next().unwrap().into_inner())?);
1550 Ok(Expr::Conditional {
1551 condition,
1552 then_expr,
1553 else_expr,
1554 })
1555 }
1556 Rule::do_block => {
1557 let inner_pairs = primary.into_inner();
1558 let mut statements = Vec::new();
1559 let mut return_expr = Box::new(Expr::Null);
1560
1561 for pair in inner_pairs {
1562 match pair.as_rule() {
1563 Rule::do_statement => {
1564 if let Some(inner) = pair.into_inner().next() {
1565 if inner.as_rule() == Rule::expression {
1566 statements.push(DoStatement::Expression(pairs_to_expr(
1567 inner.into_inner(),
1568 )?));
1569 } else if inner.as_rule() == Rule::comment {
1570 statements
1571 .push(DoStatement::Comment(inner.as_str().to_string()));
1572 }
1573 }
1574 }
1575 Rule::return_statement => {
1576 let return_expr_pair = pair.into_inner().next().unwrap();
1577 return_expr = Box::new(pairs_to_expr(return_expr_pair.into_inner())?);
1578 }
1579 _ => {}
1580 }
1581 }
1582
1583 Ok(Expr::DoBlock {
1584 statements,
1585 return_expr,
1586 })
1587 }
1588 Rule::identifier => {
1589 let ident = primary.as_str();
1590
1591 if let Some(built_in) = BuiltInFunction::from_ident(ident) {
1593 Ok(Expr::BuiltIn(built_in))
1594 } else {
1595 Ok(Expr::Identifier(ident.to_string()))
1596 }
1597 }
1598 Rule::expression => pairs_to_expr(primary.into_inner()),
1599 _ => unreachable!("{}", primary.as_str()),
1600 })
1601 .map_prefix(|op, rhs| match op.as_rule() {
1602 Rule::negation => Ok(Expr::UnaryOp {
1603 op: UnaryOp::Negate,
1604 expr: Box::new(rhs?),
1605 }),
1606 Rule::spread_operator => Ok(Expr::Spread(Box::new(rhs?))),
1607 Rule::invert | Rule::natural_not => Ok(Expr::UnaryOp {
1608 op: UnaryOp::Not,
1609 expr: Box::new(rhs?),
1610 }),
1611 _ => unreachable!(),
1612 })
1613 .map_postfix(|lhs, op| match op.as_rule() {
1614 Rule::factorial => Ok(Expr::PostfixOp {
1615 op: PostfixOp::Factorial,
1616 expr: Box::new(lhs?),
1617 }),
1618 Rule::access => {
1619 let index_expr = pairs_to_expr(op.into_inner())?;
1620 Ok(Expr::Access {
1621 expr: Box::new(lhs?),
1622 index: Box::new(index_expr),
1623 })
1624 }
1625 Rule::dot_access => {
1626 let field = op.into_inner().as_str().to_string();
1627 Ok(Expr::DotAccess {
1628 expr: Box::new(lhs?),
1629 field,
1630 })
1631 }
1632 Rule::call_list => {
1633 let call_list = op.into_inner();
1634 let args = call_list
1635 .into_iter()
1636 .map(|arg| pairs_to_expr(arg.into_inner()))
1637 .collect::<Result<Vec<Expr>>>()?;
1638 Ok(Expr::Call {
1639 func: Box::new(lhs?),
1640 args,
1641 })
1642 }
1643 _ => unreachable!(),
1644 })
1645 .map_infix(|lhs, op, rhs| {
1646 let op = match op.as_rule() {
1647 Rule::add => BinaryOp::Add,
1648 Rule::subtract => BinaryOp::Subtract,
1649 Rule::multiply => BinaryOp::Multiply,
1650 Rule::divide => BinaryOp::Divide,
1651 Rule::modulo => BinaryOp::Modulo,
1652 Rule::power => BinaryOp::Power,
1653 Rule::equal => BinaryOp::Equal,
1654 Rule::not_equal => BinaryOp::NotEqual,
1655 Rule::less => BinaryOp::Less,
1656 Rule::less_eq => BinaryOp::LessEq,
1657 Rule::greater => BinaryOp::Greater,
1658 Rule::greater_eq => BinaryOp::GreaterEq,
1659 Rule::dot_equal => BinaryOp::DotEqual,
1660 Rule::dot_not_equal => BinaryOp::DotNotEqual,
1661 Rule::dot_less => BinaryOp::DotLess,
1662 Rule::dot_less_eq => BinaryOp::DotLessEq,
1663 Rule::dot_greater => BinaryOp::DotGreater,
1664 Rule::dot_greater_eq => BinaryOp::DotGreaterEq,
1665 Rule::and => BinaryOp::And,
1666 Rule::natural_and => BinaryOp::NaturalAnd,
1667 Rule::or => BinaryOp::Or,
1668 Rule::natural_or => BinaryOp::NaturalOr,
1669 Rule::via => BinaryOp::Via,
1670 Rule::into => BinaryOp::Into,
1671 Rule::coalesce => BinaryOp::Coalesce,
1672 _ => unreachable!(),
1673 };
1674 Ok(Expr::BinaryOp {
1675 op,
1676 left: Box::new(lhs?),
1677 right: Box::new(rhs?),
1678 })
1679 })
1680 .parse(pairs)
1681}
1682
1683#[cfg(test)]
1684mod tests {
1685 use super::*;
1686 use crate::{heap::LambdaPointer, parser::get_pairs};
1687
1688 fn parse_and_evaluate(
1689 input: &str,
1690 heap: Option<Rc<RefCell<Heap>>>,
1691 bindings: Option<Rc<RefCell<HashMap<String, Value>>>>,
1692 ) -> Result<Value> {
1693 let binding = input.to_string();
1694 let mut pairs = get_pairs(&binding).unwrap();
1695 let expr = pairs.next().unwrap().into_inner();
1696 evaluate_pairs(
1697 expr,
1698 heap.unwrap_or(Rc::new(RefCell::new(Heap::new()))),
1699 bindings.unwrap_or(Rc::new(RefCell::new(HashMap::new()))),
1700 0,
1701 )
1702 }
1703
1704 #[test]
1705 fn addition_of_integers() {
1706 let result = parse_and_evaluate("5 + 2", None, None).unwrap();
1707 assert_eq!(result, Value::Number(7.0));
1708 }
1709
1710 #[test]
1711 fn exponentiation_of_two_integers() {
1712 let result = parse_and_evaluate("2 ^ 3", None, None).unwrap();
1713 assert_eq!(result, Value::Number(8.0));
1714 }
1715
1716 #[test]
1717 fn multiplication_of_integers() {
1718 let result = parse_and_evaluate("8 * 4", None, None).unwrap();
1719 assert_eq!(result, Value::Number(32.0));
1720 }
1721
1722 #[test]
1723 fn division_with_integer_resulting_in_decimal() {
1724 let result = parse_and_evaluate("9 / 2", None, None).unwrap();
1725 assert_eq!(result, Value::Number(4.5));
1726 }
1727
1728 #[test]
1729 fn addition_with_nested_expression() {
1730 let result = parse_and_evaluate("5 + (2 * 4)", None, None).unwrap();
1731 assert_eq!(result, Value::Number(13.0));
1732 }
1733
1734 #[test]
1735 fn grouping_and_multiplication_in_expression() {
1736 let result = parse_and_evaluate("(3 + 2) * 2", None, None).unwrap();
1737 assert_eq!(result, Value::Number(10.0));
1738 }
1739
1740 #[test]
1741 fn mixed_operations_with_decimal_and_precedence() {
1742 let result = parse_and_evaluate("6.5 / 2 + 4 * 2", None, None).unwrap();
1743 assert_eq!(result, Value::Number(11.25));
1744 }
1745
1746 #[test]
1747 fn exponentiation_with_nested_expression() {
1748 let result = parse_and_evaluate("2 ^ (1 + 2)", None, None).unwrap();
1749 assert_eq!(result, Value::Number(8.0));
1750 }
1751
1752 #[test]
1753 fn complex_expression_with_decimals() {
1754 let result = parse_and_evaluate("7.5 - 3.25 + 2 * (8 / 4)", None, None).unwrap();
1755 assert_eq!(result, Value::Number(8.25));
1756 }
1757
1758 #[test]
1759 fn subtraction_with_decimal_result() {
1760 let result = parse_and_evaluate("10.75 - 3.5", None, None).unwrap();
1761 assert_eq!(result, Value::Number(7.25));
1762 }
1763
1764 #[test]
1765 fn multiplication_of_two_decimals() {
1766 let result = parse_and_evaluate("3.5 * 2.0", None, None).unwrap();
1767 assert_eq!(result, Value::Number(7.0));
1768 }
1769
1770 #[test]
1771 fn division_of_two_decimals() {
1772 let result = parse_and_evaluate("7.5 / 2.5", None, None).unwrap();
1773 assert_eq!(result, Value::Number(3.0));
1774 }
1775
1776 #[test]
1777 fn boolean_and() {
1778 let result = parse_and_evaluate("true and false", None, None).unwrap();
1779 assert_eq!(result, Value::Bool(false));
1780 }
1781
1782 #[test]
1783 fn boolean_and_alt() {
1784 let result = parse_and_evaluate("true && false", None, None).unwrap();
1785 assert_eq!(result, Value::Bool(false));
1786 }
1787
1788 #[test]
1789 fn boolean_or() {
1790 let result = parse_and_evaluate("true or false", None, None).unwrap();
1791 assert_eq!(result, Value::Bool(true));
1792 }
1793
1794 #[test]
1795 fn boolean_or_alt() {
1796 let result = parse_and_evaluate("true || false", None, None).unwrap();
1797 assert_eq!(result, Value::Bool(true));
1798 }
1799
1800 #[test]
1801 fn boolean_and_with_nested_expression() {
1802 let result = parse_and_evaluate("true and (false or true)", None, None).unwrap();
1803 assert_eq!(result, Value::Bool(true));
1804 }
1805
1806 #[test]
1807 fn boolean_and_with_nested_expression_alt() {
1808 let result = parse_and_evaluate("true && (false || true)", None, None).unwrap();
1809 assert_eq!(result, Value::Bool(true));
1810 }
1811
1812 #[test]
1813 fn boolean_or_with_nested_expression() {
1814 let result = parse_and_evaluate("true or (false and true)", None, None).unwrap();
1815 assert_eq!(result, Value::Bool(true));
1816 }
1817
1818 #[test]
1819 fn boolean_or_with_nested_expression_alt() {
1820 let result = parse_and_evaluate("true || (false && true)", None, None).unwrap();
1821 assert_eq!(result, Value::Bool(true));
1822 }
1823
1824 #[test]
1825 fn logical_not() {
1826 let result = parse_and_evaluate("!true", None, None).unwrap();
1827 assert_eq!(result, Value::Bool(false));
1828 }
1829
1830 #[test]
1831 fn logical_not_with_nested_expression() {
1832 let result = parse_and_evaluate("!(true and false)", None, None).unwrap();
1833 assert_eq!(result, Value::Bool(true));
1834 }
1835
1836 #[test]
1837 fn equality_of_two_integers() {
1838 let result = parse_and_evaluate("5 == 5", None, None).unwrap();
1839 assert_eq!(result, Value::Bool(true));
1840 }
1841
1842 #[test]
1843 fn inequality_of_two_integers() {
1844 let result = parse_and_evaluate("5 != 5", None, None).unwrap();
1845 assert_eq!(result, Value::Bool(false));
1846 }
1847
1848 #[test]
1849 fn less_than_comparison() {
1850 let result = parse_and_evaluate("5 < 10", None, None).unwrap();
1851 assert_eq!(result, Value::Bool(true));
1852 }
1853
1854 #[test]
1855 fn less_than_or_equal_comparison() {
1856 let result = parse_and_evaluate("5 <= 5", None, None).unwrap();
1857 assert_eq!(result, Value::Bool(true));
1858 }
1859
1860 #[test]
1861 fn greater_than_comparison() {
1862 let result = parse_and_evaluate("10 > 5", None, None).unwrap();
1863 assert_eq!(result, Value::Bool(true));
1864 }
1865
1866 #[test]
1867 fn greater_than_or_equal_comparison() {
1868 let result = parse_and_evaluate("5 >= 5", None, None).unwrap();
1869 assert_eq!(result, Value::Bool(true));
1870 }
1871
1872 #[test]
1873 fn equality_of_two_lists() {
1874 let result = parse_and_evaluate("[1, 2, 3] == [1, 2, 3]", None, None);
1876 assert!(result.is_ok());
1877 }
1878
1879 #[test]
1880 fn inequality_of_two_lists() {
1881 let result = parse_and_evaluate("[1, 2, 3] != [2, 3, 4]", None, None);
1883 assert!(result.is_ok());
1884 }
1885
1886 #[test]
1887 fn conditional_expression_with_true_condition() {
1888 let result = parse_and_evaluate("if true then 5 else 10", None, None).unwrap();
1889 assert_eq!(result, Value::Number(5.0));
1890 }
1891
1892 #[test]
1893 fn conditional_expression_with_false_condition() {
1894 let result = parse_and_evaluate("if false then 5 else 10", None, None).unwrap();
1895 assert_eq!(result, Value::Number(10.0));
1896 }
1897
1898 #[test]
1899 fn factorial_of_integer() {
1900 let result = parse_and_evaluate("5!", None, None).unwrap();
1901 assert_eq!(result, Value::Number(120.0));
1902 }
1903
1904 #[test]
1905 fn factorial_of_zero() {
1906 let result = parse_and_evaluate("0!", None, None).unwrap();
1907 assert_eq!(result, Value::Number(1.0));
1908 }
1909
1910 #[test]
1911 fn factorial_of_negative_integer() {
1912 let result = parse_and_evaluate("(-5)!", None, None);
1913 assert!(result.is_err());
1914 }
1915
1916 #[test]
1917 fn factorial_of_decimal() {
1918 let result = parse_and_evaluate("5.5!", None, None);
1919 assert!(result.is_err());
1920 }
1921
1922 #[test]
1923 fn string_concatenation() {
1924 let heap = Rc::new(RefCell::new(Heap::new()));
1925 let result =
1926 parse_and_evaluate("\"hello\" + \"world\"", Some(Rc::clone(&heap)), None).unwrap();
1927
1928 assert!(matches!(result, Value::String(_)));
1929 assert_eq!(result.as_string(&heap.borrow()).unwrap(), "helloworld");
1930 }
1931
1932 #[test]
1933 fn string_concatenation_with_integer() {
1934 let result = parse_and_evaluate("\"hello\" + 5", None, None);
1935 assert!(result.is_err());
1936 }
1937
1938 #[test]
1939 fn variable_assignment() {
1940 let bindings = Rc::new(RefCell::new(HashMap::new()));
1941 let result = parse_and_evaluate("x = 5", None, Some(Rc::clone(&bindings))).unwrap();
1942
1943 assert_eq!(result, Value::Number(5.0));
1944 assert_eq!(bindings.borrow().get("x").unwrap(), &Value::Number(5.0));
1945 }
1946
1947 #[test]
1948 fn variable_assignment_with_expression() {
1949 let bindings = Rc::new(RefCell::new(HashMap::new()));
1950 let result = parse_and_evaluate("x = 5 + 2", None, Some(Rc::clone(&bindings))).unwrap();
1951 assert_eq!(result, Value::Number(7.0));
1952 assert_eq!(bindings.borrow().get("x").unwrap(), &Value::Number(7.0));
1953 }
1954
1955 #[test]
1956 fn variable_assignment_with_lambda() {
1957 let heap = Rc::new(RefCell::new(Heap::new()));
1958 let bindings = Rc::new(RefCell::new(HashMap::new()));
1959 let result = parse_and_evaluate(
1960 "f = x => x + 1",
1961 Some(Rc::clone(&heap)),
1962 Some(Rc::clone(&bindings)),
1963 )
1964 .unwrap();
1965
1966 {
1967 let heap_borrow = heap.borrow();
1968 let lambda_def = result.as_lambda(&heap_borrow).unwrap();
1969 assert_eq!(lambda_def.name, Some("f".to_string()));
1970 assert_eq!(lambda_def.args, vec![LambdaArg::Required("x".to_string())]);
1971 assert_eq!(lambda_def.scope, HashMap::new());
1972 match &lambda_def.body {
1974 Expr::BinaryOp {
1975 op: BinaryOp::Add,
1976 left,
1977 right,
1978 } => match (left.as_ref(), right.as_ref()) {
1979 (Expr::Identifier(x), Expr::Number(n)) => {
1980 assert_eq!(x, "x");
1981 assert_eq!(*n, 1.0);
1982 }
1983 _ => panic!("Expected Identifier('x') + Number(1)"),
1984 },
1985 _ => panic!("Expected BinaryOp(Add)"),
1986 }
1987 }
1988 assert_eq!(
1989 bindings.borrow().get("f").unwrap(),
1990 &Value::Lambda(LambdaPointer::new(1))
1991 );
1992 }
1993
1994 #[test]
1995 fn variable_assignment_with_lambda_and_call() {
1996 let heap = Rc::new(RefCell::new(Heap::new()));
1997 let bindings = Rc::new(RefCell::new(HashMap::new()));
1998 let _ = parse_and_evaluate(
1999 "f = x => x + 1",
2000 Some(Rc::clone(&heap)),
2001 Some(Rc::clone(&bindings)),
2002 )
2003 .unwrap();
2004 let result =
2005 parse_and_evaluate("f(5)", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings))).unwrap();
2006
2007 assert_eq!(result, Value::Number(6.0));
2008 }
2009
2010 #[test]
2011 fn variable_assignment_with_lambda_and_call_with_multiple_args() {
2012 let heap = Rc::new(RefCell::new(Heap::new()));
2013 let bindings = Rc::new(RefCell::new(HashMap::new()));
2014 let _ = parse_and_evaluate(
2015 "f = (x, y) => x + y",
2016 Some(Rc::clone(&heap)),
2017 Some(Rc::clone(&bindings)),
2018 )
2019 .unwrap();
2020 let result = parse_and_evaluate(
2021 "f(5, 2)",
2022 Some(Rc::clone(&heap)),
2023 Some(Rc::clone(&bindings)),
2024 )
2025 .unwrap();
2026
2027 assert_eq!(result, Value::Number(7.0));
2028 }
2029
2030 #[test]
2031 fn variable_assignment_with_lambda_and_call_with_multiple_args_and_expression() {
2032 let heap = Rc::new(RefCell::new(Heap::new()));
2033 let bindings = Rc::new(RefCell::new(HashMap::new()));
2034 let _ = parse_and_evaluate(
2035 "f = (x, y) => x + y",
2036 Some(Rc::clone(&heap)),
2037 Some(Rc::clone(&bindings)),
2038 )
2039 .unwrap();
2040 let result = parse_and_evaluate(
2041 "f(5, 2) + 3",
2042 Some(Rc::clone(&heap)),
2043 Some(Rc::clone(&bindings)),
2044 )
2045 .unwrap();
2046
2047 assert_eq!(result, Value::Number(10.0));
2048 }
2049
2050 #[test]
2051 fn coalesce_operator_with_null() {
2052 let result = parse_and_evaluate("null ?? 5", None, None).unwrap();
2053 assert_eq!(result, Value::Number(5.0));
2054 }
2055
2056 #[test]
2057 fn coalesce_operator_with_non_null() {
2058 let result = parse_and_evaluate("3 ?? 10", None, None).unwrap();
2059 assert_eq!(result, Value::Number(3.0));
2060 }
2061
2062 #[test]
2064 fn list_elementwise_addition() {
2065 let heap = Rc::new(RefCell::new(Heap::new()));
2066 let result =
2067 parse_and_evaluate("[1, 2, 3] + [4, 5, 6]", Some(Rc::clone(&heap)), None).unwrap();
2068 let expected = vec![Value::Number(5.0), Value::Number(7.0), Value::Number(9.0)];
2069 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2070 }
2071
2072 #[test]
2073 fn list_elementwise_subtraction() {
2074 let heap = Rc::new(RefCell::new(Heap::new()));
2075 let result =
2076 parse_and_evaluate("[5, 7, 9] - [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
2077 let expected = vec![Value::Number(4.0), Value::Number(5.0), Value::Number(6.0)];
2078 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2079 }
2080
2081 #[test]
2082 fn list_elementwise_multiplication() {
2083 let heap = Rc::new(RefCell::new(Heap::new()));
2084 let result =
2085 parse_and_evaluate("[2, 3, 4] * [5, 6, 7]", Some(Rc::clone(&heap)), None).unwrap();
2086 let expected = vec![
2087 Value::Number(10.0),
2088 Value::Number(18.0),
2089 Value::Number(28.0),
2090 ];
2091 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2092 }
2093
2094 #[test]
2095 fn list_elementwise_division() {
2096 let heap = Rc::new(RefCell::new(Heap::new()));
2097 let result =
2098 parse_and_evaluate("[10, 20, 30] / [2, 4, 5]", Some(Rc::clone(&heap)), None).unwrap();
2099 let expected = vec![Value::Number(5.0), Value::Number(5.0), Value::Number(6.0)];
2100 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2101 }
2102
2103 #[test]
2104 fn list_elementwise_power() {
2105 let heap = Rc::new(RefCell::new(Heap::new()));
2106 let result =
2107 parse_and_evaluate("[2, 3, 4] ^ [2, 2, 2]", Some(Rc::clone(&heap)), None).unwrap();
2108 let expected = vec![Value::Number(4.0), Value::Number(9.0), Value::Number(16.0)];
2109 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2110 }
2111
2112 #[test]
2113 fn list_elementwise_modulo() {
2114 let heap = Rc::new(RefCell::new(Heap::new()));
2115 let result =
2116 parse_and_evaluate("[10, 11, 12] % [3, 3, 3]", Some(Rc::clone(&heap)), None).unwrap();
2117 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(0.0)];
2118 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2119 }
2120
2121 #[test]
2122 fn list_elementwise_different_lengths_error() {
2123 let result = parse_and_evaluate("[1, 2, 3] + [4, 5]", None, None);
2124 assert!(result.is_err());
2125 assert!(
2126 result
2127 .unwrap_err()
2128 .to_string()
2129 .contains("left- and right-hand-side lists must be the same length")
2130 );
2131 }
2132
2133 #[test]
2135 fn list_scalar_addition() {
2136 let heap = Rc::new(RefCell::new(Heap::new()));
2137 let result = parse_and_evaluate("[1, 2, 3] + 10", Some(Rc::clone(&heap)), None).unwrap();
2138 let expected = vec![
2139 Value::Number(11.0),
2140 Value::Number(12.0),
2141 Value::Number(13.0),
2142 ];
2143 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2144 }
2145
2146 #[test]
2147 fn list_scalar_subtraction() {
2148 let heap = Rc::new(RefCell::new(Heap::new()));
2149 let result = parse_and_evaluate("[10, 20, 30] - 5", Some(Rc::clone(&heap)), None).unwrap();
2150 let expected = vec![Value::Number(5.0), Value::Number(15.0), Value::Number(25.0)];
2151 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2152 }
2153
2154 #[test]
2155 fn list_scalar_multiplication() {
2156 let heap = Rc::new(RefCell::new(Heap::new()));
2157 let result = parse_and_evaluate("[2, 3, 4] * 2", Some(Rc::clone(&heap)), None).unwrap();
2158 let expected = vec![Value::Number(4.0), Value::Number(6.0), Value::Number(8.0)];
2159 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2160 }
2161
2162 #[test]
2163 fn list_scalar_division() {
2164 let heap = Rc::new(RefCell::new(Heap::new()));
2165 let result = parse_and_evaluate("[10, 20, 30] / 10", Some(Rc::clone(&heap)), None).unwrap();
2166 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(3.0)];
2167 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2168 }
2169
2170 #[test]
2171 fn list_scalar_power() {
2172 let heap = Rc::new(RefCell::new(Heap::new()));
2173 let result = parse_and_evaluate("[2, 3, 4] ^ 2", Some(Rc::clone(&heap)), None).unwrap();
2174 let expected = vec![Value::Number(4.0), Value::Number(9.0), Value::Number(16.0)];
2175 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2176 }
2177
2178 #[test]
2179 fn list_scalar_modulo() {
2180 let heap = Rc::new(RefCell::new(Heap::new()));
2181 let result = parse_and_evaluate("[10, 11, 12] % 3", Some(Rc::clone(&heap)), None).unwrap();
2182 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(0.0)];
2183 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2184 }
2185
2186 #[test]
2187 fn list_with_operator() {
2188 let heap = Rc::new(RefCell::new(Heap::new()));
2189 let result =
2190 parse_and_evaluate("[1, 2, 3] via (x => x * x)", Some(Rc::clone(&heap)), None).unwrap();
2191 let expected = vec![Value::Number(1.0), Value::Number(4.0), Value::Number(9.0)];
2192 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2193 }
2194
2195 #[test]
2196 fn list_with_builtin_function() {
2197 let heap = Rc::new(RefCell::new(Heap::new()));
2198 let result =
2199 parse_and_evaluate("[4, 9, 16] via sqrt", Some(Rc::clone(&heap)), None).unwrap();
2200 let expected = vec![Value::Number(2.0), Value::Number(3.0), Value::Number(4.0)];
2201 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2202 }
2203
2204 #[test]
2205 fn into_operator_with_list() {
2206 let heap = Rc::new(RefCell::new(Heap::new()));
2207 let result =
2208 parse_and_evaluate("['hello', 'world'] into head", Some(Rc::clone(&heap)), None)
2209 .unwrap();
2210 assert_eq!(result.as_string(&heap.borrow()).unwrap(), "hello");
2211 }
2212
2213 #[test]
2214 fn into_operator_with_string() {
2215 let heap = Rc::new(RefCell::new(Heap::new()));
2216 let result = parse_and_evaluate("'hello' into head", Some(Rc::clone(&heap)), None).unwrap();
2217 assert_eq!(result.as_string(&heap.borrow()).unwrap(), "h");
2218 }
2219
2220 #[test]
2221 fn into_vs_via_difference() {
2222 let heap = Rc::new(RefCell::new(Heap::new()));
2223
2224 let via_result =
2226 parse_and_evaluate("['hello', 'world'] via head", Some(Rc::clone(&heap)), None)
2227 .unwrap();
2228 let borrowed_heap = heap.borrow();
2229 let via_list = via_result.as_list(&borrowed_heap).unwrap();
2230 assert_eq!(via_list.len(), 2);
2231 assert_eq!(via_list[0].as_string(&borrowed_heap).unwrap(), "h");
2232 assert_eq!(via_list[1].as_string(&borrowed_heap).unwrap(), "w");
2233 drop(borrowed_heap);
2234
2235 let into_result =
2237 parse_and_evaluate("['hello', 'world'] into head", Some(Rc::clone(&heap)), None)
2238 .unwrap();
2239 assert_eq!(into_result.as_string(&heap.borrow()).unwrap(), "hello");
2240 }
2241
2242 #[test]
2243 fn into_operator_with_aggregation() {
2244 let heap = Rc::new(RefCell::new(Heap::new()));
2245 let result =
2246 parse_and_evaluate("[1, 2, 3, 4, 5] into sum", Some(Rc::clone(&heap)), None).unwrap();
2247 assert_eq!(result.as_number().unwrap(), 15.0);
2248 }
2249
2250 #[test]
2251 fn into_operator_rejects_lists() {
2252 let heap = Rc::new(RefCell::new(Heap::new()));
2253
2254 let result = parse_and_evaluate(
2256 "[1, 2, 3] into [sqrt, sqrt, sqrt]",
2257 Some(Rc::clone(&heap)),
2258 None,
2259 );
2260 assert!(result.is_err());
2261 assert!(
2262 result
2263 .unwrap_err()
2264 .to_string()
2265 .contains("'into' operator requires a function on the right side, not a list")
2266 );
2267
2268 let result = parse_and_evaluate("[1, 2, 3] into [sqrt]", Some(Rc::clone(&heap)), None);
2270 assert!(result.is_err());
2271 assert!(
2272 result
2273 .unwrap_err()
2274 .to_string()
2275 .contains("'into' operator requires a function on the right side, not a list")
2276 );
2277 }
2278
2279 #[test]
2280 fn list_elementwise_boolean_and() {
2281 let heap = Rc::new(RefCell::new(Heap::new()));
2282 let result = parse_and_evaluate(
2283 "[true, true, false] && [true, false, true]",
2284 Some(Rc::clone(&heap)),
2285 None,
2286 )
2287 .unwrap();
2288 let expected = vec![Value::Bool(true), Value::Bool(false), Value::Bool(false)];
2289 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2290 }
2291
2292 #[test]
2293 fn list_elementwise_boolean_or() {
2294 let heap = Rc::new(RefCell::new(Heap::new()));
2295 let result = parse_and_evaluate(
2296 "[true, false, false] || [false, true, false]",
2297 Some(Rc::clone(&heap)),
2298 None,
2299 )
2300 .unwrap();
2301 let expected = vec![Value::Bool(true), Value::Bool(true), Value::Bool(false)];
2302 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2303 }
2304
2305 #[test]
2306 fn list_elementwise_coalesce() {
2307 let heap = Rc::new(RefCell::new(Heap::new()));
2308 let result = parse_and_evaluate(
2309 "[null, 2, null] ?? [1, null, 3]",
2310 Some(Rc::clone(&heap)),
2311 None,
2312 )
2313 .unwrap();
2314 let expected = vec![Value::Number(1.0), Value::Number(2.0), Value::Number(3.0)];
2315 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2316 }
2317
2318 #[test]
2319 fn list_scalar_coalesce() {
2320 let heap = Rc::new(RefCell::new(Heap::new()));
2321 let result =
2322 parse_and_evaluate("[null, 2, null] ?? 5", Some(Rc::clone(&heap)), None).unwrap();
2323 let expected = vec![Value::Number(5.0), Value::Number(2.0), Value::Number(5.0)];
2324 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2325 }
2326
2327 #[test]
2328 fn list_elementwise_string_concat() {
2329 let heap = Rc::new(RefCell::new(Heap::new()));
2330 let result = parse_and_evaluate(
2331 "[\"a\", \"b\", \"c\"] + [\"1\", \"2\", \"3\"]",
2332 Some(Rc::clone(&heap)),
2333 None,
2334 )
2335 .unwrap();
2336 let borrowed_heap = heap.borrow();
2337 let result_list = result.as_list(&borrowed_heap).unwrap();
2338 assert_eq!(result_list.len(), 3);
2339 assert_eq!(result_list[0].as_string(&borrowed_heap).unwrap(), "a1");
2340 assert_eq!(result_list[1].as_string(&borrowed_heap).unwrap(), "b2");
2341 assert_eq!(result_list[2].as_string(&borrowed_heap).unwrap(), "c3");
2342 }
2343
2344 #[test]
2345 fn list_scalar_string_concat() {
2346 let heap = Rc::new(RefCell::new(Heap::new()));
2347 let result = parse_and_evaluate(
2348 "[\"a\", \"b\", \"c\"] + \"!\"",
2349 Some(Rc::clone(&heap)),
2350 None,
2351 )
2352 .unwrap();
2353 let borrowed_heap = heap.borrow();
2354 let result_list = result.as_list(&borrowed_heap).unwrap();
2355 assert_eq!(result_list.len(), 3);
2356 assert_eq!(result_list[0].as_string(&borrowed_heap).unwrap(), "a!");
2357 assert_eq!(result_list[1].as_string(&borrowed_heap).unwrap(), "b!");
2358 assert_eq!(result_list[2].as_string(&borrowed_heap).unwrap(), "c!");
2359 }
2360
2361 #[test]
2362 fn nested_list_operations() {
2363 let heap = Rc::new(RefCell::new(Heap::new()));
2364 let result =
2365 parse_and_evaluate("([1, 2, 3] + [4, 5, 6]) * 2", Some(Rc::clone(&heap)), None)
2366 .unwrap();
2367 let expected = vec![
2368 Value::Number(10.0),
2369 Value::Number(14.0),
2370 Value::Number(18.0),
2371 ];
2372 assert_eq!(result.as_list(&heap.borrow()).unwrap(), &expected);
2373 }
2374
2375 #[test]
2376 fn list_comparison_all_equal() {
2377 let result = parse_and_evaluate("[1, 1, 1] == 1", None, None).unwrap();
2378 assert_eq!(result, Value::Bool(true));
2379 }
2380
2381 #[test]
2382 fn list_comparison_not_all_equal() {
2383 let result = parse_and_evaluate("[1, 2, 1] == 1", None, None).unwrap();
2384 assert_eq!(result, Value::Bool(false));
2385 }
2386
2387 #[test]
2388 fn list_comparison_all_less() {
2389 let result = parse_and_evaluate("[1, 2, 3] < 5", None, None).unwrap();
2390 assert_eq!(result, Value::Bool(true));
2391 }
2392
2393 #[test]
2394 fn list_comparison_not_all_less() {
2395 let result = parse_and_evaluate("[1, 6, 3] < 5", None, None).unwrap();
2396 assert_eq!(result, Value::Bool(false));
2397 }
2398
2399 #[test]
2400 fn not_operator_basic() {
2401 let result = parse_and_evaluate("not true", None, None).unwrap();
2402 assert_eq!(result, Value::Bool(false));
2403 }
2404
2405 #[test]
2406 fn not_operator_with_false() {
2407 let result = parse_and_evaluate("not false", None, None).unwrap();
2408 assert_eq!(result, Value::Bool(true));
2409 }
2410
2411 #[test]
2412 fn not_operator_with_expression() {
2413 let result = parse_and_evaluate("not (5 > 10)", None, None).unwrap();
2414 assert_eq!(result, Value::Bool(true));
2415 }
2416
2417 #[test]
2418 fn not_operator_double_negation() {
2419 let result = parse_and_evaluate("not not true", None, None).unwrap();
2420 assert_eq!(result, Value::Bool(true));
2421 }
2422
2423 #[test]
2424 fn not_operator_with_and() {
2425 let result = parse_and_evaluate("not (true and false)", None, None).unwrap();
2426 assert_eq!(result, Value::Bool(true));
2427 }
2428
2429 #[test]
2430 fn not_operator_with_or() {
2431 let result = parse_and_evaluate("not (false or false)", None, None).unwrap();
2432 assert_eq!(result, Value::Bool(true));
2433 }
2434
2435 #[test]
2436 fn not_operator_precedence() {
2437 let result = parse_and_evaluate("not true and false", None, None).unwrap();
2438 assert_eq!(result, Value::Bool(false));
2439 }
2440
2441 #[test]
2442 fn not_operator_comparison_with_invert() {
2443 let not_result = parse_and_evaluate("not true", None, None).unwrap();
2444 let invert_result = parse_and_evaluate("!true", None, None).unwrap();
2445 assert_eq!(not_result, invert_result);
2446 }
2447
2448 #[test]
2449 fn variable_immutability_prevents_reassignment() {
2450 let heap = Rc::new(RefCell::new(Heap::new()));
2451 let bindings = Rc::new(RefCell::new(HashMap::new()));
2452
2453 let result1 =
2455 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2456 assert!(result1.is_ok());
2457 assert_eq!(result1.unwrap(), Value::Number(5.0));
2458
2459 let result2 =
2461 parse_and_evaluate("x = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2462 assert!(result2.is_err());
2463 assert!(
2464 result2
2465 .unwrap_err()
2466 .to_string()
2467 .contains("x is already defined, and cannot be reassigned")
2468 );
2469
2470 let result3 = parse_and_evaluate("x", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2472 assert!(result3.is_ok());
2473 assert_eq!(result3.unwrap(), Value::Number(5.0));
2474 }
2475
2476 #[test]
2477 fn variable_immutability_allows_shadowing_in_nested_scopes() {
2478 let heap = Rc::new(RefCell::new(Heap::new()));
2479 let bindings = Rc::new(RefCell::new(HashMap::new()));
2480
2481 let result1 =
2483 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2484 assert!(result1.is_ok());
2485
2486 let result2 = parse_and_evaluate(
2488 "f = (x) => x * 2",
2489 Some(Rc::clone(&heap)),
2490 Some(Rc::clone(&bindings)),
2491 );
2492 assert!(result2.is_ok());
2493
2494 let result3 =
2496 parse_and_evaluate("f(10)", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2497 assert!(result3.is_ok());
2498 assert_eq!(result3.unwrap(), Value::Number(20.0));
2499
2500 let result4 = parse_and_evaluate("x", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2502 assert!(result4.is_ok());
2503 assert_eq!(result4.unwrap(), Value::Number(5.0));
2504 }
2505
2506 #[test]
2507 fn variable_immutability_in_do_blocks() {
2508 let heap = Rc::new(RefCell::new(Heap::new()));
2509 let bindings = Rc::new(RefCell::new(HashMap::new()));
2510
2511 let result1 =
2513 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2514 assert!(result1.is_ok());
2515
2516 let do_block = r#"do {
2518 x = 10
2519 y = x * 2
2520 return y
2521 }"#;
2522 let result2 =
2523 parse_and_evaluate(do_block, Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2524 assert!(result2.is_ok());
2525 assert_eq!(result2.unwrap(), Value::Number(20.0)); let do_block2 = r#"do {
2529 z = x * 3
2530 return z
2531 }"#;
2532 let result3 = parse_and_evaluate(
2533 do_block2,
2534 Some(Rc::clone(&heap)),
2535 Some(Rc::clone(&bindings)),
2536 );
2537 assert!(result3.is_ok());
2538 assert_eq!(result3.unwrap(), Value::Number(15.0));
2539
2540 let result4 = parse_and_evaluate("x", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2542 assert!(result4.is_ok());
2543 assert_eq!(result4.unwrap(), Value::Number(5.0));
2544 }
2545
2546 #[test]
2547 fn variable_immutability_different_variables() {
2548 let heap = Rc::new(RefCell::new(Heap::new()));
2549 let bindings = Rc::new(RefCell::new(HashMap::new()));
2550
2551 let result1 =
2553 parse_and_evaluate("x = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2554 assert!(result1.is_ok());
2555
2556 let result2 =
2557 parse_and_evaluate("y = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)));
2558 assert!(result2.is_ok());
2559
2560 let result3 = parse_and_evaluate(
2561 "z = x + y",
2562 Some(Rc::clone(&heap)),
2563 Some(Rc::clone(&bindings)),
2564 );
2565 assert!(result3.is_ok());
2566 assert_eq!(result3.unwrap(), Value::Number(15.0));
2567 }
2568
2569 #[test]
2570 fn variable_immutability_with_complex_types() {
2571 let heap = Rc::new(RefCell::new(Heap::new()));
2572 let bindings = Rc::new(RefCell::new(HashMap::new()));
2573
2574 let result1 = parse_and_evaluate(
2576 "list = [1, 2, 3]",
2577 Some(Rc::clone(&heap)),
2578 Some(Rc::clone(&bindings)),
2579 );
2580 assert!(result1.is_ok());
2581
2582 let result2 = parse_and_evaluate(
2584 "list = [4, 5, 6]",
2585 Some(Rc::clone(&heap)),
2586 Some(Rc::clone(&bindings)),
2587 );
2588 assert!(result2.is_err());
2589 assert!(
2590 result2
2591 .unwrap_err()
2592 .to_string()
2593 .contains("list is already defined, and cannot be reassigned")
2594 );
2595
2596 let result3 = parse_and_evaluate(
2598 "rec = {x: 1, y: 2}",
2599 Some(Rc::clone(&heap)),
2600 Some(Rc::clone(&bindings)),
2601 );
2602 assert!(result3.is_ok());
2603
2604 let result4 = parse_and_evaluate(
2606 "rec = {x: 3, y: 4}",
2607 Some(Rc::clone(&heap)),
2608 Some(Rc::clone(&bindings)),
2609 );
2610 assert!(result4.is_err());
2611 assert!(
2612 result4
2613 .unwrap_err()
2614 .to_string()
2615 .contains("rec is already defined, and cannot be reassigned")
2616 );
2617 }
2618
2619 #[test]
2620 fn equality_comparison_numbers() {
2621 let result = parse_and_evaluate("5e2 == 5e2", None, None).unwrap();
2622 assert_eq!(result, Value::Bool(true));
2623
2624 let result = parse_and_evaluate("42 == 42", None, None).unwrap();
2625 assert_eq!(result, Value::Bool(true));
2626
2627 let result = parse_and_evaluate("42 == 43", None, None).unwrap();
2628 assert_eq!(result, Value::Bool(false));
2629 }
2630
2631 #[test]
2632 fn equality_comparison_strings() {
2633 let result = parse_and_evaluate(r#""hey" == "hey""#, None, None).unwrap();
2634 assert_eq!(result, Value::Bool(true));
2635
2636 let result = parse_and_evaluate(r#""hello" == "world""#, None, None).unwrap();
2637 assert_eq!(result, Value::Bool(false));
2638
2639 let result = parse_and_evaluate(r#""" == """#, None, None).unwrap();
2640 assert_eq!(result, Value::Bool(true));
2641 }
2642
2643 #[test]
2644 fn equality_comparison_lists() {
2645 let result = parse_and_evaluate("[1,2,3] == [1,2,3]", None, None).unwrap();
2646 assert_eq!(result, Value::Bool(true));
2647
2648 let result = parse_and_evaluate("[1,2,3] == [1,2,4]", None, None).unwrap();
2649 assert_eq!(result, Value::Bool(false));
2650
2651 let result = parse_and_evaluate(r#"["a", "b"] == ["a", "b"]"#, None, None).unwrap();
2656 assert_eq!(result, Value::Bool(true));
2657
2658 let result = parse_and_evaluate("[[1,2,3]] == [[1,2,3]]", None, None).unwrap();
2660 assert_eq!(result, Value::Bool(true));
2661
2662 let result =
2663 parse_and_evaluate("[[1,2,3], [4,5]] == [[1,2,3], [4,5]]", None, None).unwrap();
2664 assert_eq!(result, Value::Bool(true));
2665 }
2666
2667 #[test]
2668 fn equality_comparison_records() {
2669 let result = parse_and_evaluate("{ hey: 1 } == { hey: 1 }", None, None).unwrap();
2670 assert_eq!(result, Value::Bool(true));
2671
2672 let result = parse_and_evaluate("{ hey: 1 } == { hey: 2 }", None, None).unwrap();
2673 assert_eq!(result, Value::Bool(false));
2674
2675 let result = parse_and_evaluate("{ hey: 1 } == { hello: 1 }", None, None).unwrap();
2676 assert_eq!(result, Value::Bool(false));
2677
2678 let result = parse_and_evaluate("{ a: 1, b: 2 } == { a: 1, b: 2 }", None, None).unwrap();
2680 assert_eq!(result, Value::Bool(true));
2681
2682 let result = parse_and_evaluate("{ a: 1, b: 2 } == { b: 2, a: 1 }", None, None).unwrap();
2684 assert_eq!(result, Value::Bool(true));
2685
2686 let result = parse_and_evaluate("{ x: { y: 1 } } == { x: { y: 1 } }", None, None).unwrap();
2688 assert_eq!(result, Value::Bool(true));
2689 }
2690
2691 #[test]
2692 fn equality_comparison_lambdas() {
2693 let heap = Rc::new(RefCell::new(Heap::new()));
2694 let bindings = Rc::new(RefCell::new(HashMap::new()));
2695
2696 parse_and_evaluate(
2698 "f1 = (x) => x + 2",
2699 Some(Rc::clone(&heap)),
2700 Some(Rc::clone(&bindings)),
2701 )
2702 .unwrap();
2703 parse_and_evaluate(
2704 "f2 = (x) => x + 2",
2705 Some(Rc::clone(&heap)),
2706 Some(Rc::clone(&bindings)),
2707 )
2708 .unwrap();
2709 let result = parse_and_evaluate(
2710 "f1 == f2",
2711 Some(Rc::clone(&heap)),
2712 Some(Rc::clone(&bindings)),
2713 )
2714 .unwrap();
2715 assert_eq!(result, Value::Bool(true));
2716
2717 let result = parse_and_evaluate(
2719 "f1 == f1",
2720 Some(Rc::clone(&heap)),
2721 Some(Rc::clone(&bindings)),
2722 )
2723 .unwrap();
2724 assert_eq!(result, Value::Bool(true));
2725
2726 parse_and_evaluate(
2728 "f3 = f1",
2729 Some(Rc::clone(&heap)),
2730 Some(Rc::clone(&bindings)),
2731 )
2732 .unwrap();
2733 let result = parse_and_evaluate(
2734 "f1 == f3",
2735 Some(Rc::clone(&heap)),
2736 Some(Rc::clone(&bindings)),
2737 )
2738 .unwrap();
2739 assert_eq!(result, Value::Bool(true));
2740
2741 parse_and_evaluate(
2743 "f4 = (x) => x + 3",
2744 Some(Rc::clone(&heap)),
2745 Some(Rc::clone(&bindings)),
2746 )
2747 .unwrap();
2748 let result = parse_and_evaluate(
2749 "f1 == f4",
2750 Some(Rc::clone(&heap)),
2751 Some(Rc::clone(&bindings)),
2752 )
2753 .unwrap();
2754 assert_eq!(result, Value::Bool(false));
2755
2756 parse_and_evaluate(
2758 "f5 = (y) => y + 2",
2759 Some(Rc::clone(&heap)),
2760 Some(Rc::clone(&bindings)),
2761 )
2762 .unwrap();
2763 let result = parse_and_evaluate(
2764 "f1 == f5",
2765 Some(Rc::clone(&heap)),
2766 Some(Rc::clone(&bindings)),
2767 )
2768 .unwrap();
2769 assert_eq!(result, Value::Bool(false));
2770
2771 parse_and_evaluate(
2773 "f6 = (x, y) => x + y",
2774 Some(Rc::clone(&heap)),
2775 Some(Rc::clone(&bindings)),
2776 )
2777 .unwrap();
2778 let result = parse_and_evaluate(
2779 "f1 == f6",
2780 Some(Rc::clone(&heap)),
2781 Some(Rc::clone(&bindings)),
2782 )
2783 .unwrap();
2784 assert_eq!(result, Value::Bool(false));
2785 }
2786
2787 #[test]
2788 fn equality_comparison_mixed_types() {
2789 let result = parse_and_evaluate("1 == \"1\"", None, None).unwrap();
2791 assert_eq!(result, Value::Bool(false));
2792
2793 let result = parse_and_evaluate("true == 1", None, None).unwrap();
2794 assert_eq!(result, Value::Bool(false));
2795
2796 let result = parse_and_evaluate("[1] == 1", None, None).unwrap();
2798 assert_eq!(result, Value::Bool(true));
2799
2800 let result = parse_and_evaluate("null == 0", None, None).unwrap();
2801 assert_eq!(result, Value::Bool(false));
2802 }
2803
2804 #[test]
2805 fn comparison_operators_strings() {
2806 let result = parse_and_evaluate(r#""apple" < "banana""#, None, None).unwrap();
2808 assert_eq!(result, Value::Bool(true));
2809
2810 let result = parse_and_evaluate(r#""zebra" > "apple""#, None, None).unwrap();
2811 assert_eq!(result, Value::Bool(true));
2812
2813 let result = parse_and_evaluate(r#""hello" <= "hello""#, None, None).unwrap();
2814 assert_eq!(result, Value::Bool(true));
2815 }
2816
2817 #[test]
2818 fn comparison_operators_lists() {
2819 let result = parse_and_evaluate("[1, 2] < [2, 3]", None, None).unwrap();
2822 assert_eq!(result, Value::Bool(true));
2823
2824 let result = parse_and_evaluate("[1, 2] < [1, 3]", None, None).unwrap();
2826 assert_eq!(result, Value::Bool(false));
2827
2828 let result = parse_and_evaluate("[2, 1] > [1, 0]", None, None).unwrap();
2830 assert_eq!(result, Value::Bool(true));
2831 }
2832
2833 #[test]
2834 fn late_binding_unbound_variable_succeeds() {
2835 let heap = Rc::new(RefCell::new(Heap::new()));
2837 let bindings = Rc::new(RefCell::new(HashMap::new()));
2838 let result = parse_and_evaluate("f = x => x + y", Some(heap), Some(bindings));
2839 assert!(result.is_ok());
2841 }
2842
2843 #[test]
2844 fn early_binding_bound_variable_succeeds() {
2845 let heap = Rc::new(RefCell::new(Heap::new()));
2847 let bindings = Rc::new(RefCell::new(HashMap::new()));
2848
2849 let _ = parse_and_evaluate("y = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
2851 .unwrap();
2852
2853 let result = parse_and_evaluate(
2855 "g = x => x + y",
2856 Some(Rc::clone(&heap)),
2857 Some(Rc::clone(&bindings)),
2858 );
2859 assert!(result.is_ok());
2860
2861 let call_result = parse_and_evaluate("g(2)", Some(heap), Some(bindings)).unwrap();
2863 assert_eq!(call_result, Value::Number(7.0));
2864 }
2865
2866 #[test]
2867 fn early_binding_builtin_function_succeeds() {
2868 let heap = Rc::new(RefCell::new(Heap::new()));
2870 let bindings = Rc::new(RefCell::new(HashMap::new()));
2871 let result = parse_and_evaluate(
2872 "h = x => sin(x)",
2873 Some(Rc::clone(&heap)),
2874 Some(Rc::clone(&bindings)),
2875 );
2876 assert!(result.is_ok());
2877
2878 let call_result = parse_and_evaluate("h(0)", Some(heap), Some(bindings)).unwrap();
2880 assert_eq!(call_result, Value::Number(0.0));
2881 }
2882
2883 #[test]
2884 fn late_binding_nested_function_succeeds() {
2885 let heap = Rc::new(RefCell::new(Heap::new()));
2887 let bindings = Rc::new(RefCell::new(HashMap::new()));
2888
2889 let result = parse_and_evaluate(
2891 "outer = x => do { inner = y => y + z; return inner(x) }",
2892 Some(Rc::clone(&heap)),
2893 Some(Rc::clone(&bindings)),
2894 );
2895 assert!(result.is_ok());
2896
2897 let _ = parse_and_evaluate(
2899 "z = 100",
2900 Some(Rc::clone(&heap)),
2901 Some(Rc::clone(&bindings)),
2902 )
2903 .unwrap();
2904
2905 let call_result = parse_and_evaluate("outer(5)", Some(heap), Some(bindings)).unwrap();
2907 assert_eq!(call_result, Value::Number(105.0));
2908 }
2909
2910 #[test]
2911 fn early_binding_all_variables_bound() {
2912 let heap = Rc::new(RefCell::new(Heap::new()));
2914 let bindings = Rc::new(RefCell::new(HashMap::new()));
2915
2916 let _ = parse_and_evaluate("a = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
2918 .unwrap();
2919 let _ = parse_and_evaluate("b = 20", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
2920 .unwrap();
2921
2922 let result = parse_and_evaluate(
2924 "func = x => (x + a) * b",
2925 Some(Rc::clone(&heap)),
2926 Some(Rc::clone(&bindings)),
2927 );
2928 assert!(result.is_ok());
2929
2930 let call_result = parse_and_evaluate("func(5)", Some(heap), Some(bindings)).unwrap();
2932 assert_eq!(call_result, Value::Number(300.0));
2933 }
2934
2935 #[test]
2936 fn early_binding_parameter_shadows_outer() {
2937 let heap = Rc::new(RefCell::new(Heap::new()));
2939 let bindings = Rc::new(RefCell::new(HashMap::new()));
2940
2941 let _ = parse_and_evaluate(
2943 "x = 100",
2944 Some(Rc::clone(&heap)),
2945 Some(Rc::clone(&bindings)),
2946 )
2947 .unwrap();
2948
2949 let result = parse_and_evaluate(
2951 "shadow = x => x * 2",
2952 Some(Rc::clone(&heap)),
2953 Some(Rc::clone(&bindings)),
2954 );
2955 assert!(result.is_ok());
2956
2957 let call_result = parse_and_evaluate("shadow(5)", Some(heap), Some(bindings)).unwrap();
2959 assert_eq!(call_result, Value::Number(10.0));
2960 }
2961
2962 #[test]
2963 fn early_binding_do_block_internal_binding() {
2964 let heap = Rc::new(RefCell::new(Heap::new()));
2966 let bindings = Rc::new(RefCell::new(HashMap::new()));
2967
2968 let result = parse_and_evaluate(
2970 "f = x => do { y = 5; return x + y }",
2971 Some(Rc::clone(&heap)),
2972 Some(Rc::clone(&bindings)),
2973 );
2974 assert!(result.is_ok());
2975
2976 let call_result = parse_and_evaluate("f(10)", Some(heap), Some(bindings)).unwrap();
2978 assert_eq!(call_result, Value::Number(15.0));
2979 }
2980
2981 #[test]
2982 fn early_binding_do_block_nested_scope() {
2983 let heap = Rc::new(RefCell::new(Heap::new()));
2985 let bindings = Rc::new(RefCell::new(HashMap::new()));
2986
2987 let result = parse_and_evaluate(
2988 "later_func = do { c = 30; f = x => x + c; return f(10) }",
2989 Some(Rc::clone(&heap)),
2990 Some(Rc::clone(&bindings)),
2991 );
2992 assert!(result.is_ok());
2993
2994 let later_func_result =
2996 parse_and_evaluate("later_func", Some(heap), Some(bindings)).unwrap();
2997 assert_eq!(later_func_result, Value::Number(40.0));
2998 }
2999
3000 #[test]
3001 fn late_binding_do_block_forward_reference_succeeds() {
3002 let heap = Rc::new(RefCell::new(Heap::new()));
3004 let bindings = Rc::new(RefCell::new(HashMap::new()));
3005
3006 let result = parse_and_evaluate(
3007 "g = x => do { f = y => y + z; z = 10; return f(x) }",
3008 Some(Rc::clone(&heap)),
3009 Some(Rc::clone(&bindings)),
3010 );
3011 assert!(result.is_ok());
3012
3013 let call_result = parse_and_evaluate("g(5)", Some(heap), Some(bindings)).unwrap();
3015 assert_eq!(call_result, Value::Number(15.0));
3016 }
3017
3018 #[test]
3019 fn early_binding_do_block_multiple_assignments() {
3020 let heap = Rc::new(RefCell::new(Heap::new()));
3022 let bindings = Rc::new(RefCell::new(HashMap::new()));
3023
3024 let result = parse_and_evaluate(
3025 "calc = x => do { a = 2; b = 3; c = 4; return x * a + b * c }",
3026 Some(Rc::clone(&heap)),
3027 Some(Rc::clone(&bindings)),
3028 );
3029 assert!(result.is_ok());
3030
3031 let call_result = parse_and_evaluate("calc(5)", Some(heap), Some(bindings)).unwrap();
3033 assert_eq!(call_result, Value::Number(22.0));
3034 }
3035
3036 #[test]
3037 fn late_binding_multiple_unbound_variables_succeeds() {
3038 let heap = Rc::new(RefCell::new(Heap::new()));
3040 let bindings = Rc::new(RefCell::new(HashMap::new()));
3041
3042 let result = parse_and_evaluate(
3043 "f = x => x + y + z",
3044 Some(Rc::clone(&heap)),
3045 Some(Rc::clone(&bindings)),
3046 );
3047 assert!(result.is_ok());
3048
3049 let _ = parse_and_evaluate("y = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
3051 .unwrap();
3052 let _ = parse_and_evaluate("z = 20", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
3053 .unwrap();
3054
3055 let call_result = parse_and_evaluate("f(5)", Some(heap), Some(bindings)).unwrap();
3057 assert_eq!(call_result, Value::Number(35.0));
3058 }
3059
3060 #[test]
3061 fn late_binding_with_optional_args_succeeds() {
3062 let heap = Rc::new(RefCell::new(Heap::new()));
3064 let bindings = Rc::new(RefCell::new(HashMap::new()));
3065
3066 let result = parse_and_evaluate(
3067 "f = (x, y?) => x + z",
3068 Some(Rc::clone(&heap)),
3069 Some(Rc::clone(&bindings)),
3070 );
3071 assert!(result.is_ok());
3072
3073 let _ = parse_and_evaluate(
3075 "z = 100",
3076 Some(Rc::clone(&heap)),
3077 Some(Rc::clone(&bindings)),
3078 )
3079 .unwrap();
3080
3081 let call_result = parse_and_evaluate("f(5)", Some(heap), Some(bindings)).unwrap();
3083 assert_eq!(call_result, Value::Number(105.0));
3084 }
3085
3086 #[test]
3087 fn late_binding_with_rest_args_succeeds() {
3088 let heap = Rc::new(RefCell::new(Heap::new()));
3090 let bindings = Rc::new(RefCell::new(HashMap::new()));
3091
3092 let result = parse_and_evaluate(
3093 "f = (x, ...rest) => x + y",
3094 Some(Rc::clone(&heap)),
3095 Some(Rc::clone(&bindings)),
3096 );
3097 assert!(result.is_ok());
3098
3099 let _ = parse_and_evaluate("y = 50", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
3101 .unwrap();
3102
3103 let call_result = parse_and_evaluate("f(5)", Some(heap), Some(bindings)).unwrap();
3105 assert_eq!(call_result, Value::Number(55.0));
3106 }
3107
3108 #[test]
3109 fn recursion_self_reference_allowed() {
3110 let heap = Rc::new(RefCell::new(Heap::new()));
3112 let bindings = Rc::new(RefCell::new(HashMap::new()));
3113
3114 let result = parse_and_evaluate(
3116 "factorial = n => if n <= 1 then 1 else n * factorial(n - 1)",
3117 Some(Rc::clone(&heap)),
3118 Some(Rc::clone(&bindings)),
3119 );
3120 assert!(result.is_ok());
3121
3122 let call_result = parse_and_evaluate("factorial(5)", Some(heap), Some(bindings)).unwrap();
3124 assert_eq!(call_result, Value::Number(120.0));
3125 }
3126
3127 #[test]
3128 fn recursion_fibonacci() {
3129 let heap = Rc::new(RefCell::new(Heap::new()));
3131 let bindings = Rc::new(RefCell::new(HashMap::new()));
3132
3133 let result = parse_and_evaluate(
3135 "fib = n => if n <= 1 then n else fib(n - 1) + fib(n - 2)",
3136 Some(Rc::clone(&heap)),
3137 Some(Rc::clone(&bindings)),
3138 );
3139 assert!(result.is_ok());
3140
3141 let call_result = parse_and_evaluate("fib(6)", Some(heap), Some(bindings)).unwrap();
3143 assert_eq!(call_result, Value::Number(8.0));
3144 }
3145
3146 #[test]
3147 fn recursion_in_do_block() {
3148 let heap = Rc::new(RefCell::new(Heap::new()));
3150 let bindings = Rc::new(RefCell::new(HashMap::new()));
3151
3152 let result = parse_and_evaluate(
3153 "result = do { factorial = n => if n <= 1 then 1 else n * factorial(n - 1); return factorial(4) }",
3154 Some(Rc::clone(&heap)),
3155 Some(Rc::clone(&bindings)),
3156 );
3157 assert!(result.is_ok());
3158
3159 let result_val = parse_and_evaluate("result", Some(heap), Some(bindings)).unwrap();
3161 assert_eq!(result_val, Value::Number(24.0));
3162 }
3163
3164 #[test]
3165 fn mutual_recursion_succeeds() {
3166 let heap = Rc::new(RefCell::new(Heap::new()));
3168 let bindings = Rc::new(RefCell::new(HashMap::new()));
3169
3170 let result = parse_and_evaluate(
3172 "isEven = n => if n == 0 then true else isOdd(n - 1)",
3173 Some(Rc::clone(&heap)),
3174 Some(Rc::clone(&bindings)),
3175 );
3176 assert!(result.is_ok());
3177
3178 let _ = parse_and_evaluate(
3180 "isOdd = n => if n == 0 then false else isEven(n - 1)",
3181 Some(Rc::clone(&heap)),
3182 Some(Rc::clone(&bindings)),
3183 )
3184 .unwrap();
3185
3186 let result1 = parse_and_evaluate(
3188 "isEven(4)",
3189 Some(Rc::clone(&heap)),
3190 Some(Rc::clone(&bindings)),
3191 )
3192 .unwrap();
3193 assert_eq!(result1, Value::Bool(true));
3194
3195 let result2 = parse_and_evaluate(
3196 "isEven(5)",
3197 Some(Rc::clone(&heap)),
3198 Some(Rc::clone(&bindings)),
3199 )
3200 .unwrap();
3201 assert_eq!(result2, Value::Bool(false));
3202
3203 let result3 = parse_and_evaluate(
3204 "isOdd(3)",
3205 Some(Rc::clone(&heap)),
3206 Some(Rc::clone(&bindings)),
3207 )
3208 .unwrap();
3209 assert_eq!(result3, Value::Bool(true));
3210
3211 let result4 = parse_and_evaluate("isOdd(6)", Some(heap), Some(bindings)).unwrap();
3212 assert_eq!(result4, Value::Bool(false));
3213 }
3214
3215 #[test]
3216 fn recursion_only_for_lambdas() {
3217 let heap = Rc::new(RefCell::new(Heap::new()));
3219 let bindings = Rc::new(RefCell::new(HashMap::new()));
3220
3221 let result = parse_and_evaluate("y = x + 1", Some(heap), Some(bindings));
3223 assert!(result.is_err());
3224 }
3225
3226 #[test]
3228 fn dot_equal_lists() {
3229 let heap = Rc::new(RefCell::new(Heap::new()));
3230
3231 let result =
3233 parse_and_evaluate("[1, 2, 3] .== [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3234 assert_eq!(result, Value::Bool(true));
3235
3236 let result =
3238 parse_and_evaluate("[1, 2, 3] .== [1, 2, 4]", Some(Rc::clone(&heap)), None).unwrap();
3239 assert_eq!(result, Value::Bool(false));
3240
3241 let result =
3243 parse_and_evaluate("[1, 2] .== [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3244 assert_eq!(result, Value::Bool(false));
3245
3246 let result = parse_and_evaluate("[1, 2, 3] .== 1", Some(Rc::clone(&heap)), None).unwrap();
3248 assert_eq!(result, Value::Bool(false));
3249
3250 let result = parse_and_evaluate("[] .== []", Some(Rc::clone(&heap)), None).unwrap();
3252 assert_eq!(result, Value::Bool(true));
3253
3254 let result =
3256 parse_and_evaluate("[[1, 2], [3, 4]] .== [[1, 2], [3, 4]]", Some(heap), None).unwrap();
3257 assert_eq!(result, Value::Bool(true));
3258 }
3259
3260 #[test]
3261 fn dot_not_equal_lists() {
3262 let heap = Rc::new(RefCell::new(Heap::new()));
3263
3264 let result =
3265 parse_and_evaluate("[1, 2, 3] .!= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3266 assert_eq!(result, Value::Bool(false));
3267
3268 let result =
3269 parse_and_evaluate("[1, 2, 3] .!= [1, 2, 4]", Some(Rc::clone(&heap)), None).unwrap();
3270 assert_eq!(result, Value::Bool(true));
3271
3272 let result = parse_and_evaluate("[1, 2, 3] .!= 1", Some(heap), None).unwrap();
3273 assert_eq!(result, Value::Bool(true));
3274 }
3275
3276 #[test]
3277 fn dot_less_lists() {
3278 let heap = Rc::new(RefCell::new(Heap::new()));
3279
3280 let result =
3282 parse_and_evaluate("[1, 2, 2] .< [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3283 assert_eq!(result, Value::Bool(true));
3284
3285 let result =
3286 parse_and_evaluate("[1, 2] .< [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3287 assert_eq!(result, Value::Bool(true));
3288
3289 let result = parse_and_evaluate("[] .< [1]", Some(Rc::clone(&heap)), None).unwrap();
3290 assert_eq!(result, Value::Bool(true));
3291
3292 let result = parse_and_evaluate("[2] .< [1, 9, 9]", Some(Rc::clone(&heap)), None).unwrap();
3293 assert_eq!(result, Value::Bool(false));
3294
3295 let result = parse_and_evaluate("[1, 2, 3] .< [1, 2, 3]", Some(heap), None).unwrap();
3296 assert_eq!(result, Value::Bool(false));
3297 }
3298
3299 #[test]
3300 fn dot_less_eq_lists() {
3301 let heap = Rc::new(RefCell::new(Heap::new()));
3302
3303 let result =
3304 parse_and_evaluate("[1, 2, 2] .<= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3305 assert_eq!(result, Value::Bool(true));
3306
3307 let result =
3308 parse_and_evaluate("[1, 2, 3] .<= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3309 assert_eq!(result, Value::Bool(true));
3310
3311 let result = parse_and_evaluate("[1, 2, 4] .<= [1, 2, 3]", Some(heap), None).unwrap();
3312 assert_eq!(result, Value::Bool(false));
3313 }
3314
3315 #[test]
3316 fn dot_greater_lists() {
3317 let heap = Rc::new(RefCell::new(Heap::new()));
3318
3319 let result =
3320 parse_and_evaluate("[1, 2, 3] .> [1, 2, 2]", Some(Rc::clone(&heap)), None).unwrap();
3321 assert_eq!(result, Value::Bool(true));
3322
3323 let result = parse_and_evaluate("[2] .> [1, 9, 9]", Some(Rc::clone(&heap)), None).unwrap();
3324 assert_eq!(result, Value::Bool(true));
3325
3326 let result = parse_and_evaluate("[1] .> []", Some(Rc::clone(&heap)), None).unwrap();
3327 assert_eq!(result, Value::Bool(true));
3328
3329 let result = parse_and_evaluate("[1, 2, 3] .> [1, 2, 3]", Some(heap), None).unwrap();
3330 assert_eq!(result, Value::Bool(false));
3331 }
3332
3333 #[test]
3334 fn dot_greater_eq_lists() {
3335 let heap = Rc::new(RefCell::new(Heap::new()));
3336
3337 let result =
3338 parse_and_evaluate("[1, 2, 3] .>= [1, 2, 2]", Some(Rc::clone(&heap)), None).unwrap();
3339 assert_eq!(result, Value::Bool(true));
3340
3341 let result =
3342 parse_and_evaluate("[1, 2, 3] .>= [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3343 assert_eq!(result, Value::Bool(true));
3344
3345 let result = parse_and_evaluate("[1, 2, 2] .>= [1, 2, 3]", Some(heap), None).unwrap();
3346 assert_eq!(result, Value::Bool(false));
3347 }
3348
3349 #[test]
3350 fn dot_operators_with_scalars() {
3351 let result = parse_and_evaluate("5 .== 5", None, None).unwrap();
3353 assert_eq!(result, Value::Bool(true));
3354
3355 let result = parse_and_evaluate("5 .!= 3", None, None).unwrap();
3356 assert_eq!(result, Value::Bool(true));
3357
3358 let result = parse_and_evaluate("3 .< 5", None, None).unwrap();
3359 assert_eq!(result, Value::Bool(true));
3360
3361 let result = parse_and_evaluate("5 .> 3", None, None).unwrap();
3362 assert_eq!(result, Value::Bool(true));
3363 }
3364
3365 #[test]
3366 fn dot_equal_vs_regular_equal_with_broadcasting() {
3367 let heap = Rc::new(RefCell::new(Heap::new()));
3368
3369 let result =
3371 parse_and_evaluate("[true, true, true] == true", Some(Rc::clone(&heap)), None).unwrap();
3372 assert_eq!(result, Value::Bool(true));
3373
3374 let result =
3376 parse_and_evaluate("[true, true, true] .== true", Some(Rc::clone(&heap)), None)
3377 .unwrap();
3378 assert_eq!(result, Value::Bool(false));
3379
3380 let result = parse_and_evaluate(
3382 "[true, true, true] .== [true, true, true]",
3383 Some(heap),
3384 None,
3385 )
3386 .unwrap();
3387 assert_eq!(result, Value::Bool(true));
3388 }
3389
3390 #[test]
3391 fn dot_operators_mixed_types() {
3392 let heap = Rc::new(RefCell::new(Heap::new()));
3393
3394 let result =
3396 parse_and_evaluate("\"hello\" .== [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3397 assert_eq!(result, Value::Bool(false));
3398
3399 let result = parse_and_evaluate("5 .< [1, 2, 3]", Some(Rc::clone(&heap)), None).unwrap();
3401 assert_eq!(result, Value::Bool(false));
3402
3403 let result = parse_and_evaluate("\"abc\" .< \"def\"", Some(heap), None).unwrap();
3405 assert_eq!(result, Value::Bool(true));
3406 }
3407}