From 1868f1a5062ace6da815caf5f96906678406b451 Mon Sep 17 00:00:00 2001 From: Lawrence Bethlenfalvy Date: Sun, 4 May 2025 16:37:32 +0100 Subject: [PATCH] moving back --- orchid-host/src/dealias.rs | 76 +++++++++++++++++++++++++------------- orchid-host/src/parsed.rs | 40 ++++++++++---------- 2 files changed, 70 insertions(+), 46 deletions(-) diff --git a/orchid-host/src/dealias.rs b/orchid-host/src/dealias.rs index 3cc18f0..5a36d11 100644 --- a/orchid-host/src/dealias.rs +++ b/orchid-host/src/dealias.rs @@ -3,7 +3,7 @@ use std::collections::VecDeque; use futures::FutureExt; use hashbrown::{HashMap, HashSet}; use itertools::{Either, Itertools}; -use orchid_base::error::{OrcErr, Reporter, mk_err}; +use orchid_base::error::{OrcErr, OrcRes, Reporter, mk_err, mk_errv}; use orchid_base::interner::{Interner, Tok}; use orchid_base::location::Pos; use orchid_base::name::{NameLike, Sym, VName}; @@ -85,13 +85,13 @@ pub async fn resolv_glob( pos: Pos, i: &Interner, rep: &Reporter, - walk_cx: &mut Mod::Ctx, -) -> Vec> { + ctx: &mut Mod::Ctx, +) -> OrcRes>> { let coprefix_len = cwd.iter().zip(abs_path).take_while(|(a, b)| a == b).count(); - let (co_prefix, diff_path) = abs_path.split_at(coprefix_len); - let co_parent = - root.walk(true, co_prefix.iter().cloned(), walk_cx).await.expect("Invalid step in cwd"); - let target_module = match co_parent.walk(false, diff_path.iter().cloned(), walk_cx).await { + let (co_prefix, diff_path) = abs_path.split_at(abs_path.len().min(coprefix_len + 1)); + let fst_diff = + walk(root, false, co_prefix.iter().cloned(), ctx).await.expect("Invalid step in cwd"); + let target_module = match walk(fst_diff, true, diff_path.iter().cloned(), ctx).await { Ok(t) => t, Err(e) => { let path = abs_path[..=coprefix_len + e.pos].iter().join("::"); @@ -101,11 +101,10 @@ pub async fn resolv_glob( ChildErrorKind::Missing => (i.i("Invalid import path").await, format!("{path} not found")), ChildErrorKind::Private => (i.i("Import inaccessible").await, format!("{path} is private")), }; - rep.report(mk_err(tk, msg, [pos.into()])); - return vec![]; + return Err(mk_errv(tk, msg, [pos.into()])); }, }; - target_module.children(false) + Ok(target_module.children(coprefix_len < abs_path.len())) } pub enum ChildResult<'a, T: Tree + ?Sized> { @@ -116,7 +115,12 @@ pub enum ChildResult<'a, T: Tree + ?Sized> { pub trait Tree { type Ctx; fn children(&self, public_only: bool) -> HashSet>; - fn child(&self, key: Tok, public_only: bool) -> ChildResult<'_, Self>; + fn child( + &self, + key: Tok, + public_only: bool, + ctx: &mut Self::Ctx, + ) -> impl Future>; } #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum ChildErrorKind { @@ -126,7 +130,7 @@ pub enum ChildErrorKind { } #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ChildError { - pub at_path: Vec>, + pub pos: usize, pub kind: ChildErrorKind, } @@ -141,22 +145,42 @@ pub struct ChildError { // caveat: we need to check EVERY IMPORT to ensure that all // errors are raised -fn walk_no_access_chk( - root: &T, - path: impl IntoIterator>, -) -> Result<&T, ChildError> { - let mut cur = root; - let mut cur_path = Vec::new(); - let mut path = VecDeque::from(path); - while let Some(step) = path.pop_front() { - match cur.child(step, false) { +async fn walk_no_access_chk<'a, T: Tree>( + root: &'a T, + cur: &mut &'a T, + path: impl IntoIterator, IntoIter: DoubleEndedIterator>, + ctx: &mut T::Ctx, +) -> Result<(), ChildErrorKind> { + // this VecDeque is used like a stack to leverage its Extend implementation. + let mut path: VecDeque> = path.into_iter().rev().collect(); + while let Some(step) = path.pop_back() { + match cur.child(step, false, ctx).await { ChildResult::Alias(target) => { - path.reserve(target.len()); - target.iter().rev().for_each(|tok| path.push_front(tok.clone())); - cur = root; - cur_path = Vec::new(); + path.extend(target.iter().cloned().rev()); + *cur = root; }, - ChildResult::Err(e) => return Err(ChildError { pos: (), kind: () }), + ChildResult::Err(e) => return Err(e), + ChildResult::Value(v) => *cur = v, } } + Ok(()) +} + +async fn walk<'a, T: Tree>( + root: &'a T, + public_only: bool, + path: impl IntoIterator>, + ctx: &mut T::Ctx, +) -> Result<&'a T, ChildError> { + let mut cur = root; + for (i, item) in path.into_iter().enumerate() { + match cur.child(item, public_only, ctx).await { + ChildResult::Value(v) => cur = v, + ChildResult::Err(kind) => return Err(ChildError { pos: i, kind }), + ChildResult::Alias(path) => (walk_no_access_chk(root, &mut cur, path.iter().cloned(), ctx) + .await) + .map_err(|kind| ChildError { kind, pos: i })?, + } + } + Ok(cur) } diff --git a/orchid-host/src/parsed.rs b/orchid-host/src/parsed.rs index 21b8eed..aba4836 100644 --- a/orchid-host/src/parsed.rs +++ b/orchid-host/src/parsed.rs @@ -19,6 +19,7 @@ use orchid_base::tree::{TokTree, Token, TokenVariant}; use crate::api; use crate::ctx::Ctx; +use crate::dealias::{ChildErrorKind, ChildResult, Tree}; use crate::expr::{Expr, ExprParseCtx, PathSetBuilder}; use crate::expr_store::ExprStore; use crate::system::System; @@ -121,6 +122,9 @@ pub enum ParsedMemberKind { Mod(ParsedModule), } +// TODO: cannot determine alias origin at this stage; parsed tree is never +// walkable! + #[derive(Debug, Default)] pub struct ParsedModule { pub exports: Vec>, @@ -149,29 +153,25 @@ impl ParsedModule { } impl Tree for ParsedModule { type Ctx = (); - async fn walk>>( + async fn child( &self, + key: Tok, public_only: bool, - path: I, - _ctx: &'_ mut Self::Ctx, - ) -> Result<&Self, WalkError> { - let mut cur = self; - for (pos, step) in path.into_iter().enumerate() { - let Some(member) = (cur.items.iter()) - .filter_map(|it| if let ItemKind::Member(m) = &it.kind { Some(m) } else { None }) - .find(|m| m.name == step) - else { - return Err(WalkError { pos, kind: WalkErrorKind::Missing }); - }; - if public_only && !cur.exports.contains(&step) { - return Err(WalkError { pos, kind: WalkErrorKind::Private }); - } - match &member.kind { - ParsedMemberKind::Const => return Err(WalkError { pos, kind: WalkErrorKind::Constant }), - ParsedMemberKind::Mod(m) => cur = m, - } + ctx: &mut Self::Ctx, + ) -> ChildResult<'_, Self> { + let Some(member) = (self.items.iter()) + .filter_map(|it| if let ItemKind::Member(m) = &it.kind { Some(m) } else { None }) + .find(|m| m.name == key) + else { + return ChildResult::Err(ChildErrorKind::Missing); + }; + if public_only && !self.exports.contains(&key) { + return ChildResult::Err(ChildErrorKind::Private); + } + match &member.kind { + ParsedMemberKind::Const => return ChildResult::Err(ChildErrorKind::Constant), + ParsedMemberKind::Mod(m) => return ChildResult::Value(m), } - Ok(cur) } fn children(&self, public_only: bool) -> HashSet> { let mut public: HashSet<_> = self.exports.iter().cloned().collect();