commit before travel
This commit is contained in:
@@ -10,8 +10,8 @@ use crate::api;
|
|||||||
use crate::error::{OrcRes, Reporter, mk_err, mk_errv};
|
use crate::error::{OrcRes, Reporter, mk_err, mk_errv};
|
||||||
use crate::format::fmt;
|
use crate::format::fmt;
|
||||||
use crate::interner::{Interner, Tok};
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::location::{Pos, SrcRange};
|
use crate::location::SrcRange;
|
||||||
use crate::name::{VName, VPath};
|
use crate::name::{Sym, VName, VPath};
|
||||||
use crate::tree::{ExprRepr, ExtraTok, Paren, TokTree, Token, ttv_range};
|
use crate::tree::{ExprRepr, ExtraTok, Paren, TokTree, Token, ttv_range};
|
||||||
|
|
||||||
pub trait ParseCtx {
|
pub trait ParseCtx {
|
||||||
@@ -110,24 +110,24 @@ pub fn strip_fluff<A: ExprRepr, X: ExtraTok>(tt: &TokTree<A, X>) -> Option<TokTr
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Comment {
|
pub struct Comment {
|
||||||
pub text: Tok<String>,
|
pub text: Tok<String>,
|
||||||
pub range: Range<u32>,
|
pub sr: SrcRange,
|
||||||
}
|
}
|
||||||
impl Comment {
|
impl Comment {
|
||||||
// XXX: which of these four are actually used?
|
// XXX: which of these four are actually used?
|
||||||
pub async fn from_api(c: &api::Comment, i: &Interner) -> Self {
|
pub async fn from_api(c: &api::Comment, src: Sym, i: &Interner) -> Self {
|
||||||
Self { text: i.ex(c.text).await, range: c.range.clone() }
|
Self { text: i.ex(c.text).await, sr: SrcRange::new(c.range.clone(), &src) }
|
||||||
}
|
}
|
||||||
pub async fn from_tk(tk: &TokTree<impl ExprRepr, impl ExtraTok>, i: &Interner) -> Option<Self> {
|
pub async fn from_tk(tk: &TokTree<impl ExprRepr, impl ExtraTok>, i: &Interner) -> Option<Self> {
|
||||||
match &tk.tok {
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn to_tk<R: ExprRepr, X: ExtraTok>(&self) -> TokTree<R, X> {
|
pub fn to_tk<R: ExprRepr, X: ExtraTok>(&self) -> TokTree<R, X> {
|
||||||
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 {
|
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() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -299,7 +299,8 @@ pub fn extension_init(
|
|||||||
let mut ctx = get_ctx(*sys).await;
|
let mut ctx = get_ctx(*sys).await;
|
||||||
let parsers = ctx.cted().inst().dyn_parsers();
|
let parsers = ctx.cted().inst().dyn_parsers();
|
||||||
let src = Sym::from_api(*src, ctx.i()).await;
|
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<GenTokTree> = ttv_from_api(line, &mut ctx, &mut (), &src, &i).await;
|
let line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx, &mut (), &src, &i).await;
|
||||||
let snip = Snippet::new(line.first().expect("Empty line"), &line);
|
let snip = Snippet::new(line.first().expect("Empty line"), &line);
|
||||||
let (head, tail) = snip.pop_front().unwrap();
|
let (head, tail) = snip.pop_front().unwrap();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use itertools::{Either, Itertools};
|
use itertools::{Either, Itertools};
|
||||||
@@ -8,7 +10,7 @@ use orchid_base::name::{NameLike, Sym, VName};
|
|||||||
use substack::Substack;
|
use substack::Substack;
|
||||||
|
|
||||||
use crate::expr::Expr;
|
use crate::expr::Expr;
|
||||||
use crate::parsed::{ItemKind, ParsedMemberKind, ParsedModule, WalkErrorKind};
|
use crate::parsed::{ItemKind, ParsedMemberKind, ParsedModule};
|
||||||
|
|
||||||
/// Errors produced by absolute_path
|
/// Errors produced by absolute_path
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
@@ -74,129 +76,87 @@ pub fn absolute_path(
|
|||||||
pub struct DealiasCtx<'a> {
|
pub struct DealiasCtx<'a> {
|
||||||
pub i: &'a Interner,
|
pub i: &'a Interner,
|
||||||
pub rep: &'a Reporter,
|
pub rep: &'a Reporter,
|
||||||
pub consts: &'a mut HashMap<Sym, Expr>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn resolv_glob(
|
pub async fn resolv_glob<Mod: Tree>(
|
||||||
cwd: &[Tok<String>],
|
cwd: &[Tok<String>],
|
||||||
root: &ParsedModule,
|
root: &Mod,
|
||||||
abs_path: &[Tok<String>],
|
abs_path: &[Tok<String>],
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
ctx: &mut DealiasCtx<'_>,
|
i: &Interner,
|
||||||
|
rep: &Reporter,
|
||||||
|
walk_cx: &mut Mod::Ctx,
|
||||||
) -> Vec<Tok<String>> {
|
) -> Vec<Tok<String>> {
|
||||||
let coprefix_len = cwd.iter().zip(abs_path).take_while(|(a, b)| a == b).count();
|
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_prefix, diff_path) = abs_path.split_at(coprefix_len);
|
||||||
let co_parent =
|
let co_parent =
|
||||||
root.walk(false, co_prefix.iter().cloned(), ctx.consts).await.expect("Invalid step in cwd");
|
root.walk(true, co_prefix.iter().cloned(), walk_cx).await.expect("Invalid step in cwd");
|
||||||
let target_module = match co_parent.walk(true, diff_path.iter().cloned(), ctx.consts).await {
|
let target_module = match co_parent.walk(false, diff_path.iter().cloned(), walk_cx).await {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let path = abs_path[..=coprefix_len + e.pos].iter().join("::");
|
let path = abs_path[..=coprefix_len + e.pos].iter().join("::");
|
||||||
let (tk, msg) = match e.kind {
|
let (tk, msg) = match e.kind {
|
||||||
WalkErrorKind::Constant =>
|
ChildErrorKind::Constant =>
|
||||||
(ctx.i.i("Invalid import path").await, format!("{path} is a constant")),
|
(i.i("Invalid import path").await, format!("{path} is a const")),
|
||||||
WalkErrorKind::Missing =>
|
ChildErrorKind::Missing => (i.i("Invalid import path").await, format!("{path} not found")),
|
||||||
(ctx.i.i("Invalid import path").await, format!("{path} not found")),
|
ChildErrorKind::Private => (i.i("Import inaccessible").await, format!("{path} is private")),
|
||||||
WalkErrorKind::Private =>
|
|
||||||
(ctx.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![];
|
return vec![];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
target_module.exports.clone()
|
target_module.children(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read import statements and convert them into aliases, rasising any import
|
pub enum ChildResult<'a, T: Tree + ?Sized> {
|
||||||
/// errors in the process
|
Value(&'a T),
|
||||||
pub async fn imports_to_aliases(
|
Err(ChildErrorKind),
|
||||||
module: &ParsedModule,
|
Alias(&'a [Tok<String>]),
|
||||||
cwd: &mut Vec<Tok<String>>,
|
}
|
||||||
root: &ParsedModule,
|
pub trait Tree {
|
||||||
alias_map: &mut HashMap<Sym, Sym>,
|
type Ctx;
|
||||||
alias_rev_map: &mut HashMap<Sym, HashSet<Sym>>,
|
fn children(&self, public_only: bool) -> HashSet<Tok<String>>;
|
||||||
ctx: &mut DealiasCtx<'_>,
|
fn child(&self, key: Tok<String>, public_only: bool) -> ChildResult<'_, Self>;
|
||||||
) {
|
}
|
||||||
let mut import_locs = HashMap::<Sym, Vec<Pos>>::new();
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
for item in &module.items {
|
pub enum ChildErrorKind {
|
||||||
match &item.kind {
|
Missing,
|
||||||
ItemKind::Import(imp) => match absolute_path(cwd, &imp.path) {
|
Private,
|
||||||
Err(e) =>
|
Constant,
|
||||||
ctx.rep.report(e.err_obj(ctx.i, item.sr.pos(), &imp.path.iter().join("::")).await),
|
}
|
||||||
Ok(abs_path) => {
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
let names = match imp.name.as_ref() {
|
pub struct ChildError {
|
||||||
Some(n) => Either::Right([n.clone()].into_iter()),
|
pub at_path: Vec<Tok<String>>,
|
||||||
None =>
|
pub kind: ChildErrorKind,
|
||||||
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(
|
// Problem: walk should take into account aliases and visibility
|
||||||
path: Substack<'_, Tok<String>>,
|
//
|
||||||
module: &mut ParsedModule,
|
// help: since every alias is also its own import, visibility only has to be
|
||||||
alias_map: &HashMap<Sym, Sym>,
|
// checked on the top level
|
||||||
ctx: &mut DealiasCtx<'_>,
|
//
|
||||||
) {
|
// idea: do a simple stack machine like below with no visibility for aliases and
|
||||||
for item in &mut module.items {
|
// call it from an access-checking implementation for just the top level
|
||||||
match &mut item.kind {
|
//
|
||||||
ItemKind::Export(_) | ItemKind::Import(_) => (),
|
// caveat: we need to check EVERY IMPORT to ensure that all
|
||||||
ItemKind::Member(mem) => {
|
// errors are raised
|
||||||
let path = path.push(mem.name());
|
|
||||||
match mem.kind_mut(ctx.consts).await {
|
fn walk_no_access_chk<T: Tree>(
|
||||||
ParsedMemberKind::Const => (),
|
root: &T,
|
||||||
ParsedMemberKind::Mod(m) => dealias(path, m, alias_map, ctx).boxed_local().await,
|
path: impl IntoIterator<Item = Tok<String>>,
|
||||||
}
|
) -> 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: () }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,11 +150,11 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
|||||||
for sys in ctx.systems {
|
for sys in ctx.systems {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
if ctx.tail.starts_with(|c| sys.can_lex(c)) {
|
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 ctx_lck = &Mutex::new(&mut *ctx);
|
||||||
let errors_lck = &Mutex::new(&mut errors);
|
let errors_lck = &Mutex::new(&mut errors);
|
||||||
let lx = sys
|
let lx = sys
|
||||||
.lex(source, pos, |pos| async move {
|
.lex(source, path, pos, |pos| async move {
|
||||||
let mut ctx_g = ctx_lck.lock().await;
|
let mut ctx_g = ctx_lck.lock().await;
|
||||||
match lex_once(&mut ctx_g.push(pos)).boxed_local().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 }),
|
Ok(t) => Some(api::SubLexed { pos: t.sr.end(), tree: ctx_g.ser_subtree(t).await }),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use async_std::sync::{Mutex, RwLock};
|
|||||||
use async_stream::stream;
|
use async_stream::stream;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, StreamExt};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::{HashMap, HashSet};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcRes, mk_errv};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
||||||
@@ -61,18 +61,6 @@ impl TokenVariant<api::Expression> for Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ParsedFromApiCx<'a> {
|
|
||||||
pub sys: &'a System,
|
|
||||||
pub consts: &'a mut HashMap<Sym, Expr>,
|
|
||||||
pub path: Tok<Vec<Tok<String>>>,
|
|
||||||
}
|
|
||||||
impl<'a> ParsedFromApiCx<'a> {
|
|
||||||
pub async fn push<'c>(&'c mut self, name: Tok<String>) -> 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)]
|
#[derive(Debug)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub sr: SrcRange,
|
pub sr: SrcRange,
|
||||||
@@ -154,11 +142,19 @@ impl ParsedModule {
|
|||||||
std::mem::swap(self, &mut swap);
|
std::mem::swap(self, &mut swap);
|
||||||
*self = ParsedModule::new(swap.items.into_iter().chain(other.items))
|
*self = ParsedModule::new(swap.items.into_iter().chain(other.items))
|
||||||
}
|
}
|
||||||
pub async fn walk<'a>(
|
pub fn get_imports(&self) -> impl IntoIterator<Item = &Import> {
|
||||||
|
(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<I: IntoIterator<Item = Tok<String>>>(
|
||||||
&self,
|
&self,
|
||||||
allow_private: bool,
|
public_only: bool,
|
||||||
path: impl IntoIterator<Item = Tok<String>>,
|
path: I,
|
||||||
) -> Result<&ParsedModule, WalkError> {
|
_ctx: &'_ mut Self::Ctx,
|
||||||
|
) -> Result<&Self, WalkError> {
|
||||||
let mut cur = self;
|
let mut cur = self;
|
||||||
for (pos, step) in path.into_iter().enumerate() {
|
for (pos, step) in path.into_iter().enumerate() {
|
||||||
let Some(member) = (cur.items.iter())
|
let Some(member) = (cur.items.iter())
|
||||||
@@ -167,7 +163,7 @@ impl ParsedModule {
|
|||||||
else {
|
else {
|
||||||
return Err(WalkError { pos, kind: WalkErrorKind::Missing });
|
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 });
|
return Err(WalkError { pos, kind: WalkErrorKind::Private });
|
||||||
}
|
}
|
||||||
match &member.kind {
|
match &member.kind {
|
||||||
@@ -177,21 +173,19 @@ impl ParsedModule {
|
|||||||
}
|
}
|
||||||
Ok(cur)
|
Ok(cur)
|
||||||
}
|
}
|
||||||
pub fn get_imports(&self) -> impl IntoIterator<Item = &Import> {
|
fn children(&self, public_only: bool) -> HashSet<Tok<String>> {
|
||||||
|
let mut public: HashSet<_> = self.exports.iter().cloned().collect();
|
||||||
|
if !public_only {
|
||||||
|
public.extend(
|
||||||
(self.items.iter())
|
(self.items.iter())
|
||||||
.filter_map(|it| if let ItemKind::Import(i) = &it.kind { Some(i) } else { None })
|
.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 {
|
impl Format for ParsedModule {
|
||||||
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
@@ -237,7 +231,7 @@ impl Root {
|
|||||||
return Ok(val.clone());
|
return Ok(val.clone());
|
||||||
}
|
}
|
||||||
let (cn, mp) = name.split_last();
|
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())
|
let member = (module.items.iter())
|
||||||
.filter_map(|it| if let ItemKind::Member(m) = &it.kind { Some(m) } else { None })
|
.filter_map(|it| if let ItemKind::Member(m) = &it.kind { Some(m) } else { None })
|
||||||
.find(|m| m.name() == cn);
|
.find(|m| m.name() == cn);
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ use crate::api;
|
|||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::expr::{Expr, ExprParseCtx};
|
use crate::expr::{Expr, ExprParseCtx};
|
||||||
use crate::extension::{Extension, WeakExtension};
|
use crate::extension::{Extension, WeakExtension};
|
||||||
use crate::parsed::{ItemKind, ParsTokTree, ParsedFromApiCx, ParsedMember, ParsedModule, Root};
|
use crate::parsed::{ItemKind, ParsTokTree, ParsedModule, Root};
|
||||||
use crate::tree::{Member, Module};
|
use crate::tree::Module;
|
||||||
|
|
||||||
#[derive(destructure)]
|
#[derive(destructure)]
|
||||||
struct SystemInstData {
|
struct SystemInstData {
|
||||||
@@ -70,10 +70,11 @@ impl System {
|
|||||||
pub async fn lex<F: Future<Output = Option<api::SubLexed>>>(
|
pub async fn lex<F: Future<Output = Option<api::SubLexed>>>(
|
||||||
&self,
|
&self,
|
||||||
source: Tok<String>,
|
source: Tok<String>,
|
||||||
|
src: Sym,
|
||||||
pos: u32,
|
pos: u32,
|
||||||
r: impl FnMut(u32) -> F,
|
r: impl FnMut(u32) -> F,
|
||||||
) -> api::OrcResult<Option<api::LexedExpr>> {
|
) -> api::OrcResult<Option<api::LexedExpr>> {
|
||||||
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<String>) -> bool { self.0.line_types.contains(<yp) }
|
pub fn can_parse(&self, ltyp: Tok<String>) -> bool { self.0.line_types.contains(<yp) }
|
||||||
pub fn line_types(&self) -> impl Iterator<Item = &Tok<String>> + '_ { self.0.line_types.iter() }
|
pub fn line_types(&self) -> impl Iterator<Item = &Tok<String>> + '_ { self.0.line_types.iter() }
|
||||||
@@ -84,17 +85,26 @@ impl System {
|
|||||||
exported: bool,
|
exported: bool,
|
||||||
comments: Vec<Comment>,
|
comments: Vec<Comment>,
|
||||||
) -> OrcRes<Vec<ParsTokTree>> {
|
) -> OrcRes<Vec<ParsTokTree>> {
|
||||||
|
let src_path = line.first().expect("cannot be empty").sr.path();
|
||||||
let line = join_all(line.into_iter().map(|t| async {
|
let line = join_all(line.into_iter().map(|t| async {
|
||||||
let mut expr_store = self.0.ext.exprs().clone();
|
let mut expr_store = self.0.ext.exprs().clone();
|
||||||
t.into_api(&mut expr_store, &mut ()).await
|
t.into_api(&mut expr_store, &mut ()).await
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
let comments = comments.iter().map(Comment::to_api).collect_vec();
|
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 {
|
match self.reqnot().request(req).await {
|
||||||
Ok(parsed) => {
|
Ok(parsed) => {
|
||||||
let mut pctx = ExprParseCtx { ctx: self.ctx().clone(), exprs: self.ext().exprs().clone() };
|
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),
|
Err(e) => Err(OrcErrv::from_api(&e, &self.ctx().i).await),
|
||||||
}
|
}
|
||||||
@@ -153,7 +163,8 @@ impl SystemCtor {
|
|||||||
.await,
|
.await,
|
||||||
id,
|
id,
|
||||||
}));
|
}));
|
||||||
let const_root = Module::from_api((sys_inst.const_root.into_iter()).map(|k, v| api::Member {
|
let const_root =
|
||||||
|
Module::from_api((sys_inst.const_root.into_iter()).map(|(k, v)| api::Member {
|
||||||
name: k,
|
name: k,
|
||||||
kind: v,
|
kind: v,
|
||||||
comments: vec![],
|
comments: vec![],
|
||||||
|
|||||||
@@ -2,52 +2,87 @@ use std::cell::RefCell;
|
|||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use async_once_cell::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
use async_stream::stream;
|
use futures::FutureExt;
|
||||||
use futures::StreamExt;
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use orchid_base::error::{OrcRes, Reporter};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::{Sym, VPath};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::dealias::absolute_path;
|
use crate::dealias::{DealiasCtx, absolute_path, resolv_glob};
|
||||||
use crate::expr::Expr;
|
use crate::expr::{Expr, ExprParseCtx, PathSetBuilder};
|
||||||
use crate::parsed::{ParsedMemberKind, ParsedModule};
|
use crate::parsed::{ParsedMemberKind, ParsedModule, Tree, WalkError, WalkErrorKind};
|
||||||
use crate::system::System;
|
use crate::system::System;
|
||||||
|
|
||||||
pub struct Tree(Rc<RefCell<Module>>);
|
pub struct Tree(Rc<RefCell<Module>>);
|
||||||
|
|
||||||
pub struct WeakTree(Weak<RefCell<Module>>);
|
pub struct WeakTree(Weak<RefCell<Module>>);
|
||||||
|
|
||||||
|
pub struct TreeFromApiCtx<'a> {
|
||||||
|
pub sys: &'a System,
|
||||||
|
pub consts: &'a mut HashMap<Sym, Expr>,
|
||||||
|
pub path: Tok<Vec<Tok<String>>>,
|
||||||
|
}
|
||||||
|
impl<'a> TreeFromApiCtx<'a> {
|
||||||
|
pub async fn push<'c>(&'c mut self, name: Tok<String>) -> 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 struct Module {
|
||||||
pub members: HashMap<Tok<String>, Rc<Member>>,
|
pub members: HashMap<Tok<String>, Rc<Member>>,
|
||||||
}
|
}
|
||||||
impl Module {
|
impl Module {
|
||||||
pub async fn from_api(
|
pub async fn from_api(api: api::Module, ctx: &mut TreeFromApiCtx<'_>) -> Self {
|
||||||
api: api::Module,
|
|
||||||
consts: &mut HashMap<Sym, Expr>,
|
|
||||||
sys: System,
|
|
||||||
path: &mut Vec<Tok<String>>
|
|
||||||
) -> Self {
|
|
||||||
let mut members = HashMap::new();
|
let mut members = HashMap::new();
|
||||||
for mem in api.members {
|
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 {
|
let (lazy, kind) = match mem.kind {
|
||||||
orchid_api::MemberKind::Lazy(id) => (Some(LazyMemberHandle{ id, sys: sys.clone(), path: }))
|
api::MemberKind::Lazy(id) =>
|
||||||
}
|
(Some(LazyMemberHandle { id, sys: ctx.sys.clone(), path: name.clone() }), None),
|
||||||
members.insert(sys.ctx().i.ex(mem.name).await, member);
|
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 }
|
Self { members }
|
||||||
}
|
}
|
||||||
async fn walk(&self, mut path: impl Iterator<Item = Tok<String>>, ) -> &Self { todo!()}
|
async fn walk(&self, mut path: impl Iterator<Item = Tok<String>>) -> &Self { todo!() }
|
||||||
async fn from_parsed(
|
async fn from_parsed(
|
||||||
parsed: &ParsedModule,
|
parsed: &ParsedModule,
|
||||||
path: Sym,
|
path: Sym,
|
||||||
parsed_root_path: Sym,
|
pars_root_path: Sym,
|
||||||
parsed_root: &ParsedModule,
|
pars_root: &ParsedModule,
|
||||||
root: &Module,
|
root: &Module,
|
||||||
preload: &mut HashMap<Sym, Module>,
|
preload: &mut HashMap<Sym, Module>,
|
||||||
|
ctx: &Ctx,
|
||||||
|
rep: &Reporter,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut imported_names = Vec::new();
|
let mut imported_names = HashMap::new();
|
||||||
for import in parsed.get_imports() {
|
for import in parsed.get_imports() {
|
||||||
if let Some(n) = import.name.clone() {
|
if let Some(n) = import.name.clone() {
|
||||||
imported_names.push(n);
|
imported_names.push(n);
|
||||||
@@ -57,22 +92,52 @@ impl Module {
|
|||||||
if import.path.is_empty() {
|
if import.path.is_empty() {
|
||||||
panic!("Imported root")
|
panic!("Imported root")
|
||||||
}
|
}
|
||||||
if let Some(subpath) = import.path.strip_prefix(&parsed_root_path) {
|
let abs_path = match absolute_path(&path, &import.path) {
|
||||||
let abs = absolute_path(&path, subpath);
|
Ok(p) => p,
|
||||||
// path is in parsed_root
|
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 {
|
} else {
|
||||||
// path is in root
|
resolv_glob(&path, root, &abs_path, import.sr.pos(), &ctx.i, rep, &mut ()).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Tree for Module {
|
||||||
|
type Ctx = HashMap<Sym, Expr>;
|
||||||
|
async fn walk<I: IntoIterator<Item = Tok<String>>>(
|
||||||
|
&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 struct Member {
|
||||||
pub public: bool,
|
pub public: bool,
|
||||||
pub root: WeakTree,
|
pub path: Sym,
|
||||||
pub canonical_path: Sym,
|
pub lazy: RefCell<Option<LazyMemberHandle>>,
|
||||||
pub lazy: RefCell<Option<(LazyMemberHandle, Rc<ParsedModule>)>>,
|
|
||||||
pub kind: OnceCell<MemberKind>,
|
pub kind: OnceCell<MemberKind>,
|
||||||
}
|
}
|
||||||
impl Member {
|
impl Member {
|
||||||
@@ -82,10 +147,8 @@ impl Member {
|
|||||||
}
|
}
|
||||||
pub async fn kind(&self, consts: &mut HashMap<Sym, Expr>) -> &MemberKind {
|
pub async fn kind(&self, consts: &mut HashMap<Sym, Expr>) -> &MemberKind {
|
||||||
(self.kind.get_or_init(async {
|
(self.kind.get_or_init(async {
|
||||||
let (handle, root) =
|
let handle = self.lazy.borrow_mut().take().expect("If kind is uninit, lazy must be Some");
|
||||||
self.lazy.borrow_mut().take().expect("If kind is uninit, lazy must be Some");
|
handle.run(consts).await
|
||||||
let parsed = handle.run(consts).await;
|
|
||||||
MemberKind::from_parsed(&parsed, &root).await
|
|
||||||
}))
|
}))
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -94,6 +157,8 @@ impl Member {
|
|||||||
pub enum MemberKind {
|
pub enum MemberKind {
|
||||||
Const,
|
Const,
|
||||||
Module(Module),
|
Module(Module),
|
||||||
|
/// This must be pointing at the final value, not a second alias.
|
||||||
|
Alias(Sym),
|
||||||
}
|
}
|
||||||
impl MemberKind {
|
impl MemberKind {
|
||||||
async fn from_parsed(parsed: &ParsedMemberKind, root: &ParsedModule) -> Self {
|
async fn from_parsed(parsed: &ParsedMemberKind, root: &ParsedModule) -> Self {
|
||||||
@@ -110,33 +175,24 @@ pub struct LazyMemberHandle {
|
|||||||
path: Sym,
|
path: Sym,
|
||||||
}
|
}
|
||||||
impl LazyMemberHandle {
|
impl LazyMemberHandle {
|
||||||
pub async fn run(self, consts: &mut HashMap<Sym, Expr>) -> ParsedMemberKind {
|
pub async fn run(self, consts: &mut HashMap<Sym, Expr>) -> MemberKind {
|
||||||
match self.sys.get_tree(self.id).await {
|
match self.sys.get_tree(self.id).await {
|
||||||
api::MemberKind::Const(c) => {
|
api::MemberKind::Const(c) => {
|
||||||
let mut pctx =
|
let mut pctx =
|
||||||
ExprParseCtx { ctx: self.sys.ctx().clone(), exprs: self.sys.ext().exprs().clone() };
|
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);
|
consts.insert(self.path, Expr::from_api(&c, PathSetBuilder::new(), &mut pctx).await);
|
||||||
ParsedMemberKind::Const
|
MemberKind::Const
|
||||||
},
|
},
|
||||||
api::MemberKind::Module(m) => ParsedMemberKind::Mod(
|
api::MemberKind::Module(m) => MemberKind::Module(
|
||||||
ParsedModule::from_api(m, &mut ParsedFromApiCx {
|
Module::from_api(m, &mut TreeFromApiCtx { sys: &self.sys, consts, path: self.path.tok() })
|
||||||
sys: &self.sys,
|
|
||||||
consts,
|
|
||||||
path: self.path.tok(),
|
|
||||||
})
|
|
||||||
.await,
|
.await,
|
||||||
),
|
),
|
||||||
api::MemberKind::Lazy(id) => Self { id, ..self }.run(consts).boxed_local().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<String>) -> Member {
|
pub async fn into_member(self, public: bool, path: Sym) -> Member {
|
||||||
Member {
|
Member { public, path, kind: OnceCell::new(), lazy: RefCell::new(Some(self)) }
|
||||||
name,
|
|
||||||
public,
|
|
||||||
canonical_path: self.path.clone(),
|
|
||||||
kind: OnceCell::new(),
|
|
||||||
lazy: Mutex::new(Some(self)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user