intuicio_frontend_simpleton/library/
iter.rs

1use crate::{library::closure::Closure, Array, Boolean, Function, Integer, Map, Reference};
2use intuicio_core::{context::Context, registry::Registry, IntuicioStruct};
3use intuicio_derive::{intuicio_function, intuicio_method, intuicio_methods, IntuicioStruct};
4
5const GENERATOR: &str = "next";
6
7#[intuicio_function(module_name = "iter", use_context, use_registry)]
8pub fn next(context: &mut Context, registry: &Registry, iterator: Reference) -> Reference {
9    let iter = iterator.clone();
10    if let Some(closure) = iterator.read::<Closure>() {
11        closure.invoke(context, registry, &[iter])
12    } else if let Some(map) = iterator.read::<Map>() {
13        map.get(GENERATOR)
14            .unwrap()
15            .read::<Closure>()
16            .unwrap()
17            .invoke(context, registry, &[iter])
18    } else {
19        let closure = {
20            let iterator = iterator.read_object().unwrap();
21            iterator.read_field::<Reference>(GENERATOR).unwrap().clone()
22        };
23        let closure = closure.read::<Closure>().unwrap();
24        closure.invoke(context, registry, &[iter])
25    }
26}
27
28pub fn build_impl(
29    context: &mut Context,
30    registry: &Registry,
31    previous: Option<Reference>,
32    next: &[Reference],
33) -> Reference {
34    if next.is_empty() {
35        return previous.unwrap_or_default();
36    }
37    let current = &next[0];
38    if let Some(current) = current.read::<Array>() {
39        let function = current[0].read::<Function>().unwrap();
40        for argument in current[1..].iter().rev() {
41            context.stack().push(argument.to_owned());
42        }
43        if let Some(previous) = previous {
44            context.stack().push(previous);
45        }
46        function.handle().unwrap().invoke(context, registry);
47        let previous = context.stack().pop::<Reference>().unwrap();
48        build_impl(context, registry, Some(previous), &next[1..])
49    } else {
50        build_impl(context, registry, Some(current.clone()), &next[1..])
51    }
52}
53
54#[intuicio_function(module_name = "iter", use_context, use_registry)]
55pub fn build(context: &mut Context, registry: &Registry, iterators: Reference) -> Reference {
56    let iterators = iterators.read::<Array>().unwrap();
57    build_impl(context, registry, None, &iterators)
58}
59
60#[intuicio_function(module_name = "iter", use_registry)]
61pub fn enumerate(registry: &Registry, iterator: Reference) -> Reference {
62    Reference::new(
63        IterEnumerate {
64            iterator,
65            index: 0,
66            next: Reference::new(
67                Closure {
68                    function: Function::by_name("next", "iter_enumerate", registry).unwrap(),
69                    captured: vec![],
70                },
71                registry,
72            ),
73        },
74        registry,
75    )
76}
77
78#[intuicio_function(module_name = "iter", use_registry)]
79pub fn walk(registry: &Registry, start: Reference, steps: Reference) -> Reference {
80    Reference::new(
81        IterWalk {
82            current: *start.read::<Integer>().unwrap(),
83            steps: *steps.read::<Integer>().unwrap(),
84            next: Reference::new(
85                Closure {
86                    function: Function::by_name("next", "iter_walk", registry).unwrap(),
87                    captured: vec![],
88                },
89                registry,
90            ),
91        },
92        registry,
93    )
94}
95
96#[intuicio_function(module_name = "iter", use_registry)]
97pub fn range(registry: &Registry, from: Reference, to: Reference) -> Reference {
98    let from = *from.read::<Integer>().unwrap();
99    let to = *to.read::<Integer>().unwrap();
100    Reference::new(
101        IterWalk {
102            current: from,
103            steps: to - from,
104            next: Reference::new(
105                Closure {
106                    function: Function::by_name("next", "iter_walk", registry).unwrap(),
107                    captured: vec![],
108                },
109                registry,
110            ),
111        },
112        registry,
113    )
114}
115
116#[intuicio_function(module_name = "iter", use_registry)]
117pub fn range_inclusive(registry: &Registry, from: Reference, to: Reference) -> Reference {
118    let from = *from.read::<Integer>().unwrap();
119    let to = *to.read::<Integer>().unwrap();
120    let steps = to - from;
121    Reference::new(
122        IterWalk {
123            current: from,
124            steps: steps + steps.signum(),
125            next: Reference::new(
126                Closure {
127                    function: Function::by_name("next", "iter_walk", registry).unwrap(),
128                    captured: vec![],
129                },
130                registry,
131            ),
132        },
133        registry,
134    )
135}
136
137#[intuicio_function(module_name = "iter", use_registry)]
138pub fn filter(registry: &Registry, iterator: Reference, closure: Reference) -> Reference {
139    Reference::new(
140        IterFilter {
141            iterator,
142            closure,
143            next: Reference::new(
144                Closure {
145                    function: Function::by_name("next", "iter_filter", registry).unwrap(),
146                    captured: vec![],
147                },
148                registry,
149            ),
150        },
151        registry,
152    )
153}
154
155#[intuicio_function(module_name = "iter", use_registry)]
156pub fn map(registry: &Registry, iterator: Reference, closure: Reference) -> Reference {
157    Reference::new(
158        IterMap {
159            iterator,
160            closure,
161            next: Reference::new(
162                Closure {
163                    function: Function::by_name("next", "iter_map", registry).unwrap(),
164                    captured: vec![],
165                },
166                registry,
167            ),
168        },
169        registry,
170    )
171}
172
173#[intuicio_function(module_name = "iter", use_registry)]
174pub fn filter_map(registry: &Registry, iterator: Reference, closure: Reference) -> Reference {
175    Reference::new(
176        IterFilterMap {
177            iterator,
178            closure,
179            next: Reference::new(
180                Closure {
181                    function: Function::by_name("next", "iter_filter_map", registry).unwrap(),
182                    captured: vec![],
183                },
184                registry,
185            ),
186        },
187        registry,
188    )
189}
190
191#[intuicio_function(module_name = "iter", use_registry)]
192pub fn flatten(registry: &Registry, iterator: Reference) -> Reference {
193    Reference::new(
194        IterFlatten {
195            iterator,
196            current: Reference::null(),
197            next: Reference::new(
198                Closure {
199                    function: Function::by_name("next", "iter_flatten", registry).unwrap(),
200                    captured: vec![],
201                },
202                registry,
203            ),
204        },
205        registry,
206    )
207}
208
209#[intuicio_function(module_name = "iter", use_registry)]
210pub fn chain(registry: &Registry, iterators: Reference) -> Reference {
211    Reference::new(
212        IterChain {
213            iterators: iterators.read::<Array>().unwrap().clone(),
214            current: 0,
215            next: Reference::new(
216                Closure {
217                    function: Function::by_name("next", "iter_chain", registry).unwrap(),
218                    captured: vec![],
219                },
220                registry,
221            ),
222        },
223        registry,
224    )
225}
226
227#[intuicio_function(module_name = "iter", use_registry)]
228pub fn zip(registry: &Registry, iterators: Reference) -> Reference {
229    Reference::new(
230        IterZip {
231            iterators: iterators.read::<Array>().unwrap().clone(),
232            next: Reference::new(
233                Closure {
234                    function: Function::by_name("next", "iter_zip", registry).unwrap(),
235                    captured: vec![],
236                },
237                registry,
238            ),
239        },
240        registry,
241    )
242}
243
244#[intuicio_function(module_name = "iter", use_registry)]
245pub fn chunks(registry: &Registry, iterator: Reference, count: Reference) -> Reference {
246    Reference::new(
247        IterChunks {
248            iterator,
249            count,
250            next: Reference::new(
251                Closure {
252                    function: Function::by_name("next", "iter_chunks", registry).unwrap(),
253                    captured: vec![],
254                },
255                registry,
256            ),
257        },
258        registry,
259    )
260}
261
262#[intuicio_function(module_name = "iter", use_context, use_registry)]
263pub fn fold(
264    context: &mut Context,
265    registry: &Registry,
266    iterator: Reference,
267    mut start: Reference,
268    closure: Reference,
269) -> Reference {
270    loop {
271        let value = crate::library::iter::next(context, registry, iterator.clone());
272        if value.is_null() {
273            return start;
274        }
275        let closure = closure.read::<Closure>().unwrap();
276        start = closure.invoke(context, registry, &[start.clone(), value]);
277    }
278}
279
280#[intuicio_function(module_name = "iter", use_context, use_registry)]
281pub fn find(
282    context: &mut Context,
283    registry: &Registry,
284    iterator: Reference,
285    closure: Reference,
286) -> Reference {
287    loop {
288        let value = crate::library::iter::next(context, registry, iterator.clone());
289        if value.is_null() {
290            return value;
291        }
292        let closure = closure.read::<Closure>().unwrap();
293        let result = closure.invoke(context, registry, &[value.clone()]);
294        if *result.read::<Boolean>().unwrap() {
295            return value;
296        }
297    }
298}
299
300#[intuicio_function(module_name = "iter", use_context, use_registry)]
301pub fn find_map(
302    context: &mut Context,
303    registry: &Registry,
304    iterator: Reference,
305    closure: Reference,
306) -> Reference {
307    loop {
308        let value = crate::library::iter::next(context, registry, iterator.clone());
309        if value.is_null() {
310            return value;
311        }
312        let closure = closure.read::<Closure>().unwrap();
313        let result = closure.invoke(context, registry, &[value]);
314        if !result.is_null() {
315            return result;
316        }
317    }
318}
319
320#[intuicio_function(module_name = "iter", use_context, use_registry)]
321pub fn position(
322    context: &mut Context,
323    registry: &Registry,
324    iterator: Reference,
325    closure: Reference,
326) -> Reference {
327    let mut index = 0;
328    loop {
329        let value = crate::library::iter::next(context, registry, iterator.clone());
330        if value.is_null() {
331            return value;
332        }
333        let closure = closure.read::<Closure>().unwrap();
334        let result = closure.invoke(context, registry, &[value]);
335        if *result.read::<Boolean>().unwrap() {
336            return Reference::new_integer(index, registry);
337        }
338        index += 1;
339    }
340}
341
342#[intuicio_function(module_name = "iter", use_context, use_registry)]
343pub fn any(
344    context: &mut Context,
345    registry: &Registry,
346    iterator: Reference,
347    closure: Reference,
348) -> Reference {
349    loop {
350        let value = crate::library::iter::next(context, registry, iterator.clone());
351        if value.is_null() {
352            return Reference::new_boolean(false, registry);
353        }
354        let closure = closure.read::<Closure>().unwrap();
355        let result = closure.invoke(context, registry, &[value]);
356        if *result.read::<Boolean>().unwrap() {
357            return Reference::new_boolean(true, registry);
358        }
359    }
360}
361
362#[intuicio_function(module_name = "iter", use_context, use_registry)]
363pub fn all(
364    context: &mut Context,
365    registry: &Registry,
366    iterator: Reference,
367    closure: Reference,
368) -> Reference {
369    loop {
370        let value = crate::library::iter::next(context, registry, iterator.clone());
371        if value.is_null() {
372            return Reference::new_boolean(true, registry);
373        }
374        let closure = closure.read::<Closure>().unwrap();
375        let result = closure.invoke(context, registry, &[value]);
376        if !*result.read::<Boolean>().unwrap() {
377            return Reference::new_boolean(false, registry);
378        }
379    }
380}
381
382#[intuicio_function(module_name = "iter", use_context, use_registry)]
383pub fn count(context: &mut Context, registry: &Registry, iterator: Reference) -> Reference {
384    let mut result = 0;
385    loop {
386        let value = crate::library::iter::next(context, registry, iterator.clone());
387        if value.is_null() {
388            return Reference::new_integer(result, registry);
389        }
390        result += 1;
391    }
392}
393
394#[intuicio_function(module_name = "iter", use_context, use_registry)]
395pub fn compared_by(
396    context: &mut Context,
397    registry: &Registry,
398    iterator: Reference,
399    closure: Reference,
400) -> Reference {
401    let mut found = crate::library::iter::next(context, registry, iterator.clone());
402    if found.is_null() {
403        return Reference::null();
404    }
405    loop {
406        let value = crate::library::iter::next(context, registry, iterator.clone());
407        if value.is_null() {
408            return found;
409        }
410        let closure = closure.read::<Closure>().unwrap();
411        let result = closure.invoke(context, registry, &[value.clone(), found.clone()]);
412        if *result.read::<Boolean>().unwrap() {
413            found = value;
414        }
415    }
416}
417
418#[derive(IntuicioStruct, Default)]
419#[intuicio(name = "IterWalk", module_name = "iter_walk")]
420pub struct IterWalk {
421    #[intuicio(ignore)]
422    pub current: Integer,
423    #[intuicio(ignore)]
424    pub steps: Integer,
425    pub next: Reference,
426}
427
428#[intuicio_methods(module_name = "iter_walk")]
429impl IterWalk {
430    #[intuicio_method(use_registry)]
431    pub fn next(registry: &Registry, mut iterator: Reference) -> Reference {
432        let mut iterator = iterator.write::<IterWalk>().unwrap();
433        if iterator.steps.abs() == 0 {
434            return Reference::null();
435        }
436        let value = iterator.current;
437        let step = iterator.steps.signum();
438        iterator.current += step;
439        iterator.steps -= step;
440        Reference::new_integer(value, registry)
441    }
442}
443
444#[derive(IntuicioStruct, Default)]
445#[intuicio(name = "Enumeration", module_name = "iter")]
446pub struct Enumeration {
447    pub index: Reference,
448    pub value: Reference,
449}
450
451#[derive(IntuicioStruct, Default)]
452#[intuicio(name = "IterEnumerate", module_name = "iter_enumerate")]
453pub struct IterEnumerate {
454    #[intuicio(ignore)]
455    pub iterator: Reference,
456    #[intuicio(ignore)]
457    pub index: usize,
458    pub next: Reference,
459}
460
461#[intuicio_methods(module_name = "iter_enumerate")]
462impl IterEnumerate {
463    #[intuicio_method(use_context, use_registry)]
464    pub fn next(context: &mut Context, registry: &Registry, mut iterator: Reference) -> Reference {
465        let mut iterator = iterator.write::<IterEnumerate>().unwrap();
466        let value = next(context, registry, iterator.iterator.clone());
467        if value.is_null() {
468            return Reference::null();
469        }
470        let index = iterator.index;
471        iterator.index += 1;
472        Reference::new(
473            Enumeration {
474                index: Reference::new_integer(index as Integer, registry),
475                value,
476            },
477            registry,
478        )
479    }
480}
481
482#[derive(IntuicioStruct, Default)]
483#[intuicio(name = "IterFilter", module_name = "iter_filter")]
484pub struct IterFilter {
485    #[intuicio(ignore)]
486    pub iterator: Reference,
487    #[intuicio(ignore)]
488    pub closure: Reference,
489    pub next: Reference,
490}
491
492#[intuicio_methods(module_name = "iter_filter")]
493impl IterFilter {
494    #[intuicio_method(use_context, use_registry)]
495    pub fn next(context: &mut Context, registry: &Registry, iterator: Reference) -> Reference {
496        let iterator = iterator.read::<IterFilter>().unwrap();
497        loop {
498            let value = next(context, registry, iterator.iterator.clone());
499            if value.is_null() {
500                return value;
501            }
502            let closure = iterator.closure.read::<Closure>().unwrap();
503            let result = closure.invoke(context, registry, &[value.clone()]);
504            if *result.read::<Boolean>().unwrap() {
505                return value;
506            }
507        }
508    }
509}
510
511#[derive(IntuicioStruct, Default)]
512#[intuicio(name = "IterMap", module_name = "iter_map")]
513pub struct IterMap {
514    #[intuicio(ignore)]
515    pub iterator: Reference,
516    #[intuicio(ignore)]
517    pub closure: Reference,
518    pub next: Reference,
519}
520
521#[intuicio_methods(module_name = "iter_map")]
522impl IterMap {
523    #[intuicio_method(use_context, use_registry)]
524    pub fn next(context: &mut Context, registry: &Registry, iterator: Reference) -> Reference {
525        let iterator = iterator.read::<IterMap>().unwrap();
526        let value = next(context, registry, iterator.iterator.clone());
527        if value.is_null() {
528            value
529        } else {
530            let closure = iterator.closure.read::<Closure>().unwrap();
531            closure.invoke(context, registry, &[value])
532        }
533    }
534}
535
536#[derive(IntuicioStruct, Default)]
537#[intuicio(name = "IterMap", module_name = "iter_filter_map")]
538pub struct IterFilterMap {
539    #[intuicio(ignore)]
540    pub iterator: Reference,
541    #[intuicio(ignore)]
542    pub closure: Reference,
543    pub next: Reference,
544}
545
546#[intuicio_methods(module_name = "iter_filter_map")]
547impl IterFilterMap {
548    #[intuicio_method(use_context, use_registry)]
549    pub fn next(context: &mut Context, registry: &Registry, iterator: Reference) -> Reference {
550        let iterator = iterator.read::<IterFilterMap>().unwrap();
551        loop {
552            let value = next(context, registry, iterator.iterator.clone());
553            if value.is_null() {
554                return value;
555            }
556            let closure = iterator.closure.read::<Closure>().unwrap();
557            let result = closure.invoke(context, registry, &[value]);
558            if !result.is_null() {
559                return result;
560            }
561        }
562    }
563}
564
565#[derive(IntuicioStruct, Default)]
566#[intuicio(name = "IterFlatten", module_name = "iter_flatten")]
567pub struct IterFlatten {
568    #[intuicio(ignore)]
569    pub iterator: Reference,
570    #[intuicio(ignore)]
571    pub current: Reference,
572    pub next: Reference,
573}
574
575#[intuicio_methods(module_name = "iter_flatten")]
576impl IterFlatten {
577    #[intuicio_method(use_context, use_registry)]
578    pub fn next(context: &mut Context, registry: &Registry, mut iterator: Reference) -> Reference {
579        let mut iterator = iterator.write::<IterFlatten>().unwrap();
580        loop {
581            if iterator.current.is_null() {
582                iterator.current = next(context, registry, iterator.iterator.clone());
583                if iterator.current.is_null() {
584                    return Reference::null();
585                }
586            }
587            let value = next(context, registry, iterator.current.clone());
588            if value.is_null() {
589                iterator.current = Reference::null()
590            } else {
591                return value;
592            }
593        }
594    }
595}
596
597#[derive(IntuicioStruct, Default)]
598#[intuicio(name = "IterChain", module_name = "iter_chain")]
599pub struct IterChain {
600    #[intuicio(ignore)]
601    pub iterators: Array,
602    #[intuicio(ignore)]
603    pub current: usize,
604    pub next: Reference,
605}
606
607#[intuicio_methods(module_name = "iter_chain")]
608impl IterChain {
609    #[intuicio_method(use_context, use_registry)]
610    pub fn next(context: &mut Context, registry: &Registry, mut iterator: Reference) -> Reference {
611        let mut iterator = iterator.write::<IterChain>().unwrap();
612        while let Some(current) = iterator.iterators.get(iterator.current) {
613            let value = next(context, registry, current.clone());
614            if value.is_null() {
615                iterator.current += 1;
616            } else {
617                return value;
618            }
619        }
620        Reference::null()
621    }
622}
623
624#[derive(IntuicioStruct, Default)]
625#[intuicio(name = "IterZip", module_name = "iter_zip")]
626pub struct IterZip {
627    #[intuicio(ignore)]
628    pub iterators: Array,
629    pub next: Reference,
630}
631
632#[intuicio_methods(module_name = "iter_zip")]
633impl IterZip {
634    #[intuicio_method(use_context, use_registry)]
635    pub fn next(context: &mut Context, registry: &Registry, iterator: Reference) -> Reference {
636        let iterator = iterator.read::<IterZip>().unwrap();
637        let result = iterator
638            .iterators
639            .iter()
640            .map(|iterator| next(context, registry, iterator.clone()))
641            .collect::<Array>();
642        if result.iter().any(|value| value.is_null()) {
643            Reference::null()
644        } else {
645            Reference::new_array(result, registry)
646        }
647    }
648}
649
650#[derive(IntuicioStruct, Default)]
651#[intuicio(name = "IterChunks", module_name = "iter_chunks")]
652pub struct IterChunks {
653    #[intuicio(ignore)]
654    pub iterator: Reference,
655    #[intuicio(ignore)]
656    pub count: Reference,
657    pub next: Reference,
658}
659
660#[intuicio_methods(module_name = "iter_chunks")]
661impl IterChunks {
662    #[intuicio_method(use_context, use_registry)]
663    pub fn next(context: &mut Context, registry: &Registry, iterator: Reference) -> Reference {
664        let iterator = iterator.read::<IterChunks>().unwrap();
665        let count = *iterator.count.read::<Integer>().unwrap() as usize;
666        if count == 0 {
667            return Reference::null();
668        }
669        let mut result = Vec::with_capacity(count);
670        for _ in 0..count {
671            let value = next(context, registry, iterator.iterator.clone());
672            if value.is_null() {
673                return Reference::null();
674            }
675            result.push(value);
676        }
677        Reference::new_array(result, registry)
678    }
679}
680
681pub fn install(registry: &mut Registry) {
682    registry.add_function(next::define_function(registry));
683    registry.add_function(build::define_function(registry));
684    registry.add_function(walk::define_function(registry));
685    registry.add_function(range::define_function(registry));
686    registry.add_function(range_inclusive::define_function(registry));
687    registry.add_function(enumerate::define_function(registry));
688    registry.add_function(filter::define_function(registry));
689    registry.add_function(map::define_function(registry));
690    registry.add_function(filter_map::define_function(registry));
691    registry.add_function(flatten::define_function(registry));
692    registry.add_function(chain::define_function(registry));
693    registry.add_function(zip::define_function(registry));
694    registry.add_function(chunks::define_function(registry));
695    registry.add_function(fold::define_function(registry));
696    registry.add_function(find::define_function(registry));
697    registry.add_function(find_map::define_function(registry));
698    registry.add_function(position::define_function(registry));
699    registry.add_function(any::define_function(registry));
700    registry.add_function(all::define_function(registry));
701    registry.add_function(count::define_function(registry));
702    registry.add_function(compared_by::define_function(registry));
703    registry.add_type(IterWalk::define_struct(registry));
704    registry.add_function(IterWalk::next__define_function(registry));
705    registry.add_type(Enumeration::define_struct(registry));
706    registry.add_type(IterEnumerate::define_struct(registry));
707    registry.add_function(IterEnumerate::next__define_function(registry));
708    registry.add_type(IterFilter::define_struct(registry));
709    registry.add_function(IterFilter::next__define_function(registry));
710    registry.add_type(IterMap::define_struct(registry));
711    registry.add_function(IterMap::next__define_function(registry));
712    registry.add_type(IterFilterMap::define_struct(registry));
713    registry.add_function(IterFilterMap::next__define_function(registry));
714    registry.add_type(IterFlatten::define_struct(registry));
715    registry.add_function(IterFlatten::next__define_function(registry));
716    registry.add_type(IterChain::define_struct(registry));
717    registry.add_function(IterChain::next__define_function(registry));
718    registry.add_type(IterZip::define_struct(registry));
719    registry.add_function(IterZip::next__define_function(registry));
720    registry.add_type(IterChunks::define_struct(registry));
721    registry.add_function(IterChunks::next__define_function(registry));
722}