Returned from Italy
This commit is contained in:
@@ -22,5 +22,3 @@ mod system;
|
|||||||
pub use system::*;
|
pub use system::*;
|
||||||
mod tree;
|
mod tree;
|
||||||
pub use tree::*;
|
pub use tree::*;
|
||||||
mod vfs;
|
|
||||||
pub use vfs::*;
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use async_std::io::{Read, Write};
|
|||||||
use orchid_api_derive::{Coding, Hierarchy};
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
use orchid_api_traits::{Channel, Decode, Encode, MsgSet, Request, read_exact, write_exact};
|
use orchid_api_traits::{Channel, Decode, Encode, MsgSet, Request, read_exact, write_exact};
|
||||||
|
|
||||||
use crate::{atom, expr, interner, lexer, logging, parser, system, tree, vfs};
|
use crate::{atom, expr, interner, lexer, logging, parser, system, tree};
|
||||||
|
|
||||||
static HOST_INTRO: &[u8] = b"Orchid host, binary API v0\n";
|
static HOST_INTRO: &[u8] = b"Orchid host, binary API v0\n";
|
||||||
pub struct HostHeader {
|
pub struct HostHeader {
|
||||||
@@ -120,7 +120,6 @@ pub enum HostExtReq {
|
|||||||
ParseLine(parser::ParseLine),
|
ParseLine(parser::ParseLine),
|
||||||
FetchParsedConst(parser::FetchParsedConst),
|
FetchParsedConst(parser::FetchParsedConst),
|
||||||
GetMember(tree::GetMember),
|
GetMember(tree::GetMember),
|
||||||
VfsRead(vfs::VfsRead),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notifications sent from the host to the extension
|
/// Notifications sent from the host to the extension
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use orchid_api_derive::{Coding, Hierarchy};
|
|||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
use crate::{CharFilter, EagerVfs, ExtHostReq, HostExtNotif, HostExtReq, MemberKind, TStr};
|
use crate::{CharFilter, ExtHostReq, HostExtNotif, HostExtReq, MemberKind, TStr};
|
||||||
|
|
||||||
/// ID of a system type
|
/// ID of a system type
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||||
@@ -63,7 +63,6 @@ pub struct NewSystemResponse {
|
|||||||
pub lex_filter: CharFilter,
|
pub lex_filter: CharFilter,
|
||||||
pub line_types: Vec<TStr>,
|
pub line_types: Vec<TStr>,
|
||||||
pub const_root: HashMap<TStr, MemberKind>,
|
pub const_root: HashMap<TStr, MemberKind>,
|
||||||
pub vfs: HashMap<TStr, EagerVfs>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::num::NonZeroU16;
|
|
||||||
|
|
||||||
use orchid_api_derive::{Coding, Hierarchy};
|
|
||||||
use orchid_api_traits::Request;
|
|
||||||
|
|
||||||
use crate::error::OrcResult;
|
|
||||||
use crate::interner::TStr;
|
|
||||||
use crate::proto::HostExtReq;
|
|
||||||
use crate::system::SysId;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
|
||||||
pub struct VfsId(pub NonZeroU16);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
|
||||||
pub enum Loaded {
|
|
||||||
Code(String),
|
|
||||||
Collection(Vec<TStr>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
|
||||||
#[extends(HostExtReq)]
|
|
||||||
pub struct VfsRead(pub SysId, pub VfsId, pub Vec<TStr>);
|
|
||||||
impl Request for VfsRead {
|
|
||||||
type Response = OrcResult<Loaded>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
|
||||||
pub enum EagerVfs {
|
|
||||||
Lazy(VfsId),
|
|
||||||
Eager(HashMap<TStr, EagerVfs>),
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -177,6 +178,29 @@ pub fn mk_errv<I: Into<ErrPos>>(
|
|||||||
mk_err(description, message, posv.into_iter().map_into()).into()
|
mk_err(description, message, posv.into_iter().map_into()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn async_io_err<I: Into<ErrPos>>(
|
||||||
|
err: async_std::io::Error,
|
||||||
|
i: &Interner,
|
||||||
|
posv: impl IntoIterator<Item = I>,
|
||||||
|
) -> OrcErrv {
|
||||||
|
mk_errv(i.i(&err.kind().to_string()).await, err.to_string(), posv)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn os_str_to_string<'a, I: Into<ErrPos>>(
|
||||||
|
str: &'a OsStr,
|
||||||
|
i: &Interner,
|
||||||
|
posv: impl IntoIterator<Item = I>,
|
||||||
|
) -> OrcRes<&'a str> {
|
||||||
|
match str.to_str() {
|
||||||
|
Some(str) => Ok(str),
|
||||||
|
None => Err(mk_errv(
|
||||||
|
i.i("Non-unicode string").await,
|
||||||
|
format!("{str:?} is not representable as unicode"),
|
||||||
|
posv,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Reporter {
|
pub struct Reporter {
|
||||||
errors: RefCell<Vec<OrcErr>>,
|
errors: RefCell<Vec<OrcErr>>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ use crate::api;
|
|||||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
||||||
use crate::atom_owned::take_atom;
|
use crate::atom_owned::take_atom;
|
||||||
use crate::expr::{Expr, ExprHandle};
|
use crate::expr::{Expr, ExprHandle};
|
||||||
use crate::fs::VirtFS;
|
|
||||||
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
||||||
use crate::parser::{ParsCtx, get_const, linev_into_api};
|
use crate::parser::{ParsCtx, get_const, linev_into_api};
|
||||||
use crate::system::{SysCtx, atom_by_idx};
|
use crate::system::{SysCtx, atom_by_idx};
|
||||||
@@ -56,7 +55,6 @@ pub enum MemberRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SystemRecord {
|
pub struct SystemRecord {
|
||||||
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
|
|
||||||
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
||||||
ctx: SysCtx,
|
ctx: SysCtx,
|
||||||
}
|
}
|
||||||
@@ -169,7 +167,6 @@ pub fn extension_init(
|
|||||||
let (sys_id, _) = (decls.iter().enumerate().find(|(_, s)| s.id == new_sys.system))
|
let (sys_id, _) = (decls.iter().enumerate().find(|(_, s)| s.id == new_sys.system))
|
||||||
.expect("NewSystem call received for invalid system");
|
.expect("NewSystem call received for invalid system");
|
||||||
let cted = data.systems[sys_id].new_system(&new_sys);
|
let cted = data.systems[sys_id].new_system(&new_sys);
|
||||||
let mut vfses = HashMap::new();
|
|
||||||
let lex_filter =
|
let lex_filter =
|
||||||
cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
|
cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
|
||||||
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
||||||
@@ -192,12 +189,10 @@ pub fn extension_init(
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
let vfs = cted.inst().dyn_vfs().to_api_rec(&mut vfses, &i).await;
|
let record = SystemRecord { ctx, lazy_members: lazy_mems.into_inner() };
|
||||||
let record = SystemRecord { vfses, ctx, lazy_members: lazy_mems.into_inner() };
|
|
||||||
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
||||||
systems.lock().await.insert(new_sys.id, record);
|
systems.lock().await.insert(new_sys.id, record);
|
||||||
let response =
|
let response = api::NewSystemResponse { lex_filter, const_root, line_types: vec![] };
|
||||||
api::NewSystemResponse { lex_filter, const_root, line_types: vec![], vfs };
|
|
||||||
hand.handle(&new_sys, &response).await
|
hand.handle(&new_sys, &response).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
||||||
@@ -227,15 +222,6 @@ pub fn extension_init(
|
|||||||
let sys = ctx.cted().inst();
|
let sys = ctx.cted().inst();
|
||||||
sys.dyn_request(hand, payload).await
|
sys.dyn_request(hand, payload).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::VfsRead(vfs_read) => {
|
|
||||||
let api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
|
|
||||||
let ctx = get_ctx(*sys_id).await;
|
|
||||||
let systems = systems_weak.upgrade().expect("VFS requested during shutdoown");
|
|
||||||
let systems_g = systems.lock().await;
|
|
||||||
let path = join_all(path.iter().map(|t| Tok::from_api(*t, &i))).await;
|
|
||||||
let vfs = systems_g[sys_id].vfses[vfs_id].load(&path, ctx).await;
|
|
||||||
hand.handle(&vfs_read, &vfs).await
|
|
||||||
},
|
|
||||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, src, text, pos, id }) => {
|
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, src, text, pos, id }) => {
|
||||||
let sys_ctx = get_ctx(sys).await;
|
let sys_ctx = get_ctx(sys).await;
|
||||||
let text = Tok::from_api(text, &i).await;
|
let text = Tok::from_api(text, &i).await;
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
use std::num::NonZero;
|
|
||||||
|
|
||||||
use futures::FutureExt;
|
|
||||||
use futures::future::LocalBoxFuture;
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use orchid_base::interner::{Interner, Tok};
|
|
||||||
use orchid_base::pure_seq::pushed;
|
|
||||||
|
|
||||||
use crate::api;
|
|
||||||
use crate::system::SysCtx;
|
|
||||||
|
|
||||||
pub trait VirtFS: Send + Sync + 'static {
|
|
||||||
fn load<'a>(
|
|
||||||
&'a self,
|
|
||||||
path: &'a [Tok<String>],
|
|
||||||
ctx: SysCtx,
|
|
||||||
) -> LocalBoxFuture<'a, api::OrcResult<api::Loaded>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DeclVmod(Cow<'static, [(&'static str, DeclFs)]>);
|
|
||||||
impl DeclVmod {
|
|
||||||
pub fn new(items: &'static [(&'static str, DeclFs)]) -> DeclVmod {
|
|
||||||
DeclVmod(Cow::Borrowed(items))
|
|
||||||
}
|
|
||||||
pub fn entry(
|
|
||||||
key: &'static str,
|
|
||||||
items: &'static [(&'static str, DeclFs)],
|
|
||||||
) -> (&'static str, DeclVmod) {
|
|
||||||
(key, DeclVmod(Cow::Borrowed(items)))
|
|
||||||
}
|
|
||||||
pub fn merge(&self, other: &Self) -> Result<Self, Vec<&'static str>> {
|
|
||||||
let mut items = Vec::new();
|
|
||||||
for (k, v1) in self.0.iter() {
|
|
||||||
items.push((*k, match other.0.iter().find(|(k2, _)| k == k2) {
|
|
||||||
Some((_, v2)) => v1.merge(v2).map_err(|e| pushed::<_, Vec<_>>(e, *k))?,
|
|
||||||
None => v1.clone(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
for (k, v) in other.0.iter() {
|
|
||||||
if !items.iter().any(|(k2, _)| k2 == k) {
|
|
||||||
items.push((*k, v.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Self(Cow::Owned(items)))
|
|
||||||
}
|
|
||||||
pub async fn to_api_rec(
|
|
||||||
&self,
|
|
||||||
vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>,
|
|
||||||
i: &Interner,
|
|
||||||
) -> std::collections::HashMap<api::TStr, api::EagerVfs> {
|
|
||||||
let mut output = std::collections::HashMap::new();
|
|
||||||
for (k, v) in self.0.iter() {
|
|
||||||
output.insert(i.i::<String>(*k).await.to_api(), v.to_api_rec(vfses, i).boxed_local().await);
|
|
||||||
}
|
|
||||||
output
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum DeclFs {
|
|
||||||
Lazy(&'static dyn VirtFS),
|
|
||||||
Mod(DeclVmod),
|
|
||||||
}
|
|
||||||
impl DeclFs {
|
|
||||||
pub fn merge(&self, other: &Self) -> Result<Self, Vec<&'static str>> {
|
|
||||||
match (self, other) {
|
|
||||||
(Self::Mod(m1), Self::Mod(m2)) => Ok(Self::Mod(m1.merge(m2)?)),
|
|
||||||
(..) => Err(Vec::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn to_api_rec(
|
|
||||||
&self,
|
|
||||||
vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>,
|
|
||||||
i: &Interner,
|
|
||||||
) -> api::EagerVfs {
|
|
||||||
match self {
|
|
||||||
DeclFs::Lazy(fs) => {
|
|
||||||
let vfsc: u16 = vfses.len().try_into().expect("too many vfses (more than u16::MAX)");
|
|
||||||
let id = api::VfsId(NonZero::new(vfsc + 1).unwrap());
|
|
||||||
vfses.insert(id, *fs);
|
|
||||||
api::EagerVfs::Lazy(id)
|
|
||||||
},
|
|
||||||
DeclFs::Mod(m) => api::EagerVfs::Eager(m.to_api_rec(vfses, i).await),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ pub mod atom_thin;
|
|||||||
pub mod conv;
|
pub mod conv;
|
||||||
pub mod entrypoint;
|
pub mod entrypoint;
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
pub mod fs;
|
|
||||||
pub mod func_atom;
|
pub mod func_atom;
|
||||||
pub mod gen_expr;
|
pub mod gen_expr;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ use orchid_base::reqnot::{Receipt, ReqNot};
|
|||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
||||||
use crate::entrypoint::ExtReq;
|
use crate::entrypoint::ExtReq;
|
||||||
use crate::fs::DeclVmod;
|
|
||||||
use crate::func_atom::Fun;
|
use crate::func_atom::Fun;
|
||||||
use crate::lexer::LexerObj;
|
use crate::lexer::LexerObj;
|
||||||
use crate::parser::ParserObj;
|
use crate::parser::ParserObj;
|
||||||
@@ -83,7 +82,6 @@ impl<T: SystemCard> DynSystemCard for T {
|
|||||||
/// System as defined by author
|
/// System as defined by author
|
||||||
pub trait System: Send + Sync + SystemCard + 'static {
|
pub trait System: Send + Sync + SystemCard + 'static {
|
||||||
fn env() -> Vec<GenMember>;
|
fn env() -> Vec<GenMember>;
|
||||||
fn vfs() -> DeclVmod;
|
|
||||||
fn lexers() -> Vec<LexerObj>;
|
fn lexers() -> Vec<LexerObj>;
|
||||||
fn parsers() -> Vec<ParserObj>;
|
fn parsers() -> Vec<ParserObj>;
|
||||||
fn request(hand: ExtReq<'_>, req: Self::Req) -> impl Future<Output = Receipt<'_>>;
|
fn request(hand: ExtReq<'_>, req: Self::Req) -> impl Future<Output = Receipt<'_>>;
|
||||||
@@ -91,7 +89,6 @@ pub trait System: Send + Sync + SystemCard + 'static {
|
|||||||
|
|
||||||
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
||||||
fn dyn_env(&self) -> Vec<GenMember>;
|
fn dyn_env(&self) -> Vec<GenMember>;
|
||||||
fn dyn_vfs(&self) -> DeclVmod;
|
|
||||||
fn dyn_lexers(&self) -> Vec<LexerObj>;
|
fn dyn_lexers(&self) -> Vec<LexerObj>;
|
||||||
fn dyn_parsers(&self) -> Vec<ParserObj>;
|
fn dyn_parsers(&self) -> Vec<ParserObj>;
|
||||||
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>>;
|
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>>;
|
||||||
@@ -100,7 +97,6 @@ pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
|||||||
|
|
||||||
impl<T: System> DynSystem for T {
|
impl<T: System> DynSystem for T {
|
||||||
fn dyn_env(&self) -> Vec<GenMember> { Self::env() }
|
fn dyn_env(&self) -> Vec<GenMember> { Self::env() }
|
||||||
fn dyn_vfs(&self) -> DeclVmod { Self::vfs() }
|
|
||||||
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
|
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
|
||||||
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
|
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
|
||||||
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>> {
|
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>> {
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use async_std::path::PathBuf;
|
|
||||||
use async_stream::stream;
|
|
||||||
use futures::{FutureExt, StreamExt};
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use orchid_base::interner::Tok;
|
|
||||||
use orchid_base::name::Sym;
|
|
||||||
use orchid_base::pure_seq::pushed;
|
|
||||||
|
|
||||||
use crate::api;
|
|
||||||
use crate::system::System;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DeclMod(Rc<HashMap<Tok<String>, DeclFS>>);
|
|
||||||
impl DeclMod {
|
|
||||||
pub async fn from_api(
|
|
||||||
api: &std::collections::HashMap<api::TStr, api::EagerVfs>,
|
|
||||||
owner: System,
|
|
||||||
) -> Self {
|
|
||||||
let item_stream = stream! {
|
|
||||||
for (key, value) in api {
|
|
||||||
yield (
|
|
||||||
owner.i().ex(*key).await,
|
|
||||||
DeclFS::from_api(value, owner.clone()).boxed_local().await
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Self(Rc::new(item_stream.collect().await))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum DeclFS {
|
|
||||||
Lazy(System, api::VfsId),
|
|
||||||
Eager(DeclMod),
|
|
||||||
Path(PathBuf),
|
|
||||||
}
|
|
||||||
impl DeclFS {
|
|
||||||
pub async fn from_api(api: &api::EagerVfs, owner: System) -> Self {
|
|
||||||
match api {
|
|
||||||
api::EagerVfs::Eager(items) => Self::Eager(DeclMod::from_api(items, owner.clone()).await),
|
|
||||||
api::EagerVfs::Lazy(id) => Self::Lazy(owner.clone(), *id),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn merge(&self, other: &Self) -> Result<Self, Vec<Tok<String>>> {
|
|
||||||
let (Self::Eager(m1), Self::Eager(m2)) = (self, other) else { return Err(Vec::new()) };
|
|
||||||
let mut mix = m1.0.iter().map(|(k, v)| (k.clone(), v.clone())).collect::<HashMap<_, _>>();
|
|
||||||
for (key, value) in m2.0.iter() {
|
|
||||||
match mix.entry(key.clone()) {
|
|
||||||
hashbrown::hash_map::Entry::Vacant(ent) => {
|
|
||||||
ent.insert(value.clone());
|
|
||||||
},
|
|
||||||
hashbrown::hash_map::Entry::Occupied(mut ent) => match ent.get().merge(value) {
|
|
||||||
Err(e) => return Err(pushed(e, key.clone())),
|
|
||||||
Ok(new) => {
|
|
||||||
ent.insert(new);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Self::Eager(DeclMod(Rc::new(mix))))
|
|
||||||
}
|
|
||||||
/// Walk through eager fs. Returns if the path ends, if it hits anything other
|
|
||||||
/// than eager, or if the path is invalid.
|
|
||||||
pub fn walk<'a, 'b>(&'a self, path: &'b [Tok<String>]) -> (&'a DeclFS, &'b [Tok<String>]) {
|
|
||||||
let mut cur = self;
|
|
||||||
for (i, step) in path.iter().enumerate() {
|
|
||||||
match self {
|
|
||||||
fs @ (DeclFS::Path(_) | DeclFS::Lazy(..)) => return (fs, &path[i..]),
|
|
||||||
fs @ DeclFS::Eager(m) => match &m.0.get(step) {
|
|
||||||
None => return (fs, &path[i..]),
|
|
||||||
Some(next) => cur = next,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(cur, &[])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn load_code(fs: &DeclFS, systems: &[System], path: &[Tok<String>]) -> OrcRes<Parsed
|
|
||||||
|
|
||||||
pub async fn gather_fs(systems: &[System]) -> Result<DeclFS, Sym> {
|
|
||||||
let (head, tail) = systems.split_first().expect("Empty system list");
|
|
||||||
let mut vfs = head.vfs().await;
|
|
||||||
for sys in tail {
|
|
||||||
match vfs.merge(&sys.vfs().await) {
|
|
||||||
Err(e) => return Err(Sym::new(e.iter().rev().cloned(), head.i()).await.unwrap()),
|
|
||||||
Ok(next) => vfs = next,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(vfs)
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ pub mod execute;
|
|||||||
pub mod expr;
|
pub mod expr;
|
||||||
pub mod expr_store;
|
pub mod expr_store;
|
||||||
pub mod extension;
|
pub mod extension;
|
||||||
pub mod fs;
|
|
||||||
pub mod lex;
|
pub mod lex;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
pub mod parsed;
|
pub mod parsed;
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ pub struct HostParseCtxImpl<'a> {
|
|||||||
pub ctx: Ctx,
|
pub ctx: Ctx,
|
||||||
pub src: Sym,
|
pub src: Sym,
|
||||||
pub systems: &'a [System],
|
pub systems: &'a [System],
|
||||||
pub reporter: &'a Reporter,
|
pub rep: &'a Reporter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseCtx for HostParseCtxImpl<'_> {
|
impl ParseCtx for HostParseCtxImpl<'_> {
|
||||||
fn reporter(&self) -> &Reporter { self.reporter }
|
fn reporter(&self) -> &Reporter { self.rep }
|
||||||
fn i(&self) -> &Interner { &self.ctx.i }
|
fn i(&self) -> &Interner { &self.ctx.i }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,10 @@ impl ParsedModule {
|
|||||||
(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::Import(i) = &it.kind { Some(i) } else { None })
|
||||||
}
|
}
|
||||||
|
pub fn default_item(self, name: Tok<String>, sr: SrcRange) -> Item {
|
||||||
|
let mem = ParsedMember { exported: true, name, kind: ParsedMemberKind::Mod(self) };
|
||||||
|
Item { comments: vec![], sr, kind: ItemKind::Member(mem) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Tree for ParsedModule {
|
impl Tree for ParsedModule {
|
||||||
type Ctx<'a> = ();
|
type Ctx<'a> = ();
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ use crate::dealias::{absolute_path, walk};
|
|||||||
use crate::expr::{ExprParseCtx, ExprWillPanic};
|
use crate::expr::{ExprParseCtx, ExprWillPanic};
|
||||||
use crate::expr_store::ExprStore;
|
use crate::expr_store::ExprStore;
|
||||||
use crate::extension::{Extension, WeakExtension};
|
use crate::extension::{Extension, WeakExtension};
|
||||||
use crate::fs::{DeclFS, DeclMod};
|
|
||||||
use crate::parsed::{Item, ItemKind, ParsTokTree, ParsedMember, ParsedMemberKind, ParsedModule};
|
use crate::parsed::{Item, ItemKind, ParsTokTree, ParsedMember, ParsedMemberKind, ParsedModule};
|
||||||
use crate::tree::Root;
|
use crate::tree::Root;
|
||||||
|
|
||||||
@@ -40,7 +39,6 @@ struct SystemInstData {
|
|||||||
lex_filter: api::CharFilter,
|
lex_filter: api::CharFilter,
|
||||||
id: api::SysId,
|
id: api::SysId,
|
||||||
line_types: Vec<Tok<String>>,
|
line_types: Vec<Tok<String>>,
|
||||||
vfs: std::collections::HashMap<api::TStr, api::EagerVfs>,
|
|
||||||
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
|
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
|
||||||
}
|
}
|
||||||
impl Drop for SystemInstData {
|
impl Drop for SystemInstData {
|
||||||
@@ -79,10 +77,6 @@ impl System {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn has_lexer(&self) -> bool { !self.0.lex_filter.0.is_empty() }
|
pub fn has_lexer(&self) -> bool { !self.0.lex_filter.0.is_empty() }
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn vfs(&self) -> DeclFS {
|
|
||||||
DeclFS::Eager(DeclMod::from_api(&self.0.vfs, self.clone()).await)
|
|
||||||
}
|
|
||||||
#[must_use]
|
|
||||||
pub fn can_lex(&self, c: char) -> bool { char_filter_match(&self.0.lex_filter, c) }
|
pub fn can_lex(&self, c: char) -> bool { char_filter_match(&self.0.lex_filter, c) }
|
||||||
/// Have this system lex a part of the source. It is assumed that
|
/// Have this system lex a part of the source. It is assumed that
|
||||||
/// [Self::can_lex] was called and returned true.
|
/// [Self::can_lex] was called and returned true.
|
||||||
@@ -255,7 +249,6 @@ impl SystemCtor {
|
|||||||
ext: ext.clone(),
|
ext: ext.clone(),
|
||||||
ctx: ext.ctx().clone(),
|
ctx: ext.ctx().clone(),
|
||||||
lex_filter: sys_inst.lex_filter,
|
lex_filter: sys_inst.lex_filter,
|
||||||
vfs: sys_inst.vfs,
|
|
||||||
line_types: join_all(sys_inst.line_types.iter().map(|m| Tok::from_api(*m, &ext.ctx().i)))
|
line_types: join_all(sys_inst.line_types.iter().map(|m| Tok::from_api(*m, &ext.ctx().i)))
|
||||||
.await,
|
.await,
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use never::Never;
|
|||||||
use orchid_base::reqnot::Receipt;
|
use orchid_base::reqnot::Receipt;
|
||||||
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
||||||
use orchid_extension::entrypoint::ExtReq;
|
use orchid_extension::entrypoint::ExtReq;
|
||||||
use orchid_extension::fs::DeclVmod;
|
|
||||||
use orchid_extension::lexer::LexerObj;
|
use orchid_extension::lexer::LexerObj;
|
||||||
use orchid_extension::parser::ParserObj;
|
use orchid_extension::parser::ParserObj;
|
||||||
use orchid_extension::system::{System, SystemCard};
|
use orchid_extension::system::{System, SystemCard};
|
||||||
@@ -36,6 +35,5 @@ impl System for StdSystem {
|
|||||||
async fn request(_: ExtReq<'_>, req: Self::Req) -> Receipt<'_> { match req {} }
|
async fn request(_: ExtReq<'_>, req: Self::Req) -> Receipt<'_> { match req {} }
|
||||||
fn lexers() -> Vec<LexerObj> { vec![&StringLexer, &NumLexer] }
|
fn lexers() -> Vec<LexerObj> { vec![&StringLexer, &NumLexer] }
|
||||||
fn parsers() -> Vec<ParserObj> { vec![] }
|
fn parsers() -> Vec<ParserObj> { vec![] }
|
||||||
fn vfs() -> DeclVmod { DeclVmod::new(&[]) }
|
|
||||||
fn env() -> Vec<GenMember> { merge_trivial([gen_num_lib(), gen_str_lib()]) }
|
fn env() -> Vec<GenMember> { merge_trivial([gen_num_lib(), gen_str_lib()]) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
pub mod parse_folder;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
@@ -6,6 +8,7 @@ use std::process::{Command, ExitCode};
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use async_std::io::stdin;
|
use async_std::io::stdin;
|
||||||
|
use async_std::path::PathBuf;
|
||||||
use async_stream::try_stream;
|
use async_stream::try_stream;
|
||||||
use camino::Utf8PathBuf;
|
use camino::Utf8PathBuf;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
@@ -27,6 +30,8 @@ use orchid_host::system::init_systems;
|
|||||||
use substack::Substack;
|
use substack::Substack;
|
||||||
use tokio::task::{LocalSet, spawn_local};
|
use tokio::task::{LocalSet, spawn_local};
|
||||||
|
|
||||||
|
use crate::parse_folder::parse_folder;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about, long_about)]
|
#[command(version, about, long_about)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
@@ -54,6 +59,8 @@ pub enum Commands {
|
|||||||
},
|
},
|
||||||
Repl,
|
Repl,
|
||||||
Execute {
|
Execute {
|
||||||
|
#[arg(long)]
|
||||||
|
proj: Option<Utf8PathBuf>,
|
||||||
#[arg()]
|
#[arg()]
|
||||||
code: String,
|
code: String,
|
||||||
},
|
},
|
||||||
@@ -117,7 +124,7 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
};
|
};
|
||||||
let reporter = Reporter::new();
|
let reporter = Reporter::new();
|
||||||
let pctx = HostParseCtxImpl {
|
let pctx = HostParseCtxImpl {
|
||||||
reporter: &reporter,
|
rep: &reporter,
|
||||||
systems: &systems,
|
systems: &systems,
|
||||||
ctx: ctx.clone(),
|
ctx: ctx.clone(),
|
||||||
src: sym!(usercode; i).await,
|
src: sym!(usercode; i).await,
|
||||||
@@ -155,7 +162,7 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
let reporter = Reporter::new();
|
let reporter = Reporter::new();
|
||||||
let parse_ctx = HostParseCtxImpl {
|
let parse_ctx = HostParseCtxImpl {
|
||||||
ctx: ctx.clone(),
|
ctx: ctx.clone(),
|
||||||
reporter: &reporter,
|
rep: &reporter,
|
||||||
src: path.clone(),
|
src: path.clone(),
|
||||||
systems: &systems[..],
|
systems: &systems[..],
|
||||||
};
|
};
|
||||||
@@ -185,18 +192,29 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
ExecResult::Gas(_) => println!("Ran out of gas!"),
|
ExecResult::Gas(_) => println!("Ran out of gas!"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Commands::Execute { code } => {
|
Commands::Execute { proj, code } => {
|
||||||
let (root, systems) = init_systems(&args.system, &extensions).await.unwrap();
|
let reporter = Reporter::new();
|
||||||
|
let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap();
|
||||||
|
if let Some(proj_path) = proj {
|
||||||
|
let path = PathBuf::from(proj_path.into_std_path_buf());
|
||||||
|
match parse_folder(&root, path, sym!(src; i).await, &reporter, ctx.clone()).await {
|
||||||
|
Ok(r) => root = r,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{e}");
|
||||||
|
*exit_code1.borrow_mut() = ExitCode::FAILURE;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
let lexemes =
|
let lexemes =
|
||||||
lex(i.i(code.trim()).await, sym!(usercode; i).await, &systems, ctx).await.unwrap();
|
lex(i.i(code.trim()).await, sym!(usercode; i).await, &systems, ctx).await.unwrap();
|
||||||
if args.logs {
|
if args.logs {
|
||||||
println!("lexed: {}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl { i }).await, true));
|
println!("lexed: {}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl { i }).await, true));
|
||||||
}
|
}
|
||||||
let path = sym!(usercode; i).await;
|
let path = sym!(usercode; i).await;
|
||||||
let reporter = Reporter::new();
|
|
||||||
let parse_ctx = HostParseCtxImpl {
|
let parse_ctx = HostParseCtxImpl {
|
||||||
ctx: ctx.clone(),
|
ctx: ctx.clone(),
|
||||||
reporter: &reporter,
|
rep: &reporter,
|
||||||
src: path.clone(),
|
src: path.clone(),
|
||||||
systems: &systems[..],
|
systems: &systems[..],
|
||||||
};
|
};
|
||||||
|
|||||||
91
orcx/src/parse_folder.rs
Normal file
91
orcx/src/parse_folder.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
use async_std::fs;
|
||||||
|
use async_std::fs::File;
|
||||||
|
use async_std::io::ReadExt;
|
||||||
|
use async_std::path::{Path, PathBuf};
|
||||||
|
use async_std::stream::StreamExt;
|
||||||
|
use futures::FutureExt;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use orchid_base::error::{OrcRes, Reporter, async_io_err, mk_errv, os_str_to_string};
|
||||||
|
use orchid_base::location::SrcRange;
|
||||||
|
use orchid_base::name::Sym;
|
||||||
|
use orchid_base::parse::Snippet;
|
||||||
|
use orchid_host::ctx::Ctx;
|
||||||
|
use orchid_host::lex::lex;
|
||||||
|
use orchid_host::parse::{HostParseCtxImpl, parse_items};
|
||||||
|
use orchid_host::parsed::ParsedModule;
|
||||||
|
use orchid_host::tree::Root;
|
||||||
|
use substack::Substack;
|
||||||
|
|
||||||
|
pub async fn parse_folder(
|
||||||
|
root: &Root,
|
||||||
|
path: PathBuf,
|
||||||
|
ns: Sym,
|
||||||
|
rep: &Reporter,
|
||||||
|
ctx: Ctx,
|
||||||
|
) -> OrcRes<Root> {
|
||||||
|
let parsed_module = (recur(&path, ns.clone(), rep, ctx).await?)
|
||||||
|
.expect("Project folder is a single non-orchid file");
|
||||||
|
return Ok(root.add_parsed(&parsed_module, ns, rep).await);
|
||||||
|
async fn recur(path: &Path, ns: Sym, rep: &Reporter, ctx: Ctx) -> OrcRes<Option<ParsedModule>> {
|
||||||
|
let sr = SrcRange::new(0..0, &ns);
|
||||||
|
if path.is_dir().await {
|
||||||
|
let Some(name_os) = path.file_name() else {
|
||||||
|
return Err(mk_errv(
|
||||||
|
ctx.i.i("Could not read directory name").await,
|
||||||
|
format!("Path {} ends in ..", path.to_string_lossy()),
|
||||||
|
[sr],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let name = ctx.i.i(os_str_to_string(name_os, &ctx.i, [sr]).await?).await;
|
||||||
|
let ns = ns.push(name.clone(), &ctx.i).await;
|
||||||
|
let sr = SrcRange::new(0..0, &ns);
|
||||||
|
let mut items = Vec::new();
|
||||||
|
let mut stream = match fs::read_dir(path).await {
|
||||||
|
Err(err) => return Err(async_io_err(err, &ctx.i, [sr]).await),
|
||||||
|
Ok(s) => s,
|
||||||
|
};
|
||||||
|
while let Some(entry_res) = stream.next().await {
|
||||||
|
let entry = match entry_res {
|
||||||
|
Ok(ent) => ent,
|
||||||
|
Err(err) => {
|
||||||
|
rep.report(async_io_err(err, &ctx.i, [sr.clone()]).await);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
match recur(&entry.path(), ns.clone(), rep, ctx.clone()).boxed_local().await {
|
||||||
|
Err(e) => {
|
||||||
|
rep.report(e);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
Ok(None) => continue,
|
||||||
|
Ok(Some(module)) => items.push(module.default_item(name.clone(), sr.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Some(ParsedModule::new(items)))
|
||||||
|
} else if path.extension() == Some(OsStr::new("orc")) {
|
||||||
|
let name_os = path.file_stem().expect("If there is an extension, there must be a stem");
|
||||||
|
let name = ctx.i.i(os_str_to_string(name_os, &ctx.i, [sr]).await?).await;
|
||||||
|
let ns = ns.push(name, &ctx.i).await;
|
||||||
|
let sr = SrcRange::new(0..0, &ns);
|
||||||
|
let mut file = match File::open(path).await {
|
||||||
|
Err(e) => return Err(async_io_err(e, &ctx.i, [sr]).await),
|
||||||
|
Ok(file) => file,
|
||||||
|
};
|
||||||
|
let mut text = String::new();
|
||||||
|
if let Err(e) = file.read_to_string(&mut text).await {
|
||||||
|
return Err(async_io_err(e, &ctx.i, [sr]).await);
|
||||||
|
}
|
||||||
|
let systems =
|
||||||
|
ctx.systems.read().await.iter().filter_map(|(_, sys)| sys.upgrade()).collect_vec();
|
||||||
|
let lexemes = lex(ctx.i.i(&text).await, ns.clone(), &systems, &ctx).await?;
|
||||||
|
let hpctx = HostParseCtxImpl { ctx: ctx.clone(), rep, src: ns.clone(), systems: &systems };
|
||||||
|
let Some(fst) = lexemes.first() else { return Ok(Some(ParsedModule::new([]))) };
|
||||||
|
let items = parse_items(&hpctx, Substack::Bottom, Snippet::new(fst, &lexemes)).await?;
|
||||||
|
Ok(Some(ParsedModule::new(items)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user