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