graphix_compiler/expr/
resolver.rs

1use crate::{
2    expr::{
3        parser, Bind, CouldNotResolve, Expr, ExprId, ExprKind, Lambda, ModPath,
4        ModuleKind, Origin, Pattern, Source, TryCatch,
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
62async fn resolve(
63    scope: ModPath,
64    prepend: Option<Arc<ModuleResolver>>,
65    resolvers: Arc<[ModuleResolver]>,
66    id: ExprId,
67    parent: Arc<Origin>,
68    pos: SourcePosition,
69    export: bool,
70    name: ArcStr,
71) -> Result<Expr> {
72    let jh = task::spawn(async move {
73        let ts = Instant::now();
74        let name = Path::from(name);
75        let mut errors = vec![];
76        for r in prepend.iter().map(|r| r.as_ref()).chain(resolvers.iter()) {
77            let ori = match r {
78                ModuleResolver::VFS(vfs) => {
79                    let scoped = scope.append(&name);
80                    match vfs.get(&scoped) {
81                        Some(s) => Origin {
82                            parent: Some(parent.clone()),
83                            source: Source::Internal(name.clone().into()),
84                            text: s.clone(),
85                        },
86                        None => continue,
87                    }
88                }
89                ModuleResolver::Files(base) => {
90                    let mut full_path = base.clone();
91                    for part in Path::parts(&name) {
92                        full_path.push(part);
93                    }
94                    full_path.set_extension("gx");
95                    match tokio::fs::read_to_string(&full_path).await {
96                        Ok(s) => Origin {
97                            parent: Some(parent.clone()),
98                            source: Source::File(full_path),
99                            text: ArcStr::from(s),
100                        },
101                        Err(_) => {
102                            full_path.set_extension("");
103                            full_path.push("mod.gx");
104                            match tokio::fs::read_to_string(&full_path).await {
105                                Ok(s) => Origin {
106                                    parent: Some(parent.clone()),
107                                    source: Source::File(full_path),
108                                    text: ArcStr::from(s),
109                                },
110                                Err(e) => {
111                                    errors.push(anyhow::Error::from(e));
112                                    continue;
113                                }
114                            }
115                        }
116                    }
117                }
118                ModuleResolver::Netidx { subscriber, base, timeout } => {
119                    let full_path = base.append(&name);
120                    let source = Source::Netidx(full_path.clone());
121                    let sub =
122                        subscriber.subscribe_nondurable_one(full_path, *timeout).await;
123                    match sub {
124                        Err(e) => {
125                            errors.push(e);
126                            continue;
127                        }
128                        Ok(v) => match v.last() {
129                            Event::Update(Value::String(text)) => {
130                                Origin { parent: Some(parent.clone()), source, text }
131                            }
132                            Event::Unsubscribed | Event::Update(_) => {
133                                errors.push(anyhow!("expected string"));
134                                continue;
135                            }
136                        },
137                    }
138                }
139            };
140            let value = ModuleKind::Resolved(
141                parser::parse(ori.clone())
142                    .with_context(|| format!("parsing file {ori:?}"))?,
143            );
144            let kind = ExprKind::Module { name: name.clone().into(), export, value };
145            format_with_flags(PrintFlag::NoSource | PrintFlag::NoParents, || {
146                info!("load and parse {ori} {:?}", ts.elapsed())
147            });
148            return Ok(Expr { id, ori: Arc::new(ori), pos, kind });
149        }
150        bail!("module {name} could not be found {errors:?}")
151    });
152    jh.await?
153}
154
155impl Expr {
156    pub fn has_unresolved_modules(&self) -> bool {
157        self.fold(false, &mut |acc, e| {
158            acc || match &e.kind {
159                ExprKind::Module { value: ModuleKind::Unresolved, .. } => true,
160                _ => false,
161            }
162        })
163    }
164
165    /// Resolve external modules referenced in the expression using
166    /// the resolvers list. Each resolver will be tried in order,
167    /// until one succeeds. If no resolver succeeds then an error will
168    /// be returned.
169    pub async fn resolve_modules<'a>(
170        &'a self,
171        resolvers: &'a Arc<[ModuleResolver]>,
172    ) -> Result<Expr> {
173        self.resolve_modules_int(&ModPath::root(), &None, resolvers).await
174    }
175
176    async fn resolve_modules_int<'a>(
177        &'a self,
178        scope: &ModPath,
179        prepend: &'a Option<Arc<ModuleResolver>>,
180        resolvers: &'a Arc<[ModuleResolver]>,
181    ) -> Result<Expr> {
182        if self.has_unresolved_modules() {
183            self.resolve_modules_inner(scope, prepend, resolvers).await
184        } else {
185            Ok(self.clone())
186        }
187    }
188
189    fn resolve_modules_inner<'a>(
190        &'a self,
191        scope: &'a ModPath,
192        prepend: &'a Option<Arc<ModuleResolver>>,
193        resolvers: &'a Arc<[ModuleResolver]>,
194    ) -> Pin<Box<dyn Future<Output = Result<Expr>> + Send + Sync + 'a>> {
195        macro_rules! subexprs {
196            ($args:expr) => {{
197                try_join_all($args.iter().map(|e| async {
198                    e.resolve_modules_int(scope, prepend, resolvers).await
199                }))
200                .await?
201            }};
202        }
203        macro_rules! subtuples {
204            ($args:expr) => {{
205                try_join_all($args.iter().map(|(k, e)| async {
206                    Ok::<_, anyhow::Error>((
207                        k.clone(),
208                        e.resolve_modules_int(scope, prepend, resolvers).await?,
209                    ))
210                }))
211                .await?
212            }};
213        }
214        macro_rules! expr {
215            ($kind:expr) => {
216                Ok(Expr {
217                    id: self.id,
218                    ori: self.ori.clone(),
219                    pos: self.pos,
220                    kind: $kind,
221                })
222            };
223        }
224        macro_rules! only_args {
225            ($kind:ident, $args:expr) => {
226                Box::pin(async move {
227                    let args = Arc::from(subexprs!($args));
228                    expr!(ExprKind::$kind { args })
229                })
230            };
231        }
232        macro_rules! bin_op {
233            ($kind:ident, $lhs:expr, $rhs:expr) => {
234                Box::pin(async move {
235                    let (lhs, rhs) = try_join!(
236                        $lhs.resolve_modules_int(scope, prepend, resolvers),
237                        $rhs.resolve_modules_int(scope, prepend, resolvers)
238                    )?;
239                    expr!(ExprKind::$kind { lhs: Arc::from(lhs), rhs: Arc::from(rhs) })
240                })
241            };
242        }
243        if !self.has_unresolved_modules() {
244            return Box::pin(async { Ok(self.clone()) });
245        }
246        match self.kind.clone() {
247            ExprKind::Module { value: ModuleKind::Unresolved, export, name } => {
248                let (id, pos, prepend, resolvers) =
249                    (self.id, self.pos, prepend.clone(), Arc::clone(resolvers));
250                Box::pin(async move {
251                    let e = resolve(
252                        scope.clone(),
253                        prepend.clone(),
254                        resolvers.clone(),
255                        id,
256                        self.ori.clone(),
257                        pos,
258                        export,
259                        name.clone(),
260                    )
261                    .await
262                    .with_context(|| CouldNotResolve(name.clone()))?;
263                    let scope = ModPath(scope.append(&*name));
264                    e.resolve_modules_int(&scope, &prepend, &resolvers).await
265                })
266            }
267            ExprKind::Constant(_)
268            | ExprKind::Use { .. }
269            | ExprKind::Ref { .. }
270            | ExprKind::StructRef { .. }
271            | ExprKind::TupleRef { .. }
272            | ExprKind::TypeDef { .. } => Box::pin(async move { Ok(self.clone()) }),
273            ExprKind::Module { value: ModuleKind::Inline(exprs), export, name } => {
274                Box::pin(async move {
275                    let scope = ModPath(scope.append(&*name));
276                    let exprs = try_join_all(exprs.iter().map(|e| async {
277                        e.resolve_modules_int(&scope, prepend, resolvers).await
278                    }))
279                    .await?;
280                    expr!(ExprKind::Module {
281                        value: ModuleKind::Inline(Arc::from(exprs)),
282                        name,
283                        export,
284                    })
285                })
286            }
287            ExprKind::Module { value: ModuleKind::Resolved(exprs), export, name } => {
288                Box::pin(async move {
289                    let prepend = match &self.ori.source {
290                        Source::Unspecified | Source::Internal(_) => None,
291                        Source::File(p) => {
292                            p.parent().map(|p| Arc::new(ModuleResolver::Files(p.into())))
293                        }
294                        Source::Netidx(p) => resolvers.iter().find_map(|m| match m {
295                            ModuleResolver::Netidx { subscriber, timeout, .. } => {
296                                Some(Arc::new(ModuleResolver::Netidx {
297                                    subscriber: subscriber.clone(),
298                                    base: p.clone(),
299                                    timeout: *timeout,
300                                }))
301                            }
302                            ModuleResolver::Files(_) | ModuleResolver::VFS(_) => None,
303                        }),
304                    };
305                    let exprs = try_join_all(exprs.iter().map(|e| async {
306                        e.resolve_modules_int(&scope, &prepend, resolvers).await
307                    }))
308                    .await?;
309                    expr!(ExprKind::Module {
310                        value: ModuleKind::Resolved(Arc::from(exprs)),
311                        name,
312                        export,
313                    })
314                })
315            }
316            ExprKind::Module {
317                name,
318                export,
319                value: ModuleKind::Dynamic { sandbox, sig, source },
320            } => Box::pin(async move {
321                let source = Arc::new(
322                    source.resolve_modules_int(scope, prepend, resolvers).await?,
323                );
324                expr!(ExprKind::Module {
325                    name,
326                    export,
327                    value: ModuleKind::Dynamic { sandbox, sig, source },
328                })
329            }),
330            ExprKind::Do { exprs } => Box::pin(async move {
331                let exprs = Arc::from(subexprs!(exprs));
332                expr!(ExprKind::Do { exprs })
333            }),
334            ExprKind::Bind(b) => Box::pin(async move {
335                let Bind { rec, doc, pattern, typ, export, value } = &*b;
336                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
337                expr!(ExprKind::Bind(Arc::new(Bind {
338                    rec: *rec,
339                    doc: doc.clone(),
340                    pattern: pattern.clone(),
341                    typ: typ.clone(),
342                    export: *export,
343                    value,
344                })))
345            }),
346            ExprKind::StructWith { source, replace } => Box::pin(async move {
347                expr!(ExprKind::StructWith {
348                    source: Arc::new(
349                        source.resolve_modules_int(scope, prepend, resolvers).await?,
350                    ),
351                    replace: Arc::from(subtuples!(replace)),
352                })
353            }),
354            ExprKind::Connect { name, value, deref } => Box::pin(async move {
355                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
356                expr!(ExprKind::Connect { name, value: Arc::new(value), deref })
357            }),
358            ExprKind::Lambda(l) => Box::pin(async move {
359                let Lambda { args, vargs, rtype, constraints, throws, body } = &*l;
360                let body = match body {
361                    Either::Right(s) => Either::Right(s.clone()),
362                    Either::Left(e) => Either::Left(
363                        e.resolve_modules_int(scope, prepend, resolvers).await?,
364                    ),
365                };
366                let l = Lambda {
367                    args: args.clone(),
368                    vargs: vargs.clone(),
369                    rtype: rtype.clone(),
370                    throws: throws.clone(),
371                    constraints: constraints.clone(),
372                    body,
373                };
374                expr!(ExprKind::Lambda(Arc::new(l)))
375            }),
376            ExprKind::TypeCast { expr, typ } => Box::pin(async move {
377                let expr = expr.resolve_modules_int(scope, prepend, resolvers).await?;
378                expr!(ExprKind::TypeCast { expr: Arc::new(expr), typ })
379            }),
380            ExprKind::Apply { args, function } => Box::pin(async move {
381                expr!(ExprKind::Apply { args: Arc::from(subtuples!(args)), function })
382            }),
383            ExprKind::Any { args } => only_args!(Any, args),
384            ExprKind::Array { args } => only_args!(Array, args),
385            ExprKind::Map { args } => Box::pin(async move {
386                let args = Arc::from(subtuples!(args));
387                expr!(ExprKind::Map { args })
388            }),
389            ExprKind::MapRef { source, key } => Box::pin(async move {
390                let source = Arc::new(
391                    source.resolve_modules_int(scope, prepend, resolvers).await?,
392                );
393                let key =
394                    Arc::new(key.resolve_modules_inner(scope, prepend, resolvers).await?);
395                expr!(ExprKind::MapRef { source, key })
396            }),
397            ExprKind::Tuple { args } => only_args!(Tuple, args),
398            ExprKind::StringInterpolate { args } => only_args!(StringInterpolate, args),
399            ExprKind::Struct { args } => Box::pin(async move {
400                let args = Arc::from(subtuples!(args));
401                expr!(ExprKind::Struct { args })
402            }),
403            ExprKind::ArrayRef { source, i } => Box::pin(async move {
404                let source = Arc::new(
405                    source.resolve_modules_int(scope, prepend, resolvers).await?,
406                );
407                let i = Arc::new(i.resolve_modules_int(scope, prepend, resolvers).await?);
408                expr!(ExprKind::ArrayRef { source, i })
409            }),
410            ExprKind::ArraySlice { source, start, end } => Box::pin(async move {
411                let source = Arc::new(
412                    source.resolve_modules_int(scope, prepend, resolvers).await?,
413                );
414                let start = match start {
415                    None => None,
416                    Some(e) => Some(Arc::new(
417                        e.resolve_modules_int(scope, prepend, resolvers).await?,
418                    )),
419                };
420                let end = match end {
421                    None => None,
422                    Some(e) => Some(Arc::new(
423                        e.resolve_modules_int(scope, prepend, resolvers).await?,
424                    )),
425                };
426                expr!(ExprKind::ArraySlice { source, start, end })
427            }),
428            ExprKind::Variant { tag, args } => Box::pin(async move {
429                let args = Arc::from(subexprs!(args));
430                expr!(ExprKind::Variant { tag, args })
431            }),
432            ExprKind::Select { arg, arms } => Box::pin(async move {
433                let arg =
434                    Arc::new(arg.resolve_modules_int(scope, prepend, resolvers).await?);
435                let arms = try_join_all(arms.iter().map(|(p, e)| async {
436                    let p = match &p.guard {
437                        None => p.clone(),
438                        Some(e) => {
439                            let e =
440                                e.resolve_modules_int(scope, prepend, resolvers).await?;
441                            Pattern {
442                                guard: Some(e),
443                                type_predicate: p.type_predicate.clone(),
444                                structure_predicate: p.structure_predicate.clone(),
445                            }
446                        }
447                    };
448                    let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
449                    Ok::<_, anyhow::Error>((p, e))
450                }))
451                .await?;
452                expr!(ExprKind::Select { arg, arms: Arc::from(arms) })
453            }),
454            ExprKind::Qop(e) => Box::pin(async move {
455                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
456                expr!(ExprKind::Qop(Arc::new(e)))
457            }),
458            ExprKind::OrNever(e) => Box::pin(async move {
459                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
460                expr!(ExprKind::OrNever(Arc::new(e)))
461            }),
462            ExprKind::TryCatch(tc) => Box::pin(async move {
463                let exprs = try_join_all(tc.exprs.iter().map(|e| async {
464                    e.resolve_modules_int(&scope, &prepend, resolvers).await
465                }))
466                .await?;
467                let handler =
468                    tc.handler.resolve_modules_int(scope, prepend, resolvers).await?;
469                expr!(ExprKind::TryCatch(Arc::new(TryCatch {
470                    bind: tc.bind.clone(),
471                    constraint: tc.constraint.clone(),
472                    handler: Arc::new(handler),
473                    exprs: Arc::from_iter(exprs),
474                })))
475            }),
476            ExprKind::ByRef(e) => Box::pin(async move {
477                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
478                expr!(ExprKind::ByRef(Arc::new(e)))
479            }),
480            ExprKind::Deref(e) => Box::pin(async move {
481                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
482                expr!(ExprKind::Deref(Arc::new(e)))
483            }),
484            ExprKind::Not { expr: e } => Box::pin(async move {
485                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
486                expr!(ExprKind::Not { expr: Arc::new(e) })
487            }),
488            ExprKind::Add { lhs, rhs } => bin_op!(Add, lhs, rhs),
489            ExprKind::Sub { lhs, rhs } => bin_op!(Sub, lhs, rhs),
490            ExprKind::Mul { lhs, rhs } => bin_op!(Mul, lhs, rhs),
491            ExprKind::Div { lhs, rhs } => bin_op!(Div, lhs, rhs),
492            ExprKind::Mod { lhs, rhs } => bin_op!(Mul, lhs, rhs),
493            ExprKind::And { lhs, rhs } => bin_op!(And, lhs, rhs),
494            ExprKind::Or { lhs, rhs } => bin_op!(Or, lhs, rhs),
495            ExprKind::Eq { lhs, rhs } => bin_op!(Eq, lhs, rhs),
496            ExprKind::Ne { lhs, rhs } => bin_op!(Ne, lhs, rhs),
497            ExprKind::Gt { lhs, rhs } => bin_op!(Gt, lhs, rhs),
498            ExprKind::Lt { lhs, rhs } => bin_op!(Lt, lhs, rhs),
499            ExprKind::Gte { lhs, rhs } => bin_op!(Gte, lhs, rhs),
500            ExprKind::Lte { lhs, rhs } => bin_op!(Lte, lhs, rhs),
501            ExprKind::Sample { lhs, rhs } => bin_op!(Sample, lhs, rhs),
502        }
503    }
504}