1#![doc(
2 html_logo_url = "https://graphix-lang.github.io/graphix/graphix-icon.svg",
3 html_favicon_url = "https://graphix-lang.github.io/graphix/graphix-icon.svg"
4)]
5use anyhow::{bail, Result};
6use arcstr::literal;
7use compact_str::format_compact;
8use graphix_compiler::{
9 expr::ExprId,
10 node::genn,
11 typ::{FnType, Type},
12 Apply, BindId, BuiltIn, Event, ExecCtx, LambdaId, Node, Refs, Rt, Scope,
13 TypecheckPhase, UserEvent,
14};
15use graphix_package_core::{
16 CachedArgs, CachedVals, EvalCached, FoldFn, FoldQ, MapCollection, MapFn, MapQ, Slot,
17};
18use graphix_rt::GXRt;
19use netidx::{publisher::Typ, subscriber::Value};
20use netidx_value::ValArray;
21use smallvec::SmallVec;
22use std::{collections::hash_map::Entry, collections::VecDeque, fmt::Debug};
23use triomphe::Arc as TArc;
24
25fn make_nil() -> Value {
28 Value::String(literal!("Nil"))
29}
30
31fn make_cons(head: Value, tail: Value) -> Value {
32 Value::Array(ValArray::from_iter_exact(
33 [Value::String(literal!("Cons")), head, tail].into_iter(),
34 ))
35}
36
37fn get_cons(v: &Value) -> Option<(&Value, &Value)> {
39 match v {
40 Value::Array(a) if a.len() == 3 => match &a[0] {
41 Value::String(s) if &**s == "Cons" => Some((&a[1], &a[2])),
42 _ => None,
43 },
44 _ => None,
45 }
46}
47
48fn is_nil(v: &Value) -> bool {
49 matches!(v, Value::String(s) if &**s == "Nil")
50}
51
52fn is_list(v: &Value) -> bool {
53 is_nil(v) || get_cons(v).is_some()
54}
55
56fn count_list(v: &Value) -> Option<usize> {
58 let mut len = 0;
59 let mut cur = v.clone();
60 loop {
61 if is_nil(&cur) {
62 return Some(len);
63 }
64 match get_cons(&cur) {
65 Some((_, tail)) => {
66 len += 1;
67 cur = tail.clone();
68 }
69 None => return None,
70 }
71 }
72}
73
74fn from_iter_back(iter: impl Iterator<Item = Value>) -> Value {
77 let mut buf: SmallVec<[Value; 32]> = iter.collect();
78 let mut result = make_nil();
79 while let Some(v) = buf.pop() {
80 result = make_cons(v, result);
81 }
82 result
83}
84
85struct ListIter {
88 cur: Value,
89}
90
91impl Iterator for ListIter {
92 type Item = Value;
93
94 fn next(&mut self) -> Option<Value> {
95 let cur = self.cur.clone();
96 match get_cons(&cur) {
97 Some((head, tail)) => {
98 let head = head.clone();
99 self.cur = tail.clone();
100 Some(head)
101 }
102 None => None,
103 }
104 }
105}
106
107#[derive(Debug, Clone)]
112struct ListColl {
113 value: Value,
114 len: usize,
115}
116
117impl Default for ListColl {
118 fn default() -> Self {
119 Self { value: make_nil(), len: 0 }
120 }
121}
122
123impl MapCollection for ListColl {
124 fn len(&self) -> usize {
125 self.len
126 }
127
128 fn iter_values(&self) -> impl Iterator<Item = Value> {
129 ListIter { cur: self.value.clone() }
130 }
131
132 fn select(v: Value) -> Option<Self> {
133 let len = count_list(&v)?;
134 Some(ListColl { value: v, len })
135 }
136
137 fn project(self) -> Value {
138 self.value
139 }
140
141 fn etyp(ft: &FnType) -> Result<Type> {
142 if let Type::Abstract { params, .. } = &ft.args[0].typ {
145 if !params.is_empty() {
146 return Ok(params[0].clone());
147 }
148 }
149 for arg in ft.args.iter() {
155 if let Type::Fn(inner) = &arg.typ {
156 if let Some(last) = inner.args.last() {
157 return Ok(last.typ.clone());
158 }
159 }
160 }
161 bail!("cannot extract list element type from {:?}", ft.args[0].typ)
162 }
163}
164
165#[derive(Debug, Default)]
168struct ListMapImpl;
169
170impl<R: Rt, E: UserEvent> MapFn<R, E> for ListMapImpl {
171 type Collection = ListColl;
172 const NAME: &str = "list_map";
173
174 fn finish(&mut self, slots: &[Slot<R, E>], _: &ListColl) -> Option<Value> {
175 Some(from_iter_back(slots.iter().map(|s| s.cur.clone().unwrap())))
176 }
177}
178
179type ListMap<R, E> = MapQ<R, E, ListMapImpl>;
180
181#[derive(Debug, Default)]
182struct ListFilterImpl;
183
184impl<R: Rt, E: UserEvent> MapFn<R, E> for ListFilterImpl {
185 type Collection = ListColl;
186 const NAME: &str = "list_filter";
187
188 fn finish(&mut self, slots: &[Slot<R, E>], a: &ListColl) -> Option<Value> {
189 Some(from_iter_back(
190 slots.iter().zip(ListIter { cur: a.value.clone() }).filter_map(|(p, v)| {
191 match p.cur {
192 Some(Value::Bool(true)) => Some(v),
193 _ => None,
194 }
195 }),
196 ))
197 }
198}
199
200type ListFilter<R, E> = MapQ<R, E, ListFilterImpl>;
201
202#[derive(Debug, Default)]
203struct ListFilterMapImpl;
204
205impl<R: Rt, E: UserEvent> MapFn<R, E> for ListFilterMapImpl {
206 type Collection = ListColl;
207 const NAME: &str = "list_filter_map";
208
209 fn finish(&mut self, slots: &[Slot<R, E>], _: &ListColl) -> Option<Value> {
210 Some(from_iter_back(slots.iter().filter_map(|s| match s.cur.as_ref().unwrap() {
211 Value::Null => None,
212 v => Some(v.clone()),
213 })))
214 }
215}
216
217type ListFilterMap<R, E> = MapQ<R, E, ListFilterMapImpl>;
218
219#[derive(Debug, Default)]
220struct ListFlatMapImpl;
221
222impl<R: Rt, E: UserEvent> MapFn<R, E> for ListFlatMapImpl {
223 type Collection = ListColl;
224 const NAME: &str = "list_flat_map";
225
226 fn finish(&mut self, slots: &[Slot<R, E>], _: &ListColl) -> Option<Value> {
227 Some(from_iter_back(slots.iter().flat_map(|s| {
228 let v = s.cur.as_ref().unwrap();
229 if is_list(v) {
230 let items: SmallVec<[Value; 32]> = ListIter { cur: v.clone() }.collect();
231 items.into_iter()
232 } else {
233 let mut one: SmallVec<[Value; 32]> = SmallVec::new();
234 one.push(v.clone());
235 one.into_iter()
236 }
237 })))
238 }
239}
240
241type ListFlatMap<R, E> = MapQ<R, E, ListFlatMapImpl>;
242
243#[derive(Debug, Default)]
244struct ListFindImpl;
245
246impl<R: Rt, E: UserEvent> MapFn<R, E> for ListFindImpl {
247 type Collection = ListColl;
248 const NAME: &str = "list_find";
249
250 fn finish(&mut self, slots: &[Slot<R, E>], a: &ListColl) -> Option<Value> {
251 let r = slots
252 .iter()
253 .zip(ListIter { cur: a.value.clone() })
254 .find(|(s, _)| matches!(s.cur.as_ref(), Some(Value::Bool(true))))
255 .map(|(_, v)| v)
256 .unwrap_or(Value::Null);
257 Some(r)
258 }
259}
260
261type ListFind<R, E> = MapQ<R, E, ListFindImpl>;
262
263#[derive(Debug, Default)]
264struct ListFindMapImpl;
265
266impl<R: Rt, E: UserEvent> MapFn<R, E> for ListFindMapImpl {
267 type Collection = ListColl;
268 const NAME: &str = "list_find_map";
269
270 fn finish(&mut self, slots: &[Slot<R, E>], _: &ListColl) -> Option<Value> {
271 let r = slots
272 .iter()
273 .find_map(|s| match s.cur.as_ref().unwrap() {
274 Value::Null => None,
275 v => Some(v.clone()),
276 })
277 .unwrap_or(Value::Null);
278 Some(r)
279 }
280}
281
282type ListFindMap<R, E> = MapQ<R, E, ListFindMapImpl>;
283
284#[derive(Debug)]
287struct ListFoldImpl;
288
289impl<R: Rt, E: UserEvent> FoldFn<R, E> for ListFoldImpl {
290 type Collection = ListColl;
291 const NAME: &str = "list_fold";
292}
293
294type ListFold<R, E> = FoldQ<R, E, ListFoldImpl>;
295
296#[derive(Debug, Default)]
299struct NilEv;
300
301impl<R: Rt, E: UserEvent> EvalCached<R, E> for NilEv {
302 const NAME: &str = "list_nil";
303 const NEEDS_CALLSITE: bool = false;
304
305 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
306 from.0[0].as_ref()?;
307 Some(make_nil())
308 }
309}
310
311type Nil = CachedArgs<NilEv>;
312
313#[derive(Debug, Default)]
314struct ConsEv;
315
316impl<R: Rt, E: UserEvent> EvalCached<R, E> for ConsEv {
317 const NAME: &str = "list_cons";
318 const NEEDS_CALLSITE: bool = false;
319
320 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
321 let head = from.0[0].as_ref()?;
322 let tail = from.0[1].as_ref()?;
323 Some(make_cons(head.clone(), tail.clone()))
324 }
325}
326
327type Cons = CachedArgs<ConsEv>;
328
329#[derive(Debug, Default)]
330struct SingletonEv;
331
332impl<R: Rt, E: UserEvent> EvalCached<R, E> for SingletonEv {
333 const NAME: &str = "list_singleton";
334 const NEEDS_CALLSITE: bool = false;
335
336 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
337 let v = from.0[0].as_ref()?;
338 Some(make_cons(v.clone(), make_nil()))
339 }
340}
341
342type Singleton = CachedArgs<SingletonEv>;
343
344#[derive(Debug, Default)]
345struct HeadEv;
346
347impl<R: Rt, E: UserEvent> EvalCached<R, E> for HeadEv {
348 const NAME: &str = "list_head";
349 const NEEDS_CALLSITE: bool = false;
350
351 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
352 let list = from.0[0].as_ref()?;
353 match get_cons(list) {
354 Some((head, _)) => Some(head.clone()),
355 None => Some(Value::Null),
356 }
357 }
358}
359
360type Head = CachedArgs<HeadEv>;
361
362#[derive(Debug, Default)]
363struct TailEv;
364
365impl<R: Rt, E: UserEvent> EvalCached<R, E> for TailEv {
366 const NAME: &str = "list_tail";
367 const NEEDS_CALLSITE: bool = false;
368
369 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
370 let list = from.0[0].as_ref()?;
371 match get_cons(list) {
372 Some((_, tail)) => Some(tail.clone()),
373 None => Some(Value::Null),
374 }
375 }
376}
377
378type Tail = CachedArgs<TailEv>;
379
380#[derive(Debug, Default)]
381struct UnconsEv;
382
383impl<R: Rt, E: UserEvent> EvalCached<R, E> for UnconsEv {
384 const NAME: &str = "list_uncons";
385 const NEEDS_CALLSITE: bool = false;
386
387 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
388 let list = from.0[0].as_ref()?;
389 match get_cons(list) {
390 Some((head, tail)) => Some(Value::Array(ValArray::from_iter_exact(
391 [head.clone(), tail.clone()].into_iter(),
392 ))),
393 None => Some(Value::Null),
394 }
395 }
396}
397
398type Uncons = CachedArgs<UnconsEv>;
399
400#[derive(Debug, Default)]
401struct IsEmptyEv;
402
403impl<R: Rt, E: UserEvent> EvalCached<R, E> for IsEmptyEv {
404 const NAME: &str = "list_is_empty";
405 const NEEDS_CALLSITE: bool = false;
406
407 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
408 let list = from.0[0].as_ref()?;
409 Some(Value::Bool(is_nil(list)))
410 }
411}
412
413type IsEmpty = CachedArgs<IsEmptyEv>;
414
415#[derive(Debug, Default)]
416struct NthEv;
417
418impl<R: Rt, E: UserEvent> EvalCached<R, E> for NthEv {
419 const NAME: &str = "list_nth";
420 const NEEDS_CALLSITE: bool = false;
421
422 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
423 let list = from.0[0].as_ref()?;
424 let n = match from.0[1].as_ref()? {
425 Value::I64(n) => *n,
426 _ => return None,
427 };
428 if n < 0 {
429 return Some(Value::Null);
430 }
431 let mut cur = list.clone();
432 for _ in 0..n {
433 match get_cons(&cur) {
434 Some((_, tail)) => cur = tail.clone(),
435 None => return Some(Value::Null),
436 }
437 }
438 match get_cons(&cur) {
439 Some((head, _)) => Some(head.clone()),
440 None => Some(Value::Null),
441 }
442 }
443}
444
445type Nth = CachedArgs<NthEv>;
446
447#[derive(Debug, Default)]
448struct LenEv;
449
450impl<R: Rt, E: UserEvent> EvalCached<R, E> for LenEv {
451 const NAME: &str = "list_len";
452 const NEEDS_CALLSITE: bool = false;
453
454 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
455 let list = from.0[0].as_ref()?;
456 Some(Value::I64(count_list(list)? as i64))
457 }
458}
459
460type Len = CachedArgs<LenEv>;
461
462#[derive(Debug, Default)]
463struct ReverseEv;
464
465impl<R: Rt, E: UserEvent> EvalCached<R, E> for ReverseEv {
466 const NAME: &str = "list_reverse";
467 const NEEDS_CALLSITE: bool = false;
468
469 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
470 let list = from.0[0].as_ref()?;
471 if !is_list(list) {
472 return None;
473 }
474 let mut result = make_nil();
475 for v in (ListIter { cur: list.clone() }) {
476 result = make_cons(v, result);
477 }
478 Some(result)
479 }
480}
481
482type Reverse = CachedArgs<ReverseEv>;
483
484#[derive(Debug, Default)]
485struct TakeEv;
486
487impl<R: Rt, E: UserEvent> EvalCached<R, E> for TakeEv {
488 const NAME: &str = "list_take";
489 const NEEDS_CALLSITE: bool = false;
490
491 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
492 let n = match from.0[0].as_ref()? {
493 Value::I64(n) => (*n).max(0) as usize,
494 _ => return None,
495 };
496 let list = from.0[1].as_ref()?;
497 if !is_list(list) {
498 return None;
499 }
500 Some(from_iter_back(ListIter { cur: list.clone() }.take(n)))
501 }
502}
503
504type Take = CachedArgs<TakeEv>;
505
506#[derive(Debug, Default)]
507struct DropEv;
508
509impl<R: Rt, E: UserEvent> EvalCached<R, E> for DropEv {
510 const NAME: &str = "list_drop";
511 const NEEDS_CALLSITE: bool = false;
512
513 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
514 let n = match from.0[0].as_ref()? {
515 Value::I64(n) => (*n).max(0) as usize,
516 _ => return None,
517 };
518 let list = from.0[1].as_ref()?;
519 if !is_list(list) {
520 return None;
521 }
522 let mut cur = list.clone();
523 for _ in 0..n {
524 match get_cons(&cur) {
525 Some((_, tail)) => cur = tail.clone(),
526 None => return Some(make_nil()),
527 }
528 }
529 Some(cur)
530 }
531}
532
533type Drop_ = CachedArgs<DropEv>;
534
535#[derive(Debug, Default)]
536struct ToArrayEv;
537
538impl<R: Rt, E: UserEvent> EvalCached<R, E> for ToArrayEv {
539 const NAME: &str = "list_to_array";
540 const NEEDS_CALLSITE: bool = false;
541
542 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
543 let list = from.0[0].as_ref()?;
544 if !is_list(list) {
545 return None;
546 }
547 Some(Value::Array(ValArray::from_iter(ListIter { cur: list.clone() })))
548 }
549}
550
551type ToArray = CachedArgs<ToArrayEv>;
552
553#[derive(Debug, Default)]
554struct FromArrayEv;
555
556impl<R: Rt, E: UserEvent> EvalCached<R, E> for FromArrayEv {
557 const NAME: &str = "list_from_array";
558 const NEEDS_CALLSITE: bool = false;
559
560 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
561 match from.0[0].as_ref()? {
562 Value::Array(a) => Some(from_iter_back(a.iter().cloned())),
563 _ => None,
564 }
565 }
566}
567
568type FromArray = CachedArgs<FromArrayEv>;
569
570#[derive(Debug, Default)]
571struct ConcatEv(SmallVec<[Value; 32]>);
572
573impl<R: Rt, E: UserEvent> EvalCached<R, E> for ConcatEv {
574 const NAME: &str = "list_concat";
575 const NEEDS_CALLSITE: bool = false;
576
577 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
578 let mut present = true;
581 for v in from.0.iter() {
582 match v {
583 Some(v) if is_list(v) => {
584 self.0.extend(ListIter { cur: v.clone() });
585 }
586 _ => present = false,
587 }
588 }
589 if present {
590 let result = from_iter_back(self.0.drain(..));
591 Some(result)
592 } else {
593 self.0.clear();
594 None
595 }
596 }
597}
598
599type Concat = CachedArgs<ConcatEv>;
600
601#[derive(Debug, Default)]
602struct FlattenEv(SmallVec<[Value; 32]>);
603
604impl<R: Rt, E: UserEvent> EvalCached<R, E> for FlattenEv {
605 const NAME: &str = "list_flatten";
606 const NEEDS_CALLSITE: bool = false;
607
608 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
609 let list = from.0[0].as_ref()?;
610 if !is_list(list) {
611 return None;
612 }
613 for inner in (ListIter { cur: list.clone() }) {
614 self.0.extend(ListIter { cur: inner });
615 }
616 let result = from_iter_back(self.0.drain(..));
617 Some(result)
618 }
619}
620
621type Flatten = CachedArgs<FlattenEv>;
622
623#[derive(Debug, Default)]
624struct SortEv(SmallVec<[Value; 32]>);
625
626impl<R: Rt, E: UserEvent> EvalCached<R, E> for SortEv {
627 const NAME: &str = "list_sort";
628 const NEEDS_CALLSITE: bool = false;
629
630 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
631 fn cn(v: &Value) -> Value {
632 v.clone().cast(Typ::F64).unwrap_or_else(|| v.clone())
633 }
634 match &from.0[..] {
635 [Some(Value::String(dir)), Some(Value::Bool(numeric)), Some(list)]
636 if is_list(list) =>
637 {
638 match &**dir {
639 "Ascending" => {
640 self.0.extend(ListIter { cur: list.clone() });
641 if *numeric {
642 self.0.sort_by(|v0, v1| cn(v0).cmp(&cn(v1)))
643 } else {
644 self.0.sort();
645 }
646 Some(from_iter_back(self.0.drain(..)))
647 }
648 "Descending" => {
649 self.0.extend(ListIter { cur: list.clone() });
650 if *numeric {
651 self.0.sort_by(|a0, a1| cn(a1).cmp(&cn(a0)))
652 } else {
653 self.0.sort_by(|a0, a1| a1.cmp(a0));
654 }
655 Some(from_iter_back(self.0.drain(..)))
656 }
657 _ => None,
658 }
659 }
660 _ => None,
661 }
662 }
663}
664
665type Sort = CachedArgs<SortEv>;
666
667#[derive(Debug, Default)]
668struct EnumerateEv;
669
670impl<R: Rt, E: UserEvent> EvalCached<R, E> for EnumerateEv {
671 const NAME: &str = "list_enumerate";
672 const NEEDS_CALLSITE: bool = false;
673
674 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
675 let list = from.0[0].as_ref()?;
676 if !is_list(list) {
677 return None;
678 }
679 Some(from_iter_back(
680 ListIter { cur: list.clone() }.enumerate().map(|(i, v)| (i, v).into()),
681 ))
682 }
683}
684
685type Enumerate_ = CachedArgs<EnumerateEv>;
686
687#[derive(Debug, Default)]
688struct ZipEv;
689
690impl<R: Rt, E: UserEvent> EvalCached<R, E> for ZipEv {
691 const NAME: &str = "list_zip";
692 const NEEDS_CALLSITE: bool = false;
693
694 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
695 let l0 = from.0[0].as_ref()?;
696 let l1 = from.0[1].as_ref()?;
697 if !is_list(l0) || !is_list(l1) {
698 return None;
699 }
700 Some(from_iter_back(
701 ListIter { cur: l0.clone() }
702 .zip(ListIter { cur: l1.clone() })
703 .map(|p| p.into()),
704 ))
705 }
706}
707
708type Zip = CachedArgs<ZipEv>;
709
710#[derive(Debug, Default)]
711struct UnzipEv {
712 t0: SmallVec<[Value; 32]>,
713 t1: SmallVec<[Value; 32]>,
714}
715
716impl<R: Rt, E: UserEvent> EvalCached<R, E> for UnzipEv {
717 const NAME: &str = "list_unzip";
718 const NEEDS_CALLSITE: bool = false;
719
720 fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
721 let list = from.0[0].as_ref()?;
722 if !is_list(list) {
723 return None;
724 }
725 for v in (ListIter { cur: list.clone() }) {
726 if let Value::Array(a) = v {
727 if a.len() == 2 {
728 self.t0.push(a[0].clone());
729 self.t1.push(a[1].clone());
730 }
731 }
732 }
733 let v0 = from_iter_back(self.t0.drain(..));
734 let v1 = from_iter_back(self.t1.drain(..));
735 Some(Value::Array(ValArray::from_iter_exact([v0, v1].into_iter())))
736 }
737}
738
739type Unzip = CachedArgs<UnzipEv>;
740
741#[derive(Debug)]
744struct ListIterBI(BindId, ExprId);
745
746impl<R: Rt, E: UserEvent> BuiltIn<R, E> for ListIterBI {
747 const NAME: &str = "list_iter";
748 const NEEDS_CALLSITE: bool = false;
749
750 fn init<'a, 'b, 'c, 'd>(
751 ctx: &'a mut ExecCtx<R, E>,
752 _typ: &'a FnType,
753 _resolved: Option<&'d FnType>,
754 _scope: &'b Scope,
755 _from: &'c [Node<R, E>],
756 top_id: ExprId,
757 ) -> Result<Box<dyn Apply<R, E>>> {
758 let id = BindId::new();
759 ctx.rt.ref_var(id, top_id);
760 Ok(Box::new(ListIterBI(id, top_id)))
761 }
762}
763
764impl<R: Rt, E: UserEvent> Apply<R, E> for ListIterBI {
765 fn update(
766 &mut self,
767 ctx: &mut ExecCtx<R, E>,
768 from: &mut [Node<R, E>],
769 event: &mut Event<E>,
770 ) -> Option<Value> {
771 if let Some(list) = from[0].update(ctx, event) {
772 for v in (ListIter { cur: list }) {
773 ctx.rt.set_var(self.0, v);
774 }
775 }
776 event.variables.get(&self.0).cloned()
777 }
778
779 fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
780 ctx.rt.unref_var(self.0, self.1)
781 }
782
783 fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
784 ctx.rt.unref_var(self.0, self.1);
785 self.0 = BindId::new();
786 ctx.rt.ref_var(self.0, self.1);
787 }
788}
789
790#[derive(Debug)]
791struct ListIterQ {
792 triggered: usize,
793 queue: VecDeque<(usize, Vec<Value>)>,
794 id: BindId,
795 top_id: ExprId,
796}
797
798impl<R: Rt, E: UserEvent> BuiltIn<R, E> for ListIterQ {
799 const NAME: &str = "list_iterq";
800 const NEEDS_CALLSITE: bool = false;
801
802 fn init<'a, 'b, 'c, 'd>(
803 ctx: &'a mut ExecCtx<R, E>,
804 _typ: &'a FnType,
805 _resolved: Option<&'d FnType>,
806 _scope: &'b Scope,
807 _from: &'c [Node<R, E>],
808 top_id: ExprId,
809 ) -> Result<Box<dyn Apply<R, E>>> {
810 let id = BindId::new();
811 ctx.rt.ref_var(id, top_id);
812 Ok(Box::new(ListIterQ { triggered: 0, queue: VecDeque::new(), id, top_id }))
813 }
814}
815
816impl<R: Rt, E: UserEvent> Apply<R, E> for ListIterQ {
817 fn update(
818 &mut self,
819 ctx: &mut ExecCtx<R, E>,
820 from: &mut [Node<R, E>],
821 event: &mut Event<E>,
822 ) -> Option<Value> {
823 if from[0].update(ctx, event).is_some() {
824 self.triggered += 1;
825 }
826 if let Some(list) = from[1].update(ctx, event) {
827 if is_list(&list) {
828 let elems: Vec<Value> = ListIter { cur: list }.collect();
829 if !elems.is_empty() {
830 self.queue.push_back((0, elems));
831 }
832 }
833 }
834 while self.triggered > 0 && !self.queue.is_empty() {
835 let (i, elems) = self.queue.front_mut().unwrap();
836 while self.triggered > 0 && *i < elems.len() {
837 ctx.rt.set_var(self.id, elems[*i].clone());
838 *i += 1;
839 self.triggered -= 1;
840 }
841 if *i == elems.len() {
842 self.queue.pop_front();
843 }
844 }
845 event.variables.get(&self.id).cloned()
846 }
847
848 fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
849 ctx.rt.unref_var(self.id, self.top_id)
850 }
851
852 fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
853 ctx.rt.unref_var(self.id, self.top_id);
854 self.id = BindId::new();
855 self.queue.clear();
856 self.triggered = 0;
857 }
858}
859
860#[derive(Debug)]
861struct ListInit<R: Rt, E: UserEvent> {
862 scope: Scope,
863 fid: BindId,
864 top_id: ExprId,
865 mftyp: TArc<FnType>,
866 slots: Vec<Slot<R, E>>,
867}
868
869impl<R: Rt, E: UserEvent> BuiltIn<R, E> for ListInit<R, E> {
870 const NAME: &str = "list_init";
871 const NEEDS_CALLSITE: bool = false;
872
873 fn init<'a, 'b, 'c, 'd>(
874 _ctx: &'a mut ExecCtx<R, E>,
875 typ: &'a FnType,
876 resolved: Option<&'d FnType>,
877 scope: &'b Scope,
878 from: &'c [Node<R, E>],
879 top_id: ExprId,
880 ) -> Result<Box<dyn Apply<R, E>>> {
881 match from {
882 [_, _] => {
883 let typ = resolved.unwrap_or(typ);
884 Ok(Box::new(Self {
885 scope: scope
886 .append(&format_compact!("fn{}", LambdaId::new().inner())),
887 fid: BindId::new(),
888 top_id,
889 mftyp: match &typ.args[1].typ {
890 Type::Fn(ft) => ft.clone(),
891 t => bail!("expected a function not {t}"),
892 },
893 slots: vec![],
894 }))
895 }
896 _ => bail!("expected two arguments"),
897 }
898 }
899}
900
901impl<R: Rt, E: UserEvent> Apply<R, E> for ListInit<R, E> {
902 fn update(
903 &mut self,
904 ctx: &mut ExecCtx<R, E>,
905 from: &mut [Node<R, E>],
906 event: &mut Event<E>,
907 ) -> Option<Value> {
908 let slen = self.slots.len();
909 if let Some(v) = from[1].update(ctx, event) {
910 ctx.cached.insert(self.fid, v.clone());
911 event.variables.insert(self.fid, v);
912 }
913 let (size_fired, resized) = match from[0].update(ctx, event) {
914 Some(Value::I64(n)) => {
915 let n = n.max(0) as usize;
916 if n == slen {
917 (true, false)
918 } else if n < slen {
919 while self.slots.len() > n {
920 if let Some(mut s) = self.slots.pop() {
921 s.delete(ctx)
922 }
923 }
924 (true, true)
925 } else {
926 let i_typ = Type::Primitive(Typ::I64.into());
927 while self.slots.len() < n {
928 let i = self.slots.len();
929 let (id, node) = genn::bind(
930 ctx,
931 &self.scope.lexical,
932 "i",
933 i_typ.clone(),
934 self.top_id,
935 );
936 ctx.cached.insert(id, Value::I64(i as i64));
937 let fnode = genn::reference(
938 ctx,
939 self.fid,
940 Type::Fn(self.mftyp.clone()),
941 self.top_id,
942 );
943 let pred = genn::apply(
944 fnode,
945 self.scope.clone(),
946 vec![node],
947 &self.mftyp,
948 self.top_id,
949 );
950 self.slots.push(Slot { id, pred, cur: None });
951 }
952 (true, true)
953 }
954 }
955 _ => (false, false),
956 };
957 if resized && self.slots.len() > slen {
958 for i in slen..self.slots.len() {
959 let id = self.slots[i].id;
960 event.variables.insert(id, Value::I64(i as i64));
961 }
962 }
963 if size_fired && self.slots.is_empty() {
964 return Some(make_nil());
965 }
966 let init = event.init;
967 let mut up = resized;
968 for (i, s) in self.slots.iter_mut().enumerate() {
969 if i == slen {
970 event.init = true;
971 if let Entry::Vacant(e) = event.variables.entry(self.fid)
972 && let Some(v) = ctx.cached.get(&self.fid)
973 {
974 e.insert(v.clone());
975 }
976 }
977 if let Some(v) = s.pred.update(ctx, event) {
978 s.cur = Some(v);
979 up = true;
980 }
981 }
982 event.init = init;
983 if up && self.slots.iter().all(|s| s.cur.is_some()) {
984 Some(from_iter_back(self.slots.iter().map(|s| s.cur.clone().unwrap())))
985 } else {
986 None
987 }
988 }
989
990 fn typecheck(
991 &mut self,
992 ctx: &mut ExecCtx<R, E>,
993 _from: &mut [Node<R, E>],
994 _phase: TypecheckPhase,
995 ) -> anyhow::Result<()> {
996 let i_typ = Type::Primitive(Typ::I64.into());
997 let (_, node) = genn::bind(ctx, &self.scope.lexical, "i", i_typ, self.top_id);
998 let ft = self.mftyp.clone();
999 let fnode = genn::reference(ctx, self.fid, Type::Fn(ft.clone()), self.top_id);
1000 let mut node =
1001 genn::apply(fnode, self.scope.clone(), vec![node], &ft, self.top_id);
1002 let r = node.typecheck(ctx);
1003 node.delete(ctx);
1004 r?;
1005 Ok(())
1006 }
1007
1008 fn refs(&self, refs: &mut Refs) {
1009 for s in &self.slots {
1010 s.pred.refs(refs)
1011 }
1012 }
1013
1014 fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
1015 ctx.cached.remove(&self.fid);
1016 for sl in &mut self.slots {
1017 sl.delete(ctx)
1018 }
1019 }
1020
1021 fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
1022 for sl in &mut self.slots {
1023 sl.cur = None;
1024 sl.pred.sleep(ctx);
1025 }
1026 }
1027}
1028
1029graphix_derive::defpackage! {
1032 builtins => [
1033 Concat,
1034 Cons,
1035 Drop_ as Drop_,
1036 Enumerate_ as Enumerate_,
1037 Flatten,
1038 FromArray,
1039 Head,
1040 IsEmpty,
1041 Len,
1042 ListFilter as ListFilter<GXRt<X>, X::UserEvent>,
1043 ListFilterMap as ListFilterMap<GXRt<X>, X::UserEvent>,
1044 ListFind as ListFind<GXRt<X>, X::UserEvent>,
1045 ListFindMap as ListFindMap<GXRt<X>, X::UserEvent>,
1046 ListFlatMap as ListFlatMap<GXRt<X>, X::UserEvent>,
1047 ListFold as ListFold<GXRt<X>, X::UserEvent>,
1048 ListInit as ListInit<GXRt<X>, X::UserEvent>,
1049 ListIterBI,
1050 ListIterQ,
1051 ListMap as ListMap<GXRt<X>, X::UserEvent>,
1052 Nil,
1053 Nth,
1054 Reverse,
1055 Singleton,
1056 Sort,
1057 Tail,
1058 Take,
1059 ToArray,
1060 Uncons,
1061 Unzip,
1062 Zip,
1063 ],
1064}