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