seq_runtime/list_ops/
combinators.rs1use crate::stack::{Stack, drop_stack_value, get_stack_base, pop, pop_sv, push, stack_value_size};
6use crate::value::{Value, VariantData};
7use std::sync::Arc;
8
9#[inline]
11pub(super) fn stack_depth(stack: Stack) -> usize {
12 if stack.is_null() {
13 return 0;
14 }
15 let base = get_stack_base();
16 if base.is_null() {
17 return 0;
18 }
19 (stack as usize - base as usize) / stack_value_size()
20}
21
22unsafe fn drain_stack_to_base(mut stack: Stack, base: Stack) {
27 unsafe {
28 while stack > base {
29 let (rest, sv) = pop_sv(stack);
30 drop_stack_value(sv);
31 stack = rest;
32 }
33 }
34}
35
36unsafe fn call_with_value(base: Stack, value: Value, callable: &Value) -> Stack {
41 unsafe {
42 let stack = push(base, value);
43 crate::quotations::invoke_callable(stack, callable)
44 }
45}
46
47#[unsafe(no_mangle)]
57pub unsafe extern "C" fn patch_seq_list_map(stack: Stack) -> Stack {
58 unsafe {
59 let (stack, callable) = pop(stack);
61
62 match &callable {
64 Value::Quotation { .. } | Value::Closure { .. } => {}
65 _ => panic!(
66 "list-map: expected Quotation or Closure, got {:?}",
67 callable
68 ),
69 }
70
71 let (stack, list_val) = pop(stack);
73
74 let variant_data = match list_val {
75 Value::Variant(v) => v,
76 _ => panic!("list-map: expected Variant (list), got {:?}", list_val),
77 };
78
79 let mut results = Vec::with_capacity(variant_data.fields.len());
81
82 for field in variant_data.fields.iter() {
83 let temp_base = crate::stack::alloc_stack();
85 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
86
87 if temp_stack <= temp_base {
89 panic!("list-map: quotation consumed element without producing result");
90 }
91 let (remaining, result) = pop(temp_stack);
92 results.push(result);
93
94 if remaining > temp_base {
96 drain_stack_to_base(remaining, temp_base);
97 }
98 }
99
100 let new_variant = Value::Variant(Arc::new(VariantData::new(
102 variant_data.tag.clone(),
103 results,
104 )));
105
106 push(stack, new_variant)
107 }
108}
109
110#[unsafe(no_mangle)]
120pub unsafe extern "C" fn patch_seq_list_filter(stack: Stack) -> Stack {
121 unsafe {
122 let (stack, callable) = pop(stack);
124
125 match &callable {
127 Value::Quotation { .. } | Value::Closure { .. } => {}
128 _ => panic!(
129 "list-filter: expected Quotation or Closure, got {:?}",
130 callable
131 ),
132 }
133
134 let (stack, list_val) = pop(stack);
136
137 let variant_data = match list_val {
138 Value::Variant(v) => v,
139 _ => panic!("list-filter: expected Variant (list), got {:?}", list_val),
140 };
141
142 let mut results = Vec::new();
144
145 for field in variant_data.fields.iter() {
146 let temp_base = crate::stack::alloc_stack();
148 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
149
150 if temp_stack <= temp_base {
152 panic!("list-filter: quotation consumed element without producing result");
153 }
154 let (remaining, result) = pop(temp_stack);
155
156 let keep = match result {
157 Value::Bool(b) => b,
158 _ => panic!("list-filter: quotation must return Bool, got {:?}", result),
159 };
160
161 if keep {
162 results.push(field.clone());
163 }
164
165 if remaining > temp_base {
167 drain_stack_to_base(remaining, temp_base);
168 }
169 }
170
171 let new_variant = Value::Variant(Arc::new(VariantData::new(
173 variant_data.tag.clone(),
174 results,
175 )));
176
177 push(stack, new_variant)
178 }
179}
180
181#[unsafe(no_mangle)]
191pub unsafe extern "C" fn patch_seq_list_fold(stack: Stack) -> Stack {
192 unsafe {
193 let (stack, callable) = pop(stack);
195
196 match &callable {
198 Value::Quotation { .. } | Value::Closure { .. } => {}
199 _ => panic!(
200 "list-fold: expected Quotation or Closure, got {:?}",
201 callable
202 ),
203 }
204
205 let (stack, init) = pop(stack);
207
208 let (stack, list_val) = pop(stack);
210
211 let variant_data = match list_val {
212 Value::Variant(v) => v,
213 _ => panic!("list-fold: expected Variant (list), got {:?}", list_val),
214 };
215
216 let mut acc = init;
218
219 for field in variant_data.fields.iter() {
220 let temp_base = crate::stack::alloc_stack();
222 let temp_stack = push(temp_base, acc);
223 let temp_stack = push(temp_stack, field.clone());
224
225 let temp_stack = match &callable {
226 Value::Quotation { wrapper, .. } => {
227 let fn_ref: unsafe extern "C" fn(Stack) -> Stack =
228 std::mem::transmute(*wrapper);
229 fn_ref(temp_stack)
230 }
231 Value::Closure { fn_ptr, env } => {
232 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
233 std::mem::transmute(*fn_ptr);
234 fn_ref(temp_stack, env.as_ptr(), env.len())
235 }
236 _ => unreachable!(),
237 };
238
239 if temp_stack <= temp_base {
241 panic!("list-fold: quotation consumed inputs without producing result");
242 }
243 let (remaining, new_acc) = pop(temp_stack);
244 acc = new_acc;
245
246 if remaining > temp_base {
248 drain_stack_to_base(remaining, temp_base);
249 }
250 }
251
252 push(stack, acc)
253 }
254}
255
256#[unsafe(no_mangle)]
266pub unsafe extern "C" fn patch_seq_list_each(stack: Stack) -> Stack {
267 unsafe {
268 let (stack, callable) = pop(stack);
270
271 match &callable {
273 Value::Quotation { .. } | Value::Closure { .. } => {}
274 _ => panic!(
275 "list-each: expected Quotation or Closure, got {:?}",
276 callable
277 ),
278 }
279
280 let (stack, list_val) = pop(stack);
282
283 let variant_data = match list_val {
284 Value::Variant(v) => v,
285 _ => panic!("list-each: expected Variant (list), got {:?}", list_val),
286 };
287
288 for field in variant_data.fields.iter() {
290 let temp_base = crate::stack::alloc_stack();
291 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
292 if temp_stack > temp_base {
294 drain_stack_to_base(temp_stack, temp_base);
295 }
296 }
297
298 stack
299 }
300}