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 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 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
194fn 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 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}