graphix_compiler/expr/
resolver.rs

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