blots_core/
do_block_tests.rs1#[cfg(test)]
3mod do_block_shadowing_tests {
4 use crate::expressions::evaluate_pairs;
5 use crate::heap::Heap;
6 use crate::parser::{Rule, get_pairs};
7 use crate::values::Value;
8 use std::cell::RefCell;
9 use std::collections::HashMap;
10 use std::rc::Rc;
11
12 fn parse_and_evaluate(
13 code: &str,
14 heap: Option<Rc<RefCell<Heap>>>,
15 bindings: Option<Rc<RefCell<HashMap<String, Value>>>>,
16 ) -> Result<Value, anyhow::Error> {
17 let pairs = get_pairs(code)?;
18
19 let heap = heap.unwrap_or_else(|| Rc::new(RefCell::new(Heap::new())));
20 let bindings = bindings.unwrap_or_else(|| Rc::new(RefCell::new(HashMap::new())));
21
22 let mut result = Value::Null;
23 for pair in pairs {
24 match pair.as_rule() {
25 Rule::statement => {
26 if let Some(inner_pair) = pair.into_inner().next() {
27 match inner_pair.as_rule() {
28 Rule::expression | Rule::assignment => {
29 result = evaluate_pairs(
30 inner_pair.into_inner(),
31 Rc::clone(&heap),
32 Rc::clone(&bindings),
33 0,
34 )?;
35 }
36 _ => {}
37 }
38 }
39 }
40 Rule::EOI => {}
41 _ => {}
42 }
43 }
44 Ok(result)
45 }
46
47 #[test]
48 fn test_do_block_allows_shadowing() {
49 let heap = Rc::new(RefCell::new(Heap::new()));
51 let bindings = Rc::new(RefCell::new(HashMap::new()));
52
53 let _ = parse_and_evaluate("g = 25", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
55 .unwrap();
56
57 let _ = parse_and_evaluate(
59 "make_f = x => do { g = y => x * y; return g }",
60 Some(Rc::clone(&heap)),
61 Some(Rc::clone(&bindings)),
62 )
63 .unwrap();
64
65 let f = parse_and_evaluate(
67 "make_f(5)",
68 Some(Rc::clone(&heap)),
69 Some(Rc::clone(&bindings)),
70 )
71 .unwrap();
72
73 assert!(matches!(f, Value::Lambda(_)));
75
76 let result = parse_and_evaluate("make_f(5)(3)", Some(heap), Some(bindings)).unwrap();
78
79 assert_eq!(result, Value::Number(15.0)); }
81
82 #[test]
83 fn test_do_block_shadowing_preserves_outer() {
84 let heap = Rc::new(RefCell::new(Heap::new()));
86 let bindings = Rc::new(RefCell::new(HashMap::new()));
87
88 let _ = parse_and_evaluate("x = 10", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
90 .unwrap();
91
92 let _ = parse_and_evaluate(
94 "result = do { x = 20; return x }",
95 Some(Rc::clone(&heap)),
96 Some(Rc::clone(&bindings)),
97 )
98 .unwrap();
99
100 let outer_x =
102 parse_and_evaluate("x", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings))).unwrap();
103 assert_eq!(outer_x, Value::Number(10.0));
104
105 let result = parse_and_evaluate("result", Some(heap), Some(bindings)).unwrap();
107 assert_eq!(result, Value::Number(20.0));
108 }
109
110 #[test]
111 fn test_nested_do_blocks_shadowing() {
112 let heap = Rc::new(RefCell::new(Heap::new()));
114 let bindings = Rc::new(RefCell::new(HashMap::new()));
115
116 let _ = parse_and_evaluate("z = 1", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
118 .unwrap();
119
120 let result = parse_and_evaluate(
122 "do { z = 10; return do { z = 100; return z } }",
123 Some(heap),
124 Some(bindings),
125 )
126 .unwrap();
127
128 assert_eq!(result, Value::Number(100.0));
129 }
130
131 #[test]
132 fn test_do_block_multiple_shadowings() {
133 let heap = Rc::new(RefCell::new(Heap::new()));
135 let bindings = Rc::new(RefCell::new(HashMap::new()));
136
137 let _ = parse_and_evaluate("a = 1", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
139 .unwrap();
140 let _ = parse_and_evaluate("b = 2", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
141 .unwrap();
142
143 let result = parse_and_evaluate(
145 "do { a = 10; b = 20; return a + b }",
146 Some(heap),
147 Some(bindings),
148 )
149 .unwrap();
150
151 assert_eq!(result, Value::Number(30.0)); }
153
154 #[test]
155 fn test_do_block_function_capture_with_shadowing() {
156 let heap = Rc::new(RefCell::new(Heap::new()));
158 let bindings = Rc::new(RefCell::new(HashMap::new()));
159
160 let _ = parse_and_evaluate("v = 5", Some(Rc::clone(&heap)), Some(Rc::clone(&bindings)))
162 .unwrap();
163
164 let _ = parse_and_evaluate(
166 "get_func = do { v = 100; f = () => v; return f }",
167 Some(Rc::clone(&heap)),
168 Some(Rc::clone(&bindings)),
169 )
170 .unwrap();
171
172 let result = parse_and_evaluate("get_func()", Some(heap), Some(bindings)).unwrap();
174
175 assert_eq!(result, Value::Number(100.0)); }
177}