graphix_compiler/node/
mod.rs

1use crate::{
2    env,
3    expr::{Expr, ExprId, ExprKind, ModPath},
4    typ::{TVal, TVar, Type},
5    wrap, BindId, CFlag, Event, ExecCtx, Node, Refs, Rt, Scope, Update, UserEvent,
6};
7use anyhow::{bail, Context, Result};
8use arcstr::{literal, ArcStr};
9use compiler::compile;
10use enumflags2::BitFlags;
11use netidx_value::{Typ, Value};
12use std::{cell::RefCell, sync::LazyLock};
13use triomphe::Arc;
14
15pub(crate) mod array;
16pub(crate) mod bind;
17pub(crate) mod callsite;
18pub(crate) mod compiler;
19pub(crate) mod data;
20pub(crate) mod dynamic;
21pub(crate) mod error;
22pub mod genn;
23pub(crate) mod lambda;
24pub(crate) mod map;
25pub(crate) mod op;
26pub(crate) mod pattern;
27pub(crate) mod select;
28
29#[macro_export]
30macro_rules! wrap {
31    ($n:expr, $e:expr) => {
32        match $e {
33            Ok(x) => Ok(x),
34            e => {
35                anyhow::Context::context(e, $crate::expr::ErrorContext($n.spec().clone()))
36            }
37        }
38    };
39}
40
41#[macro_export]
42macro_rules! update_args {
43    ($args:expr, $ctx:expr, $event:expr) => {{
44        let mut updated = false;
45        let mut determined = true;
46        for n in $args.iter_mut() {
47            updated |= n.update($ctx, $event);
48            determined &= n.cached.is_some();
49        }
50        (updated, determined)
51    }};
52}
53
54#[macro_export]
55macro_rules! deref_typ {
56    ($name:literal, $ctx:expr, $typ:expr, $($pat:pat => $body:expr),+) => {
57        $typ.with_deref(|typ| {
58            let mut typ = typ.cloned();
59            let mut hist: poolshark::local::LPooled<fxhash::FxHashSet<usize>> = poolshark::local::LPooled::take();
60            loop {
61                match &typ {
62                    $($pat => break $body),+,
63                    Some(rt @ Type::Ref { .. }) => {
64                        let rt = rt.lookup_ref(&$ctx.env)?;
65                        if hist.insert(rt as *const _ as usize) {
66                            typ = Some(rt.clone());
67                        } else {
68                            $crate::format_with_flags(PrintFlag::DerefTVars, || {
69                                anyhow::bail!("expected {} not {rt}", $name)
70                            })?
71                        }
72                    }
73                    Some(t) => $crate::format_with_flags(PrintFlag::DerefTVars, || {
74                        anyhow::bail!("expected {} not {t}", $name)
75                    })?,
76                    None => anyhow::bail!("type must be known, annotations needed"),
77                }
78            }
79        })
80    };
81}
82
83static NOP: LazyLock<Arc<Expr>> = LazyLock::new(|| {
84    Arc::new(
85        ExprKind::Constant(Value::String(literal!("nop"))).to_expr(Default::default()),
86    )
87});
88
89#[derive(Debug)]
90pub(crate) struct Nop {
91    pub typ: Type,
92}
93
94impl Nop {
95    pub(crate) fn new<R: Rt, E: UserEvent>(typ: Type) -> Node<R, E> {
96        Box::new(Nop { typ })
97    }
98}
99
100impl<R: Rt, E: UserEvent> Update<R, E> for Nop {
101    fn update(
102        &mut self,
103        _ctx: &mut ExecCtx<R, E>,
104        _event: &mut Event<E>,
105    ) -> Option<Value> {
106        None
107    }
108
109    fn delete(&mut self, _ctx: &mut ExecCtx<R, E>) {}
110
111    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
112
113    fn typecheck(&mut self, _ctx: &mut ExecCtx<R, E>) -> Result<()> {
114        Ok(())
115    }
116
117    fn spec(&self) -> &Expr {
118        &NOP
119    }
120
121    fn typ(&self) -> &Type {
122        &self.typ
123    }
124
125    fn refs(&self, _refs: &mut Refs) {}
126}
127
128#[derive(Debug)]
129struct Cached<R: Rt, E: UserEvent> {
130    cached: Option<Value>,
131    node: Node<R, E>,
132}
133
134impl<R: Rt, E: UserEvent> Cached<R, E> {
135    fn new(node: Node<R, E>) -> Self {
136        Self { cached: None, node }
137    }
138
139    /// update the node, return whether the node updated. If it did,
140    /// the updated value will be stored in the cached field, if not,
141    /// the previous value will remain there.
142    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> bool {
143        match self.node.update(ctx, event) {
144            None => false,
145            Some(v) => {
146                self.cached = Some(v);
147                true
148            }
149        }
150    }
151
152    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
153        self.cached = None;
154        self.node.sleep(ctx)
155    }
156}
157
158#[derive(Debug)]
159pub(crate) struct Use {
160    spec: Expr,
161    scope: ModPath,
162    name: ModPath,
163}
164
165impl Use {
166    pub(crate) fn compile<R: Rt, E: UserEvent>(
167        ctx: &mut ExecCtx<R, E>,
168        spec: Expr,
169        scope: &Scope,
170        name: &ModPath,
171    ) -> Result<Node<R, E>> {
172        match ctx.env.canonical_modpath(&scope.lexical, name) {
173            None => bail!("at {} no such module {name}", spec.pos),
174            Some(_) => {
175                let used = ctx.env.used.get_or_default_cow(scope.lexical.clone());
176                Arc::make_mut(used).push(name.clone());
177                Ok(Box::new(Self {
178                    spec,
179                    scope: scope.lexical.clone(),
180                    name: name.clone(),
181                }))
182            }
183        }
184    }
185}
186
187impl<R: Rt, E: UserEvent> Update<R, E> for Use {
188    fn update(
189        &mut self,
190        _ctx: &mut ExecCtx<R, E>,
191        _event: &mut Event<E>,
192    ) -> Option<Value> {
193        None
194    }
195
196    fn typecheck(&mut self, _ctx: &mut ExecCtx<R, E>) -> Result<()> {
197        Ok(())
198    }
199
200    fn refs(&self, _refs: &mut Refs) {}
201
202    fn spec(&self) -> &Expr {
203        &self.spec
204    }
205
206    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
207        if let Some(used) = ctx.env.used.get_mut_cow(&self.scope) {
208            Arc::make_mut(used).retain(|n| n != &self.name);
209            if used.is_empty() {
210                ctx.env.used.remove_cow(&self.scope);
211            }
212        }
213    }
214
215    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
216
217    fn typ(&self) -> &Type {
218        &Type::Bottom
219    }
220}
221
222#[derive(Debug)]
223pub(crate) struct TypeDef {
224    spec: Expr,
225    scope: ModPath,
226    name: ArcStr,
227}
228
229impl TypeDef {
230    pub(crate) fn compile<R: Rt, E: UserEvent>(
231        ctx: &mut ExecCtx<R, E>,
232        spec: Expr,
233        scope: &Scope,
234        name: &ArcStr,
235        params: &Arc<[(TVar, Option<Type>)]>,
236        typ: &Type,
237    ) -> Result<Node<R, E>> {
238        let typ = typ.scope_refs(&scope.lexical);
239        ctx.env
240            .deftype(&scope.lexical, name, params.clone(), typ)
241            .with_context(|| format!("in typedef at {}", spec.pos))?;
242        let name = name.clone();
243        Ok(Box::new(Self { spec, scope: scope.lexical.clone(), name }))
244    }
245}
246
247impl<R: Rt, E: UserEvent> Update<R, E> for TypeDef {
248    fn update(
249        &mut self,
250        _ctx: &mut ExecCtx<R, E>,
251        _event: &mut Event<E>,
252    ) -> Option<Value> {
253        None
254    }
255
256    fn typecheck(&mut self, _ctx: &mut ExecCtx<R, E>) -> Result<()> {
257        Ok(())
258    }
259
260    fn refs(&self, _refs: &mut Refs) {}
261
262    fn spec(&self) -> &Expr {
263        &self.spec
264    }
265
266    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
267        ctx.env.undeftype(&self.scope, &self.name)
268    }
269
270    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
271
272    fn typ(&self) -> &Type {
273        &Type::Bottom
274    }
275}
276
277#[derive(Debug)]
278pub(crate) struct Constant {
279    spec: Arc<Expr>,
280    value: Value,
281    typ: Type,
282}
283
284impl Constant {
285    pub(crate) fn compile<R: Rt, E: UserEvent>(
286        spec: Expr,
287        value: &Value,
288    ) -> Result<Node<R, E>> {
289        let spec = Arc::new(spec);
290        let value = value.clone();
291        let typ = Type::Primitive(Typ::get(&value).into());
292        Ok(Box::new(Self { spec, value, typ }))
293    }
294}
295
296impl<R: Rt, E: UserEvent> Update<R, E> for Constant {
297    fn update(
298        &mut self,
299        _ctx: &mut ExecCtx<R, E>,
300        event: &mut Event<E>,
301    ) -> Option<Value> {
302        if event.init {
303            Some(self.value.clone())
304        } else {
305            None
306        }
307    }
308
309    fn delete(&mut self, _ctx: &mut ExecCtx<R, E>) {}
310
311    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
312
313    fn refs(&self, _refs: &mut Refs) {}
314
315    fn typ(&self) -> &Type {
316        &self.typ
317    }
318
319    fn typecheck(&mut self, _ctx: &mut ExecCtx<R, E>) -> Result<()> {
320        Ok(())
321    }
322
323    fn spec(&self) -> &Expr {
324        &self.spec
325    }
326}
327
328// used for both mod and do
329#[derive(Debug)]
330pub(crate) struct Block<R: Rt, E: UserEvent> {
331    module: bool,
332    spec: Expr,
333    children: Box<[Node<R, E>]>,
334}
335
336impl<R: Rt, E: UserEvent> Block<R, E> {
337    pub(crate) fn compile(
338        ctx: &mut ExecCtx<R, E>,
339        flags: BitFlags<CFlag>,
340        spec: Expr,
341        scope: &Scope,
342        top_id: ExprId,
343        module: bool,
344        exprs: &Arc<[Expr]>,
345    ) -> Result<Node<R, E>> {
346        let children = exprs
347            .iter()
348            .map(|e| compile(ctx, flags, e.clone(), scope, top_id))
349            .collect::<Result<Box<[Node<R, E>]>>>()?;
350        Ok(Box::new(Self { module, spec, children }))
351    }
352}
353
354impl<R: Rt, E: UserEvent> Update<R, E> for Block<R, E> {
355    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> Option<Value> {
356        self.children.iter_mut().fold(None, |_, n| n.update(ctx, event))
357    }
358
359    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
360        for n in &mut self.children {
361            n.delete(ctx)
362        }
363    }
364
365    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
366        for n in &mut self.children {
367            n.sleep(ctx)
368        }
369    }
370
371    fn refs(&self, refs: &mut Refs) {
372        for n in &self.children {
373            n.refs(refs)
374        }
375    }
376
377    fn typ(&self) -> &Type {
378        &self.children.last().map(|n| n.typ()).unwrap_or(&Type::Bottom)
379    }
380
381    fn typecheck(&mut self, ctx: &mut ExecCtx<R, E>) -> Result<()> {
382        for n in &mut self.children {
383            if self.module {
384                wrap!(n, n.typecheck(ctx)).with_context(|| self.spec.ori.clone())?
385            } else {
386                wrap!(n, n.typecheck(ctx))?
387            }
388        }
389        Ok(())
390    }
391
392    fn spec(&self) -> &Expr {
393        &self.spec
394    }
395}
396
397#[derive(Debug)]
398pub(crate) struct StringInterpolate<R: Rt, E: UserEvent> {
399    spec: Expr,
400    typ: Type,
401    typs: Box<[Type]>,
402    args: Box<[Cached<R, E>]>,
403}
404
405impl<R: Rt, E: UserEvent> StringInterpolate<R, E> {
406    pub(crate) fn compile(
407        ctx: &mut ExecCtx<R, E>,
408        flags: BitFlags<CFlag>,
409        spec: Expr,
410        scope: &Scope,
411        top_id: ExprId,
412        args: &[Expr],
413    ) -> Result<Node<R, E>> {
414        let args: Box<[Cached<R, E>]> = args
415            .iter()
416            .map(|e| Ok(Cached::new(compile(ctx, flags, e.clone(), scope, top_id)?)))
417            .collect::<Result<_>>()?;
418        let typs = args.iter().map(|c| c.node.typ().clone()).collect();
419        let typ = Type::Primitive(Typ::String.into());
420        Ok(Box::new(Self { spec, typ, typs, args }))
421    }
422}
423
424impl<R: Rt, E: UserEvent> Update<R, E> for StringInterpolate<R, E> {
425    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> Option<Value> {
426        use std::fmt::Write;
427        thread_local! {
428            static BUF: RefCell<String> = RefCell::new(String::new());
429        }
430        let (updated, determined) = update_args!(self.args, ctx, event);
431        if updated && determined {
432            BUF.with_borrow_mut(|buf| {
433                buf.clear();
434                for (typ, c) in self.typs.iter().zip(self.args.iter()) {
435                    match c.cached.as_ref().unwrap() {
436                        Value::String(s) => write!(buf, "{s}"),
437                        v => write!(buf, "{}", TVal { env: &ctx.env, typ, v }),
438                    }
439                    .unwrap()
440                }
441                Some(Value::String(buf.as_str().into()))
442            })
443        } else {
444            None
445        }
446    }
447
448    fn spec(&self) -> &Expr {
449        &self.spec
450    }
451
452    fn typ(&self) -> &Type {
453        &self.typ
454    }
455
456    fn refs(&self, refs: &mut Refs) {
457        for a in &self.args {
458            a.node.refs(refs)
459        }
460    }
461
462    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
463        for n in &mut self.args {
464            n.node.delete(ctx)
465        }
466    }
467
468    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
469        for n in &mut self.args {
470            n.sleep(ctx);
471        }
472    }
473
474    fn typecheck(&mut self, ctx: &mut ExecCtx<R, E>) -> Result<()> {
475        for (i, a) in self.args.iter_mut().enumerate() {
476            wrap!(a.node, a.node.typecheck(ctx))?;
477            self.typs[i] = a.node.typ().with_deref(|t| match t {
478                None => Type::Any,
479                Some(t) => t.clone(),
480            });
481        }
482        Ok(())
483    }
484}
485
486#[derive(Debug)]
487pub(crate) struct Connect<R: Rt, E: UserEvent> {
488    spec: Expr,
489    node: Node<R, E>,
490    id: BindId,
491}
492
493impl<R: Rt, E: UserEvent> Connect<R, E> {
494    pub(crate) fn compile(
495        ctx: &mut ExecCtx<R, E>,
496        flags: BitFlags<CFlag>,
497        spec: Expr,
498        scope: &Scope,
499        top_id: ExprId,
500        name: &ModPath,
501        value: &Expr,
502    ) -> Result<Node<R, E>> {
503        let id = match ctx.env.lookup_bind(&scope.lexical, name) {
504            None => bail!("at {} {name} is undefined", spec.pos),
505            Some((_, env::Bind { id, .. })) => *id,
506        };
507        let node = compile(ctx, flags, value.clone(), scope, top_id)?;
508        Ok(Box::new(Self { spec, node, id }))
509    }
510}
511
512impl<R: Rt, E: UserEvent> Update<R, E> for Connect<R, E> {
513    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> Option<Value> {
514        if let Some(v) = self.node.update(ctx, event) {
515            ctx.set_var(self.id, v)
516        }
517        None
518    }
519
520    fn spec(&self) -> &Expr {
521        &self.spec
522    }
523
524    fn typ(&self) -> &Type {
525        &Type::Bottom
526    }
527
528    fn refs(&self, refs: &mut Refs) {
529        self.node.refs(refs)
530    }
531
532    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
533        self.node.delete(ctx)
534    }
535
536    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
537        self.node.sleep(ctx);
538    }
539
540    fn typecheck(&mut self, ctx: &mut ExecCtx<R, E>) -> Result<()> {
541        wrap!(self.node, self.node.typecheck(ctx))?;
542        let bind = match ctx.env.by_id.get(&self.id) {
543            None => bail!("BUG missing bind {:?}", self.id),
544            Some(bind) => bind,
545        };
546        wrap!(self, bind.typ.check_contains(&ctx.env, self.node.typ()))
547    }
548}
549
550#[derive(Debug)]
551pub(crate) struct ConnectDeref<R: Rt, E: UserEvent> {
552    spec: Expr,
553    rhs: Cached<R, E>,
554    src_id: BindId,
555    target_id: Option<BindId>,
556    top_id: ExprId,
557}
558
559impl<R: Rt, E: UserEvent> ConnectDeref<R, E> {
560    pub(crate) fn compile(
561        ctx: &mut ExecCtx<R, E>,
562        flags: BitFlags<CFlag>,
563        spec: Expr,
564        scope: &Scope,
565        top_id: ExprId,
566        name: &ModPath,
567        value: &Expr,
568    ) -> Result<Node<R, E>> {
569        let src_id = match ctx.env.lookup_bind(&scope.lexical, name) {
570            None => bail!("at {} {name} is undefined", spec.pos),
571            Some((_, env::Bind { id, .. })) => *id,
572        };
573        ctx.rt.ref_var(src_id, top_id);
574        let rhs = Cached::new(compile(ctx, flags, value.clone(), scope, top_id)?);
575        Ok(Box::new(Self { spec, rhs, src_id, target_id: None, top_id }))
576    }
577}
578
579impl<R: Rt, E: UserEvent> Update<R, E> for ConnectDeref<R, E> {
580    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> Option<Value> {
581        let mut up = self.rhs.update(ctx, event);
582        if let Some(Value::U64(id)) = event.variables.get(&self.src_id) {
583            if let Some(target_id) = ctx.env.byref_chain.get(&BindId::from(*id)) {
584                self.target_id = Some(*target_id);
585                up = true;
586            }
587        }
588        if up {
589            if let Some(v) = &self.rhs.cached {
590                if let Some(id) = self.target_id {
591                    ctx.set_var(id, v.clone())
592                }
593            }
594        }
595        None
596    }
597
598    fn spec(&self) -> &Expr {
599        &self.spec
600    }
601
602    fn typ(&self) -> &Type {
603        &Type::Bottom
604    }
605
606    fn refs(&self, refs: &mut Refs) {
607        refs.refed.insert(self.src_id);
608        self.rhs.node.refs(refs)
609    }
610
611    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
612        ctx.rt.unref_var(self.src_id, self.top_id);
613        self.rhs.node.delete(ctx)
614    }
615
616    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
617        self.rhs.sleep(ctx);
618    }
619
620    fn typecheck(&mut self, ctx: &mut ExecCtx<R, E>) -> Result<()> {
621        wrap!(self.rhs.node, self.rhs.node.typecheck(ctx))?;
622        let bind = match ctx.env.by_id.get(&self.src_id) {
623            None => bail!("BUG missing bind {:?}", self.src_id),
624            Some(bind) => bind,
625        };
626        let typ = Type::ByRef(Arc::new(self.rhs.node.typ().clone()));
627        wrap!(self, bind.typ.check_contains(&ctx.env, &typ))
628    }
629}
630
631#[derive(Debug)]
632pub(crate) struct TypeCast<R: Rt, E: UserEvent> {
633    spec: Expr,
634    typ: Type,
635    target: Type,
636    n: Node<R, E>,
637}
638
639impl<R: Rt, E: UserEvent> TypeCast<R, E> {
640    pub(crate) fn compile(
641        ctx: &mut ExecCtx<R, E>,
642        flags: BitFlags<CFlag>,
643        spec: Expr,
644        scope: &Scope,
645        top_id: ExprId,
646        expr: &Expr,
647        typ: &Type,
648    ) -> Result<Node<R, E>> {
649        let n = compile(ctx, flags, expr.clone(), scope, top_id)?;
650        let target = typ.scope_refs(&scope.lexical);
651        if let Err(e) = target.check_cast(&ctx.env) {
652            bail!("in cast at {} {e}", spec.pos);
653        }
654        let typ = target.union(&ctx.env, &Type::Primitive(Typ::Error.into()))?;
655        Ok(Box::new(Self { spec, typ, target, n }))
656    }
657}
658
659impl<R: Rt, E: UserEvent> Update<R, E> for TypeCast<R, E> {
660    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> Option<Value> {
661        self.n.update(ctx, event).map(|v| self.target.cast_value(&ctx.env, v))
662    }
663
664    fn spec(&self) -> &Expr {
665        &self.spec
666    }
667
668    fn typ(&self) -> &Type {
669        &self.typ
670    }
671
672    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
673        self.n.delete(ctx)
674    }
675
676    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
677        self.n.sleep(ctx);
678    }
679
680    fn refs(&self, refs: &mut Refs) {
681        self.n.refs(refs)
682    }
683
684    fn typecheck(&mut self, ctx: &mut ExecCtx<R, E>) -> Result<()> {
685        Ok(wrap!(self.n, self.n.typecheck(ctx))?)
686    }
687}
688
689#[derive(Debug)]
690pub(crate) struct Any<R: Rt, E: UserEvent> {
691    spec: Expr,
692    typ: Type,
693    n: Box<[Node<R, E>]>,
694}
695
696impl<R: Rt, E: UserEvent> Any<R, E> {
697    pub(crate) fn compile(
698        ctx: &mut ExecCtx<R, E>,
699        flags: BitFlags<CFlag>,
700        spec: Expr,
701        scope: &Scope,
702        top_id: ExprId,
703        args: &[Expr],
704    ) -> Result<Node<R, E>> {
705        let n = args
706            .iter()
707            .map(|e| compile(ctx, flags, e.clone(), scope, top_id))
708            .collect::<Result<Box<[_]>>>()?;
709        let typ =
710            Type::Set(Arc::from_iter(n.iter().map(|n| n.typ().clone()))).normalize();
711        Ok(Box::new(Self { spec, typ, n }))
712    }
713}
714
715impl<R: Rt, E: UserEvent> Update<R, E> for Any<R, E> {
716    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> Option<Value> {
717        self.n
718            .iter_mut()
719            .filter_map(|s| s.update(ctx, event))
720            .fold(None, |r, v| r.or(Some(v)))
721    }
722
723    fn spec(&self) -> &Expr {
724        &self.spec
725    }
726
727    fn typ(&self) -> &Type {
728        &self.typ
729    }
730
731    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
732        self.n.iter_mut().for_each(|n| n.delete(ctx))
733    }
734
735    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
736        self.n.iter_mut().for_each(|n| n.sleep(ctx))
737    }
738
739    fn refs(&self, refs: &mut Refs) {
740        self.n.iter().for_each(|n| n.refs(refs))
741    }
742
743    fn typecheck(&mut self, ctx: &mut ExecCtx<R, E>) -> Result<()> {
744        for n in self.n.iter_mut() {
745            wrap!(n, n.typecheck(ctx))?
746        }
747        let rtyp = Type::Primitive(BitFlags::empty());
748        let rtyp = wrap!(
749            self,
750            self.n.iter().fold(Ok(rtyp), |rtype, n| n.typ().union(&ctx.env, &rtype?))
751        )?;
752        Ok(self.typ.check_contains(&ctx.env, &rtyp)?)
753    }
754}
755
756#[derive(Debug)]
757struct Sample<R: Rt, E: UserEvent> {
758    spec: Expr,
759    triggered: usize,
760    typ: Type,
761    id: BindId,
762    top_id: ExprId,
763    trigger: Node<R, E>,
764    arg: Cached<R, E>,
765}
766
767impl<R: Rt, E: UserEvent> Sample<R, E> {
768    pub(crate) fn compile(
769        ctx: &mut ExecCtx<R, E>,
770        flags: BitFlags<CFlag>,
771        spec: Expr,
772        scope: &Scope,
773        top_id: ExprId,
774        lhs: &Arc<Expr>,
775        rhs: &Arc<Expr>,
776    ) -> Result<Node<R, E>> {
777        let id = BindId::new();
778        ctx.rt.ref_var(id, top_id);
779        let trigger = compile(ctx, flags, (**lhs).clone(), scope, top_id)?;
780        let arg = Cached::new(compile(ctx, flags, (**rhs).clone(), scope, top_id)?);
781        let typ = arg.node.typ().clone();
782        Ok(Box::new(Self { triggered: 0, id, top_id, spec, typ, trigger, arg }))
783    }
784}
785
786impl<R: Rt, E: UserEvent> Update<R, E> for Sample<R, E> {
787    fn update(&mut self, ctx: &mut ExecCtx<R, E>, event: &mut Event<E>) -> Option<Value> {
788        if let Some(_) = self.trigger.update(ctx, event) {
789            self.triggered += 1;
790        }
791        self.arg.update(ctx, event);
792        let var = event.variables.get(&self.id).cloned();
793        let res = if self.triggered > 0 && self.arg.cached.is_some() && var.is_none() {
794            self.triggered -= 1;
795            self.arg.cached.clone()
796        } else {
797            var
798        };
799        if self.arg.cached.is_some() {
800            while self.triggered > 0 {
801                self.triggered -= 1;
802                ctx.rt.set_var(self.id, self.arg.cached.clone().unwrap());
803            }
804        }
805        res
806    }
807
808    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
809        ctx.rt.unref_var(self.id, self.top_id);
810        self.arg.node.delete(ctx);
811        self.trigger.delete(ctx);
812    }
813
814    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
815        self.arg.sleep(ctx);
816        self.trigger.sleep(ctx);
817    }
818
819    fn spec(&self) -> &Expr {
820        &self.spec
821    }
822
823    fn typ(&self) -> &Type {
824        &self.typ
825    }
826
827    fn refs(&self, refs: &mut Refs) {
828        refs.refed.insert(self.id);
829        self.arg.node.refs(refs);
830        self.trigger.refs(refs);
831    }
832
833    fn typecheck(&mut self, ctx: &mut ExecCtx<R, E>) -> Result<()> {
834        wrap!(self.trigger, self.trigger.typecheck(ctx))?;
835        wrap!(self.arg.node, self.arg.node.typecheck(ctx))
836    }
837}