netidx_bscript/node/
mod.rs

1use crate::{
2    env::LambdaDef,
3    err,
4    expr::{Expr, ExprId, ExprKind, ModPath},
5    node::pattern::PatternNode,
6    typ::{FnType, NoRefs, Type},
7    Apply, BindId, Ctx, Event, ExecCtx, LambdaId, UserEvent,
8};
9use anyhow::{anyhow, bail, Result};
10use arcstr::{literal, ArcStr};
11use compact_str::format_compact;
12use fxhash::FxHashMap;
13use netidx::{publisher::Typ, subscriber::Value};
14use netidx_netproto::valarray::ValArray;
15use pattern::StructPatternNode;
16use smallvec::{smallvec, SmallVec};
17use std::{
18    cell::RefCell, collections::HashMap, fmt, iter, marker::PhantomData, mem, sync::Arc,
19};
20use triomphe::Arc as TArc;
21
22mod compiler;
23mod lambda;
24pub mod pattern;
25mod typecheck;
26
27#[derive(Debug)]
28pub struct Cached<C: Ctx, E: UserEvent> {
29    pub cached: Option<Value>,
30    pub node: Node<C, E>,
31}
32
33impl<C: Ctx, E: UserEvent> Default for Cached<C, E> {
34    fn default() -> Self {
35        Self { cached: None, node: Default::default() }
36    }
37}
38
39impl<C: Ctx, E: UserEvent> Cached<C, E> {
40    pub fn new(node: Node<C, E>) -> Self {
41        Self { cached: None, node }
42    }
43
44    /// update the node, return whether the node updated. If it did,
45    /// the updated value will be stored in the cached field, if not,
46    /// the previous value will remain there.
47    pub fn update(&mut self, ctx: &mut ExecCtx<C, E>, event: &mut Event<E>) -> bool {
48        match self.node.update(ctx, event) {
49            None => false,
50            Some(v) => {
51                self.cached = Some(v);
52                true
53            }
54        }
55    }
56
57    /// update the node, return true if the node updated AND the new
58    /// value is different from the old value. The cached field will
59    /// only be updated if the value changed.
60    pub fn update_changed(
61        &mut self,
62        ctx: &mut ExecCtx<C, E>,
63        event: &mut Event<E>,
64    ) -> bool {
65        match self.node.update(ctx, event) {
66            v @ Some(_) if v != self.cached => {
67                self.cached = v;
68                true
69            }
70            Some(_) | None => false,
71        }
72    }
73}
74
75pub struct CallSite<C: Ctx, E: UserEvent> {
76    ftype: TArc<FnType<NoRefs>>,
77    fnode: Node<C, E>,
78    args: Vec<Node<C, E>>,
79    arg_spec: FxHashMap<ArcStr, bool>, // true if arg is using the default value
80    function: Option<(LambdaId, Box<dyn Apply<C, E> + Send + Sync>)>,
81    top_id: ExprId,
82}
83
84impl<C: Ctx, E: UserEvent> fmt::Debug for CallSite<C, E> {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        write!(f, "CallSite({:?}, [", self.fnode)?;
87        for (i, n) in self.args.iter().enumerate() {
88            if i < self.args.len() - 1 {
89                write!(f, "{:?}, ", n)?;
90            } else {
91                write!(f, "{:?}", n)?;
92            }
93        }
94        write!(f, "])")
95    }
96}
97
98impl<C: Ctx, E: UserEvent> Default for CallSite<C, E> {
99    fn default() -> Self {
100        Self {
101            ftype: Default::default(),
102            fnode: Default::default(),
103            args: vec![],
104            arg_spec: HashMap::default(),
105            function: None,
106            top_id: ExprId::new(),
107        }
108    }
109}
110
111impl<C: Ctx, E: UserEvent> CallSite<C, E> {
112    fn bind(&mut self, ctx: &mut ExecCtx<C, E>, f: Arc<LambdaDef<C, E>>) -> Result<()> {
113        macro_rules! compile_default {
114            ($i:expr, $f:expr) => {{
115                match &$f.argspec[$i].labeled {
116                    None | Some(None) => bail!("expected default value"),
117                    Some(Some(expr)) => {
118                        let orig_env = ctx.env.restore_lexical_env(&$f.env);
119                        let n =
120                            compiler::compile(ctx, expr.clone(), &$f.scope, self.top_id);
121                        ctx.env = ctx.env.merge_lexical(&orig_env);
122                        n?
123                    }
124                }
125            }};
126        }
127        for (name, map) in self.ftype.map_argpos(&f.typ) {
128            let is_default = *self.arg_spec.get(&name).unwrap_or(&false);
129            match map {
130                (Some(si), Some(oi)) if si == oi => {
131                    if is_default {
132                        self.args[si] = compile_default!(si, f);
133                    }
134                }
135                (Some(si), Some(oi)) if si < oi => {
136                    let mut i = si;
137                    while i < oi {
138                        self.args.swap(i, i + 1);
139                        i += 1;
140                    }
141                    if is_default {
142                        self.args[i] = compile_default!(si, f);
143                    }
144                }
145                (Some(si), Some(oi)) if oi < si => {
146                    let mut i = si;
147                    while i > oi {
148                        self.args.swap(i, i - 1);
149                        i -= 1
150                    }
151                    if is_default {
152                        self.args[i] = compile_default!(i, f);
153                    }
154                }
155                (Some(_), Some(_)) => unreachable!(),
156                (Some(i), None) => {
157                    self.args.remove(i);
158                }
159                (None, Some(i)) => self.args.insert(i, compile_default!(i, f)),
160                (None, None) => bail!("unexpected args"),
161            }
162        }
163        let rf = (f.init)(ctx, &self.args, self.top_id)?;
164        self.ftype = f.typ.clone();
165        self.function = Some((f.id, rf));
166        Ok(())
167    }
168
169    fn update(&mut self, ctx: &mut ExecCtx<C, E>, event: &mut Event<E>) -> Option<Value> {
170        macro_rules! error {
171            ($m:literal) => {{
172                let m = format_compact!($m);
173                return Some(Value::Error(m.as_str().into()));
174            }};
175        }
176        let bound = match (&self.function, self.fnode.update(ctx, event)) {
177            (_, None) => false,
178            (Some((cid, _)), Some(Value::U64(id))) if cid.0 == id => false,
179            (_, Some(Value::U64(id))) => match ctx.env.lambdas.get(&LambdaId(id)) {
180                None => error!("no such function {id:?}"),
181                Some(lb) => match lb.upgrade() {
182                    None => error!("function {id:?} is no longer callable"),
183                    Some(lb) => {
184                        if let Err(e) = self.bind(ctx, lb) {
185                            error!("failed to bind to lambda {e}")
186                        }
187                        true
188                    }
189                },
190            },
191            (_, Some(v)) => error!("invalid function {v}"),
192        };
193        match &mut self.function {
194            None => None,
195            Some((_, f)) if !bound => f.update(ctx, &mut self.args, event),
196            Some((_, f)) => {
197                let init = mem::replace(&mut event.init, true);
198                let mut set = vec![];
199                f.refs(&mut |id| {
200                    if !event.variables.contains_key(&id) {
201                        if let Some(v) = ctx.cached.get(&id) {
202                            event.variables.insert(id, v.clone());
203                            set.push(id);
204                        }
205                    }
206                });
207                let res = f.update(ctx, &mut self.args, event);
208                event.init = init;
209                for id in set {
210                    event.variables.remove(&id);
211                }
212                res
213            }
214        }
215    }
216
217    fn delete(self, ctx: &mut ExecCtx<C, E>) {
218        let Self { ftype: _, fnode, args, arg_spec: _, function, top_id: _ } = self;
219        if let Some((_, mut f)) = function {
220            f.delete(ctx)
221        }
222        fnode.delete(ctx);
223        for n in args {
224            n.delete(ctx)
225        }
226    }
227}
228
229#[derive(Debug)]
230pub struct SelectNode<C: Ctx, E: UserEvent> {
231    selected: Option<usize>,
232    arg: Cached<C, E>,
233    arms: Box<[(PatternNode<C, E>, Cached<C, E>)]>,
234}
235
236impl<C: Ctx, E: UserEvent> Default for SelectNode<C, E> {
237    fn default() -> Self {
238        Self { selected: None, arg: Default::default(), arms: Box::from_iter([]) }
239    }
240}
241
242impl<C: Ctx, E: UserEvent> SelectNode<C, E> {
243    fn update(&mut self, ctx: &mut ExecCtx<C, E>, event: &mut Event<E>) -> Option<Value> {
244        let SelectNode { selected, arg, arms } = self;
245        let mut val_up: SmallVec<[bool; 64]> = smallvec![];
246        let arg_up = arg.update(ctx, event);
247        macro_rules! bind {
248            ($i:expr) => {{
249                if let Some(arg) = arg.cached.as_ref() {
250                    arms[$i].0.bind_event(event, arg);
251                }
252            }};
253        }
254        macro_rules! update {
255            () => {
256                for (_, val) in arms.iter_mut() {
257                    val_up.push(val.update(ctx, event));
258                }
259            };
260        }
261        macro_rules! val {
262            ($i:expr) => {{
263                if val_up[$i] {
264                    arms[$i].1.cached.clone()
265                } else {
266                    None
267                }
268            }};
269        }
270        let mut pat_up = false;
271        for (pat, _) in arms.iter_mut() {
272            if arg_up && pat.guard.is_some() {
273                if let Some(arg) = arg.cached.as_ref() {
274                    pat.bind_event(event, arg);
275                }
276            }
277            pat_up |= pat.update(ctx, event);
278            if arg_up && pat.guard.is_some() {
279                pat.unbind_event(event);
280            }
281        }
282        if !arg_up && !pat_up {
283            update!();
284            selected.and_then(|i| val!(i))
285        } else {
286            let sel = match arg.cached.as_ref() {
287                None => None,
288                Some(v) => {
289                    let typ = Typ::get(v);
290                    arms.iter().enumerate().find_map(|(i, (pat, _))| {
291                        if pat.is_match(typ, v) {
292                            Some(i)
293                        } else {
294                            None
295                        }
296                    })
297                }
298            };
299            match (sel, *selected) {
300                (Some(i), Some(j)) if i == j => {
301                    if arg_up {
302                        bind!(i);
303                    }
304                    update!();
305                    val!(i)
306                }
307                (Some(i), Some(_) | None) => {
308                    bind!(i);
309                    update!();
310                    *selected = Some(i);
311                    val_up[i] = true;
312                    val!(i)
313                }
314                (None, Some(_)) => {
315                    update!();
316                    *selected = None;
317                    None
318                }
319                (None, None) => {
320                    update!();
321                    None
322                }
323            }
324        }
325    }
326
327    fn delete(self, ctx: &mut ExecCtx<C, E>) {
328        let mut ids: SmallVec<[BindId; 8]> = smallvec![];
329        let Self { selected: _, arg, arms } = self;
330        arg.node.delete(ctx);
331        for (pat, arg) in arms {
332            arg.node.delete(ctx);
333            pat.structure_predicate.ids(&mut |id| ids.push(id));
334            if let Some(n) = pat.guard {
335                n.node.delete(ctx);
336            }
337            for id in ids.drain(..) {
338                ctx.env.unbind_variable(id);
339            }
340        }
341    }
342
343    fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
344        let Self { selected: _, arg, arms } = self;
345        arg.node.refs(f);
346        for (pat, arg) in arms {
347            arg.node.refs(f);
348            pat.structure_predicate.ids(f);
349            if let Some(n) = &pat.guard {
350                n.node.refs(f);
351            }
352        }
353    }
354
355    fn typecheck(&mut self, ctx: &mut ExecCtx<C, E>) -> Result<Type<NoRefs>> {
356        self.arg.node.typecheck(ctx)?;
357        let mut rtype = Type::Bottom(PhantomData);
358        let mut mtype = Type::Bottom(PhantomData);
359        let mut itype = Type::Bottom(PhantomData);
360        for (pat, n) in self.arms.iter_mut() {
361            match &mut pat.guard {
362                Some(guard) => guard.node.typecheck(ctx)?,
363                None => mtype = mtype.union(&pat.type_predicate),
364            }
365            itype = itype.union(&pat.type_predicate);
366            n.node.typecheck(ctx)?;
367            rtype = rtype.union(&n.node.typ);
368        }
369        itype
370            .check_contains(&self.arg.node.typ)
371            .map_err(|e| anyhow!("missing match cases {e}"))?;
372        mtype
373            .check_contains(&self.arg.node.typ)
374            .map_err(|e| anyhow!("missing match cases {e}"))?;
375        self.arg.node.typ = self.arg.node.typ.normalize();
376        let mut atype = self.arg.node.typ.clone();
377        for (pat, _) in self.arms.iter() {
378            let can_match = atype.contains(&pat.type_predicate)
379                || pat.type_predicate.contains(&atype);
380            if !can_match {
381                bail!(
382                    "pattern {} will never match {}, unused match cases",
383                    pat.type_predicate,
384                    atype
385                )
386            }
387            if !pat.structure_predicate.is_refutable() && pat.guard.is_none() {
388                atype = atype.diff(&pat.type_predicate);
389            }
390        }
391        Ok(rtype)
392    }
393}
394
395#[derive(Debug)]
396pub struct ArrayRefNode<C: Ctx, E: UserEvent> {
397    pub source: Cached<C, E>,
398    pub i: Cached<C, E>,
399}
400
401impl<C: Ctx, E: UserEvent> Default for ArrayRefNode<C, E> {
402    fn default() -> Self {
403        Self { source: Default::default(), i: Default::default() }
404    }
405}
406
407impl<C: Ctx, E: UserEvent> ArrayRefNode<C, E> {
408    fn update(&mut self, ctx: &mut ExecCtx<C, E>, event: &mut Event<E>) -> Option<Value> {
409        let up = self.source.update(ctx, event);
410        let up = self.i.update(ctx, event) || up;
411        if !up {
412            return None;
413        }
414        let i = match &self.i.cached {
415            Some(Value::I64(i)) => *i,
416            Some(v) => match v.clone().cast_to::<i64>() {
417                Ok(i) => i,
418                Err(_) => return err!("op::index(array, index): expected an integer"),
419            },
420            None => return None,
421        };
422        match &self.source.cached {
423            Some(Value::Array(elts)) if i >= 0 => {
424                let i = i as usize;
425                if i < elts.len() {
426                    Some(elts[i].clone())
427                } else {
428                    err!("array index out of bounds")
429                }
430            }
431            Some(Value::Array(elts)) if i < 0 => {
432                let len = elts.len();
433                let i = len as i64 + i;
434                if i > 0 {
435                    Some(elts[i as usize].clone())
436                } else {
437                    err!("array index out of bounds")
438                }
439            }
440            None => None,
441            _ => err!("op::index(array, index): expected an array"),
442        }
443    }
444
445    pub fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
446        self.source.node.refs(f);
447        self.i.node.refs(f);
448    }
449
450    pub fn delete(self, ctx: &mut ExecCtx<C, E>) {
451        self.source.node.delete(ctx);
452        self.i.node.delete(ctx);
453    }
454}
455
456#[derive(Debug)]
457pub struct ArraySliceNode<C: Ctx, E: UserEvent> {
458    pub source: Cached<C, E>,
459    pub start: Option<Cached<C, E>>,
460    pub end: Option<Cached<C, E>>,
461}
462
463impl<C: Ctx, E: UserEvent> Default for ArraySliceNode<C, E> {
464    fn default() -> Self {
465        Self {
466            source: Default::default(),
467            start: Default::default(),
468            end: Default::default(),
469        }
470    }
471}
472
473impl<C: Ctx, E: UserEvent> ArraySliceNode<C, E> {
474    fn update(&mut self, ctx: &mut ExecCtx<C, E>, event: &mut Event<E>) -> Option<Value> {
475        macro_rules! number {
476            ($e:expr) => {
477                match $e.clone().cast_to::<usize>() {
478                    Ok(i) => i,
479                    Err(_) => return err!("expected a non negative number"),
480                }
481            };
482        }
483        macro_rules! bound {
484            ($bound:expr) => {{
485                match $bound.cached.as_ref() {
486                    None => return None,
487                    Some(Value::U64(i) | Value::V64(i)) => Some(*i as usize),
488                    Some(v) => Some(number!(v)),
489                }
490            }};
491        }
492        let up = self.source.update(ctx, event);
493        let up = self.start.as_mut().map(|c| c.update(ctx, event)).unwrap_or(false) || up;
494        let up = self.end.as_mut().map(|c| c.update(ctx, event)).unwrap_or(false) || up;
495        if !up {
496            return None;
497        }
498        let (start, end) = match (&self.start, &self.end) {
499            (None, None) => (None, None),
500            (Some(c), None) => (bound!(c), None),
501            (None, Some(c)) => (None, bound!(c)),
502            (Some(c0), Some(c1)) => (bound!(c0), bound!(c1)),
503        };
504        match &self.source.cached {
505            Some(Value::Array(elts)) => match (start, end) {
506                (None, None) => Some(Value::Array(elts.clone())),
507                (Some(i), Some(j)) => match elts.subslice(i..j) {
508                    Ok(a) => Some(Value::Array(a)),
509                    Err(e) => Some(Value::Error(e.to_string().into())),
510                },
511                (Some(i), None) => match elts.subslice(i..) {
512                    Ok(a) => Some(Value::Array(a)),
513                    Err(e) => Some(Value::Error(e.to_string().into())),
514                },
515                (None, Some(i)) => match elts.subslice(..i) {
516                    Ok(a) => Some(Value::Array(a)),
517                    Err(e) => Some(Value::Error(e.to_string().into())),
518                },
519            },
520            Some(_) => err!("expected array"),
521            None => None,
522        }
523    }
524
525    pub fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
526        self.source.node.refs(f);
527        if let Some(start) = &self.start {
528            start.node.refs(f)
529        }
530        if let Some(end) = &self.end {
531            end.node.refs(f)
532        }
533    }
534
535    pub fn delete(self, ctx: &mut ExecCtx<C, E>) {
536        self.source.node.delete(ctx);
537        if let Some(start) = self.start {
538            start.node.delete(ctx);
539        }
540        if let Some(end) = self.end {
541            end.node.delete(ctx);
542        }
543    }
544}
545
546#[derive(Debug)]
547pub enum NodeKind<C: Ctx, E: UserEvent> {
548    Nop,
549    Use {
550        scope: ModPath,
551        name: ModPath,
552    },
553    TypeDef {
554        scope: ModPath,
555        name: ArcStr,
556    },
557    Constant(Value),
558    Module(Box<[Node<C, E>]>),
559    Do(Box<[Node<C, E>]>),
560    Bind {
561        pattern: Box<StructPatternNode>,
562        node: Box<Node<C, E>>,
563    },
564    Ref {
565        id: BindId,
566        top_id: ExprId,
567    },
568    StructRef {
569        source: Box<Node<C, E>>,
570        field: usize,
571        top_id: ExprId,
572    },
573    TupleRef {
574        source: Box<Node<C, E>>,
575        field: usize,
576        top_id: ExprId,
577    },
578    ArrayRef(Box<ArrayRefNode<C, E>>),
579    ArraySlice(Box<ArraySliceNode<C, E>>),
580    StringInterpolate {
581        args: Box<[Cached<C, E>]>,
582    },
583    Connect(BindId, Box<Node<C, E>>),
584    Lambda(Arc<LambdaDef<C, E>>),
585    Qop(BindId, Box<Node<C, E>>),
586    TypeCast {
587        target: Type<NoRefs>,
588        n: Box<Node<C, E>>,
589    },
590    Any {
591        args: Box<[Node<C, E>]>,
592    },
593    Array {
594        args: Box<[Cached<C, E>]>,
595    },
596    Tuple {
597        args: Box<[Cached<C, E>]>,
598    },
599    Variant {
600        tag: ArcStr,
601        args: Box<[Cached<C, E>]>,
602    },
603    Struct {
604        names: Box<[ArcStr]>,
605        args: Box<[Cached<C, E>]>,
606    },
607    StructWith {
608        source: Box<Node<C, E>>,
609        current: Option<ValArray>,
610        replace: Box<[(usize, Cached<C, E>)]>,
611    },
612    Apply(Box<CallSite<C, E>>),
613    Select(Box<SelectNode<C, E>>),
614    Eq {
615        lhs: Box<Cached<C, E>>,
616        rhs: Box<Cached<C, E>>,
617    },
618    Ne {
619        lhs: Box<Cached<C, E>>,
620        rhs: Box<Cached<C, E>>,
621    },
622    Lt {
623        lhs: Box<Cached<C, E>>,
624        rhs: Box<Cached<C, E>>,
625    },
626    Gt {
627        lhs: Box<Cached<C, E>>,
628        rhs: Box<Cached<C, E>>,
629    },
630    Lte {
631        lhs: Box<Cached<C, E>>,
632        rhs: Box<Cached<C, E>>,
633    },
634    Gte {
635        lhs: Box<Cached<C, E>>,
636        rhs: Box<Cached<C, E>>,
637    },
638    And {
639        lhs: Box<Cached<C, E>>,
640        rhs: Box<Cached<C, E>>,
641    },
642    Or {
643        lhs: Box<Cached<C, E>>,
644        rhs: Box<Cached<C, E>>,
645    },
646    Not {
647        node: Box<Node<C, E>>,
648    },
649    Add {
650        lhs: Box<Cached<C, E>>,
651        rhs: Box<Cached<C, E>>,
652    },
653    Sub {
654        lhs: Box<Cached<C, E>>,
655        rhs: Box<Cached<C, E>>,
656    },
657    Mul {
658        lhs: Box<Cached<C, E>>,
659        rhs: Box<Cached<C, E>>,
660    },
661    Div {
662        lhs: Box<Cached<C, E>>,
663        rhs: Box<Cached<C, E>>,
664    },
665}
666
667pub struct Node<C: Ctx, E: UserEvent> {
668    pub spec: Box<Expr>,
669    pub typ: Type<NoRefs>,
670    pub kind: NodeKind<C, E>,
671}
672
673impl<C: Ctx, E: UserEvent> fmt::Debug for Node<C, E> {
674    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
675        write!(f, "{:?}", self.kind)
676    }
677}
678
679impl<C: Ctx, E: UserEvent> Default for Node<C, E> {
680    fn default() -> Self {
681        genn::nop()
682    }
683}
684
685impl<C: Ctx, E: UserEvent> fmt::Display for Node<C, E> {
686    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
687        write!(f, "{}", &self.spec)
688    }
689}
690
691impl<C: Ctx, E: UserEvent> Node<C, E> {
692    pub fn compile(ctx: &mut ExecCtx<C, E>, scope: &ModPath, spec: Expr) -> Result<Self> {
693        let top_id = spec.id;
694        let env = ctx.env.clone();
695        let mut node = match compiler::compile(ctx, spec, scope, top_id) {
696            Ok(n) => n,
697            Err(e) => {
698                ctx.env = env;
699                return Err(e);
700            }
701        };
702        if let Err(e) = node.typecheck(ctx) {
703            ctx.env = env;
704            return Err(e);
705        }
706        Ok(node)
707    }
708
709    pub fn delete(self, ctx: &mut ExecCtx<C, E>) {
710        let mut ids: SmallVec<[BindId; 8]> = smallvec![];
711        match self.kind {
712            NodeKind::Constant(_) | NodeKind::Nop => (),
713            NodeKind::Ref { id, top_id } => ctx.user.unref_var(id, top_id),
714            NodeKind::StructRef { mut source, field: _, top_id: _ }
715            | NodeKind::TupleRef { mut source, field: _, top_id: _ } => {
716                mem::take(&mut *source).delete(ctx)
717            }
718            NodeKind::ArrayRef(mut n) => mem::take(&mut *n).delete(ctx),
719            NodeKind::ArraySlice(mut n) => mem::take(&mut *n).delete(ctx),
720            NodeKind::Add { mut lhs, mut rhs }
721            | NodeKind::Sub { mut lhs, mut rhs }
722            | NodeKind::Mul { mut lhs, mut rhs }
723            | NodeKind::Div { mut lhs, mut rhs }
724            | NodeKind::Eq { mut lhs, mut rhs }
725            | NodeKind::Ne { mut lhs, mut rhs }
726            | NodeKind::Lte { mut lhs, mut rhs }
727            | NodeKind::Lt { mut lhs, mut rhs }
728            | NodeKind::Gt { mut lhs, mut rhs }
729            | NodeKind::Gte { mut lhs, mut rhs }
730            | NodeKind::And { mut lhs, mut rhs }
731            | NodeKind::Or { mut lhs, mut rhs } => {
732                mem::take(&mut lhs.node).delete(ctx);
733                mem::take(&mut rhs.node).delete(ctx);
734            }
735            NodeKind::Use { scope, name } => {
736                if let Some(used) = ctx.env.used.get_mut_cow(&scope) {
737                    TArc::make_mut(used).retain(|n| n != &name);
738                    if used.is_empty() {
739                        ctx.env.used.remove_cow(&scope);
740                    }
741                }
742            }
743            NodeKind::TypeDef { scope, name } => ctx.env.undeftype(&scope, &name),
744            NodeKind::Module(nodes)
745            | NodeKind::Do(nodes)
746            | NodeKind::Any { args: nodes } => {
747                for n in nodes {
748                    n.delete(ctx)
749                }
750            }
751            NodeKind::StringInterpolate { args } => {
752                for n in args {
753                    n.node.delete(ctx)
754                }
755            }
756            NodeKind::Connect(_, mut n)
757            | NodeKind::TypeCast { target: _, mut n }
758            | NodeKind::Qop(_, mut n)
759            | NodeKind::Not { node: mut n } => mem::take(&mut *n).delete(ctx),
760            NodeKind::Variant { tag: _, args }
761            | NodeKind::Array { args }
762            | NodeKind::Tuple { args }
763            | NodeKind::Struct { names: _, args } => {
764                for n in args {
765                    n.node.delete(ctx)
766                }
767            }
768            NodeKind::StructWith { mut source, current: _, replace } => {
769                mem::take(&mut *source).delete(ctx);
770                for (_, n) in replace {
771                    n.node.delete(ctx)
772                }
773            }
774            NodeKind::Bind { pattern, node } => {
775                pattern.ids(&mut |id| ids.push(id));
776                node.delete(ctx);
777                for id in ids.drain(..) {
778                    ctx.env.unbind_variable(id)
779                }
780            }
781            NodeKind::Select(sn) => sn.delete(ctx),
782            NodeKind::Lambda(lb) => {
783                ctx.env.lambdas.remove_cow(&lb.id);
784            }
785            NodeKind::Apply(site) => site.delete(ctx),
786        }
787    }
788
789    /// call f with the id of every variable referenced by self
790    pub fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
791        match &self.kind {
792            NodeKind::Constant(_)
793            | NodeKind::Nop
794            | NodeKind::Use { .. }
795            | NodeKind::TypeDef { .. }
796            | NodeKind::Lambda(_) => (),
797            NodeKind::Ref { id, top_id: _ } => f(*id),
798            NodeKind::StructRef { source, field: _, top_id: _ }
799            | NodeKind::TupleRef { source, field: _, top_id: _ } => {
800                source.refs(f);
801            }
802            NodeKind::ArrayRef(n) => n.refs(f),
803            NodeKind::ArraySlice(n) => n.refs(f),
804            NodeKind::StringInterpolate { args } => {
805                for a in args {
806                    a.node.refs(f)
807                }
808            }
809            NodeKind::Add { lhs, rhs }
810            | NodeKind::Sub { lhs, rhs }
811            | NodeKind::Mul { lhs, rhs }
812            | NodeKind::Div { lhs, rhs }
813            | NodeKind::Eq { lhs, rhs }
814            | NodeKind::Ne { lhs, rhs }
815            | NodeKind::Lte { lhs, rhs }
816            | NodeKind::Lt { lhs, rhs }
817            | NodeKind::Gt { lhs, rhs }
818            | NodeKind::Gte { lhs, rhs }
819            | NodeKind::And { lhs, rhs }
820            | NodeKind::Or { lhs, rhs } => {
821                lhs.node.refs(f);
822                rhs.node.refs(f);
823            }
824            NodeKind::Module(nodes)
825            | NodeKind::Do(nodes)
826            | NodeKind::Any { args: nodes } => {
827                for n in nodes {
828                    n.refs(f)
829                }
830            }
831            NodeKind::Connect(_, n)
832            | NodeKind::TypeCast { target: _, n }
833            | NodeKind::Qop(_, n)
834            | NodeKind::Not { node: n } => n.refs(f),
835            NodeKind::Variant { tag: _, args }
836            | NodeKind::Array { args }
837            | NodeKind::Tuple { args }
838            | NodeKind::Struct { names: _, args } => {
839                for n in args {
840                    n.node.refs(f)
841                }
842            }
843            NodeKind::StructWith { source, current: _, replace } => {
844                source.refs(f);
845                for (_, n) in replace {
846                    n.node.refs(f)
847                }
848            }
849            NodeKind::Bind { pattern, node } => {
850                pattern.ids(f);
851                node.refs(f);
852            }
853            NodeKind::Select(sn) => sn.refs(f),
854            NodeKind::Apply(site) => {
855                let CallSite { ftype: _, fnode, args, arg_spec: _, function, top_id: _ } =
856                    &**site;
857                if let Some((_, fun)) = function {
858                    fun.refs(f)
859                }
860                fnode.refs(f);
861                for n in args {
862                    n.refs(f)
863                }
864            }
865        }
866    }
867
868    pub fn update(
869        &mut self,
870        ctx: &mut ExecCtx<C, E>,
871        event: &mut Event<E>,
872    ) -> Option<Value> {
873        macro_rules! binary_op {
874            ($op:tt, $lhs:expr, $rhs:expr) => {{
875                let lhs_up = $lhs.update(ctx, event);
876                let rhs_up = $rhs.update(ctx, event);
877                if lhs_up || rhs_up {
878                    return $lhs.cached.as_ref().and_then(|lhs| {
879                        $rhs.cached.as_ref().map(|rhs| (lhs $op rhs).into())
880                    })
881                }
882                None
883            }}
884        }
885        macro_rules! binary_op_clone {
886            ($op:tt, $lhs:expr, $rhs:expr) => {{
887                let lhs_up = $lhs.update(ctx, event);
888                let rhs_up = $rhs.update(ctx, event);
889                if lhs_up || rhs_up {
890                    return $lhs.cached.as_ref().and_then(|lhs| {
891                        $rhs.cached.as_ref().map(|rhs| (lhs.clone() $op rhs.clone()).into())
892                    })
893                }
894                None
895            }}
896        }
897        macro_rules! cast_bool {
898            ($v:expr) => {
899                match $v.cached.as_ref().map(|v| v.clone().get_as::<bool>()) {
900                    None => return None,
901                    Some(None) => return Some(Value::Error(literal!("expected bool"))),
902                    Some(Some(lhs)) => lhs,
903                }
904            };
905        }
906        macro_rules! binary_boolean_op {
907            ($op:tt, $lhs:expr, $rhs:expr) => {{
908                let lhs_up = $lhs.update(ctx, event);
909                let rhs_up = $rhs.update(ctx, event);
910                if lhs_up || rhs_up {
911                    let lhs = cast_bool!($lhs);
912                    let rhs = cast_bool!($rhs);
913                    Some((lhs $op rhs).into())
914                } else {
915                    None
916                }
917            }}
918        }
919        macro_rules! update_args {
920            ($args:expr) => {{
921                let mut updated = false;
922                let mut determined = true;
923                for n in $args.iter_mut() {
924                    updated |= n.update(ctx, event);
925                    determined &= n.cached.is_some();
926                }
927                (updated, determined)
928            }};
929        }
930        match &mut self.kind {
931            NodeKind::Constant(v) => {
932                if event.init {
933                    Some(v.clone())
934                } else {
935                    None
936                }
937            }
938            NodeKind::StringInterpolate { args } => {
939                thread_local! {
940                    static BUF: RefCell<String> = RefCell::new(String::new());
941                }
942                let (updated, determined) = update_args!(args);
943                if updated && determined {
944                    BUF.with_borrow_mut(|buf| {
945                        buf.clear();
946                        for c in args {
947                            match c.cached.as_ref().unwrap() {
948                                Value::String(c) => buf.push_str(c.as_ref()),
949                                v => match v.clone().cast_to::<ArcStr>().ok() {
950                                    Some(c) => buf.push_str(c.as_ref()),
951                                    None => {
952                                        let m = literal!("args must be strings");
953                                        return Some(Value::Error(m));
954                                    }
955                                },
956                            }
957                        }
958                        Some(Value::String(buf.as_str().into()))
959                    })
960                } else {
961                    None
962                }
963            }
964            NodeKind::ArrayRef(n) => n.update(ctx, event),
965            NodeKind::ArraySlice(n) => n.update(ctx, event),
966            NodeKind::Array { args } | NodeKind::Tuple { args } => {
967                if args.is_empty() && event.init {
968                    return Some(Value::Array(ValArray::from([])));
969                }
970                let (updated, determined) = update_args!(args);
971                if updated && determined {
972                    let iter = args.iter().map(|n| n.cached.clone().unwrap());
973                    Some(Value::Array(ValArray::from_iter_exact(iter)))
974                } else {
975                    None
976                }
977            }
978            NodeKind::Variant { tag, args } if args.len() == 0 => {
979                if event.init {
980                    Some(Value::String(tag.clone()))
981                } else {
982                    None
983                }
984            }
985            NodeKind::Variant { tag, args } => {
986                let (updated, determined) = update_args!(args);
987                if updated && determined {
988                    let a = iter::once(Value::String(tag.clone()))
989                        .chain(args.iter().map(|n| n.cached.clone().unwrap()))
990                        .collect::<SmallVec<[_; 8]>>();
991                    Some(Value::Array(ValArray::from_iter_exact(a.into_iter())))
992                } else {
993                    None
994                }
995            }
996            NodeKind::Any { args } => args
997                .iter_mut()
998                .filter_map(|s| s.update(ctx, event))
999                .fold(None, |r, v| r.or(Some(v))),
1000            NodeKind::Struct { names, args } => {
1001                if args.is_empty() && event.init {
1002                    return Some(Value::Array(ValArray::from([])));
1003                }
1004                let mut updated = false;
1005                let mut determined = true;
1006                for n in args.iter_mut() {
1007                    updated |= n.update(ctx, event);
1008                    determined &= n.cached.is_some();
1009                }
1010                if updated && determined {
1011                    let iter = names.iter().zip(args.iter()).map(|(name, n)| {
1012                        let name = Value::String(name.clone());
1013                        let v = n.cached.clone().unwrap();
1014                        Value::Array(ValArray::from_iter_exact([name, v].into_iter()))
1015                    });
1016                    Some(Value::Array(ValArray::from_iter_exact(iter)))
1017                } else {
1018                    None
1019                }
1020            }
1021            NodeKind::StructWith { source, current, replace } => {
1022                let mut updated = source
1023                    .update(ctx, event)
1024                    .map(|v| match v {
1025                        Value::Array(a) => {
1026                            *current = Some(a.clone());
1027                            true
1028                        }
1029                        _ => false,
1030                    })
1031                    .unwrap_or(false);
1032                let mut determined = current.is_some();
1033                for (_, n) in replace.iter_mut() {
1034                    updated |= n.update(ctx, event);
1035                    determined &= n.cached.is_some();
1036                }
1037                if updated && determined {
1038                    let mut si = 0;
1039                    let iter = current.as_ref().unwrap().iter().enumerate().map(
1040                        |(i, v)| match v {
1041                            Value::Array(v) if v.len() == 2 => {
1042                                if si < replace.len() && i == replace[si].0 {
1043                                    let r = replace[si].1.cached.clone().unwrap();
1044                                    si += 1;
1045                                    Value::Array(ValArray::from_iter_exact(
1046                                        [v[0].clone(), r].into_iter(),
1047                                    ))
1048                                } else {
1049                                    Value::Array(v.clone())
1050                                }
1051                            }
1052                            _ => v.clone(),
1053                        },
1054                    );
1055                    Some(Value::Array(ValArray::from_iter_exact(iter)))
1056                } else {
1057                    None
1058                }
1059            }
1060            NodeKind::Apply(site) => site.update(ctx, event),
1061            NodeKind::Bind { pattern, node } => {
1062                if let Some(v) = node.update(ctx, event) {
1063                    pattern.bind(&v, &mut |id, v| ctx.set_var(id, v))
1064                }
1065                None
1066            }
1067            NodeKind::Connect(id, rhs) => {
1068                if let Some(v) = rhs.update(ctx, event) {
1069                    ctx.set_var(*id, v)
1070                }
1071                None
1072            }
1073            NodeKind::Ref { id: bid, .. } => event.variables.get(bid).map(|v| v.clone()),
1074            NodeKind::TupleRef { source, field: i, .. } => {
1075                source.update(ctx, event).and_then(|v| match v {
1076                    Value::Array(a) => a.get(*i).map(|v| v.clone()),
1077                    _ => None,
1078                })
1079            }
1080            NodeKind::StructRef { source, field: i, .. } => {
1081                match source.update(ctx, event) {
1082                    Some(Value::Array(a)) => a.get(*i).and_then(|v| match v {
1083                        Value::Array(a) if a.len() == 2 => Some(a[1].clone()),
1084                        _ => None,
1085                    }),
1086                    Some(_) | None => None,
1087                }
1088            }
1089            NodeKind::Qop(id, n) => match n.update(ctx, event) {
1090                None => None,
1091                Some(e @ Value::Error(_)) => {
1092                    ctx.set_var(*id, e);
1093                    None
1094                }
1095                Some(v) => Some(v),
1096            },
1097            NodeKind::Module(children) | NodeKind::Do(children) => {
1098                children.into_iter().fold(None, |_, n| n.update(ctx, event))
1099            }
1100            NodeKind::TypeCast { target, n } => {
1101                n.update(ctx, event).map(|v| target.cast_value(v))
1102            }
1103            NodeKind::Not { node } => node.update(ctx, event).map(|v| !v),
1104            NodeKind::Eq { lhs, rhs } => binary_op!(==, lhs, rhs),
1105            NodeKind::Ne { lhs, rhs } => binary_op!(!=, lhs, rhs),
1106            NodeKind::Lt { lhs, rhs } => binary_op!(<, lhs, rhs),
1107            NodeKind::Gt { lhs, rhs } => binary_op!(>, lhs, rhs),
1108            NodeKind::Lte { lhs, rhs } => binary_op!(<=, lhs, rhs),
1109            NodeKind::Gte { lhs, rhs } => binary_op!(>=, lhs, rhs),
1110            NodeKind::And { lhs, rhs } => binary_boolean_op!(&&, lhs, rhs),
1111            NodeKind::Or { lhs, rhs } => binary_boolean_op!(||, lhs, rhs),
1112            NodeKind::Add { lhs, rhs } => binary_op_clone!(+, lhs, rhs),
1113            NodeKind::Sub { lhs, rhs } => binary_op_clone!(-, lhs, rhs),
1114            NodeKind::Mul { lhs, rhs } => binary_op_clone!(*, lhs, rhs),
1115            NodeKind::Div { lhs, rhs } => binary_op_clone!(/, lhs, rhs),
1116            NodeKind::Select(sn) => sn.update(ctx, event),
1117            NodeKind::Lambda(lb) if event.init => Some(Value::U64(lb.id.0)),
1118            NodeKind::Use { .. }
1119            | NodeKind::Lambda(_)
1120            | NodeKind::TypeDef { .. }
1121            | NodeKind::Nop => None,
1122        }
1123    }
1124}
1125
1126/// helpers for dynamically generating code in built-in functions. Not used by the compiler
1127pub mod genn {
1128    use super::*;
1129
1130    /// return a no op node
1131    pub fn nop<C: Ctx, E: UserEvent>() -> Node<C, E> {
1132        Node {
1133            spec: Box::new(
1134                ExprKind::Constant(Value::String(literal!("nop")))
1135                    .to_expr(Default::default()),
1136            ),
1137            typ: Type::Bottom(PhantomData),
1138            kind: NodeKind::Nop,
1139        }
1140    }
1141
1142    /// bind a variable and return a node referencing it
1143    pub fn bind<C: Ctx, E: UserEvent>(
1144        ctx: &mut ExecCtx<C, E>,
1145        scope: &ModPath,
1146        name: &str,
1147        typ: Type<NoRefs>,
1148        top_id: ExprId,
1149    ) -> (BindId, Node<C, E>) {
1150        let id = ctx.env.bind_variable(scope, name, typ.clone()).id;
1151        ctx.user.ref_var(id, top_id);
1152        let spec = Box::new(
1153            ExprKind::Ref { name: ModPath(scope.0.append(name)) }
1154                .to_expr(Default::default()),
1155        );
1156        let kind = NodeKind::Ref { id, top_id };
1157        (id, Node { spec, kind, typ })
1158    }
1159
1160    /// generate a reference to a bind id
1161    pub fn reference<C: Ctx, E: UserEvent>(
1162        ctx: &mut ExecCtx<C, E>,
1163        id: BindId,
1164        typ: Type<NoRefs>,
1165        top_id: ExprId,
1166    ) -> Node<C, E> {
1167        ctx.user.ref_var(id, top_id);
1168        let spec = Box::new(
1169            ExprKind::Ref { name: ModPath::from(["x"]) }.to_expr(Default::default()),
1170        );
1171        let kind = NodeKind::Ref { id, top_id };
1172        Node { spec, kind, typ }
1173    }
1174
1175    /// generate and return an apply node for the given lambda
1176    pub fn apply<C: Ctx, E: UserEvent>(
1177        fnode: Node<C, E>,
1178        args: Vec<Node<C, E>>,
1179        typ: TArc<FnType<NoRefs>>,
1180        top_id: ExprId,
1181    ) -> Node<C, E> {
1182        let spec = ExprKind::Apply {
1183            args: TArc::from_iter(args.iter().map(|n| (None, (*n.spec).clone()))),
1184            function: TArc::new((*fnode.spec).clone()),
1185        }
1186        .to_expr(Default::default());
1187        let site = Box::new(CallSite {
1188            ftype: typ.clone(),
1189            args,
1190            arg_spec: HashMap::default(),
1191            fnode,
1192            function: None,
1193            top_id,
1194        });
1195        let typ = typ.rtype.clone();
1196        Node { spec: Box::new(spec), typ, kind: NodeKind::Apply(site) }
1197    }
1198}