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