graphix_compiler/expr/
resolver.rs

1use crate::{
2    expr::{
3        parser, Bind, Expr, ExprId, ExprKind, Lambda, ModPath, ModuleKind, Origin,
4        Pattern, Source,
5    },
6    format_with_flags, PrintFlag,
7};
8use anyhow::{anyhow, bail, Context, Result};
9use arcstr::ArcStr;
10use combine::stream::position::SourcePosition;
11use futures::future::try_join_all;
12use fxhash::FxHashMap;
13use log::info;
14use netidx::{
15    path::Path,
16    subscriber::{Event, Subscriber},
17    utils::Either,
18};
19use netidx_value::Value;
20use std::{path::PathBuf, pin::Pin, str::FromStr, time::Duration};
21use tokio::{task, time::Instant, try_join};
22use triomphe::Arc;
23
24#[derive(Debug, Clone)]
25pub enum ModuleResolver {
26    VFS(FxHashMap<Path, ArcStr>),
27    Files(PathBuf),
28    Netidx { subscriber: Subscriber, base: Path, timeout: Option<Duration> },
29}
30
31impl ModuleResolver {
32    /// Parse a comma separated list of module resolvers. Netidx
33    /// resolvers are of the form, netidx:/path/in/netidx, and
34    /// filesystem resolvers are of the form file:/path/in/fs
35    ///
36    /// This format is intended to be used in an environment variable,
37    /// for example.
38    pub fn parse_env(
39        subscriber: Subscriber,
40        timeout: Option<Duration>,
41        s: &str,
42    ) -> Result<Vec<Self>> {
43        let mut res = vec![];
44        for l in escaping::split(s, '\\', ',') {
45            let l = l.trim();
46            if let Some(s) = l.strip_prefix("netidx:") {
47                let base = Path::from_str(s);
48                let r = Self::Netidx { subscriber: subscriber.clone(), timeout, base };
49                res.push(r);
50            } else if let Some(s) = l.strip_prefix("file:") {
51                let base = PathBuf::from_str(s)?;
52                let r = Self::Files(base);
53                res.push(r);
54            } else {
55                bail!("expected netidx: or file:")
56            }
57        }
58        Ok(res)
59    }
60}
61
62impl Expr {
63    pub fn has_unresolved_modules(&self) -> bool {
64        self.fold(false, &mut |acc, e| {
65            acc || match &e.kind {
66                ExprKind::Module { value: ModuleKind::Unresolved, .. } => true,
67                _ => false,
68            }
69        })
70    }
71
72    /// Resolve external modules referenced in the expression using
73    /// the resolvers list. Each resolver will be tried in order,
74    /// until one succeeds. If no resolver succeeds then an error will
75    /// be returned.
76    pub async fn resolve_modules<'a>(
77        &'a self,
78        resolvers: &'a Arc<[ModuleResolver]>,
79    ) -> Result<Expr> {
80        self.resolve_modules_int(&ModPath::root(), &None, resolvers).await
81    }
82
83    async fn resolve_modules_int<'a>(
84        &'a self,
85        scope: &ModPath,
86        prepend: &'a Option<Arc<ModuleResolver>>,
87        resolvers: &'a Arc<[ModuleResolver]>,
88    ) -> Result<Expr> {
89        if self.has_unresolved_modules() {
90            self.resolve_modules_inner(scope, prepend, resolvers).await
91        } else {
92            Ok(self.clone())
93        }
94    }
95
96    fn resolve_modules_inner<'a>(
97        &'a self,
98        scope: &'a ModPath,
99        prepend: &'a Option<Arc<ModuleResolver>>,
100        resolvers: &'a Arc<[ModuleResolver]>,
101    ) -> Pin<Box<dyn Future<Output = Result<Expr>> + Send + Sync + 'a>> {
102        macro_rules! subexprs {
103            ($args:expr) => {{
104                try_join_all($args.iter().map(|e| async {
105                    e.resolve_modules_int(scope, prepend, resolvers).await
106                }))
107                .await?
108            }};
109        }
110        macro_rules! subtuples {
111            ($args:expr) => {{
112                try_join_all($args.iter().map(|(k, e)| async {
113                    Ok::<_, anyhow::Error>((
114                        k.clone(),
115                        e.resolve_modules_int(scope, prepend, resolvers).await?,
116                    ))
117                }))
118                .await?
119            }};
120        }
121        macro_rules! only_args {
122            ($kind:ident, $args:expr) => {
123                Box::pin(async move {
124                    let args = Arc::from(subexprs!($args));
125                    Ok(Expr {
126                        id: self.id,
127                        ori: self.ori.clone(),
128                        pos: self.pos,
129                        kind: ExprKind::$kind { args },
130                    })
131                })
132            };
133        }
134        macro_rules! bin_op {
135            ($kind:ident, $lhs:expr, $rhs:expr) => {
136                Box::pin(async move {
137                    let (lhs, rhs) = try_join!(
138                        $lhs.resolve_modules_int(scope, prepend, resolvers),
139                        $rhs.resolve_modules_int(scope, prepend, resolvers)
140                    )?;
141                    Ok(Expr {
142                        id: self.id,
143                        ori: self.ori.clone(),
144                        pos: self.pos,
145                        kind: ExprKind::$kind {
146                            lhs: Arc::from(lhs),
147                            rhs: Arc::from(rhs),
148                        },
149                    })
150                })
151            };
152        }
153        async fn resolve(
154            scope: ModPath,
155            prepend: Option<Arc<ModuleResolver>>,
156            resolvers: Arc<[ModuleResolver]>,
157            id: ExprId,
158            parent: Arc<Origin>,
159            pos: SourcePosition,
160            export: bool,
161            name: ArcStr,
162        ) -> Result<Expr> {
163            let jh = task::spawn(async move {
164                let ts = Instant::now();
165                let name_rel = name.trim_start_matches(Path::SEP);
166                let name_mod = Path::from(name.clone()).append("mod.gx");
167                let name_mod = name_mod.trim_start_matches(Path::SEP);
168                let mut errors = vec![];
169                for r in prepend.iter().map(|r| r.as_ref()).chain(resolvers.iter()) {
170                    let ori = match r {
171                        ModuleResolver::VFS(vfs) => {
172                            let scoped = scope.append(&*name);
173                            match vfs.get(&scoped) {
174                                Some(s) => Origin {
175                                    parent: Some(parent.clone()),
176                                    source: Source::Internal(name.clone()),
177                                    text: s.clone(),
178                                },
179                                None => continue,
180                            }
181                        }
182                        ModuleResolver::Files(base) => {
183                            let full_path = base
184                                .join(name_rel)
185                                .with_extension("gx")
186                                .canonicalize()?;
187                            match tokio::fs::read_to_string(&full_path).await {
188                                Ok(s) => Origin {
189                                    parent: Some(parent.clone()),
190                                    source: Source::File(full_path),
191                                    text: ArcStr::from(s),
192                                },
193                                Err(_) => {
194                                    let full_path = base.join(name_mod).canonicalize()?;
195                                    match tokio::fs::read_to_string(&full_path).await {
196                                        Ok(s) => Origin {
197                                            parent: Some(parent.clone()),
198                                            source: Source::File(full_path),
199                                            text: ArcStr::from(s),
200                                        },
201                                        Err(e) => {
202                                            errors.push(anyhow::Error::from(e));
203                                            continue;
204                                        }
205                                    }
206                                }
207                            }
208                        }
209                        ModuleResolver::Netidx { subscriber, base, timeout } => {
210                            let full_path = base.append(name_rel);
211                            let source = Source::Netidx(full_path.clone());
212                            let sub = subscriber
213                                .subscribe_nondurable_one(full_path, *timeout)
214                                .await;
215                            match sub {
216                                Err(e) => {
217                                    errors.push(e);
218                                    continue;
219                                }
220                                Ok(v) => match v.last() {
221                                    Event::Update(Value::String(text)) => Origin {
222                                        parent: Some(parent.clone()),
223                                        source,
224                                        text,
225                                    },
226                                    Event::Unsubscribed | Event::Update(_) => {
227                                        errors.push(anyhow!("expected string"));
228                                        continue;
229                                    }
230                                },
231                            }
232                        }
233                    };
234                    let value = ModuleKind::Resolved(
235                        parser::parse(ori.clone())
236                            .with_context(|| format!("parsing file {ori:?}"))?,
237                    );
238                    let kind = ExprKind::Module { name, export, value };
239                    format_with_flags(PrintFlag::NoSource | PrintFlag::NoParents, || {
240                        info!("load and parse {ori} {:?}", ts.elapsed())
241                    });
242                    return Ok(Expr { id, ori: Arc::new(ori), pos, kind });
243                }
244                bail!("module {name} could not be found {errors:?}")
245            });
246            jh.await?
247        }
248        if !self.has_unresolved_modules() {
249            return Box::pin(async { Ok(self.clone()) });
250        }
251        match self.kind.clone() {
252            ExprKind::Module { value: ModuleKind::Unresolved, export, name } => {
253                let (id, pos, prepend, resolvers) =
254                    (self.id, self.pos, prepend.clone(), Arc::clone(resolvers));
255                Box::pin(async move {
256                    let e = resolve(
257                        scope.clone(),
258                        prepend.clone(),
259                        resolvers.clone(),
260                        id,
261                        self.ori.clone(),
262                        pos,
263                        export,
264                        name.clone(),
265                    )
266                    .await?;
267                    let scope = ModPath(scope.append(&*name));
268                    e.resolve_modules_int(&scope, &prepend, &resolvers).await
269                })
270            }
271            ExprKind::Constant(_)
272            | ExprKind::Use { .. }
273            | ExprKind::Ref { .. }
274            | ExprKind::StructRef { .. }
275            | ExprKind::TupleRef { .. }
276            | ExprKind::TypeDef { .. } => Box::pin(async move { Ok(self.clone()) }),
277            ExprKind::Module { value: ModuleKind::Inline(exprs), export, name } => {
278                Box::pin(async move {
279                    let scope = ModPath(scope.append(&*name));
280                    let exprs = try_join_all(exprs.iter().map(|e| async {
281                        e.resolve_modules_int(&scope, prepend, resolvers).await
282                    }))
283                    .await?;
284                    Ok(Expr {
285                        id: self.id,
286                        ori: self.ori.clone(),
287                        pos: self.pos,
288                        kind: ExprKind::Module {
289                            value: ModuleKind::Inline(Arc::from(exprs)),
290                            name,
291                            export,
292                        },
293                    })
294                })
295            }
296            ExprKind::Module { value: ModuleKind::Resolved(exprs), export, name } => {
297                Box::pin(async move {
298                    let prepend = match &self.ori.source {
299                        Source::Unspecified | Source::Internal(_) => None,
300                        Source::File(p) => {
301                            p.parent().map(|p| Arc::new(ModuleResolver::Files(p.into())))
302                        }
303                        Source::Netidx(p) => resolvers.iter().find_map(|m| match m {
304                            ModuleResolver::Netidx { subscriber, timeout, .. } => {
305                                Some(Arc::new(ModuleResolver::Netidx {
306                                    subscriber: subscriber.clone(),
307                                    base: p.clone(),
308                                    timeout: *timeout,
309                                }))
310                            }
311                            ModuleResolver::Files(_) | ModuleResolver::VFS(_) => None,
312                        }),
313                    };
314                    let exprs = try_join_all(exprs.iter().map(|e| async {
315                        e.resolve_modules_int(&scope, &prepend, resolvers).await
316                    }))
317                    .await?;
318                    Ok(Expr {
319                        id: self.id,
320                        ori: self.ori.clone(),
321                        pos: self.pos,
322                        kind: ExprKind::Module {
323                            value: ModuleKind::Resolved(Arc::from(exprs)),
324                            name,
325                            export,
326                        },
327                    })
328                })
329            }
330            ExprKind::Module {
331                name,
332                export,
333                value: ModuleKind::Dynamic { sandbox, sig, source },
334            } => Box::pin(async move {
335                let source = Arc::new(
336                    source.resolve_modules_int(scope, prepend, resolvers).await?,
337                );
338                Ok(Expr {
339                    id: self.id,
340                    ori: self.ori.clone(),
341                    pos: self.pos,
342                    kind: ExprKind::Module {
343                        name,
344                        export,
345                        value: ModuleKind::Dynamic { sandbox, sig, source },
346                    },
347                })
348            }),
349            ExprKind::Do { exprs } => Box::pin(async move {
350                let exprs = Arc::from(subexprs!(exprs));
351                Ok(Expr {
352                    id: self.id,
353                    ori: self.ori.clone(),
354                    pos: self.pos,
355                    kind: ExprKind::Do { exprs },
356                })
357            }),
358            ExprKind::Bind(b) => Box::pin(async move {
359                let Bind { rec, doc, pattern, typ, export, value } = &*b;
360                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
361                Ok(Expr {
362                    id: self.id,
363                    ori: self.ori.clone(),
364                    pos: self.pos,
365                    kind: ExprKind::Bind(Arc::new(Bind {
366                        rec: *rec,
367                        doc: doc.clone(),
368                        pattern: pattern.clone(),
369                        typ: typ.clone(),
370                        export: *export,
371                        value,
372                    })),
373                })
374            }),
375            ExprKind::StructWith { source, replace } => Box::pin(async move {
376                Ok(Expr {
377                    id: self.id,
378                    ori: self.ori.clone(),
379                    pos: self.pos,
380                    kind: ExprKind::StructWith {
381                        source: Arc::new(
382                            source.resolve_modules_int(scope, prepend, resolvers).await?,
383                        ),
384                        replace: Arc::from(subtuples!(replace)),
385                    },
386                })
387            }),
388            ExprKind::Connect { name, value, deref } => Box::pin(async move {
389                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
390                Ok(Expr {
391                    id: self.id,
392                    ori: self.ori.clone(),
393                    pos: self.pos,
394                    kind: ExprKind::Connect { name, value: Arc::new(value), deref },
395                })
396            }),
397            ExprKind::Lambda(l) => Box::pin(async move {
398                let Lambda { args, vargs, rtype, constraints, body } = &*l;
399                let body = match body {
400                    Either::Right(s) => Either::Right(s.clone()),
401                    Either::Left(e) => Either::Left(
402                        e.resolve_modules_int(scope, prepend, resolvers).await?,
403                    ),
404                };
405                let l = Lambda {
406                    args: args.clone(),
407                    vargs: vargs.clone(),
408                    rtype: rtype.clone(),
409                    constraints: constraints.clone(),
410                    body,
411                };
412                let kind = ExprKind::Lambda(Arc::new(l));
413                Ok(Expr { id: self.id, ori: self.ori.clone(), pos: self.pos, kind })
414            }),
415            ExprKind::TypeCast { expr, typ } => Box::pin(async move {
416                let expr = expr.resolve_modules_int(scope, prepend, resolvers).await?;
417                Ok(Expr {
418                    id: self.id,
419                    ori: self.ori.clone(),
420                    pos: self.pos,
421                    kind: ExprKind::TypeCast { expr: Arc::new(expr), typ },
422                })
423            }),
424            ExprKind::Apply { args, function } => Box::pin(async move {
425                Ok(Expr {
426                    id: self.id,
427                    ori: self.ori.clone(),
428                    pos: self.pos,
429                    kind: ExprKind::Apply { args: Arc::from(subtuples!(args)), function },
430                })
431            }),
432            ExprKind::Any { args } => only_args!(Any, args),
433            ExprKind::Array { args } => only_args!(Array, args),
434            ExprKind::Tuple { args } => only_args!(Tuple, args),
435            ExprKind::StringInterpolate { args } => only_args!(StringInterpolate, args),
436            ExprKind::Struct { args } => Box::pin(async move {
437                let args = Arc::from(subtuples!(args));
438                Ok(Expr {
439                    id: self.id,
440                    ori: self.ori.clone(),
441                    pos: self.pos,
442                    kind: ExprKind::Struct { args },
443                })
444            }),
445            ExprKind::ArrayRef { source, i } => Box::pin(async move {
446                let source = Arc::new(
447                    source.resolve_modules_int(scope, prepend, resolvers).await?,
448                );
449                let i = Arc::new(i.resolve_modules_int(scope, prepend, resolvers).await?);
450                Ok(Expr {
451                    id: self.id,
452                    ori: self.ori.clone(),
453                    pos: self.pos,
454                    kind: ExprKind::ArrayRef { source, i },
455                })
456            }),
457            ExprKind::ArraySlice { source, start, end } => Box::pin(async move {
458                let source = Arc::new(
459                    source.resolve_modules_int(scope, prepend, resolvers).await?,
460                );
461                let start = match start {
462                    None => None,
463                    Some(e) => Some(Arc::new(
464                        e.resolve_modules_int(scope, prepend, resolvers).await?,
465                    )),
466                };
467                let end = match end {
468                    None => None,
469                    Some(e) => Some(Arc::new(
470                        e.resolve_modules_int(scope, prepend, resolvers).await?,
471                    )),
472                };
473                Ok(Expr {
474                    id: self.id,
475                    ori: self.ori.clone(),
476                    pos: self.pos,
477                    kind: ExprKind::ArraySlice { source, start, end },
478                })
479            }),
480            ExprKind::Variant { tag, args } => Box::pin(async move {
481                let args = Arc::from(subexprs!(args));
482                Ok(Expr {
483                    id: self.id,
484                    ori: self.ori.clone(),
485                    pos: self.pos,
486                    kind: ExprKind::Variant { tag, args },
487                })
488            }),
489            ExprKind::Select { arg, arms } => Box::pin(async move {
490                let arg =
491                    Arc::new(arg.resolve_modules_int(scope, prepend, resolvers).await?);
492                let arms = try_join_all(arms.iter().map(|(p, e)| async {
493                    let p = match &p.guard {
494                        None => p.clone(),
495                        Some(e) => {
496                            let e =
497                                e.resolve_modules_int(scope, prepend, resolvers).await?;
498                            Pattern {
499                                guard: Some(e),
500                                type_predicate: p.type_predicate.clone(),
501                                structure_predicate: p.structure_predicate.clone(),
502                            }
503                        }
504                    };
505                    let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
506                    Ok::<_, anyhow::Error>((p, e))
507                }))
508                .await?;
509                Ok(Expr {
510                    id: self.id,
511                    ori: self.ori.clone(),
512                    pos: self.pos,
513                    kind: ExprKind::Select { arg, arms: Arc::from(arms) },
514                })
515            }),
516            ExprKind::Qop(e) => Box::pin(async move {
517                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
518                Ok(Expr {
519                    id: self.id,
520                    ori: self.ori.clone(),
521                    pos: self.pos,
522                    kind: ExprKind::Qop(Arc::new(e)),
523                })
524            }),
525            ExprKind::ByRef(e) => Box::pin(async move {
526                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
527                Ok(Expr {
528                    id: self.id,
529                    ori: self.ori.clone(),
530                    pos: self.pos,
531                    kind: ExprKind::ByRef(Arc::new(e)),
532                })
533            }),
534            ExprKind::Deref(e) => Box::pin(async move {
535                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
536                Ok(Expr {
537                    id: self.id,
538                    ori: self.ori.clone(),
539                    pos: self.pos,
540                    kind: ExprKind::Deref(Arc::new(e)),
541                })
542            }),
543            ExprKind::Not { expr: e } => Box::pin(async move {
544                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
545                Ok(Expr {
546                    id: self.id,
547                    ori: self.ori.clone(),
548                    pos: self.pos,
549                    kind: ExprKind::Not { expr: Arc::new(e) },
550                })
551            }),
552            ExprKind::Add { lhs, rhs } => bin_op!(Add, lhs, rhs),
553            ExprKind::Sub { lhs, rhs } => bin_op!(Sub, lhs, rhs),
554            ExprKind::Mul { lhs, rhs } => bin_op!(Mul, lhs, rhs),
555            ExprKind::Div { lhs, rhs } => bin_op!(Div, lhs, rhs),
556            ExprKind::Mod { lhs, rhs } => bin_op!(Mul, lhs, rhs),
557            ExprKind::And { lhs, rhs } => bin_op!(And, lhs, rhs),
558            ExprKind::Or { lhs, rhs } => bin_op!(Or, lhs, rhs),
559            ExprKind::Eq { lhs, rhs } => bin_op!(Eq, lhs, rhs),
560            ExprKind::Ne { lhs, rhs } => bin_op!(Ne, lhs, rhs),
561            ExprKind::Gt { lhs, rhs } => bin_op!(Gt, lhs, rhs),
562            ExprKind::Lt { lhs, rhs } => bin_op!(Lt, lhs, rhs),
563            ExprKind::Gte { lhs, rhs } => bin_op!(Gte, lhs, rhs),
564            ExprKind::Lte { lhs, rhs } => bin_op!(Lte, lhs, rhs),
565            ExprKind::Sample { lhs, rhs } => bin_op!(Sample, lhs, rhs),
566        }
567    }
568}