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 => 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
181fn 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 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}