diff --git a/orchid-base/src/parse.rs b/orchid-base/src/parse.rs index c41c83c..b135b6c 100644 --- a/orchid-base/src/parse.rs +++ b/orchid-base/src/parse.rs @@ -10,8 +10,8 @@ use crate::api; use crate::error::{OrcRes, Reporter, mk_err, mk_errv}; use crate::format::fmt; use crate::interner::{Interner, Tok}; -use crate::location::{Pos, SrcRange}; -use crate::name::{VName, VPath}; +use crate::location::SrcRange; +use crate::name::{Sym, VName, VPath}; use crate::tree::{ExprRepr, ExtraTok, Paren, TokTree, Token, ttv_range}; pub trait ParseCtx { @@ -110,24 +110,24 @@ pub fn strip_fluff(tt: &TokTree) -> Option, - pub range: Range, + pub sr: SrcRange, } impl Comment { // XXX: which of these four are actually used? - pub async fn from_api(c: &api::Comment, i: &Interner) -> Self { - Self { text: i.ex(c.text).await, range: c.range.clone() } + pub async fn from_api(c: &api::Comment, src: Sym, i: &Interner) -> Self { + Self { text: i.ex(c.text).await, sr: SrcRange::new(c.range.clone(), &src) } } pub async fn from_tk(tk: &TokTree, i: &Interner) -> Option { match &tk.tok { - Token::Comment(text) => Some(Self { text: i.i(&**text).await, range: tk.range.clone() }), + Token::Comment(text) => Some(Self { text: i.i(&**text).await, sr: tk.sr.clone() }), _ => None, } } pub fn to_tk(&self) -> TokTree { - TokTree { tok: Token::Comment(self.text.rc().clone()), range: self.range.clone() } + TokTree { tok: Token::Comment(self.text.rc().clone()), sr: self.sr.clone() } } pub fn to_api(&self) -> api::Comment { - api::Comment { range: self.range.clone(), text: self.text.to_api() } + api::Comment { range: self.sr.range(), text: self.text.to_api() } } } diff --git a/orchid-extension/src/entrypoint.rs b/orchid-extension/src/entrypoint.rs index 0d62a2c..02c30d8 100644 --- a/orchid-extension/src/entrypoint.rs +++ b/orchid-extension/src/entrypoint.rs @@ -299,7 +299,8 @@ pub fn extension_init( let mut ctx = get_ctx(*sys).await; let parsers = ctx.cted().inst().dyn_parsers(); let src = Sym::from_api(*src, ctx.i()).await; - let comments = join_all(comments.iter().map(|c| Comment::from_api(c, &i))).await; + let comments = + join_all(comments.iter().map(|c| Comment::from_api(c, src.clone(), &i))).await; let line: Vec = ttv_from_api(line, &mut ctx, &mut (), &src, &i).await; let snip = Snippet::new(line.first().expect("Empty line"), &line); let (head, tail) = snip.pop_front().unwrap(); diff --git a/orchid-host/src/dealias.rs b/orchid-host/src/dealias.rs index 56cd4c6..3cc18f0 100644 --- a/orchid-host/src/dealias.rs +++ b/orchid-host/src/dealias.rs @@ -1,3 +1,5 @@ +use std::collections::VecDeque; + use futures::FutureExt; use hashbrown::{HashMap, HashSet}; use itertools::{Either, Itertools}; @@ -8,7 +10,7 @@ use orchid_base::name::{NameLike, Sym, VName}; use substack::Substack; use crate::expr::Expr; -use crate::parsed::{ItemKind, ParsedMemberKind, ParsedModule, WalkErrorKind}; +use crate::parsed::{ItemKind, ParsedMemberKind, ParsedModule}; /// Errors produced by absolute_path #[derive(Clone, Debug, Hash, PartialEq, Eq)] @@ -74,129 +76,87 @@ pub fn absolute_path( pub struct DealiasCtx<'a> { pub i: &'a Interner, pub rep: &'a Reporter, - pub consts: &'a mut HashMap, } -pub async fn resolv_glob( +pub async fn resolv_glob( cwd: &[Tok], - root: &ParsedModule, + root: &Mod, abs_path: &[Tok], pos: Pos, - ctx: &mut DealiasCtx<'_>, + i: &Interner, + rep: &Reporter, + walk_cx: &mut Mod::Ctx, ) -> Vec> { 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(false, co_prefix.iter().cloned(), ctx.consts).await.expect("Invalid step in cwd"); - let target_module = match co_parent.walk(true, diff_path.iter().cloned(), ctx.consts).await { + 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 { Ok(t) => t, Err(e) => { let path = abs_path[..=coprefix_len + e.pos].iter().join("::"); let (tk, msg) = match e.kind { - WalkErrorKind::Constant => - (ctx.i.i("Invalid import path").await, format!("{path} is a constant")), - WalkErrorKind::Missing => - (ctx.i.i("Invalid import path").await, format!("{path} not found")), - WalkErrorKind::Private => - (ctx.i.i("Import inaccessible").await, format!("{path} is private")), + ChildErrorKind::Constant => + (i.i("Invalid import path").await, format!("{path} is a const")), + ChildErrorKind::Missing => (i.i("Invalid import path").await, format!("{path} not found")), + ChildErrorKind::Private => (i.i("Import inaccessible").await, format!("{path} is private")), }; - (&ctx.rep).report(mk_err(tk, msg, [pos.into()])); + rep.report(mk_err(tk, msg, [pos.into()])); return vec![]; }, }; - target_module.exports.clone() + target_module.children(false) } -/// Read import statements and convert them into aliases, rasising any import -/// errors in the process -pub async fn imports_to_aliases( - module: &ParsedModule, - cwd: &mut Vec>, - root: &ParsedModule, - alias_map: &mut HashMap, - alias_rev_map: &mut HashMap>, - ctx: &mut DealiasCtx<'_>, -) { - let mut import_locs = HashMap::>::new(); - for item in &module.items { - match &item.kind { - ItemKind::Import(imp) => match absolute_path(cwd, &imp.path) { - Err(e) => - ctx.rep.report(e.err_obj(ctx.i, item.sr.pos(), &imp.path.iter().join("::")).await), - Ok(abs_path) => { - let names = match imp.name.as_ref() { - Some(n) => Either::Right([n.clone()].into_iter()), - None => - Either::Left(resolv_glob(cwd, root, &abs_path, item.sr.pos(), ctx).await.into_iter()), - }; - for name in names { - let mut tgt = abs_path.clone().suffix([name.clone()]).to_sym(ctx.i).await; - let src = Sym::new(cwd.iter().cloned().chain([name]), ctx.i).await.unwrap(); - import_locs.entry(src.clone()).or_insert(vec![]).push(item.sr.pos()); - if let Some(tgt2) = alias_map.get(&tgt) { - tgt = tgt2.clone(); - } - if src == tgt { - ctx.rep.report(mk_err( - ctx.i.i("Circular references").await, - format!("{src} circularly refers to itself"), - [item.sr.pos().into()], - )); - continue; - } - if let Some(fst_val) = alias_map.get(&src) { - let locations = (import_locs.get(&src)) - .expect("The same name could only have appeared in the same module"); - ctx.rep.report(mk_err( - ctx.i.i("Conflicting imports").await, - if fst_val == &src { - format!("{src} is imported multiple times") - } else { - format!("{} could refer to both {fst_val} and {src}", src.last()) - }, - locations.iter().map(|p| p.clone().into()).collect_vec(), - )) - } - let mut srcv = vec![src.clone()]; - if let Some(src_extra) = alias_rev_map.remove(&src) { - srcv.extend(src_extra); - } - for src in srcv { - alias_map.insert(src.clone(), tgt.clone()); - alias_rev_map.entry(tgt.clone()).or_insert(HashSet::new()).insert(src); - } - } - }, - }, - ItemKind::Member(mem) => match mem.kind(ctx.consts).await { - ParsedMemberKind::Const => (), - ParsedMemberKind::Mod(m) => { - cwd.push(mem.name()); - imports_to_aliases(m, cwd, root, alias_map, alias_rev_map, ctx).boxed_local().await; - cwd.pop(); - }, - }, - ItemKind::Export(_) => (), - } - } -} - -pub async fn dealias( - path: Substack<'_, Tok>, - module: &mut ParsedModule, - alias_map: &HashMap, - ctx: &mut DealiasCtx<'_>, -) { - for item in &mut module.items { - match &mut item.kind { - ItemKind::Export(_) | ItemKind::Import(_) => (), - ItemKind::Member(mem) => { - let path = path.push(mem.name()); - match mem.kind_mut(ctx.consts).await { - ParsedMemberKind::Const => (), - ParsedMemberKind::Mod(m) => dealias(path, m, alias_map, ctx).boxed_local().await, - } +pub enum ChildResult<'a, T: Tree + ?Sized> { + Value(&'a T), + Err(ChildErrorKind), + Alias(&'a [Tok]), +} +pub trait Tree { + type Ctx; + fn children(&self, public_only: bool) -> HashSet>; + fn child(&self, key: Tok, public_only: bool) -> ChildResult<'_, Self>; +} +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub enum ChildErrorKind { + Missing, + Private, + Constant, +} +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct ChildError { + pub at_path: Vec>, + pub kind: ChildErrorKind, +} + +// Problem: walk should take into account aliases and visibility +// +// help: since every alias is also its own import, visibility only has to be +// checked on the top level +// +// idea: do a simple stack machine like below with no visibility for aliases and +// call it from an access-checking implementation for just the top level +// +// 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) { + ChildResult::Alias(target) => { + path.reserve(target.len()); + target.iter().rev().for_each(|tok| path.push_front(tok.clone())); + cur = root; + cur_path = Vec::new(); }, + ChildResult::Err(e) => return Err(ChildError { pos: (), kind: () }), } } } diff --git a/orchid-host/src/lex.rs b/orchid-host/src/lex.rs index d4d8988..eb9438f 100644 --- a/orchid-host/src/lex.rs +++ b/orchid-host/src/lex.rs @@ -150,11 +150,11 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes { for sys in ctx.systems { let mut errors = Vec::new(); if ctx.tail.starts_with(|c| sys.can_lex(c)) { - let (source, pos) = (ctx.source.clone(), ctx.get_pos()); + let (source, pos, path) = (ctx.source.clone(), ctx.get_pos(), ctx.path.clone()); let ctx_lck = &Mutex::new(&mut *ctx); let errors_lck = &Mutex::new(&mut errors); let lx = sys - .lex(source, pos, |pos| async move { + .lex(source, path, pos, |pos| async move { let mut ctx_g = ctx_lck.lock().await; match lex_once(&mut ctx_g.push(pos)).boxed_local().await { Ok(t) => Some(api::SubLexed { pos: t.sr.end(), tree: ctx_g.ser_subtree(t).await }), diff --git a/orchid-host/src/parsed.rs b/orchid-host/src/parsed.rs index 5090687..21b8eed 100644 --- a/orchid-host/src/parsed.rs +++ b/orchid-host/src/parsed.rs @@ -6,7 +6,7 @@ use async_std::sync::{Mutex, RwLock}; use async_stream::stream; use futures::future::join_all; use futures::{FutureExt, StreamExt}; -use hashbrown::HashMap; +use hashbrown::{HashMap, HashSet}; use itertools::Itertools; use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants}; @@ -61,18 +61,6 @@ impl TokenVariant for Expr { } } -pub struct ParsedFromApiCx<'a> { - pub sys: &'a System, - pub consts: &'a mut HashMap, - pub path: Tok>>, -} -impl<'a> ParsedFromApiCx<'a> { - pub async fn push<'c>(&'c mut self, name: Tok) -> ParsedFromApiCx<'c> { - let path = self.sys.ctx().i.i(&self.path.iter().cloned().chain([name]).collect_vec()).await; - ParsedFromApiCx { path, consts: &mut *self.consts, sys: self.sys } - } -} - #[derive(Debug)] pub struct Item { pub sr: SrcRange, @@ -154,11 +142,19 @@ impl ParsedModule { std::mem::swap(self, &mut swap); *self = ParsedModule::new(swap.items.into_iter().chain(other.items)) } - pub async fn walk<'a>( + pub fn get_imports(&self) -> impl IntoIterator { + (self.items.iter()) + .filter_map(|it| if let ItemKind::Import(i) = &it.kind { Some(i) } else { None }) + } +} +impl Tree for ParsedModule { + type Ctx = (); + async fn walk>>( &self, - allow_private: bool, - path: impl IntoIterator>, - ) -> Result<&ParsedModule, WalkError> { + 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()) @@ -167,7 +163,7 @@ impl ParsedModule { else { return Err(WalkError { pos, kind: WalkErrorKind::Missing }); }; - if !allow_private && !cur.exports.contains(&step) { + if public_only && !cur.exports.contains(&step) { return Err(WalkError { pos, kind: WalkErrorKind::Private }); } match &member.kind { @@ -177,22 +173,20 @@ impl ParsedModule { } Ok(cur) } - pub fn get_imports(&self) -> impl IntoIterator { - (self.items.iter()) - .filter_map(|it| if let ItemKind::Import(i) = &it.kind { Some(i) } else { None }) + fn children(&self, public_only: bool) -> HashSet> { + let mut public: HashSet<_> = self.exports.iter().cloned().collect(); + if !public_only { + public.extend( + (self.items.iter()) + .filter_map( + |it| if let ItemKind::Member(mem) = &it.kind { Some(&mem.name) } else { None }, + ) + .cloned(), + ) + } + public } } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub enum WalkErrorKind { - Missing, - Private, - Constant, -} -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct WalkError { - pub pos: usize, - pub kind: WalkErrorKind, -} impl Format for ParsedModule { async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { let head_str = format!("export ::({})\n", self.exports.iter().join(", ")); @@ -237,7 +231,7 @@ impl Root { return Ok(val.clone()); } let (cn, mp) = name.split_last(); - let module = self.tree.walk(true, mp.iter().cloned()).await.unwrap(); + let module = self.tree.walk(false, mp.iter().cloned(), &mut ()).await.unwrap(); let member = (module.items.iter()) .filter_map(|it| if let ItemKind::Member(m) = &it.kind { Some(m) } else { None }) .find(|m| m.name() == cn); diff --git a/orchid-host/src/system.rs b/orchid-host/src/system.rs index 184a96c..3b7a0d2 100644 --- a/orchid-host/src/system.rs +++ b/orchid-host/src/system.rs @@ -26,8 +26,8 @@ use crate::api; use crate::ctx::Ctx; use crate::expr::{Expr, ExprParseCtx}; use crate::extension::{Extension, WeakExtension}; -use crate::parsed::{ItemKind, ParsTokTree, ParsedFromApiCx, ParsedMember, ParsedModule, Root}; -use crate::tree::{Member, Module}; +use crate::parsed::{ItemKind, ParsTokTree, ParsedModule, Root}; +use crate::tree::Module; #[derive(destructure)] struct SystemInstData { @@ -70,10 +70,11 @@ impl System { pub async fn lex>>( &self, source: Tok, + src: Sym, pos: u32, r: impl FnMut(u32) -> F, ) -> api::OrcResult> { - self.0.ext.lex_req(source, pos, self.id(), r).await + self.0.ext.lex_req(source, src, pos, self.id(), r).await } pub fn can_parse(&self, ltyp: Tok) -> bool { self.0.line_types.contains(<yp) } pub fn line_types(&self) -> impl Iterator> + '_ { self.0.line_types.iter() } @@ -84,17 +85,26 @@ impl System { exported: bool, comments: Vec, ) -> OrcRes> { + let src_path = line.first().expect("cannot be empty").sr.path(); let line = join_all(line.into_iter().map(|t| async { let mut expr_store = self.0.ext.exprs().clone(); t.into_api(&mut expr_store, &mut ()).await })) .await; let comments = comments.iter().map(Comment::to_api).collect_vec(); - let req = api::ParseLine { module: module.to_api(), exported, sys: self.id(), comments, line }; + let req = api::ParseLine { + module: module.to_api(), + src: src_path.to_api(), + exported, + sys: self.id(), + comments, + line, + }; match self.reqnot().request(req).await { Ok(parsed) => { let mut pctx = ExprParseCtx { ctx: self.ctx().clone(), exprs: self.ext().exprs().clone() }; - Ok(ttv_from_api(parsed, &mut self.ext().exprs().clone(), &mut pctx, self.i()).await) + let mut ext_exprs = self.ext().exprs().clone(); + Ok(ttv_from_api(parsed, &mut ext_exprs, &mut pctx, &src_path, self.i()).await) }, Err(e) => Err(OrcErrv::from_api(&e, &self.ctx().i).await), } @@ -153,13 +163,14 @@ impl SystemCtor { .await, id, })); - let const_root = Module::from_api((sys_inst.const_root.into_iter()).map(|k, v| api::Member { - name: k, - kind: v, - comments: vec![], - exported: true, - })) - .await; + let const_root = + Module::from_api((sys_inst.const_root.into_iter()).map(|(k, v)| api::Member { + name: k, + kind: v, + comments: vec![], + exported: true, + })) + .await; let const_root = clone!(data, ext; stream! { for (k, v) in sys_inst.const_root { yield Member::from_api( diff --git a/orchid-host/src/tree.rs b/orchid-host/src/tree.rs index cf77c45..c921698 100644 --- a/orchid-host/src/tree.rs +++ b/orchid-host/src/tree.rs @@ -2,52 +2,87 @@ use std::cell::RefCell; use std::rc::{Rc, Weak}; use async_once_cell::OnceCell; -use async_stream::stream; -use futures::StreamExt; +use futures::FutureExt; use hashbrown::HashMap; +use itertools::Itertools; +use orchid_base::error::{OrcRes, Reporter}; use orchid_base::interner::Tok; -use orchid_base::name::Sym; +use orchid_base::name::{Sym, VPath}; use crate::api; use crate::ctx::Ctx; -use crate::dealias::absolute_path; -use crate::expr::Expr; -use crate::parsed::{ParsedMemberKind, ParsedModule}; +use crate::dealias::{DealiasCtx, absolute_path, resolv_glob}; +use crate::expr::{Expr, ExprParseCtx, PathSetBuilder}; +use crate::parsed::{ParsedMemberKind, ParsedModule, Tree, WalkError, WalkErrorKind}; use crate::system::System; pub struct Tree(Rc>); pub struct WeakTree(Weak>); +pub struct TreeFromApiCtx<'a> { + pub sys: &'a System, + pub consts: &'a mut HashMap, + pub path: Tok>>, +} +impl<'a> TreeFromApiCtx<'a> { + pub async fn push<'c>(&'c mut self, name: Tok) -> TreeFromApiCtx<'c> { + let path = self.sys.ctx().i.i(&self.path.iter().cloned().chain([name]).collect_vec()).await; + TreeFromApiCtx { path, consts: &mut *self.consts, sys: self.sys } + } +} + pub struct Module { pub members: HashMap, Rc>, } impl Module { - pub async fn from_api( - api: api::Module, - consts: &mut HashMap, - sys: System, - path: &mut Vec> - ) -> Self { + pub async fn from_api(api: api::Module, ctx: &mut TreeFromApiCtx<'_>) -> Self { let mut members = HashMap::new(); for mem in api.members { + let mem_name = ctx.sys.i().ex(mem.name).await; + let vname = VPath::new(ctx.path.iter().cloned()).name_with_suffix(mem_name.clone()); + let name = vname.to_sym(ctx.sys.i()).await; let (lazy, kind) = match mem.kind { - orchid_api::MemberKind::Lazy(id) => (Some(LazyMemberHandle{ id, sys: sys.clone(), path: })) - } - members.insert(sys.ctx().i.ex(mem.name).await, member); + api::MemberKind::Lazy(id) => + (Some(LazyMemberHandle { id, sys: ctx.sys.clone(), path: name.clone() }), None), + api::MemberKind::Const(val) => { + let mut expr_ctx = + ExprParseCtx { ctx: ctx.sys.ctx().clone(), exprs: ctx.sys.ext().exprs().clone() }; + let expr = Expr::from_api(&val, PathSetBuilder::new(), &mut expr_ctx).await; + ctx.consts.insert(name.clone(), expr); + (None, Some(MemberKind::Const)) + }, + api::MemberKind::Module(m) => { + let m = Self::from_api(m, &mut ctx.push(mem_name.clone()).await).boxed_local().await; + (None, Some(MemberKind::Module(m))) + }, + api::MemberKind::Import(import_path) => + (None, Some(MemberKind::Alias(Sym::from_api(import_path, ctx.sys.i()).await))), + }; + members.insert( + mem_name.clone(), + Rc::new(Member { + path: name.clone(), + public: mem.exported, + lazy: RefCell::new(lazy), + kind: kind.map_or_else(OnceCell::new, OnceCell::from), + }), + ); } Self { members } } - async fn walk(&self, mut path: impl Iterator>, ) -> &Self { todo!()} + async fn walk(&self, mut path: impl Iterator>) -> &Self { todo!() } async fn from_parsed( parsed: &ParsedModule, path: Sym, - parsed_root_path: Sym, - parsed_root: &ParsedModule, + pars_root_path: Sym, + pars_root: &ParsedModule, root: &Module, preload: &mut HashMap, + ctx: &Ctx, + rep: &Reporter, ) -> Self { - let mut imported_names = Vec::new(); + let mut imported_names = HashMap::new(); for import in parsed.get_imports() { if let Some(n) = import.name.clone() { imported_names.push(n); @@ -57,22 +92,52 @@ impl Module { if import.path.is_empty() { panic!("Imported root") } - if let Some(subpath) = import.path.strip_prefix(&parsed_root_path) { - let abs = absolute_path(&path, subpath); - // path is in parsed_root + let abs_path = match absolute_path(&path, &import.path) { + Ok(p) => p, + Err(e) => { + rep.report(e.err_obj(&ctx.i, import.sr.pos(), &path.to_string()).await); + continue; + }, + }; + let names = if let Some(subpath) = abs_path.strip_prefix(&pars_root_path[..]) { + let pars_path = (path.strip_prefix(&pars_root_path[..])) + .expect("pars path outside pars root"); + resolv_glob(&pars_path, pars_root, &subpath, import.sr.pos(), &ctx.i, rep, &mut ()).await } else { - // path is in root + resolv_glob(&path, root, &abs_path, import.sr.pos(), &ctx.i, rep, &mut ()).await } } todo!() } } +impl Tree for Module { + type Ctx = HashMap; + async fn walk>>( + &self, + public_only: bool, + path: I, + ctx: &'_ mut Self::Ctx, + ) -> Result<&Self, crate::parsed::WalkError> { + let mut cur = self; + for (pos, step) in path.into_iter().enumerate() { + let Some(member) = self.members.get(&step) else { + return Err(WalkError{ pos, kind: WalkErrorKind::Missing }) + }; + if public_only && !member.public { + return Err(WalkError { pos, kind: WalkErrorKind::Private }) + } + match &member.kind { + MemberKind::Module(m) => cur = m, + MemberKind::Alias() + } + } + } +} pub struct Member { pub public: bool, - pub root: WeakTree, - pub canonical_path: Sym, - pub lazy: RefCell)>>, + pub path: Sym, + pub lazy: RefCell>, pub kind: OnceCell, } impl Member { @@ -82,10 +147,8 @@ impl Member { } pub async fn kind(&self, consts: &mut HashMap) -> &MemberKind { (self.kind.get_or_init(async { - let (handle, root) = - self.lazy.borrow_mut().take().expect("If kind is uninit, lazy must be Some"); - let parsed = handle.run(consts).await; - MemberKind::from_parsed(&parsed, &root).await + let handle = self.lazy.borrow_mut().take().expect("If kind is uninit, lazy must be Some"); + handle.run(consts).await })) .await } @@ -94,6 +157,8 @@ impl Member { pub enum MemberKind { Const, Module(Module), + /// This must be pointing at the final value, not a second alias. + Alias(Sym), } impl MemberKind { async fn from_parsed(parsed: &ParsedMemberKind, root: &ParsedModule) -> Self { @@ -110,33 +175,24 @@ pub struct LazyMemberHandle { path: Sym, } impl LazyMemberHandle { - pub async fn run(self, consts: &mut HashMap) -> ParsedMemberKind { + pub async fn run(self, consts: &mut HashMap) -> MemberKind { match self.sys.get_tree(self.id).await { api::MemberKind::Const(c) => { let mut pctx = ExprParseCtx { ctx: self.sys.ctx().clone(), exprs: self.sys.ext().exprs().clone() }; consts.insert(self.path, Expr::from_api(&c, PathSetBuilder::new(), &mut pctx).await); - ParsedMemberKind::Const + MemberKind::Const }, - api::MemberKind::Module(m) => ParsedMemberKind::Mod( - ParsedModule::from_api(m, &mut ParsedFromApiCx { - sys: &self.sys, - consts, - path: self.path.tok(), - }) - .await, + api::MemberKind::Module(m) => MemberKind::Module( + Module::from_api(m, &mut TreeFromApiCtx { sys: &self.sys, consts, path: self.path.tok() }) + .await, ), api::MemberKind::Lazy(id) => Self { id, ..self }.run(consts).boxed_local().await, + api::MemberKind::Import(path) => MemberKind::Alias(Sym::from_api(path, self.sys.i()).await), } } - pub async fn into_member(self, public: bool, name: Tok) -> Member { - Member { - name, - public, - canonical_path: self.path.clone(), - kind: OnceCell::new(), - lazy: Mutex::new(Some(self)), - } + pub async fn into_member(self, public: bool, path: Sym) -> Member { + Member { public, path, kind: OnceCell::new(), lazy: RefCell::new(Some(self)) } } }