Skip to main content

graphix_compiler/expr/
resolver.rs

1use crate::{
2    expr::{
3        parser, ApplyExpr, BindExpr, CouldNotResolve, Expr, ExprId, ExprKind, LambdaExpr,
4        ModPath, ModuleKind, Origin, Pattern, SelectExpr, Sig, SigItem, SigKind, Source,
5        StructExpr, StructWithExpr, StructurePattern, TryCatchExpr,
6    },
7    format_with_flags, PrintFlag,
8};
9use anyhow::{anyhow, bail, Context, Result};
10use arcstr::ArcStr;
11use combine::stream::position::SourcePosition;
12use compact_str::format_compact;
13use futures::future::try_join_all;
14use fxhash::{FxHashMap, FxHashSet};
15use log::info;
16use netidx::{
17    path::Path,
18    subscriber::{Event, Subscriber},
19    utils::Either,
20};
21use netidx_value::Value;
22use poolshark::local::LPooled;
23use std::{path::PathBuf, pin::Pin, str::FromStr, time::Duration};
24use tokio::{join, task, time::Instant, try_join};
25use triomphe::Arc;
26
27#[derive(Debug, Clone)]
28pub enum ModuleResolver {
29    VFS(FxHashMap<Path, ArcStr>),
30    Files(PathBuf),
31    Netidx { subscriber: Subscriber, base: Path, timeout: Option<Duration> },
32}
33
34impl ModuleResolver {
35    /// Parse a comma separated list of module resolvers. Netidx
36    /// resolvers are of the form, netidx:/path/in/netidx, and
37    /// filesystem resolvers are of the form file:/path/in/fs
38    ///
39    /// This format is intended to be used in an environment variable,
40    /// for example.
41    pub fn parse_env(
42        subscriber: Subscriber,
43        timeout: Option<Duration>,
44        s: &str,
45    ) -> Result<Vec<Self>> {
46        let mut res = vec![];
47        for l in escaping::split(s, '\\', ',') {
48            let l = l.trim();
49            if let Some(s) = l.strip_prefix("netidx:") {
50                let base = Path::from_str(s);
51                let r = Self::Netidx { subscriber: subscriber.clone(), timeout, base };
52                res.push(r);
53            } else if let Some(s) = l.strip_prefix("file:") {
54                let base = PathBuf::from_str(s)?;
55                let r = Self::Files(base);
56                res.push(r);
57            } else {
58                bail!("expected netidx: or file:")
59            }
60        }
61        Ok(res)
62    }
63}
64
65enum Resolution {
66    Resolved { interface: Option<Origin>, implementation: Origin },
67    TryNextMethod,
68}
69
70fn resolve_from_vfs(
71    scope: &ModPath,
72    parent: &Arc<Origin>,
73    name: &Path,
74    vfs: &FxHashMap<Path, ArcStr>,
75) -> Resolution {
76    macro_rules! ori {
77        ($s:expr) => {
78            Origin {
79                parent: Some(parent.clone()),
80                source: Source::Internal(name.clone().into()),
81                text: $s.clone(),
82            }
83        };
84    }
85    let scoped_intf = scope.append(&format_compact!("{name}.gxi"));
86    let scoped_impl = scope.append(&format_compact!("{name}.gx"));
87    let implementation = match vfs.get(&scoped_impl) {
88        Some(s) => ori!(s),
89        None => {
90            // try {name}/mod.gx fallback (consistent with file resolver)
91            let mod_impl = scope.append(&format_compact!("{name}/mod.gx"));
92            match vfs.get(&mod_impl) {
93                Some(s) => ori!(s),
94                None => return Resolution::TryNextMethod,
95            }
96        }
97    };
98    let interface = vfs
99        .get(&scoped_intf)
100        .or_else(|| {
101            let mod_intf = scope.append(&format_compact!("{name}/mod.gxi"));
102            vfs.get(&mod_intf)
103        })
104        .map(|s| ori!(s));
105    Resolution::Resolved { interface, implementation }
106}
107
108async fn resolve_from_files(
109    parent: &Arc<Origin>,
110    name: &Path,
111    base: &PathBuf,
112    errors: &mut Vec<anyhow::Error>,
113) -> Resolution {
114    macro_rules! ori {
115        ($s:expr, $path:expr) => {
116            Origin {
117                parent: Some(parent.clone()),
118                source: Source::File($path),
119                text: ArcStr::from($s),
120            }
121        };
122    }
123    let mut impl_path = base.clone();
124    for part in Path::parts(&name) {
125        impl_path.push(part);
126    }
127    impl_path.set_extension("gx");
128    let mut intf_path = impl_path.with_extension("gxi");
129    let implementation = match tokio::fs::read_to_string(&impl_path).await {
130        Ok(s) => ori!(s, impl_path),
131        Err(_) => {
132            impl_path.set_extension("");
133            impl_path.push("mod.gx");
134            intf_path.set_extension("");
135            intf_path.push("mod.gxi");
136            match tokio::fs::read_to_string(&impl_path).await {
137                Ok(s) => ori!(s, impl_path.clone()),
138                Err(e) => {
139                    errors.push(anyhow::Error::from(e));
140                    return Resolution::TryNextMethod;
141                }
142            }
143        }
144    };
145    let interface = match tokio::fs::read_to_string(&intf_path).await {
146        Ok(s) => Some(ori!(s, intf_path)),
147        Err(_) => None,
148    };
149    Resolution::Resolved { interface, implementation }
150}
151
152async fn resolve_from_netidx(
153    parent: &Arc<Origin>,
154    name: &Path,
155    subscriber: &Subscriber,
156    base: &Path,
157    timeout: &Option<Duration>,
158    errors: &mut Vec<anyhow::Error>,
159) -> Resolution {
160    macro_rules! ori {
161        ($v:expr, $p:expr) => {
162            match $v.last() {
163                Event::Update(Value::String(text)) => Origin {
164                    parent: Some(parent.clone()),
165                    source: Source::Netidx($p.clone()),
166                    text,
167                },
168                Event::Unsubscribed | Event::Update(_) => {
169                    errors.push(anyhow!("expected string"));
170                    return Resolution::TryNextMethod;
171                }
172            }
173        };
174    }
175    let impl_path = base.append(&format_compact!("{name}.gx"));
176    let intf_path = base.append(&format_compact!("{name}.gxi"));
177    let impl_sub = subscriber.subscribe_nondurable_one(impl_path.clone(), *timeout);
178    let intf_sub = subscriber.subscribe_nondurable_one(intf_path.clone(), *timeout);
179    let (impl_sub, intf_sub) = join!(impl_sub, intf_sub);
180    let implementation = match impl_sub {
181        Ok(v) => ori!(v, impl_path),
182        Err(e) => {
183            errors.push(e);
184            return Resolution::TryNextMethod;
185        }
186    };
187    let interface = match intf_sub {
188        Ok(v) => Some(ori!(v, intf_path)),
189        Err(_) => None,
190    };
191    Resolution::Resolved { interface, implementation }
192}
193
194// add modules that are only mentioned in the interface to the implementation
195// keep their relative location and order intact
196fn add_interface_modules(exprs: Arc<[Expr]>, sig: &Sig) -> Arc<[Expr]> {
197    let mut in_sig: LPooled<FxHashSet<&ArcStr>> = LPooled::take();
198    let mut after_bind: LPooled<FxHashMap<&ArcStr, &ArcStr>> = LPooled::take();
199    let mut after_td: LPooled<FxHashMap<&ArcStr, &ArcStr>> = LPooled::take();
200    let mut after_mod: LPooled<FxHashMap<&ArcStr, &ArcStr>> = LPooled::take();
201    let mut after_use: LPooled<FxHashMap<&ModPath, &ArcStr>> = LPooled::take();
202    let mut first: Option<&ArcStr> = None;
203    let mut last: Option<&SigItem> = None;
204    for si in &*sig.items {
205        if let SigKind::Module(name) = &si.kind {
206            in_sig.insert(name);
207            match last {
208                None => first = Some(name),
209                Some(si) => {
210                    match &si.kind {
211                        SigKind::Bind(v) => after_bind.insert(&v.name, name),
212                        SigKind::Module(m) => after_mod.insert(m, name),
213                        SigKind::TypeDef(td) => after_td.insert(&td.name, name),
214                        SigKind::Use(n) => after_use.insert(n, name),
215                    };
216                }
217            }
218        }
219        last = Some(si);
220    }
221    for e in &*exprs {
222        if let ExprKind::Module { name, .. } = &e.kind {
223            in_sig.remove(&name);
224        }
225    }
226    if in_sig.is_empty() {
227        drop(in_sig);
228        drop(after_bind);
229        drop(after_td);
230        drop(after_mod);
231        drop(after_use);
232        return exprs;
233    }
234    let synth = |name: &ArcStr| {
235        ExprKind::Module {
236            name: name.clone(),
237            value: ModuleKind::Unresolved { from_interface: true },
238        }
239        .to_expr_nopos()
240    };
241    let mut res: LPooled<Vec<Expr>> = LPooled::take();
242    if let Some(name) = first.take() {
243        res.push(synth(name));
244    }
245    let mut iter = exprs.iter();
246    loop {
247        match res.last().map(|e| &e.kind) {
248            Some(ExprKind::Bind(v)) => match &v.pattern {
249                StructurePattern::Bind(n) => {
250                    if let Some(name) = after_bind.remove(n) {
251                        in_sig.remove(name);
252                        res.push(synth(name));
253                        continue;
254                    }
255                }
256                _ => (),
257            },
258            Some(ExprKind::TypeDef(td)) => {
259                if let Some(name) = after_td.remove(&td.name) {
260                    in_sig.remove(name);
261                    res.push(synth(name));
262                    continue;
263                }
264            }
265            Some(ExprKind::Module { name, .. }) => {
266                if let Some(name) = after_mod.remove(name) {
267                    in_sig.remove(name);
268                    res.push(synth(name));
269                    continue;
270                }
271            }
272            Some(ExprKind::Use { name }) => {
273                if let Some(name) = after_use.remove(name) {
274                    in_sig.remove(name);
275                    res.push(synth(name));
276                    continue;
277                }
278            }
279            _ => (),
280        };
281        match iter.next() {
282            None => break,
283            Some(e) => res.push(e.clone()),
284        }
285    }
286    for name in in_sig.drain() {
287        res.push(synth(name));
288    }
289    Arc::from_iter(res.drain(..))
290}
291
292async fn resolve(
293    scope: ModPath,
294    prepend: Option<Arc<ModuleResolver>>,
295    resolvers: Arc<[ModuleResolver]>,
296    id: ExprId,
297    parent: Arc<Origin>,
298    pos: SourcePosition,
299    name: ArcStr,
300    from_interface: bool,
301) -> Result<Expr> {
302    macro_rules! check {
303        ($res:expr) => {
304            match $res {
305                Resolution::TryNextMethod => continue,
306                Resolution::Resolved { interface, implementation } => {
307                    (interface, implementation)
308                }
309            }
310        };
311    }
312    let ts = Instant::now();
313    let name = Path::from(name);
314    let mut errors: LPooled<Vec<anyhow::Error>> = LPooled::take();
315    for r in prepend.iter().map(|r| r.as_ref()).chain(resolvers.iter()) {
316        let (interface, implementation) = match r {
317            ModuleResolver::VFS(vfs) => {
318                check!(resolve_from_vfs(&scope, &parent, &name, vfs))
319            }
320            ModuleResolver::Files(base) => {
321                check!(resolve_from_files(&parent, &name, base, &mut errors).await)
322            }
323            ModuleResolver::Netidx { subscriber, base, timeout } => {
324                let r = resolve_from_netidx(
325                    &parent,
326                    &name,
327                    subscriber,
328                    base,
329                    timeout,
330                    &mut errors,
331                )
332                .await;
333                check!(r)
334            }
335        };
336        let exprs = task::spawn_blocking({
337            let ori = implementation.clone();
338            move || parser::parse(ori)
339        });
340        let sig = match &interface {
341            None => None,
342            Some(ori) => {
343                let ori = ori.clone();
344                let sig = task::spawn_blocking(move || parser::parse_sig(ori))
345                    .await?
346                    .with_context(|| format!("parsing file {interface:?}"))?;
347                Some(sig)
348            }
349        };
350        let exprs =
351            exprs.await?.with_context(|| format!("parsing file {implementation:?}"))?;
352        let exprs = match &sig {
353            Some(sig) => add_interface_modules(exprs, &sig),
354            None => exprs,
355        };
356        let value = ModuleKind::Resolved { exprs, sig, from_interface };
357        let kind = ExprKind::Module { name: name.clone().into(), value };
358        format_with_flags(PrintFlag::NoSource | PrintFlag::NoParents, || {
359            info!(
360                "load and parse {implementation:?} and {interface:?} {:?}",
361                ts.elapsed()
362            )
363        });
364        return Ok(Expr { id, ori: Arc::new(implementation), pos, kind });
365    }
366    bail!("module {name} could not be found {errors:?}")
367}
368
369impl Expr {
370    pub fn has_unresolved_modules(&self) -> bool {
371        self.fold(false, &mut |acc, e| {
372            acc || match &e.kind {
373                ExprKind::Module { value: ModuleKind::Unresolved { .. }, .. } => true,
374                _ => false,
375            }
376        })
377    }
378
379    /// Resolve external modules referenced in the expression using
380    /// the resolvers list. Each resolver will be tried in order,
381    /// until one succeeds. If no resolver succeeds then an error will
382    /// be returned.
383    pub async fn resolve_modules<'a>(
384        &'a self,
385        resolvers: &'a Arc<[ModuleResolver]>,
386    ) -> Result<Expr> {
387        self.resolve_modules_int(&ModPath::root(), &None, resolvers).await
388    }
389
390    async fn resolve_modules_int<'a>(
391        &'a self,
392        scope: &ModPath,
393        prepend: &'a Option<Arc<ModuleResolver>>,
394        resolvers: &'a Arc<[ModuleResolver]>,
395    ) -> Result<Expr> {
396        if self.has_unresolved_modules() {
397            self.resolve_modules_inner(scope, prepend, resolvers).await
398        } else {
399            Ok(self.clone())
400        }
401    }
402
403    fn resolve_modules_inner<'a>(
404        &'a self,
405        scope: &'a ModPath,
406        prepend: &'a Option<Arc<ModuleResolver>>,
407        resolvers: &'a Arc<[ModuleResolver]>,
408    ) -> Pin<Box<dyn Future<Output = Result<Expr>> + Send + Sync + 'a>> {
409        macro_rules! subexprs {
410            ($args:expr) => {{
411                try_join_all($args.iter().map(|e| async {
412                    e.resolve_modules_int(scope, prepend, resolvers).await
413                }))
414                .await?
415            }};
416        }
417        macro_rules! subtuples {
418            ($args:expr) => {{
419                try_join_all($args.iter().map(|(k, e)| async {
420                    Ok::<_, anyhow::Error>((
421                        k.clone(),
422                        e.resolve_modules_int(scope, prepend, resolvers).await?,
423                    ))
424                }))
425                .await?
426            }};
427        }
428        macro_rules! expr {
429            ($kind:expr) => {
430                Ok(Expr {
431                    id: self.id,
432                    ori: self.ori.clone(),
433                    pos: self.pos,
434                    kind: $kind,
435                })
436            };
437        }
438        macro_rules! only_args {
439            ($kind:ident, $args:expr) => {
440                Box::pin(async move {
441                    let args = Arc::from(subexprs!($args));
442                    expr!(ExprKind::$kind { args })
443                })
444            };
445        }
446        macro_rules! bin_op {
447            ($kind:ident, $lhs:expr, $rhs:expr) => {
448                Box::pin(async move {
449                    let (lhs, rhs) = try_join!(
450                        $lhs.resolve_modules_int(scope, prepend, resolvers),
451                        $rhs.resolve_modules_int(scope, prepend, resolvers)
452                    )?;
453                    expr!(ExprKind::$kind { lhs: Arc::from(lhs), rhs: Arc::from(rhs) })
454                })
455            };
456        }
457        if !self.has_unresolved_modules() {
458            return Box::pin(async { Ok(self.clone()) });
459        }
460        match self.kind.clone() {
461            ExprKind::Constant(_)
462            | ExprKind::NoOp
463            | ExprKind::Use { .. }
464            | ExprKind::Ref { .. }
465            | ExprKind::StructRef { .. }
466            | ExprKind::TupleRef { .. }
467            | ExprKind::TypeDef { .. } => Box::pin(async move { Ok(self.clone()) }),
468            ExprKind::Module {
469                value: ModuleKind::Unresolved { from_interface },
470                name,
471            } => {
472                let (id, pos, prepend, resolvers) =
473                    (self.id, self.pos, prepend.clone(), Arc::clone(resolvers));
474                Box::pin(async move {
475                    let e = resolve(
476                        scope.clone(),
477                        prepend.clone(),
478                        resolvers.clone(),
479                        id,
480                        self.ori.clone(),
481                        pos,
482                        name.clone(),
483                        from_interface,
484                    )
485                    .await
486                    .with_context(|| CouldNotResolve(name.clone()))?;
487                    let scope = ModPath(scope.append(&*name));
488                    e.resolve_modules_int(&scope, &prepend, &resolvers).await
489                })
490            }
491            ExprKind::Module {
492                value: ModuleKind::Resolved { exprs, sig, from_interface },
493                name,
494            } => Box::pin(async move {
495                let prepend = match &self.ori.source {
496                    Source::Unspecified | Source::Internal(_) => None,
497                    Source::File(p) => {
498                        p.parent().map(|p| Arc::new(ModuleResolver::Files(p.into())))
499                    }
500                    Source::Netidx(p) => resolvers.iter().find_map(|m| match m {
501                        ModuleResolver::Netidx { subscriber, timeout, .. } => {
502                            Some(Arc::new(ModuleResolver::Netidx {
503                                subscriber: subscriber.clone(),
504                                base: p.clone(),
505                                timeout: *timeout,
506                            }))
507                        }
508                        ModuleResolver::Files(_) | ModuleResolver::VFS(_) => None,
509                    }),
510                };
511                let exprs = try_join_all(exprs.iter().map(|e| async {
512                    e.resolve_modules_int(&scope, &prepend, resolvers).await
513                }))
514                .await?;
515                expr!(ExprKind::Module {
516                    value: ModuleKind::Resolved {
517                        exprs: Arc::from(exprs),
518                        sig,
519                        from_interface
520                    },
521                    name,
522                })
523            }),
524            ExprKind::Module {
525                name,
526                value: ModuleKind::Dynamic { sandbox, sig, source },
527            } => Box::pin(async move {
528                let source = Arc::new(
529                    source.resolve_modules_int(scope, prepend, resolvers).await?,
530                );
531                expr!(ExprKind::Module {
532                    name,
533                    value: ModuleKind::Dynamic { sandbox, sig, source },
534                })
535            }),
536            ExprKind::ExplicitParens(e) => Box::pin(async move {
537                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
538                expr!(ExprKind::ExplicitParens(Arc::new(e)))
539            }),
540            ExprKind::Do { exprs } => Box::pin(async move {
541                let exprs = Arc::from(subexprs!(exprs));
542                expr!(ExprKind::Do { exprs })
543            }),
544            ExprKind::Bind(b) => Box::pin(async move {
545                let BindExpr { rec, pattern, typ, value } = &*b;
546                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
547                expr!(ExprKind::Bind(Arc::new(BindExpr {
548                    rec: *rec,
549                    pattern: pattern.clone(),
550                    typ: typ.clone(),
551                    value,
552                })))
553            }),
554            ExprKind::StructWith(StructWithExpr { source, replace }) => {
555                Box::pin(async move {
556                    expr!(ExprKind::StructWith(StructWithExpr {
557                        source: Arc::new(
558                            source.resolve_modules_int(scope, prepend, resolvers).await?,
559                        ),
560                        replace: Arc::from(subtuples!(replace)),
561                    }))
562                })
563            }
564            ExprKind::Connect { name, value, deref } => Box::pin(async move {
565                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
566                expr!(ExprKind::Connect { name, value: Arc::new(value), deref })
567            }),
568            ExprKind::Lambda(l) => Box::pin(async move {
569                let LambdaExpr { args, vargs, rtype, constraints, throws, body } = &*l;
570                let body = match body {
571                    Either::Right(s) => Either::Right(s.clone()),
572                    Either::Left(e) => Either::Left(
573                        e.resolve_modules_int(scope, prepend, resolvers).await?,
574                    ),
575                };
576                let l = LambdaExpr {
577                    args: args.clone(),
578                    vargs: vargs.clone(),
579                    rtype: rtype.clone(),
580                    throws: throws.clone(),
581                    constraints: constraints.clone(),
582                    body,
583                };
584                expr!(ExprKind::Lambda(Arc::new(l)))
585            }),
586            ExprKind::TypeCast { expr, typ } => Box::pin(async move {
587                let expr = expr.resolve_modules_int(scope, prepend, resolvers).await?;
588                expr!(ExprKind::TypeCast { expr: Arc::new(expr), typ })
589            }),
590            ExprKind::Apply(ApplyExpr { args, function }) => Box::pin(async move {
591                expr!(ExprKind::Apply(ApplyExpr {
592                    args: Arc::from(subtuples!(args)),
593                    function
594                }))
595            }),
596            ExprKind::Any { args } => only_args!(Any, args),
597            ExprKind::Array { args } => only_args!(Array, args),
598            ExprKind::Map { args } => Box::pin(async move {
599                let args = Arc::from(subtuples!(args));
600                expr!(ExprKind::Map { args })
601            }),
602            ExprKind::MapRef { source, key } => Box::pin(async move {
603                let source = Arc::new(
604                    source.resolve_modules_int(scope, prepend, resolvers).await?,
605                );
606                let key =
607                    Arc::new(key.resolve_modules_inner(scope, prepend, resolvers).await?);
608                expr!(ExprKind::MapRef { source, key })
609            }),
610            ExprKind::Tuple { args } => only_args!(Tuple, args),
611            ExprKind::StringInterpolate { args } => only_args!(StringInterpolate, args),
612            ExprKind::Struct(StructExpr { args }) => Box::pin(async move {
613                let args = Arc::from(subtuples!(args));
614                expr!(ExprKind::Struct(StructExpr { args }))
615            }),
616            ExprKind::ArrayRef { source, i } => Box::pin(async move {
617                let source = Arc::new(
618                    source.resolve_modules_int(scope, prepend, resolvers).await?,
619                );
620                let i = Arc::new(i.resolve_modules_int(scope, prepend, resolvers).await?);
621                expr!(ExprKind::ArrayRef { source, i })
622            }),
623            ExprKind::ArraySlice { source, start, end } => Box::pin(async move {
624                let source = Arc::new(
625                    source.resolve_modules_int(scope, prepend, resolvers).await?,
626                );
627                let start = match start {
628                    None => None,
629                    Some(e) => Some(Arc::new(
630                        e.resolve_modules_int(scope, prepend, resolvers).await?,
631                    )),
632                };
633                let end = match end {
634                    None => None,
635                    Some(e) => Some(Arc::new(
636                        e.resolve_modules_int(scope, prepend, resolvers).await?,
637                    )),
638                };
639                expr!(ExprKind::ArraySlice { source, start, end })
640            }),
641            ExprKind::Variant { tag, args } => Box::pin(async move {
642                let args = Arc::from(subexprs!(args));
643                expr!(ExprKind::Variant { tag, args })
644            }),
645            ExprKind::Select(SelectExpr { arg, arms }) => Box::pin(async move {
646                let arg =
647                    Arc::new(arg.resolve_modules_int(scope, prepend, resolvers).await?);
648                let arms = try_join_all(arms.iter().map(|(p, e)| async {
649                    let p = match &p.guard {
650                        None => p.clone(),
651                        Some(e) => {
652                            let e =
653                                e.resolve_modules_int(scope, prepend, resolvers).await?;
654                            Pattern {
655                                guard: Some(e),
656                                type_predicate: p.type_predicate.clone(),
657                                structure_predicate: p.structure_predicate.clone(),
658                            }
659                        }
660                    };
661                    let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
662                    Ok::<_, anyhow::Error>((p, e))
663                }))
664                .await?;
665                expr!(ExprKind::Select(SelectExpr { arg, arms: Arc::from(arms) }))
666            }),
667            ExprKind::Qop(e) => Box::pin(async move {
668                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
669                expr!(ExprKind::Qop(Arc::new(e)))
670            }),
671            ExprKind::OrNever(e) => Box::pin(async move {
672                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
673                expr!(ExprKind::OrNever(Arc::new(e)))
674            }),
675            ExprKind::TryCatch(tc) => Box::pin(async move {
676                let exprs = try_join_all(tc.exprs.iter().map(|e| async {
677                    e.resolve_modules_int(&scope, &prepend, resolvers).await
678                }))
679                .await?;
680                let handler =
681                    tc.handler.resolve_modules_int(scope, prepend, resolvers).await?;
682                expr!(ExprKind::TryCatch(Arc::new(TryCatchExpr {
683                    bind: tc.bind.clone(),
684                    constraint: tc.constraint.clone(),
685                    handler: Arc::new(handler),
686                    exprs: Arc::from_iter(exprs),
687                })))
688            }),
689            ExprKind::ByRef(e) => Box::pin(async move {
690                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
691                expr!(ExprKind::ByRef(Arc::new(e)))
692            }),
693            ExprKind::Deref(e) => Box::pin(async move {
694                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
695                expr!(ExprKind::Deref(Arc::new(e)))
696            }),
697            ExprKind::Not { expr: e } => Box::pin(async move {
698                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
699                expr!(ExprKind::Not { expr: Arc::new(e) })
700            }),
701            ExprKind::Add { lhs, rhs } => bin_op!(Add, lhs, rhs),
702            ExprKind::Sub { lhs, rhs } => bin_op!(Sub, lhs, rhs),
703            ExprKind::Mul { lhs, rhs } => bin_op!(Mul, lhs, rhs),
704            ExprKind::Div { lhs, rhs } => bin_op!(Div, lhs, rhs),
705            ExprKind::Mod { lhs, rhs } => bin_op!(Mul, lhs, rhs),
706            ExprKind::And { lhs, rhs } => bin_op!(And, lhs, rhs),
707            ExprKind::Or { lhs, rhs } => bin_op!(Or, lhs, rhs),
708            ExprKind::Eq { lhs, rhs } => bin_op!(Eq, lhs, rhs),
709            ExprKind::Ne { lhs, rhs } => bin_op!(Ne, lhs, rhs),
710            ExprKind::Gt { lhs, rhs } => bin_op!(Gt, lhs, rhs),
711            ExprKind::Lt { lhs, rhs } => bin_op!(Lt, lhs, rhs),
712            ExprKind::Gte { lhs, rhs } => bin_op!(Gte, lhs, rhs),
713            ExprKind::Lte { lhs, rhs } => bin_op!(Lte, lhs, rhs),
714            ExprKind::Sample { lhs, rhs } => bin_op!(Sample, lhs, rhs),
715        }
716    }
717}