Skip to main content

graphix_compiler/node/
mod.rs

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