diff --git a/orchid-api/src/atom.rs b/orchid-api/src/atom.rs index 636276e..2780333 100644 --- a/orchid-api/src/atom.rs +++ b/orchid-api/src/atom.rs @@ -5,7 +5,7 @@ use orchid_api_traits::Request; use crate::{ ExprTicket, Expression, ExtHostReq, FormattingUnit, HostExtNotif, HostExtReq, OrcResult, SysId, - TStrv, + TVec, }; pub type AtomData = Vec; @@ -83,14 +83,14 @@ impl Request for DeserAtom { /// A request blindly routed to the system that provides an atom. #[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)] #[extends(AtomReq, HostExtReq)] -pub struct Fwded(pub Atom, pub TStrv, pub Vec); +pub struct Fwded(pub Atom, pub TVec, pub Vec); impl Request for Fwded { type Response = Option>; } #[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)] #[extends(ExtHostReq)] -pub struct Fwd(pub Atom, pub TStrv, pub Vec); +pub struct Fwd(pub Atom, pub TVec, pub Vec); impl Request for Fwd { type Response = Option>; } diff --git a/orchid-api/src/expr.rs b/orchid-api/src/expr.rs index 4352ecf..fcc401d 100644 --- a/orchid-api/src/expr.rs +++ b/orchid-api/src/expr.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU64; use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; -use crate::{Atom, ExtHostNotif, ExtHostReq, Location, OrcError, SysId, TStrv}; +use crate::{Atom, ExtHostNotif, ExtHostReq, Location, OrcError, SysId, TVec}; /// An arbitrary ID associated with an expression on the host side. Incoming /// tickets always come with some lifetime guarantee, which can be extended with @@ -72,7 +72,7 @@ pub enum ExpressionKind { /// Because the atom is newly constructed, it also must belong to this system. NewAtom(Atom), /// A reference to a constant - Const(TStrv), + Const(TVec), /// A static runtime error. Bottom(Vec), } diff --git a/orchid-api/src/interner.rs b/orchid-api/src/interner.rs index 1263d1d..44d5587 100644 --- a/orchid-api/src/interner.rs +++ b/orchid-api/src/interner.rs @@ -47,7 +47,7 @@ impl Request for ExternStr { #[extends(IntReq, ExtHostReq)] pub struct InternStrv(pub Vec); impl Request for InternStrv { - type Response = TStrv; + type Response = TVec; } /// replica -> master to find the vector of interned strings corresponding to a /// token @@ -57,7 +57,7 @@ impl Request for InternStrv { /// See [IntReq] #[derive(Clone, Debug, Coding, Hierarchy)] #[extends(IntReq, ExtHostReq)] -pub struct ExternStrv(pub TStrv); +pub struct ExternStrv(pub TVec); impl Request for ExternStrv { type Response = Vec; } @@ -68,7 +68,7 @@ pub struct TStr(pub NonZeroU64); /// A substitute for an interned string sequence in serialized datastructures. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)] -pub struct TStrv(pub NonZeroU64); +pub struct TVec(pub NonZeroU64); /// A request to sweep the replica. The master will not be sweeped until all /// replicas respond, as it must retain everything the replicas retained @@ -84,5 +84,5 @@ impl Request for Sweep { #[derive(Clone, Debug, Coding)] pub struct Retained { pub strings: Vec, - pub vecs: Vec, + pub vecs: Vec, } diff --git a/orchid-api/src/lexer.rs b/orchid-api/src/lexer.rs index 7e00bbd..269699d 100644 --- a/orchid-api/src/lexer.rs +++ b/orchid-api/src/lexer.rs @@ -3,7 +3,7 @@ use std::ops::RangeInclusive; use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; -use crate::{ExtHostReq, HostExtReq, OrcResult, ParsId, SysId, TStr, TStrv, TokenTree}; +use crate::{ExtHostReq, HostExtReq, OrcResult, ParsId, SysId, TStr, TVec, TokenTree}; /// - All ranges contain at least one character /// - All ranges are in increasing characeter order @@ -19,7 +19,7 @@ pub struct LexExpr { pub text: TStr, pub pos: u32, /// Source root module path - pub src: TStrv, + pub src: TVec, } impl Request for LexExpr { type Response = Option>; diff --git a/orchid-api/src/location.rs b/orchid-api/src/location.rs index 361368b..047edbb 100644 --- a/orchid-api/src/location.rs +++ b/orchid-api/src/location.rs @@ -2,7 +2,7 @@ use std::ops::Range; use orchid_api_derive::Coding; -use crate::{TStr, TStrv}; +use crate::{TStr, TVec}; #[derive(Clone, Debug, Coding)] pub enum Location { @@ -21,12 +21,12 @@ pub enum Location { #[derive(Clone, Debug, Coding)] pub struct SourceRange { - pub path: TStrv, + pub path: TVec, pub range: Range, } #[derive(Clone, Debug, Coding)] pub struct CodeGenInfo { - pub generator: TStrv, + pub generator: TVec, pub details: TStr, } diff --git a/orchid-api/src/parser.rs b/orchid-api/src/parser.rs index 22da5d2..2ef6f97 100644 --- a/orchid-api/src/parser.rs +++ b/orchid-api/src/parser.rs @@ -5,7 +5,7 @@ use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; use crate::{ - Expression, ExtHostReq, HostExtReq, OrcResult, SourceRange, SysId, TStr, TStrv, TokenTree, + Expression, ExtHostReq, HostExtReq, OrcResult, SourceRange, SysId, TStr, TVec, TokenTree, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)] @@ -24,10 +24,10 @@ pub struct ParsedConstId(pub NonZeroU64); pub struct ParseLine { pub sys: SysId, /// The immediately enclosing module path - pub module: TStrv, + pub module: TVec, /// The root module path for the snipppet of source code, prefix of /// [ParseLine#module] - pub src: TStrv, + pub src: TVec, pub comments: Vec, pub exported: bool, pub idx: u16, @@ -97,9 +97,9 @@ pub struct Comment { pub struct ResolveNames { pub sys: SysId, pub constid: ParsedConstId, - pub names: Vec, + pub names: Vec, } impl Request for ResolveNames { - type Response = Vec>; + type Response = Vec>; } diff --git a/orchid-api/src/system.rs b/orchid-api/src/system.rs index c4019a7..312592f 100644 --- a/orchid-api/src/system.rs +++ b/orchid-api/src/system.rs @@ -5,7 +5,7 @@ use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; use ordered_float::NotNan; -use crate::{CharFilter, ExtHostReq, HostExtNotif, HostExtReq, MemberKind, TStr, TStrv}; +use crate::{CharFilter, ExtHostReq, HostExtNotif, HostExtReq, MemberKind, TStr, TVec}; /// ID of a system type #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)] @@ -63,7 +63,7 @@ pub struct NewSystemResponse { pub lex_filter: CharFilter, pub line_types: Vec, pub const_root: HashMap, - pub prelude: Vec, + pub prelude: Vec, } #[derive(Clone, Debug, Coding, Hierarchy)] diff --git a/orchid-api/src/tree.rs b/orchid-api/src/tree.rs index ad53241..4e701d6 100644 --- a/orchid-api/src/tree.rs +++ b/orchid-api/src/tree.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; -use crate::{ExprTicket, Expression, ExtHostReq, HostExtReq, OrcError, SysId, TStr, TStrv}; +use crate::{ExprTicket, Expression, ExtHostReq, HostExtReq, OrcError, SysId, TStr, TVec}; /// A token tree from a lexer recursion request. Its lifetime is the lex call, /// the lexer can include it in its output or discard it by implication. @@ -92,7 +92,7 @@ impl Request for GetMember { /// an atom call. #[derive(Clone, Copy, Debug, Coding, Hierarchy)] #[extends(ExtHostReq)] -pub struct LsModule(pub SysId, pub TStrv); +pub struct LsModule(pub SysId, pub TVec); impl Request for LsModule { type Response = Result; } diff --git a/orchid-base/Cargo.toml b/orchid-base/Cargo.toml index 3a49db5..72d970e 100644 --- a/orchid-base/Cargo.toml +++ b/orchid-base/Cargo.toml @@ -3,6 +3,9 @@ name = "orchid-base" version = "0.1.0" edition = "2024" +[features] +mocks = [] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/orchid-base/src/ctx.rs b/orchid-base/src/ctx.rs new file mode 100644 index 0000000..f1e464e --- /dev/null +++ b/orchid-base/src/ctx.rs @@ -0,0 +1,28 @@ +use std::any::{TypeId, type_name}; +use std::marker::PhantomData; +use std::rc::Rc; + +use orchid_api_traits::MsgSet; + +use crate::error::Reporter; +use crate::interner::Interner; +use crate::reqnot::{Client, DynClient}; + +pub trait CtxDyn { + fn i(&self) -> Interner; + fn rep(&self) -> &Reporter; + fn client(&self, msg_set: TypeId) -> Option>; + fn msg_set_type(&self) -> TypeId; +} + +pub struct Ctx(Rc); +impl Ctx { + pub fn i(&self) -> Interner { self.0.i() } + pub fn rep(&self) -> &Reporter { self.0.rep() } + pub fn client(&self) -> Client { + let Some(dyn_client) = self.0.client(TypeId::of::()) else { + panic!("Incorrect message set {} passed", type_name::()); + }; + Client(dyn_client, PhantomData) + } +} diff --git a/orchid-base/src/error.rs b/orchid-base/src/error.rs index 4d127c6..8d82aaf 100644 --- a/orchid-base/src/error.rs +++ b/orchid-base/src/error.rs @@ -1,14 +1,22 @@ use std::cell::RefCell; use std::ffi::OsStr; -use std::fmt; -use std::ops::Add; +use std::fmt::{self, Display}; +use std::ops::{Add, AddAssign, Deref}; +use std::pin::Pin; +use std::rc::Rc; use std::sync::Arc; -use futures::future::join_all; +use async_fn_stream::stream; +use async_once_cell::{Lazy, OnceCell}; +use futures::future::{join_all, ready}; +use futures::lock::Mutex; +use futures::{Stream, StreamExt, stream}; use itertools::Itertools; use crate::api; -use crate::interner::{Interner, Tok}; +use crate::ctx::Ctx; +use crate::format::{FmtCtx, FmtUnit, Format}; +use crate::interner::{IStr, Interner}; use crate::location::Pos; /// A point of interest in resolving the error, such as the point where @@ -50,40 +58,126 @@ impl fmt::Display for ErrPos { } #[derive(Clone, Debug)] -pub struct OrcErr { - pub description: Tok, +struct SingleError { + pub description: IStr, pub message: Arc, pub positions: Vec, } -impl OrcErr { - fn to_api(&self) -> api::OrcError { - api::OrcError { - description: self.description.to_api(), - message: self.message.clone(), - locations: self.positions.iter().map(ErrPos::to_api).collect(), - } - } - async fn from_api(api: &api::OrcError, i: &Interner) -> Self { - Self { - description: Tok::from_api(api.description, i).await, - message: api.message.clone(), - positions: join_all(api.locations.iter().map(|e| ErrPos::from_api(e, i))).await, - } - } -} -impl PartialEq> for OrcErr { - fn eq(&self, other: &Tok) -> bool { self.description == *other } -} -impl From for Vec { - fn from(value: OrcErr) -> Self { vec![value] } -} -impl fmt::Display for OrcErr { +impl fmt::Display for SingleError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let pstr = self.positions.iter().map(|p| format!("{p}")).join("; "); write!(f, "{}: {} @ {}", self.description, self.message, pstr) } } +pub struct OrcErr { + singles: OnceCell, + futures: Mutex>>>>, +} +impl OrcErr { + pub async fn into_owned(self) -> OwnedOrcErr { + self.to_owned().await; + self.singles.into_inner().expect("Initialized above") + } + pub async fn to_owned(&self) -> &OwnedOrcErr { + self + .singles + .get_or_init(async { + let results = join_all(self.futures.lock().await.drain(..)).await; + OwnedOrcErr(results.iter().flat_map(|err| err.0.iter()).cloned().collect()) + }) + .await + } + fn into_futures(self) -> Vec>>> { + match self.singles.into_inner() { + Some(val) => vec![Box::pin(ready(val))], + None => self.futures.into_inner(), + } + } +} +impl From for OrcErr { + fn from(value: OwnedOrcErr) -> Self { + Self { singles: OnceCell::from(value), futures: Mutex::new(vec![]) } + } +} +impl + 'static> From for OrcErr { + fn from(value: T) -> Self { + Self { + singles: OnceCell::new(), + futures: Mutex::new(vec![Box::pin(async { value.await.into_owned().await })]), + } + } +} +impl Add for OrcErr { + type Output = Self; + fn add(mut self, mut rhs: Self) -> Self::Output { + if let (Some(l), Some(r)) = (self.singles.get_mut(), rhs.singles.get_mut()) { + l.0.extend(r.0.drain(..)); + return self; + } + Self { + singles: OnceCell::new(), + futures: Mutex::new(self.into_futures().into_iter().chain(rhs.into_futures()).collect()), + } + } +} +impl AddAssign for OrcErr { + fn add_assign(&mut self, mut rhs: Self) { + if let (Some(l), Some(r)) = (self.singles.get_mut(), rhs.singles.get_mut()) { + l.0.extend(r.0.drain(..)); + } else { + let mut temp = Self { futures: Mutex::default(), singles: OnceCell::new() }; + std::mem::swap(self, &mut temp); + self.futures.get_mut().extend(temp.into_futures().into_iter().chain(rhs.into_futures())); + } + } +} +impl Format for OrcErr { + async fn print<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { + format!("{}", self.to_owned().await).into() + } +} + +#[derive(Clone)] +pub struct OwnedOrcErr(Vec); +impl OwnedOrcErr { + pub fn to_api(&self) -> Vec { + self + .0 + .iter() + .map(|err| api::OrcError { + description: err.description.to_api(), + message: err.message.clone(), + locations: err.positions.iter().map(|pos| pos.to_api()).collect(), + }) + .collect_vec() + } + pub async fn from_api(api: impl IntoIterator, i: &Interner) -> Self { + Self( + join_all(api.into_iter().map(|e| async { + SingleError { + description: i.es(e.description).await, + message: e.message.clone(), + positions: join_all(e.locations.iter().map(|pos| ErrPos::from_api(pos, i))).await, + } + })) + .await, + ) + } +} +impl Display for OwnedOrcErr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0.iter().join("\n")) + } +} +impl fmt::Debug for OwnedOrcErr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "OwnedOrcErr({self}") } +} +impl Add for OwnedOrcErr { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { Self(self.0.into_iter().chain(rhs.0).collect()) } +} + #[derive(Clone, Debug)] pub struct EmptyErrv; impl fmt::Display for EmptyErrv { @@ -92,70 +186,7 @@ impl fmt::Display for EmptyErrv { } } -#[derive(Clone, Debug)] -pub struct OrcErrv(Vec); -impl OrcErrv { - pub fn new(errors: impl IntoIterator) -> Result { - let v = errors.into_iter().collect_vec(); - if v.is_empty() { Err(EmptyErrv) } else { Ok(Self(v)) } - } - #[must_use] - pub fn extended(mut self, errors: impl IntoIterator) -> Self - where Self: Extend { - self.extend(errors); - self - } - #[must_use] - pub fn len(&self) -> usize { self.0.len() } - #[must_use] - pub fn is_empty(&self) -> bool { self.len() == 0 } - #[must_use] - pub fn any(&self, f: impl FnMut(&OrcErr) -> bool) -> bool { self.0.iter().any(f) } - #[must_use] - pub fn keep_only(self, f: impl FnMut(&OrcErr) -> bool) -> Option { - let v = self.0.into_iter().filter(f).collect_vec(); - if v.is_empty() { None } else { Some(Self(v)) } - } - #[must_use] - pub fn one(&self) -> Option<&OrcErr> { (self.0.len() == 1).then(|| &self.0[9]) } - pub fn pos_iter(&self) -> impl Iterator + '_ { - self.0.iter().flat_map(|e| e.positions.iter().cloned()) - } - pub fn to_api(&self) -> Vec { self.0.iter().map(OrcErr::to_api).collect() } - pub async fn from_api<'a>( - api: impl IntoIterator, - i: &Interner, - ) -> Self { - Self(join_all(api.into_iter().map(|e| OrcErr::from_api(e, i))).await) - } -} -impl From for OrcErrv { - fn from(value: OrcErr) -> Self { Self(vec![value]) } -} -impl Add for OrcErrv { - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { Self(self.0.into_iter().chain(rhs.0).collect_vec()) } -} -impl Extend for OrcErrv { - fn extend>(&mut self, iter: T) { self.0.extend(iter) } -} -impl Extend for OrcErrv { - fn extend>(&mut self, iter: T) { - self.0.extend(iter.into_iter().flatten()) - } -} -impl IntoIterator for OrcErrv { - type IntoIter = std::vec::IntoIter; - type Item = OrcErr; - fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } -} -impl fmt::Display for OrcErrv { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0.iter().join("\n")) - } -} - -pub type OrcRes = Result; +pub type OrcRes = Result; pub fn join_ok(left: OrcRes, right: OrcRes) -> OrcRes<(T, U)> { match (left, right) { @@ -191,62 +222,80 @@ macro_rules! join_ok { (@VALUES) => { Ok(()) }; } -pub fn mk_errv_floating(description: Tok, message: impl AsRef) -> OrcErrv { - mk_errv::(description, message, []) -} - -pub fn mk_errv>( - description: Tok, - message: impl AsRef, - posv: impl IntoIterator, -) -> OrcErrv { - OrcErr { - description, - message: Arc::new(message.as_ref().to_string()), - positions: posv.into_iter().map_into().collect(), +impl Ctx { + pub fn mk_err_floating( + &self, + description: impl AsRef + 'static, + message: impl AsRef + 'static, + ) -> OrcErr { + self.mk_err::(description, message, []) } - .into() -} - -pub async fn async_io_err>( - err: std::io::Error, - i: &Interner, - posv: impl IntoIterator, -) -> OrcErrv { - mk_errv(i.i(&err.kind().to_string()).await, err.to_string(), posv) -} - -pub async fn os_str_to_string<'a, I: Into>( - str: &'a OsStr, - i: &Interner, - posv: impl IntoIterator, -) -> 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 fn mk_err>( + &self, + description: impl AsRef + 'static, + message: impl AsRef + 'static, + posv: impl IntoIterator + 'static, + ) -> OrcErr { + let i = self.i(); + async move { + OwnedOrcErr(vec![SingleError { + description: i.is(description.as_ref()).await, + message: Arc::new(message.as_ref().to_string()), + positions: posv.into_iter().map_into().collect(), + }]) + .into() + } + .into() + } + pub async fn async_io_err>( + &self, + err: std::io::Error, + posv: impl IntoIterator + 'static, + ) -> OrcErr { + self.mk_err(err.kind().to_string(), err.to_string(), posv) + } + pub fn os_str_to_string<'a, I: Into>( + &self, + str: &'a OsStr, + posv: impl IntoIterator + 'static, + ) -> OrcRes<&'a str> { + match str.to_str() { + Some(str) => Ok(str), + None => Err(self.mk_err( + "Non-unicode string", + format!("{str:?} is not representable as unicode"), + posv, + )), + } } } pub struct Reporter { - errors: RefCell>, + errors: RefCell>, } impl Reporter { - pub fn report(&self, e: impl Into) { self.errors.borrow_mut().extend(e.into()) } - pub fn new() -> Self { Self { errors: RefCell::new(vec![]) } } - pub fn errv(self) -> Option { OrcErrv::new(self.errors.into_inner()).ok() } - pub fn merge(self, res: OrcRes) -> OrcRes { - match (res, self.errv()) { - (res, None) => res, - (Ok(_), Some(errv)) => Err(errv), - (Err(e), Some(errv)) => Err(e + errv), + pub fn report(&self, e: impl Into) { + match &mut *self.errors.borrow_mut() { + slot @ None => *slot = Some(e.into()), + Some(err) => *err += e.into(), } } - pub fn is_empty(&self) -> bool { self.errors.borrow().is_empty() } + pub fn new() -> Self { Self { errors: RefCell::new(None) } } + pub fn res(self) -> Result<(), OrcErr> { + match self.errors.into_inner() { + Some(e) => Err(e), + None => Ok(()), + } + } + pub fn merge(self, res: OrcRes) -> OrcRes { + match (res, self.res()) { + (res, Ok(())) => res, + (Ok(_), Err(e)) => Err(e), + (Err(e), Err(e2)) => Err(e + e2), + } + } + pub fn is_empty(&self) -> bool { self.errors.borrow().is_none() } } impl Default for Reporter { diff --git a/orchid-base/src/interner.rs b/orchid-base/src/interner.rs index 7e1e0b7..388f5c1 100644 --- a/orchid-base/src/interner.rs +++ b/orchid-base/src/interner.rs @@ -1,12 +1,14 @@ +use std::any::Any; use std::borrow::Borrow; use std::future::Future; -use std::hash::BuildHasher as _; +use std::hash::{BuildHasher as _, Hash}; use std::num::NonZeroU64; use std::ops::Deref; use std::rc::Rc; use std::sync::atomic; use std::{fmt, hash}; +use futures::future::LocalBoxFuture; use futures::lock::Mutex; use hashbrown::{HashMap, HashSet}; use itertools::Itertools as _; @@ -15,296 +17,460 @@ use orchid_api_traits::Request; use crate::api; use crate::reqnot::{DynRequester, Requester}; -/// Clippy crashes while verifying `Tok: Sized` without this and I cba to create -/// a minimal example -#[derive(Clone)] -struct ForceSized(T); +// /// Clippy crashes while verifying `Tok: Sized` without this and I cba to +// create /// a minimal example +// #[derive(Clone)] +// struct ForceSized(T); -#[derive(Clone)] -pub struct Tok { - data: Rc, - marker: ForceSized, -} -impl Tok { - pub fn new(data: Rc, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } } - pub fn to_api(&self) -> T::Marker { self.marker.0 } - pub async fn from_api(marker: M, i: &Interner) -> Self - where M: InternMarker { - i.ex(marker).await - } - pub fn rc(&self) -> Rc { self.data.clone() } -} -impl Deref for Tok { - type Target = T; +// #[derive(Clone)] +// pub struct Tok { +// data: Rc, +// marker: ForceSized, +// } +// impl Tok { +// pub fn new(data: Rc, marker: T::Marker) -> Self { Self { data, marker: +// ForceSized(marker) } } pub fn to_api(&self) -> T::Marker { self.marker.0 } +// pub async fn from_api(marker: M, i: &Interner) -> Self +// where M: InternMarker { +// i.ex(marker).await +// } +// pub fn rc(&self) -> Rc { self.data.clone() } +// } +// impl Deref for Tok { +// type Target = T; - fn deref(&self) -> &Self::Target { self.data.as_ref() } -} -impl Ord for Tok { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.to_api().cmp(&other.to_api()) } -} -impl PartialOrd for Tok { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} -impl Eq for Tok {} -impl PartialEq for Tok { - fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() } -} -impl hash::Hash for Tok { - fn hash(&self, state: &mut H) { self.to_api().hash(state) } -} -impl fmt::Display for Tok { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", &*self.data) - } -} -impl fmt::Debug for Tok { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Token({} -> {:?})", self.to_api().get_id(), self.data.as_ref()) - } -} +// fn deref(&self) -> &Self::Target { self.data.as_ref() } +// } +// impl Ord for Tok { +// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +// self.to_api().cmp(&other.to_api()) } } +// impl PartialOrd for Tok { +// fn partial_cmp(&self, other: &Self) -> Option { +// Some(self.cmp(other)) } } +// impl Eq for Tok {} +// impl PartialEq for Tok { +// fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() } +// } +// impl hash::Hash for Tok { +// fn hash(&self, state: &mut H) { self.to_api().hash(state) } +// } +// impl fmt::Display for Tok { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// write!(f, "{}", &*self.data) +// } +// } +// impl fmt::Debug for Tok { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// write!(f, "Token({} -> {:?})", self.to_api().get_id(), self.data.as_ref()) +// } +// } -pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable { - type Marker: InternMarker + Sized; - fn intern( - self: Rc, - req: &(impl DynRequester + ?Sized), - ) -> impl Future; - fn bimap(interner: &mut TypedInterners) -> &mut Bimap; -} +// pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + +// Internable { type Marker: InternMarker + +// Sized; fn intern( +// self: Rc, +// req: &(impl DynRequester + ?Sized), +// ) -> impl Future; +// fn bimap(interner: &mut TypedInterners) -> &mut Bimap; +// } -pub trait Internable: fmt::Debug { - type Interned: Interned; - fn get_owned(&self) -> Rc; -} +// pub trait Internable: fmt::Debug { +// type Interned: Interned; +// fn get_owned(&self) -> Rc; +// } -pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash + Sized { - type Interned: Interned; - /// Only called on replicas - fn resolve(self, i: &Interner) -> impl Future>; - fn get_id(self) -> NonZeroU64; - fn from_id(id: NonZeroU64) -> Self; -} +// pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash +// + Sized { type Interned: Interned; +// /// Only called on replicas +// fn resolve(self, i: &Interner) -> impl Future>; +// fn get_id(self) -> NonZeroU64; +// fn from_id(id: NonZeroU64) -> Self; +// } -impl Interned for String { - type Marker = api::TStr; - async fn intern( - self: Rc, - req: &(impl DynRequester + ?Sized), - ) -> Self::Marker { - req.request(api::InternStr(self.to_string())).await - } - fn bimap(interners: &mut TypedInterners) -> &mut Bimap { &mut interners.strings } -} -impl InternMarker for api::TStr { - type Interned = String; - async fn resolve(self, i: &Interner) -> Tok { - Tok::new(Rc::new(i.0.master.as_ref().unwrap().request(api::ExternStr(self)).await), self) - } - fn get_id(self) -> NonZeroU64 { self.0 } - fn from_id(id: NonZeroU64) -> Self { Self(id) } -} -impl Internable for str { - type Interned = String; - fn get_owned(&self) -> Rc { Rc::new(self.to_string()) } -} -impl Internable for String { - type Interned = String; - fn get_owned(&self) -> Rc { Rc::new(self.to_string()) } -} +// impl Interned for String { +// type Marker = api::TStr; +// async fn intern( +// self: Rc, +// req: &(impl DynRequester + ?Sized), +// ) -> Self::Marker { +// req.request(api::InternStr(self.to_string())).await +// } +// fn bimap(interners: &mut TypedInterners) -> &mut Bimap { &mut +// interners.strings } } +// impl InternMarker for api::TStr { +// type Interned = String; +// async fn resolve(self, i: &Interner) -> Tok { +// Tok::new(Rc::new(i.0.master.as_ref().unwrap(). +// request(api::ExternStr(self)).await), self) } +// fn get_id(self) -> NonZeroU64 { self.0 } +// fn from_id(id: NonZeroU64) -> Self { Self(id) } +// } +// impl Internable for str { +// type Interned = String; +// fn get_owned(&self) -> Rc { Rc::new(self.to_string()) } +// } +// impl Internable for String { +// type Interned = String; +// fn get_owned(&self) -> Rc { Rc::new(self.to_string()) } +// } -impl Interned for Vec> { - type Marker = api::TStrv; - async fn intern( - self: Rc, - req: &(impl DynRequester + ?Sized), - ) -> Self::Marker { - req.request(api::InternStrv(self.iter().map(|t| t.to_api()).collect())).await - } - fn bimap(interners: &mut TypedInterners) -> &mut Bimap { &mut interners.vecs } -} -impl InternMarker for api::TStrv { - type Interned = Vec>; - async fn resolve(self, i: &Interner) -> Tok { - let rep = i.0.master.as_ref().unwrap().request(api::ExternStrv(self)).await; - let data = futures::future::join_all(rep.into_iter().map(|m| i.ex(m))).await; - Tok::new(Rc::new(data), self) - } - fn get_id(self) -> NonZeroU64 { self.0 } - fn from_id(id: NonZeroU64) -> Self { Self(id) } -} -impl Internable for [Tok] { - type Interned = Vec>; - fn get_owned(&self) -> Rc { Rc::new(self.to_vec()) } -} -impl Internable for [Tok; N] { - type Interned = Vec>; - fn get_owned(&self) -> Rc { Rc::new(self.to_vec()) } -} -impl Internable for Vec> { - type Interned = Vec>; - fn get_owned(&self) -> Rc { Rc::new(self.to_vec()) } -} +// impl Interned for Vec { +// type Marker = api::TStrv; +// async fn intern( +// self: Rc, +// req: &(impl DynRequester + ?Sized), +// ) -> Self::Marker { +// req.request(api::InternStrv(self.iter().map(|t| +// t.to_api()).collect())).await } +// fn bimap(interners: &mut TypedInterners) -> &mut Bimap { &mut +// interners.vecs } } +// impl InternMarker for api::TStrv { +// type Interned = Vec; +// async fn resolve(self, i: &Interner) -> Tok { +// let rep = +// i.0.master.as_ref().unwrap().request(api::ExternStrv(self)).await; let data +// = futures::future::join_all(rep.into_iter().map(|m| i.ex(m))).await; +// Tok::new(Rc::new(data), self) +// } +// fn get_id(self) -> NonZeroU64 { self.0 } +// fn from_id(id: NonZeroU64) -> Self { Self(id) } +// } +// impl Internable for [IStr] { +// type Interned = Vec; +// fn get_owned(&self) -> Rc { Rc::new(self.to_vec()) } +// } +// impl Internable for [IStr; N] { +// type Interned = Vec; +// fn get_owned(&self) -> Rc { Rc::new(self.to_vec()) } +// } +// impl Internable for Vec { +// type Interned = Vec; +// fn get_owned(&self) -> Rc { Rc::new(self.to_vec()) } +// } // impl Internable for Vec { -// type Interned = Vec>; +// type Interned = Vec; // fn get_owned(&self) -> Arc { // Arc::new(self.iter().map(|ts| deintern(*ts)).collect()) // } // } // impl Internable for [api::TStr] { -// type Interned = Vec>; +// type Interned = Vec; // fn get_owned(&self) -> Arc { // Arc::new(self.iter().map(|ts| deintern(*ts)).collect()) // } // } -/// The number of references held to any token by the interner. -const BASE_RC: usize = 3; - -#[test] -fn base_rc_correct() { - let tok = Tok::new(Rc::new("foo".to_string()), api::TStr(1.try_into().unwrap())); - let mut bimap = Bimap::default(); - bimap.insert(tok.clone()); - assert_eq!(Rc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance"); +macro_rules! token_def { + ($type:ident, $trait:ident, $deref:ty, $api_repr:ty, $type_name:expr) => { + #[derive(Clone)] + pub struct $type(Rc); + impl $type { + pub fn new(t: T) -> Self { Self(Rc::new(t) as _) } + pub fn to_api(&self) -> $api_repr { self.0.to_api() } + pub fn inner(&self) -> &dyn Any { self.0.as_ref() } + fn addr(&self) -> usize { Rc::as_ptr(&self.0).addr() } + } + pub trait $trait: Deref + Any { + fn to_api(&self) -> $api_repr; + } + impl Deref for $type { + type Target = $deref; + fn deref(&self) -> &Self::Target { self.0.deref() } + } + impl Eq for $type {} + impl PartialEq for $type { + fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.0, &other.0) } + } + impl Ord for $type { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.addr().cmp(&other.addr()) } + } + impl PartialOrd for $type { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } + } + impl Hash for $type { + fn hash(&self, state: &mut H) { self.addr().hash(state) } + } + impl std::fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple($type_name).field(&self.to_api().0).field(&self.deref()).finish() + } + } + }; } -pub struct Bimap { - intern: HashMap, Tok>, - by_id: HashMap>, -} -impl Bimap { - pub fn insert(&mut self, token: Tok) { - self.intern.insert(token.data.clone(), token.clone()); - self.by_id.insert(token.to_api(), token); - } - - pub fn by_marker(&self, marker: T::Marker) -> Option> { self.by_id.get(&marker).cloned() } - - pub fn by_value(&self, q: &Q) -> Option> - where T: Borrow { - (self.intern.raw_entry()) - .from_hash(self.intern.hasher().hash_one(q), |k| k.as_ref().borrow() == q) - .map(|p| p.1.clone()) - } - - pub fn sweep_replica(&mut self) -> Vec { - (self.intern) - .extract_if(|k, _| Rc::strong_count(k) == BASE_RC) - .map(|(_, v)| { - self.by_id.remove(&v.to_api()); - v.to_api() - }) - .collect() - } - - pub fn sweep_master(&mut self, retained: HashSet) { - self.intern.retain(|k, v| BASE_RC < Rc::strong_count(k) || retained.contains(&v.to_api())) - } +token_def!(IStr, IStrDyn, str, api::TStr, "IStr"); +impl std::fmt::Display for IStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.deref()) } } -impl Default for Bimap { - fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() } } -} +token_def!(IVec, IVecDyn, [IStr], api::TVec, "IVec"); -pub trait UpComm { - fn up(&self, req: R) -> R::Response; -} - -#[derive(Default)] -pub struct TypedInterners { - strings: Bimap, - vecs: Bimap>>, -} - -#[derive(Default)] -pub struct InternerData { - interners: Mutex, - master: Option>>, -} -#[derive(Clone, Default)] -pub struct Interner(Rc); +#[derive(Clone)] +pub struct Interner(Rc); impl Interner { - pub fn new_master() -> Self { Self::default() } - pub fn new_replica(req: impl DynRequester + 'static) -> Self { - Self(Rc::new(InternerData { master: Some(Box::new(req)), interners: Mutex::default() })) + pub fn new(t: T) -> Self { Self(Rc::new(t) as _) } + pub async fn is(&self, s: &(impl Borrow + ?Sized)) -> IStr { + IStr(self.0.is(s.borrow()).await) } - /// Intern some data; query its identifier if not known locally - pub async fn i(&self, t: &(impl Internable + ?Sized)) -> Tok { - let data = t.get_owned(); - let mut g = self.0.interners.lock().await; - let typed = T::bimap(&mut g); - if let Some(tok) = typed.by_value(&data) { - return tok; - } - let marker = match &self.0.master { - Some(c) => data.clone().intern(&**c).await, - None => - T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()), - }; - let tok = Tok::new(data, marker); - T::bimap(&mut g).insert(tok.clone()); - tok - } - /// Extern an identifier; query the data it represents if not known locally - pub async fn ex(&self, marker: M) -> Tok { - if let Some(tok) = M::Interned::bimap(&mut *self.0.interners.lock().await).by_marker(marker) { - return tok; - } - assert!(self.0.master.is_some(), "ID not in local interner and this is master"); - let token = marker.resolve(self).await; - M::Interned::bimap(&mut *self.0.interners.lock().await).insert(token.clone()); - token - } - pub async fn sweep_replica(&self) -> api::Retained { - assert!(self.0.master.is_some(), "Not a replica"); - let mut g = self.0.interners.lock().await; - api::Retained { strings: g.strings.sweep_replica(), vecs: g.vecs.sweep_replica() } - } - pub async fn sweep_master(&self, retained: api::Retained) { - assert!(self.0.master.is_none(), "Not master"); - let mut g = self.0.interners.lock().await; - g.strings.sweep_master(retained.strings.into_iter().collect()); - g.vecs.sweep_master(retained.vecs.into_iter().collect()); + pub async fn iv(&self, s: &(impl Borrow<[IStr]> + ?Sized)) -> IVec { + IVec(self.0.iv(s.borrow()).await) } + pub async fn es(&self, m: api::TStr) -> IStr { IStr(self.0.es(m).await) } + pub async fn ev(&self, m: api::TVec) -> IVec { IVec(self.0.ev(m).await) } } -impl fmt::Debug for Interner { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Interner{{ replica: {} }}", self.0.master.is_none()) - } +pub trait InternerDyn { + fn is(&self, s: &str) -> LocalBoxFuture>; + fn iv(&self, v: &[IStr]) -> LocalBoxFuture>; + fn es(&self, m: api::TStr) -> LocalBoxFuture>; + fn ev(&self, m: api::TVec) -> LocalBoxFuture>; } -static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1); +#[cfg(any(feature = "mocks", test))] +pub mod test { -pub fn merge_retained(into: &mut api::Retained, from: &api::Retained) { - into.strings = into.strings.iter().chain(&from.strings).copied().unique().collect(); - into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect(); -} - -#[cfg(test)] -mod test { + use std::cell::RefCell; use std::num::NonZero; - use std::pin::Pin; - - use orchid_api_traits::{Decode, enc_vec}; - use test_executors::spin_on; + use std::sync::atomic::AtomicU64; use super::*; - use crate::api; + use crate::testing::AsyncMonitor; - #[test] - fn test_i() { - let i = Interner::new_master(); - let _: Tok = spin_on(i.i("foo")); - let _: Tok>> = spin_on(i.i(&[spin_on(i.i("bar")), spin_on(i.i("baz"))])); + pub(crate) struct DummyIStr(NonZeroU64, String); + impl Deref for DummyIStr { + type Target = str; + fn deref(&self) -> &Self::Target { &self.1 } + } + impl IStrDyn for DummyIStr { + fn to_api(&self) -> api::TStr { api::TStr(self.0) } } - #[test] - fn test_coding() { - spin_on(async { - let coded = api::TStr(NonZero::new(3u64).unwrap()); - let mut enc = &enc_vec(&coded).await[..]; - api::TStr::decode(Pin::new(&mut enc)).await; - assert_eq!(enc, [], "Did not consume all of {enc:?}") - }) + pub(crate) struct DummyIStrv(NonZeroU64, Vec); + impl Deref for DummyIStrv { + type Target = [IStr]; + fn deref(&self) -> &Self::Target { &self.1 } } + impl IVecDyn for DummyIStrv { + fn to_api(&self) -> api::TVec { api::TVec(self.0) } + } + + pub(crate) struct DummyInterner( + RefCell<( + HashMap, + HashMap>, + HashMap>, + )>, + AsyncMonitor, + ); + pub enum InternerEvent { + ExternStr(Rc), + ExternVec(Rc), + InternStr { token: Rc, new: bool }, + InternVec { token: Rc, new: bool }, + } + impl DummyInterner { + pub fn new(monitor: AsyncMonitor) -> Interner { + Interner(Rc::new(Self(RefCell::default(), monitor))) + } + } + impl InternerDyn for DummyInterner { + fn es(&self, m: api::TStr) -> LocalBoxFuture> { + let state = self.0.borrow(); + let istr = state.1.get(&m.0).unwrap_or_else(|| panic!("Externed nonexistent {m:?}")).clone(); + Box::pin(async { + self.1.notify(InternerEvent::ExternStr(istr.clone())).await; + istr as Rc + }) + } + fn ev(&self, m: api::TVec) -> LocalBoxFuture> { + let state = self.0.borrow(); + let ivec = state.2.get(&m.0).unwrap_or_else(|| panic!("Externed nonexistent {m:?}")).clone(); + Box::pin(async { + self.1.notify(InternerEvent::ExternVec(ivec.clone())).await; + ivec as Rc + }) + } + fn is(&self, s: &str) -> LocalBoxFuture> { + let mut this = self.0.borrow_mut(); + let id = *(this.0.entry(format!("{s:?}"))) + .or_insert_with(|| NonZero::new(COUNTER.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()); + let (tok, new) = match this.1.entry(id) { + hashbrown::hash_map::Entry::Occupied(ent) => (ent.get().clone(), false), + hashbrown::hash_map::Entry::Vacant(ent) => + (ent.insert(Rc::new(DummyIStr(id, s.to_string()))).clone(), true), + }; + Box::pin(async move { + self.1.notify(InternerEvent::InternStr { token: tok.clone(), new }).await; + tok as _ + }) + } + fn iv(&self, s: &[IStr]) -> LocalBoxFuture> { + let mut this = self.0.borrow_mut(); + let id = *(this.0.entry(format!("{s:?}"))) + .or_insert_with(|| NonZero::new(COUNTER.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()); + let (tok, new) = match this.2.entry(id) { + hashbrown::hash_map::Entry::Occupied(ent) => (ent.get().clone(), false), + hashbrown::hash_map::Entry::Vacant(ent) => + (ent.insert(Rc::new(DummyIStrv(id, s.to_vec()))).clone(), true), + }; + Box::pin(async move { + self.1.notify(InternerEvent::InternVec { token: tok.clone(), new }).await; + tok as _ + }) + } + } + static COUNTER: AtomicU64 = AtomicU64::new(1); } + +// /// The number of references held to any token by the interner. +// const BASE_RC: usize = 3; + +// #[test] +// fn base_rc_correct() { +// let tok = Tok::new(Rc::new("foo".to_string()), +// api::TStr(1.try_into().unwrap())); let mut bimap = Bimap::default(); +// bimap.insert(tok.clone()); +// assert_eq!(Rc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the +// current instance"); } + +// pub struct Bimap { +// intern: HashMap, +// by_id: HashMap, +// } +// impl Bimap { +// pub fn insert(&mut self, token: Tok) { +// self.intern.insert(token.data.clone(), token.clone()); +// self.by_id.insert(token.to_api(), token); +// } + +// pub fn by_marker(&self, marker: T::Marker) -> Option> { +// self.by_id.get(&marker).cloned() } + +// pub fn by_value(&self, q: &Q) -> Option> +// where T: Borrow { +// (self.intern.raw_entry()) +// .from_hash(self.intern.hasher().hash_one(q), |k| k.as_ref().borrow() == q) +// .map(|p| p.1.clone()) +// } + +// pub fn sweep_replica(&mut self) -> Vec { +// (self.intern) +// .extract_if(|k, _| Rc::strong_count(k) == BASE_RC) +// .map(|(_, v)| { +// self.by_id.remove(&v.to_api()); +// v.to_api() +// }) +// .collect() +// } + +// pub fn sweep_master(&mut self, retained: HashSet) { +// self.intern.retain(|k, v| BASE_RC < Rc::strong_count(k) || +// retained.contains(&v.to_api())) } +// } + +// impl Default for Bimap { +// fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() +// } } } + +// pub trait UpComm { +// fn up(&self, req: R) -> R::Response; +// } + +// #[derive(Default)] +// pub struct TypedInterners { +// strings: Bimap, +// vecs: Bimap>, +// } + +// #[derive(Default)] +// pub struct InternerData { +// interners: Mutex, +// master: Option>>, +// } +// #[derive(Clone, Default)] +// pub struct Interner(Rc); +// impl Interner { +// pub fn new_master() -> Self { Self::default() } +// pub fn new_replica(req: impl DynRequester + 'static) +// -> Self { Self(Rc::new(InternerData { master: Some(Box::new(req)), +// interners: Mutex::default() })) } +// /// Intern some data; query its identifier if not known locally +// pub async fn i(&self, t: &(impl Internable + +// ?Sized)) -> Tok { let data = t.get_owned(); +// let mut g = self.0.interners.lock().await; +// let typed = T::bimap(&mut g); +// if let Some(tok) = typed.by_value(&data) { +// return tok; +// } +// let marker = match &self.0.master { +// Some(c) => data.clone().intern(&**c).await, +// None => +// T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, +// atomic::Ordering::Relaxed)).unwrap()), }; +// let tok = Tok::new(data, marker); +// T::bimap(&mut g).insert(tok.clone()); +// tok +// } +// /// Extern an identifier; query the data it represents if not known locally +// pub async fn ex(&self, marker: M) -> Tok { +// if let Some(tok) = M::Interned::bimap(&mut +// *self.0.interners.lock().await).by_marker(marker) { return tok; +// } +// assert!(self.0.master.is_some(), "ID not in local interner and this is +// master"); let token = marker.resolve(self).await; +// M::Interned::bimap(&mut +// *self.0.interners.lock().await).insert(token.clone()); token +// } +// pub async fn sweep_replica(&self) -> api::Retained { +// assert!(self.0.master.is_some(), "Not a replica"); +// let mut g = self.0.interners.lock().await; +// api::Retained { strings: g.strings.sweep_replica(), vecs: +// g.vecs.sweep_replica() } } +// pub async fn sweep_master(&self, retained: api::Retained) { +// assert!(self.0.master.is_none(), "Not master"); +// let mut g = self.0.interners.lock().await; +// g.strings.sweep_master(retained.strings.into_iter().collect()); +// g.vecs.sweep_master(retained.vecs.into_iter().collect()); +// } +// } +// impl fmt::Debug for Interner { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// write!(f, "Interner{{ replica: {} }}", self.0.master.is_none()) +// } +// } + +// static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1); + +// pub fn merge_retained(into: &mut api::Retained, from: &api::Retained) { +// into.strings = +// into.strings.iter().chain(&from.strings).copied().unique().collect(); +// into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect(); +// } + +// #[cfg(test)] +// mod test { +// use std::num::NonZero; +// use std::pin::Pin; + +// use orchid_api_traits::{Decode, enc_vec}; +// use test_executors::spin_on; + +// use super::*; +// use crate::api; + +// #[test] +// fn test_i() { +// let i = Interner::new_master(); +// let _: IStr = spin_on(i.i("foo")); +// let _: Tok> = spin_on(i.i(&[spin_on(i.i("bar")), +// spin_on(i.i("baz"))])); } + +// #[test] +// fn test_coding() { +// spin_on(async { +// let coded = api::TStr(NonZero::new(3u64).unwrap()); +// let mut enc = &enc_vec(&coded).await[..]; +// api::TStr::decode(Pin::new(&mut enc)).await; +// assert_eq!(enc, [], "Did not consume all of {enc:?}") +// }) +// } +// } diff --git a/orchid-base/src/lib.rs b/orchid-base/src/lib.rs index 42a07c4..8aa9974 100644 --- a/orchid-base/src/lib.rs +++ b/orchid-base/src/lib.rs @@ -7,6 +7,7 @@ pub mod builtin; pub mod char_filter; pub mod clone; pub mod combine; +pub mod ctx; pub mod error; pub mod event; pub mod format; @@ -25,6 +26,7 @@ pub mod pure_seq; pub mod reqnot; pub mod sequence; pub mod side; +pub mod testing; mod tl_cache; pub mod tokens; pub mod tree; diff --git a/orchid-base/src/location.rs b/orchid-base/src/location.rs index 6a6d145..ae12dbb 100644 --- a/orchid-base/src/location.rs +++ b/orchid-base/src/location.rs @@ -7,12 +7,12 @@ use std::ops::Range; use trait_set::trait_set; use crate::error::ErrPos; -use crate::interner::{Interner, Tok}; +use crate::interner::{IStr, Interner}; use crate::name::Sym; use crate::{api, match_mapping, sym}; trait_set! { - pub trait GetSrc = FnMut(&Sym) -> Tok; + pub trait GetSrc = FnMut(&Sym) -> IStr; } #[derive(Debug, Clone, PartialEq, Eq)] @@ -131,24 +131,21 @@ pub struct CodeGenInfo { /// formatted like a Rust namespace pub generator: Sym, /// Unformatted user message with relevant circumstances and parameters - pub details: Tok, + pub details: IStr, } impl CodeGenInfo { /// A codegen marker with no user message and parameters pub async fn new_short(generator: Sym, i: &Interner) -> Self { - Self { generator, details: i.i("").await } + Self { generator, details: i.is("").await } } /// A codegen marker with a user message or parameters pub async fn new_details(generator: Sym, details: impl AsRef, i: &Interner) -> Self { - Self { generator, details: i.i(details.as_ref()).await } + Self { generator, details: i.is(details.as_ref()).await } } /// Syntactic location pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) } pub async fn from_api(api: &api::CodeGenInfo, i: &Interner) -> Self { - Self { - generator: Sym::from_api(api.generator, i).await, - details: Tok::from_api(api.details, i).await, - } + Self { generator: Sym::from_api(api.generator, i).await, details: i.es(api.details).await } } pub fn to_api(&self) -> api::CodeGenInfo { api::CodeGenInfo { generator: self.generator.to_api(), details: self.details.to_api() } diff --git a/orchid-base/src/name.rs b/orchid-base/src/name.rs index 2d835df..23a48dc 100644 --- a/orchid-base/src/name.rs +++ b/orchid-base/src/name.rs @@ -12,52 +12,48 @@ use itertools::Itertools; use trait_set::trait_set; use crate::api; -use crate::interner::{InternMarker, Interner, Tok}; +use crate::interner::{IStr, IVec, Interner}; trait_set! { /// Traits that all name iterators should implement - pub trait NameIter = Iterator> + DoubleEndedIterator + ExactSizeIterator; + pub trait NameIter = Iterator + DoubleEndedIterator + ExactSizeIterator; } /// A token path which may be empty. [VName] is the non-empty version #[derive(Clone, Default, Hash, PartialEq, Eq)] -pub struct VPath(Vec>); +pub struct VPath(Vec); impl VPath { /// Collect segments into a vector - pub fn new(items: impl IntoIterator>) -> Self { - Self(items.into_iter().collect()) - } + pub fn new(items: impl IntoIterator) -> Self { Self(items.into_iter().collect()) } /// Number of path segments pub fn len(&self) -> usize { self.0.len() } /// Whether there are any path segments. In other words, whether this is a /// valid name pub fn is_empty(&self) -> bool { self.len() == 0 } /// Prepend some tokens to the path - pub fn prefix(self, items: impl IntoIterator>) -> Self { + pub fn prefix(self, items: impl IntoIterator) -> Self { Self(items.into_iter().chain(self.0).collect()) } /// Append some tokens to the path - pub fn suffix(self, items: impl IntoIterator>) -> Self { + pub fn suffix(self, items: impl IntoIterator) -> Self { Self(self.0.into_iter().chain(items).collect()) } /// Partition the string by `::` namespace separators pub async fn parse(s: &str, i: &Interner) -> Self { - Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(|s| i.i(s))).await }) + Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(|s| i.is(s))).await }) } /// Walk over the segments - pub fn str_iter(&self) -> impl Iterator { - Box::new(self.0.iter().map(|s| s.as_str())) - } + pub fn str_iter(&self) -> impl Iterator { self.0.iter().map(|s| s.as_ref()) } /// Try to convert into non-empty version pub fn into_name(self) -> Result { VName::new(self.0) } /// Add a token to the path. Since now we know that it can't be empty, turn it /// into a name. - pub fn name_with_suffix(self, name: Tok) -> VName { + pub fn name_with_suffix(self, name: IStr) -> VName { VName(self.into_iter().chain([name]).collect()) } /// Add a token to the beginning of the. Since now we know that it can't be /// empty, turn it into a name. - pub fn name_with_prefix(self, name: Tok) -> VName { + pub fn name_with_prefix(self, name: IStr) -> VName { VName([name].into_iter().chain(self).collect()) } @@ -65,7 +61,7 @@ impl VPath { pub async fn from_path(path: &Path, ext: &str, i: &Interner) -> Option<(Self, bool)> { async fn to_vpath(p: &Path, i: &Interner) -> Option { let tok_opt_v = - join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(|s| i.i(s))))).await; + join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(|s| i.is(s))))).await; tok_opt_v.into_iter().collect::>().map(VPath) } match path.extension().map(|s| s.to_str()) { @@ -83,30 +79,28 @@ impl fmt::Display for VPath { write!(f, "{}", self.str_iter().join("::")) } } -impl FromIterator> for VPath { - fn from_iter>>(iter: T) -> Self { - Self(iter.into_iter().collect()) - } +impl FromIterator for VPath { + fn from_iter>(iter: T) -> Self { Self(iter.into_iter().collect()) } } impl IntoIterator for VPath { - type Item = Tok; + type Item = IStr; type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } -impl Borrow<[Tok]> for VPath { - fn borrow(&self) -> &[Tok] { &self.0[..] } +impl Borrow<[IStr]> for VPath { + fn borrow(&self) -> &[IStr] { &self.0[..] } } impl Deref for VPath { - type Target = [Tok]; + type Target = [IStr]; fn deref(&self) -> &Self::Target { self.borrow() } } impl Index for VPath -where [Tok]: Index +where [IStr]: Index { - type Output = <[Tok] as Index>::Output; + type Output = <[IStr] as Index>::Output; - fn index(&self, index: T) -> &Self::Output { &Borrow::<[Tok]>::borrow(self)[index] } + fn index(&self, index: T) -> &Self::Output { &Borrow::<[IStr]>::borrow(self)[index] } } /// A mutable representation of a namespaced identifier of at least one segment. @@ -116,11 +110,11 @@ where [Tok]: Index /// See also [Sym] for the immutable representation, and [VPath] for possibly /// empty values #[derive(Clone, Hash, PartialEq, Eq)] -pub struct VName(Vec>); +pub struct VName(Vec); impl VName { /// Assert that the sequence isn't empty and wrap it in [VName] to represent /// this invariant - pub fn new(items: impl IntoIterator>) -> Result { + pub fn new(items: impl IntoIterator) -> Result { let data: Vec<_> = items.into_iter().collect(); if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) } } @@ -128,27 +122,27 @@ impl VName { name: impl IntoIterator, i: &Interner, ) -> Result { - Self::new(join_all(name.into_iter().map(|m| Tok::from_api(m, i))).await) + Self::new(join_all(name.into_iter().map(|m| i.es(m))).await) } /// Unwrap the enclosed vector - pub fn into_vec(self) -> Vec> { self.0 } + pub fn into_vec(self) -> Vec { self.0 } /// Get a reference to the enclosed vector - pub fn vec(&self) -> &Vec> { &self.0 } + pub fn vec(&self) -> &Vec { &self.0 } /// Mutable access to the underlying vector. To ensure correct results, this /// must never be empty. - pub fn vec_mut(&mut self) -> &mut Vec> { &mut self.0 } + pub fn vec_mut(&mut self) -> &mut Vec { &mut self.0 } /// Intern the name and return a [Sym] - pub async fn to_sym(&self, i: &Interner) -> Sym { Sym(i.i(&self.0[..]).await) } + pub async fn to_sym(&self, i: &Interner) -> Sym { Sym(i.iv(&self.0[..]).await) } /// If this name has only one segment, return it - pub fn as_root(&self) -> Option> { self.0.iter().exactly_one().ok().cloned() } + pub fn as_root(&self) -> Option { self.0.iter().exactly_one().ok().cloned() } /// Prepend the segments to this name #[must_use = "This is a pure function"] - pub fn prefix(self, items: impl IntoIterator>) -> Self { + pub fn prefix(self, items: impl IntoIterator) -> Self { Self(items.into_iter().chain(self.0).collect()) } /// Append the segments to this name #[must_use = "This is a pure function"] - pub fn suffix(self, items: impl IntoIterator>) -> Self { + pub fn suffix(self, items: impl IntoIterator) -> Self { Self(self.0.into_iter().chain(items).collect()) } /// Read a `::` separated namespaced name @@ -159,7 +153,7 @@ impl VName { Self::parse(s, i).await.expect("empty literal !?") } /// Obtain an iterator over the segments of the name - pub fn iter(&self) -> impl Iterator> + '_ { self.0.iter().cloned() } + pub fn iter(&self) -> impl Iterator + '_ { self.0.iter().cloned() } } impl fmt::Debug for VName { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") } @@ -170,22 +164,22 @@ impl fmt::Display for VName { } } impl IntoIterator for VName { - type Item = Tok; + type Item = IStr; type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } impl Index for VName -where [Tok]: Index +where [IStr]: Index { - type Output = <[Tok] as Index>::Output; + type Output = <[IStr] as Index>::Output; fn index(&self, index: T) -> &Self::Output { &self.deref()[index] } } -impl Borrow<[Tok]> for VName { - fn borrow(&self) -> &[Tok] { self.0.borrow() } +impl Borrow<[IStr]> for VName { + fn borrow(&self) -> &[IStr] { self.0.borrow() } } impl Deref for VName { - type Target = [Tok]; + type Target = [IStr]; fn deref(&self) -> &Self::Target { self.borrow() } } @@ -193,11 +187,9 @@ impl Deref for VName { /// empty sequence #[derive(Debug, Copy, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct EmptyNameError; -impl TryFrom<&[Tok]> for VName { +impl TryFrom<&[IStr]> for VName { type Error = EmptyNameError; - fn try_from(value: &[Tok]) -> Result { - Self::new(value.iter().cloned()) - } + fn try_from(value: &[IStr]) -> Result { Self::new(value.iter().cloned()) } } /// An interned representation of a namespaced identifier. @@ -206,36 +198,36 @@ impl TryFrom<&[Tok]> for VName { /// /// See also [VName] #[derive(Clone, Hash, PartialEq, Eq)] -pub struct Sym(Tok>>); +pub struct Sym(IVec); impl Sym { /// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to /// represent this invariant pub async fn new( - v: impl IntoIterator>, + v: impl IntoIterator, i: &Interner, ) -> Result { let items = v.into_iter().collect_vec(); - Self::from_tok(i.i(&items).await) + Self::from_tok(i.iv(&items).await) } /// Read a `::` separated namespaced name. pub async fn parse(s: &str, i: &Interner) -> Result { - Ok(Sym(i.i(&VName::parse(s, i).await?.into_vec()).await)) + Ok(Sym(i.iv(&VName::parse(s, i).await?.into_vec()).await)) } /// Assert that a token isn't empty, and wrap it in a [Sym] - pub fn from_tok(t: Tok>>) -> Result { + pub fn from_tok(t: IVec) -> Result { if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) } } /// Grab the interner token - pub fn tok(&self) -> Tok>> { self.0.clone() } + pub fn tok(&self) -> IVec { self.0.clone() } /// Get a number unique to this name suitable for arbitrary ordering. - pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() } + pub fn id(&self) -> NonZeroU64 { self.0.to_api().0 } /// Extern the sym for editing pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) } - pub async fn from_api(marker: api::TStrv, i: &Interner) -> Sym { - Self::from_tok(Tok::from_api(marker, i).await).expect("Empty sequence found for serialized Sym") + pub async fn from_api(marker: api::TVec, i: &Interner) -> Sym { + Self::from_tok(i.ev(marker).await).expect("Empty sequence found for serialized Sym") } - pub fn to_api(&self) -> api::TStrv { self.tok().to_api() } - pub async fn suffix(&self, tokv: impl IntoIterator>, i: &Interner) -> Sym { + pub fn to_api(&self) -> api::TVec { self.tok().to_api() } + pub async fn suffix(&self, tokv: impl IntoIterator, i: &Interner) -> Sym { Self::new(self.0.iter().cloned().chain(tokv), i).await.unwrap() } } @@ -248,17 +240,17 @@ impl fmt::Display for Sym { } } impl Index for Sym -where [Tok]: Index +where [IStr]: Index { - type Output = <[Tok] as Index>::Output; + type Output = <[IStr] as Index>::Output; fn index(&self, index: T) -> &Self::Output { &self.deref()[index] } } -impl Borrow<[Tok]> for Sym { - fn borrow(&self) -> &[Tok] { &self.0[..] } +impl Borrow<[IStr]> for Sym { + fn borrow(&self) -> &[IStr] { &self.0[..] } } impl Deref for Sym { - type Target = [Tok]; + type Target = [IStr]; fn deref(&self) -> &Self::Target { self.borrow() } } @@ -266,15 +258,15 @@ impl Deref for Sym { /// handled together in datastructures. The names can never be empty #[allow(clippy::len_without_is_empty)] // never empty pub trait NameLike: - 'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<[Tok]> + 'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<[IStr]> { /// Convert into held slice - fn as_slice(&self) -> &[Tok] { Borrow::<[Tok]>::borrow(self) } + fn as_slice(&self) -> &[IStr] { Borrow::<[IStr]>::borrow(self) } /// Get iterator over tokens fn segs(&self) -> impl NameIter + '_ { self.as_slice().iter().cloned() } /// Get iterator over string segments fn str_iter(&self) -> impl Iterator + '_ { - self.as_slice().iter().map(|t| t.as_str()) + self.as_slice().iter().map(|t| t.as_ref()) } /// Fully resolve the name for printing #[must_use] @@ -286,19 +278,19 @@ pub trait NameLike: NonZeroUsize::try_from(self.segs().count()).expect("NameLike never empty") } /// Like slice's `split_first` except we know that it always returns Some - fn split_first_seg(&self) -> (Tok, &[Tok]) { + fn split_first_seg(&self) -> (IStr, &[IStr]) { let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty"); (foot.clone(), torso) } /// Like slice's `split_last` except we know that it always returns Some - fn split_last_seg(&self) -> (Tok, &[Tok]) { + fn split_last_seg(&self) -> (IStr, &[IStr]) { let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty"); (foot.clone(), torso) } /// Get the first element - fn first_seg(&self) -> Tok { self.split_first_seg().0 } + fn first_seg(&self) -> IStr { self.split_first_seg().0 } /// Get the last element - fn last_seg(&self) -> Tok { self.split_last_seg().0 } + fn last_seg(&self) -> IStr { self.split_last_seg().0 } } impl NameLike for Sym {} @@ -313,9 +305,9 @@ impl NameLike for VName {} macro_rules! sym { ($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async { $crate::name::Sym::from_tok( - $i.i(&[ - $i.i(stringify!($seg1)).await - $( , $i.i(stringify!($seg)).await )* + $i.iv(&[ + $i.is(stringify!($seg1)).await + $( , $i.is(stringify!($seg)).await )* ]) .await ).unwrap() @@ -331,8 +323,8 @@ macro_rules! sym { macro_rules! vname { ($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async { $crate::name::VName::new([ - $i.i(stringify!($seg1)).await - $( , $i.i(stringify!($seg)).await )* + $i.is(stringify!($seg1)).await + $( , $i.is(stringify!($seg)).await )* ]).unwrap() } }; } @@ -344,8 +336,8 @@ macro_rules! vname { macro_rules! vpath { ($seg1:tt $( :: $seg:tt)+ ; $i:expr) => { async { $crate::name::VPath(vec![ - $i.i(stringify!($seg1)).await - $( , $i.i(stringify!($seg)).await )+ + $i.is(stringify!($seg1)).await + $( , $i.is(stringify!($seg)).await )+ ]) } }; () => { @@ -360,35 +352,37 @@ mod test { use test_executors::spin_on; use super::{NameLike, Sym, VName}; - use crate::interner::{Interner, Tok}; + use crate::interner::test::DummyInterner; + use crate::interner::{IStr, Interner}; use crate::name::VPath; + use crate::testing::AsyncMonitor; #[test] fn recur() { spin_on(async { - let i = Interner::new_master(); + let i = DummyInterner::new(AsyncMonitor::default()); let myname = vname!(foo::bar; i).await; - let _borrowed_slice: &[Tok] = myname.borrow(); - let _deref_pathslice: &[Tok] = &myname; - let _as_slice_out: &[Tok] = myname.as_slice(); + let _borrowed_slice: &[IStr] = myname.borrow(); + let _deref_pathslice: &[IStr] = &myname; + let _as_slice_out: &[IStr] = myname.as_slice(); }) } #[test] fn literals() { spin_on(async { - let i = Interner::new_master(); + let i = DummyInterner::new(AsyncMonitor::default()); assert_eq!( sym!(foo::bar::baz; i).await, - Sym::new([i.i("foo").await, i.i("bar").await, i.i("baz").await], &i).await.unwrap() + Sym::new([i.is("foo").await, i.is("bar").await, i.is("baz").await], &i).await.unwrap() ); assert_eq!( vname!(foo::bar::baz; i).await, - VName::new([i.i("foo").await, i.i("bar").await, i.i("baz").await]).unwrap() + VName::new([i.is("foo").await, i.is("bar").await, i.is("baz").await]).unwrap() ); assert_eq!( vpath!(foo::bar::baz; i).await, - VPath::new([i.i("foo").await, i.i("bar").await, i.i("baz").await]) + VPath::new([i.is("foo").await, i.is("bar").await, i.is("baz").await]) ); }) } diff --git a/orchid-base/src/number.rs b/orchid-base/src/number.rs index 83d1ae6..b97a13a 100644 --- a/orchid-base/src/number.rs +++ b/orchid-base/src/number.rs @@ -3,8 +3,8 @@ use std::ops::Range; use ordered_float::NotNan; -use crate::error::{OrcErrv, mk_errv}; -use crate::interner::Interner; +use crate::ctx::Ctx; +use crate::error::OrcErr; use crate::location::SrcRange; use crate::name::Sym; @@ -55,14 +55,14 @@ pub struct NumError { pub kind: NumErrorKind, } -pub async fn num_to_errv( +pub fn num_to_errv( NumError { kind, range }: NumError, offset: u32, source: &Sym, - i: &Interner, -) -> OrcErrv { - mk_errv( - i.i("Failed to parse number").await, + ctx: &Ctx, +) -> OrcErr { + ctx.mk_err( + "Failed to parse number", match kind { NumErrorKind::NaN => "NaN emerged during parsing", NumErrorKind::InvalidDigit => "non-digit character encountered", diff --git a/orchid-base/src/parse.rs b/orchid-base/src/parse.rs index c14b57b..ef7d127 100644 --- a/orchid-base/src/parse.rs +++ b/orchid-base/src/parse.rs @@ -1,34 +1,21 @@ use std::fmt::{self, Display}; use std::iter; use std::ops::Deref; +use std::rc::Rc; use futures::FutureExt; use futures::future::join_all; use itertools::Itertools; use crate::api; -use crate::error::{OrcErrv, OrcRes, Reporter, mk_errv}; +use crate::ctx::Ctx; +use crate::error::{OrcErr, OrcRes, Reporter}; use crate::format::{FmtCtx, FmtUnit, Format, fmt}; -use crate::interner::{Interner, Tok}; +use crate::interner::{IStr, Interner}; use crate::location::SrcRange; use crate::name::{Sym, VName, VPath}; use crate::tree::{ExprRepr, ExtraTok, Paren, TokTree, Token, ttv_fmt, ttv_range}; -pub trait ParseCtx { - #[must_use] - fn i(&self) -> &Interner; - #[must_use] - fn rep(&self) -> &Reporter; -} -pub struct ParseCtxImpl<'a> { - pub i: &'a Interner, - pub r: &'a Reporter, -} -impl ParseCtx for ParseCtxImpl<'_> { - fn i(&self) -> &Interner { self.i } - fn rep(&self) -> &Reporter { self.r } -} - pub fn name_start(c: char) -> bool { c.is_alphabetic() || c == '_' } pub fn name_char(c: char) -> bool { name_start(c) || c.is_numeric() } pub fn op_char(c: char) -> bool { !name_char(c) && !c.is_whitespace() && !"()[]{}\\".contains(c) } @@ -103,22 +90,22 @@ impl Format for Snippet<'_, A, X> { #[derive(Clone, Debug)] pub struct Comment { - pub text: Tok, + pub text: IStr, pub sr: SrcRange, } impl Comment { // XXX: which of these four are actually used? - 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_api(c: &api::Comment, src: Sym, cx: &Ctx) -> Self { + Self { text: cx.i().es(c.text).await, sr: SrcRange::new(c.range.clone(), &src) } } - pub async fn from_tk(tk: &TokTree, i: &Interner) -> Option { + pub async fn from_tk(tk: &TokTree, cx: &Ctx) -> Option { match &tk.tok { - Token::Comment(text) => Some(Self { text: i.i(&**text).await, sr: tk.sr.clone() }), + Token::Comment(text) => Some(Self { text: cx.i().is(&**text).await, sr: tk.sr.clone() }), _ => None, } } - pub fn to_tk(&self) -> TokTree { - TokTree { tok: Token::Comment(self.text.rc().clone()), sr: self.sr.clone() } + pub fn to_tk(&self) -> TokTree { + TokTree { tok: Token::Comment(Rc::new(self.text.to_string())), sr: self.sr.clone() } } pub fn to_api(&self) -> api::Comment { api::Comment { range: self.sr.range(), text: self.text.to_api() } @@ -130,7 +117,7 @@ impl fmt::Display for Comment { } pub async fn line_items<'a, A: ExprRepr, X: ExtraTok>( - ctx: &impl ParseCtx, + ctx: &Ctx, snip: Snippet<'a, A, X>, ) -> Vec, A, X>> { let mut items = Vec::new(); @@ -146,7 +133,7 @@ pub async fn line_items<'a, A: ExprRepr, X: ExtraTok>( Some(i) => { let (cmts, tail) = line.split_at(i); let comments = join_all(comments.drain(..).chain(cmts.cur).map(|t| async { - Comment::from_tk(t, ctx.i()).await.expect("All are comments checked above") + Comment::from_tk(t, ctx).await.expect("All are comments checked above") })) .await; items.push(Parsed { output: comments, tail }); @@ -157,56 +144,50 @@ pub async fn line_items<'a, A: ExprRepr, X: ExtraTok>( } pub async fn try_pop_no_fluff<'a, A: ExprRepr, X: ExtraTok>( - ctx: &impl ParseCtx, + ctx: &Ctx, snip: Snippet<'a, A, X>, ) -> ParseRes<'a, &'a TokTree, A, X> { match snip.skip_fluff().pop_front() { Some((output, tail)) => Ok(Parsed { output, tail }), - None => Err(mk_errv( - ctx.i().i("Unexpected end").await, - "Line ends abruptly; more tokens were expected", - [snip.sr()], - )), + None => Err( + ctx.mk_err("Unexpected end", "Line ends abruptly; more tokens were expected", [snip.sr()]), + ), } } -pub async fn expect_end( - ctx: &impl ParseCtx, - snip: Snippet<'_, impl ExprRepr, impl ExtraTok>, -) -> OrcRes<()> { +pub async fn expect_end(ctx: &Ctx, snip: Snippet<'_, impl ExprRepr, impl ExtraTok>) -> OrcRes<()> { match snip.skip_fluff().get(0) { - Some(surplus) => Err(mk_errv( - ctx.i().i("Extra code after end of line").await, - "Code found after the end of the line", - [surplus.sr.pos()], - )), + Some(surplus) => + Err(ctx.mk_err("Extra code after end of line", "Code found after the end of the line", [ + surplus.sr.pos(), + ])), None => Ok(()), } } pub async fn expect_tok<'a, A: ExprRepr, X: ExtraTok>( - ctx: &impl ParseCtx, + ctx: &Ctx, snip: Snippet<'a, A, X>, - tok: Tok, + tok: IStr, ) -> ParseRes<'a, (), A, X> { let Parsed { output: head, tail } = try_pop_no_fluff(ctx, snip).await?; match &head.tok { Token::Name(n) if *n == tok => Ok(Parsed { output: (), tail }), - t => Err(mk_errv( - ctx.i().i("Expected specific keyword").await, - format!("Expected {tok} but found {:?}", fmt(t, ctx.i()).await), + t => Err(ctx.mk_err( + "Expected specific keyword", + format!("Expected {tok} but found {:?}", fmt(t, &ctx.i()).await), [head.sr()], )), } } pub async fn token_errv( - ctx: &impl ParseCtx, + ctx: &Ctx, tok: &TokTree, description: &'static str, message: impl FnOnce(&str) -> String, -) -> OrcErrv { - mk_errv(ctx.i().i(description).await, message(&fmt(tok, ctx.i()).await), [tok.sr.pos()]) +) -> OrcErr { + ctx.mk_err(description, message(&fmt(tok, &ctx.i()).await), [tok.sr.pos()]) } pub struct Parsed<'a, T, H: ExprRepr, X: ExtraTok> { @@ -217,12 +198,12 @@ pub struct Parsed<'a, T, H: ExprRepr, X: ExtraTok> { pub type ParseRes<'a, T, H, X> = OrcRes>; pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>( - ctx: &impl ParseCtx, + ctx: &Ctx, tail: Snippet<'a, A, X>, ) -> ParseRes<'a, Vec, A, X> { let Some((tt, tail)) = tail.skip_fluff().pop_front() else { - return Err(mk_errv( - ctx.i().i("Expected token").await, + return Err(ctx.mk_err( + "Expected token", "Expected a name, a parenthesized list of names, or a globstar.", [tail.sr().pos()], )); @@ -231,17 +212,14 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>( #[allow(clippy::type_complexity)] // it's an internal function pub async fn rec( tt: &TokTree, - ctx: &impl ParseCtx, - ) -> OrcRes>, Option>, SrcRange)>> { + ctx: &Ctx, + ) -> OrcRes, Option, SrcRange)>> { let ttpos = tt.sr.pos(); match &tt.tok { Token::NS(ns, body) => { if !ns.starts_with(name_start) { - ctx.rep().report(mk_errv( - ctx.i().i("Unexpected name prefix").await, - "Only names can precede ::", - [ttpos], - )) + let err = ctx.mk_err("Unexpected name prefix", "Only names can precede ::", [ttpos]); + ctx.rep().report(err) }; let out = Box::pin(rec(body, ctx)).await?; Ok(out.into_iter().update(|i| i.0.push(ns.clone())).collect_vec()) @@ -264,9 +242,9 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>( Ok(o) }, t => { - return Err(mk_errv( - ctx.i().i("Unrecognized name end").await, - format!("Names cannot end with {:?} tokens", fmt(t, ctx.i()).await), + return Err(ctx.mk_err( + "Unrecognized name end", + format!("Names cannot end with {:?} tokens", fmt(t, &ctx.i()).await), [ttpos], )); }, @@ -285,7 +263,7 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>( #[derive(Debug, Clone)] pub struct Import { pub path: VPath, - pub name: Option>, + pub name: Option, pub sr: SrcRange, } impl Import { @@ -296,14 +274,14 @@ impl Import { None => self.path.into_name().expect("Import cannot be empty"), } } - pub fn new(sr: SrcRange, path: VPath, name: Tok) -> Self { + pub fn new(sr: SrcRange, path: VPath, name: IStr) -> Self { Import { path, name: Some(name), sr } } pub fn new_glob(sr: SrcRange, path: VPath) -> Self { Import { path, name: None, sr } } } impl Display for Import { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}::{}", self.path.iter().join("::"), self.name.as_ref().map_or("*", |t| t.as_str())) + write!(f, "{}::{}", self.path, self.name.as_deref().unwrap_or("*")) } } diff --git a/orchid-base/src/reqnot.rs b/orchid-base/src/reqnot.rs index 6c4a59a..65ef872 100644 --- a/orchid-base/src/reqnot.rs +++ b/orchid-base/src/reqnot.rs @@ -5,15 +5,18 @@ use std::marker::PhantomData; use std::mem; use std::ops::{BitAnd, Deref}; use std::pin::Pin; +use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Duration; use derive_destructure::destructure; use dyn_clone::{DynClone, clone_box}; -use futures::channel::mpsc; +use futures::channel::mpsc::{self, Sender}; +use futures::channel::oneshot; use futures::future::LocalBoxFuture; use futures::lock::Mutex; -use futures::{SinkExt, StreamExt}; +use futures::{AsyncBufRead, AsyncWrite, SinkExt, Stream, StreamExt}; use hashbrown::HashMap; use orchid_api_traits::{Channel, Coding, Decode, Encode, MsgSet, Request}; use trait_set::trait_set; @@ -23,6 +26,71 @@ use crate::logging::Logger; pub struct Receipt<'a>(PhantomData<&'a mut ()>); +/// This object holds an exclusive lock on the outbound pipe. +pub trait DynRequestWriter { + fn writer(&mut self) -> Pin<&mut dyn AsyncWrite>; + /// Release the outbound pipe and wait for the response to begin. + fn get_response(self: Box) -> Pin>>>; +} +/// This object holds an exclusive lock on the inbound pipe. +pub trait DynResponseHandle { + fn reader(&mut self) -> Pin<&mut dyn AsyncBufRead>; + fn finish(self: Box) -> Pin>>; +} +/// This object holds an exclusive lock on the outbound pipe. +pub trait DynNotifWriter { + fn writer(&mut self) -> Pin<&mut dyn AsyncWrite>; + fn finish(self: Box) -> Pin>>; +} + +pub trait DynClient { + fn request(&self) -> Pin>>>; + fn notif(&self) -> Pin>>>; +} + +pub struct Client(pub(crate) Rc, pub(crate) PhantomData); +impl Client { + pub async fn notify::Notif>>(&self, notif: Notif) { + let mut notif_writer = self.0.notif().await; + notif.into().encode(notif_writer.writer()).await; + notif_writer.finish().await; + } + pub async fn request::Req>>( + &self, + req: Req, + ) -> Req::Response { + let root_req = req.into(); + let mut req_writer = self.0.request().await; + root_req.encode(req_writer.writer()).await; + let mut req_hand = req_writer.get_response().await; + let res = Req::Response::decode(req_hand.reader()).await; + req_hand.finish().await; + res + } +} + +pub struct DuplexServerState { + pending_outbound: HashMap>, + sender: Pin>, + receiver: Pin>, +} +pub enum ServerEvent { + Notif(::Notif), + Req(RequestHandle, ::Req), +} +pub async fn run_duplex_server( + sender: Pin>, + receiver: Pin>, +) -> (impl Stream>, Client) { + let sender = Rc::new(Mutex::new(sender)); + let receiver = Rc::new(Mutex::new(receiver)); + let pending_outbound = Rc::new(Mutex::new(HashMap::new())); +} +pub struct DuplexServer(Rc>); +impl DuplexServer { + pub fn receive(msg: ) +} + trait_set! { pub trait SendFn = for<'a> FnMut(&'a [u8], ReqNot) -> LocalBoxFuture<'a, ()> @@ -52,11 +120,10 @@ impl ReqHandlish for &'_ dyn ReqHandlish { } #[derive(destructure)] -pub struct RequestHandle<'a, MS: MsgSet> { +pub struct RequestHandle { defer_drop: RefCell>>, fulfilled: AtomicBool, id: u64, - _reqlt: PhantomData<&'a mut ()>, parent: ReqNot, } impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> { @@ -89,7 +156,7 @@ impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> { impl ReqHandlish for RequestHandle<'_, MS> { fn defer_drop_objsafe(&self, val: Box) { self.defer_drop.borrow_mut().push(val); } } -impl Drop for RequestHandle<'_, MS> { +impl Drop for RequestHandle { fn drop(&mut self) { let done = self.fulfilled.load(Ordering::Relaxed); debug_assert!(done, "Request {} dropped without response", self.id) @@ -123,7 +190,7 @@ impl ReqNot { notif: impl NotifFn, req: impl ReqFn, ) -> Self { - Self( + let this = Self( Arc::new(Mutex::new(ReqNotData { id: 1, send: Box::new(send), @@ -132,7 +199,13 @@ impl ReqNot { responses: HashMap::new(), })), logger, - ) + ); + let (sig_send, sig_recv) = std::sync::mpsc::sync_channel(0); + std::thread::spawn(move || { + std::thread::sleep(Duration::from_secs(10)); + sig_send.send(()).expect("Crash!"); + }); + this } /// Can be called from a polling thread or dispatched in any other way diff --git a/orchid-base/src/testing.rs b/orchid-base/src/testing.rs new file mode 100644 index 0000000..fd2c333 --- /dev/null +++ b/orchid-base/src/testing.rs @@ -0,0 +1,23 @@ +#![cfg(any(feature = "mocks", test))] + +use std::future::ready; +use std::pin::Pin; +use std::rc::Rc; + +pub struct AsyncMonitor(Rc Pin>>>); +impl AsyncMonitor { + pub fn new () + 'static>(f: F) -> Self { + let f_rc = Rc::new(f); + AsyncMonitor(Rc::new(move |e| { + let f_rc = f_rc.clone(); + Box::pin(async move { f_rc(e).await }) + })) + } + pub async fn notify(&self, e: E) -> () { (self.0)(e).await } +} +impl Default for AsyncMonitor { + fn default() -> Self { Self(Rc::new(|_| Box::pin(ready(())))) } +} +impl Clone for AsyncMonitor { + fn clone(&self) -> Self { Self(self.0.clone()) } +} diff --git a/orchid-base/src/tree.rs b/orchid-base/src/tree.rs index 0a62571..e375228 100644 --- a/orchid-base/src/tree.rs +++ b/orchid-base/src/tree.rs @@ -12,9 +12,9 @@ use never::Never; use orchid_api_traits::Coding; use trait_set::trait_set; -use crate::error::OrcErrv; +use crate::error::OwnedOrcErr; use crate::format::{FmtCtx, FmtUnit, Format, Variants}; -use crate::interner::{Interner, Tok}; +use crate::interner::{IStr, Interner}; use crate::location::{Pos, SrcRange}; use crate::name::{Sym, VName, VPath}; use crate::parse::Snippet; @@ -113,11 +113,11 @@ impl TokTree { let pos = SrcRange::new(tt.range.clone(), src); let tok = match_mapping!(&tt.token, api::Token => Token:: { BR, - NS(n => Tok::from_api(*n, i).await, + NS(n => i.es(*n).await, b => Box::new(Self::from_api(b, hctx, xctx, src, i).boxed_local().await)), - Bottom(e => OrcErrv::from_api(e, i).await), + Bottom(e => OwnedOrcErr::from_api(e, i).await), LambdaHead(arg => Box::new(Self::from_api(arg, hctx, xctx, src, i).boxed_local().await)), - Name(n => Tok::from_api(*n, i).await), + Name(n => i.es(*n).await), S(*par, b => ttv_from_api(b, hctx, xctx, src, i).await), Comment(c.clone()), NewExpr(expr => X::from_api(expr, xctx, pos.clone(), i).await), @@ -145,8 +145,8 @@ impl TokTree { api::TokenTree { range: self.sr.range.clone(), token } } - pub fn is_kw(&self, tk: Tok) -> bool { self.tok.is_kw(tk) } - pub fn as_name(&self) -> Option> { + pub fn is_kw(&self, tk: IStr) -> bool { self.tok.is_kw(tk) } + pub fn as_name(&self) -> Option { if let Token::Name(n) = &self.tok { Some(n.clone()) } else { None } } pub fn as_multiname(&self) -> Result> { @@ -245,9 +245,9 @@ pub enum Token { /// stretches to the end of the enclosing parens or the end of the const line LambdaHead(Box>), /// A binding, operator, or a segment of a namespaced::name - Name(Tok), + Name(IStr), /// A namespace prefix, like `my_ns::` followed by a token - NS(Tok, Box>), + NS(IStr, Box>), /// A line break BR, /// `()`, `[]`, or `{}` @@ -259,11 +259,11 @@ pub enum Token { /// A grammar error emitted by a lexer plugin if it was possible to continue /// reading. Parsers should treat it as an atom unless it prevents parsing, /// in which case both this and a relevant error should be returned. - Bottom(OrcErrv), + Bottom(OwnedOrcErr), } impl Token { pub fn at(self, sr: SrcRange) -> TokTree { TokTree { sr, tok: self } } - pub fn is_kw(&self, tk: Tok) -> bool { matches!(self, Token::Name(n) if *n == tk) } + pub fn is_kw(&self, tk: IStr) -> bool { matches!(self, Token::Name(n) if *n == tk) } pub fn as_s(&self, par: Paren) -> Option<&[TokTree]> { match self { Self::S(p, b) if *p == par => Some(b), @@ -275,8 +275,7 @@ impl Format for Token { async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { match self { Self::BR => "\n".to_string().into(), - Self::Bottom(err) if err.len() == 1 => format!("Bottom({}) ", err.one().unwrap()).into(), - Self::Bottom(err) => format!("Botttom(\n{}) ", indent(&err.to_string())).into(), + Self::Bottom(err) => format!("Botttom({}) ", indent(&err.to_string())).into(), Self::Comment(c) => format!("--[{c}]--").into(), Self::LambdaHead(arg) => tl_cache!(Rc: Rc::new(Variants::default().bounded("\\{0b}."))) diff --git a/orchid-base/src/virt_fs/common.rs b/orchid-base/src/virt_fs/common.rs index 47689be..fc0a81d 100644 --- a/orchid-base/src/virt_fs/common.rs +++ b/orchid-base/src/virt_fs/common.rs @@ -13,13 +13,13 @@ pub enum Loaded { Code(Arc), /// Conceptually equivalent to the list of *.orc files in a folder, without /// the extension - Collection(Arc>>), + Collection(Arc>), } impl Loaded { /// Is the loaded item source code (not a collection)? pub fn is_code(&self) -> bool { matches!(self, Loaded::Code(_)) } /// Collect the elements in a collection rreport - pub fn collection(items: impl IntoIterator>) -> Self { + pub fn collection(items: impl IntoIterator) -> Self { Self::Collection(Arc::new(items.into_iter().collect())) } } @@ -55,7 +55,7 @@ impl ErrorSansOrigin for CodeNotFound { /// formats and other sources for libraries and dependencies. pub trait VirtFS { /// Implementation of [VirtFS::read] - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult; + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult; /// Discover information about a path without reading it. /// /// Implement this if your vfs backend can do expensive operations @@ -68,7 +68,7 @@ pub trait VirtFS { } /// Convert a path into a human-readable string that is meaningful in the /// target context. - fn display(&self, path: &[Tok]) -> Option; + fn display(&self, path: &[IStr]) -> Option; /// Convert the FS handler into a type-erased version of itself for packing in /// a tree. fn rc(self) -> Rc @@ -81,15 +81,15 @@ pub trait VirtFS { } impl VirtFS for &dyn VirtFS { - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult { + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult { (*self).get(path, full_path) } - fn display(&self, path: &[Tok]) -> Option { (*self).display(path) } + fn display(&self, path: &[IStr]) -> Option { (*self).display(path) } } impl VirtFS for Rc { - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult { + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult { (**self).get(path, full_path) } - fn display(&self, path: &[Tok]) -> Option { (**self).display(path) } + fn display(&self, path: &[IStr]) -> Option { (**self).display(path) } } diff --git a/orchid-base/src/virt_fs/decl.rs b/orchid-base/src/virt_fs/decl.rs index ffc060c..84c9f46 100644 --- a/orchid-base/src/virt_fs/decl.rs +++ b/orchid-base/src/virt_fs/decl.rs @@ -32,7 +32,7 @@ impl<'a> Combine for &'a dyn VirtFS { pub type DeclTree = ModEntry, (), ()>; impl VirtFS for DeclTree { - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult { + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult { match &self.member { ModMember::Item(it) => it.get(path, full_path), ModMember::Sub(module) => match path.split_first() { @@ -44,7 +44,7 @@ impl VirtFS for DeclTree { } } - fn display(&self, path: &[Tok]) -> Option { + fn display(&self, path: &[IStr]) -> Option { let (head, tail) = path.split_first()?; match &self.member { ModMember::Item(it) => it.display(path), @@ -54,16 +54,16 @@ impl VirtFS for DeclTree { } impl VirtFS for String { - fn display(&self, _: &[Tok]) -> Option { None } - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult { + fn display(&self, _: &[IStr]) -> Option { None } + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult { (path.is_empty().then(|| Loaded::Code(Arc::new(self.as_str().to_string())))) .ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack()) } } impl<'a> VirtFS for &'a str { - fn display(&self, _: &[Tok]) -> Option { None } - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult { + fn display(&self, _: &[IStr]) -> Option { None } + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult { (path.is_empty().then(|| Loaded::Code(Arc::new(self.to_string())))) .ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack()) } diff --git a/orchid-base/src/virt_fs/dir.rs b/orchid-base/src/virt_fs/dir.rs index 728b802..6ea89c3 100644 --- a/orchid-base/src/virt_fs/dir.rs +++ b/orchid-base/src/virt_fs/dir.rs @@ -99,14 +99,14 @@ impl DirNode { } } - fn mk_pathbuf(&self, path: &[Tok]) -> PathBuf { + fn mk_pathbuf(&self, path: &[IStr]) -> PathBuf { let mut fpath = self.root.clone(); path.iter().for_each(|seg| fpath.push(seg.as_str())); fpath } } impl VirtFS for DirNode { - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult { + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult { let fpath = self.mk_pathbuf(path); let mut binding = self.cached.borrow_mut(); let (_, res) = (binding.raw_entry_mut().from_key(&fpath)) @@ -114,7 +114,7 @@ impl VirtFS for DirNode { res.clone() } - fn display(&self, path: &[Tok]) -> Option { + fn display(&self, path: &[IStr]) -> Option { let pathbuf = self.mk_pathbuf(path).with_extension(self.ext()); Some(pathbuf.to_string_lossy().to_string()) } diff --git a/orchid-base/src/virt_fs/embed.rs b/orchid-base/src/virt_fs/embed.rs index b0ec218..6357b7b 100644 --- a/orchid-base/src/virt_fs/embed.rs +++ b/orchid-base/src/virt_fs/embed.rs @@ -56,7 +56,7 @@ impl EmbeddedFS { } impl VirtFS for EmbeddedFS { - fn get(&self, path: &[Tok], full_path: &PathSlice) -> FSResult { + fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult { if path.is_empty() { return Ok(Loaded::collection(self.tree.keys(|_| true))); } @@ -67,7 +67,7 @@ impl VirtFS for EmbeddedFS { ModMember::Sub(sub) => Loaded::collection(sub.keys(|_| true)), }) } - fn display(&self, path: &[Tok]) -> Option { + fn display(&self, path: &[IStr]) -> Option { let Self { gen, suffix, .. } = self; Some(format!("{}{suffix} in {gen}", path.iter().join("/"))) } diff --git a/orchid-base/src/virt_fs/prefix.rs b/orchid-base/src/virt_fs/prefix.rs index cb29d60..ae036ef 100644 --- a/orchid-base/src/virt_fs/prefix.rs +++ b/orchid-base/src/virt_fs/prefix.rs @@ -21,18 +21,18 @@ impl<'a> PrefixFS<'a> { add: VPath::parse(add.as_ref()), } } - fn proc_path(&self, path: &[Tok]) -> Option>> { + fn proc_path(&self, path: &[IStr]) -> Option> { let path = path.strip_prefix(self.remove.as_slice())?; Some(self.add.0.iter().chain(path).cloned().collect_vec()) } } impl<'a> VirtFS for PrefixFS<'a> { - fn get(&self, path: &[Tok], full_path: &PathSlice) -> super::FSResult { + fn get(&self, path: &[IStr], full_path: &PathSlice) -> super::FSResult { let path = self.proc_path(path).ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack())?; self.wrapped.get(&path, full_path) } - fn display(&self, path: &[Tok]) -> Option { + fn display(&self, path: &[IStr]) -> Option { self.wrapped.display(&self.proc_path(path)?) } } diff --git a/orchid-extension/src/atom.rs b/orchid-extension/src/atom.rs index d44f46f..1bf0f94 100644 --- a/orchid-extension/src/atom.rs +++ b/orchid-extension/src/atom.rs @@ -13,7 +13,8 @@ use futures::{AsyncRead, AsyncWrite, FutureExt, StreamExt, stream}; use orchid_api_derive::Coding; use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec}; use orchid_base::clone; -use orchid_base::error::{OrcErrv, OrcRes, mk_errv, mk_errv_floating}; +use orchid_base::ctx::Ctx; +use orchid_base::error::{OrcErr, OrcRes}; use orchid_base::format::{FmtCtx, FmtUnit, Format}; use orchid_base::interner::Interner; use orchid_base::location::Pos; @@ -135,12 +136,10 @@ pub struct NotTypAtom { pub ctx: SysCtx, } impl NotTypAtom { - pub async fn mk_err(&self) -> OrcErrv { - mk_errv( - self.ctx.i().i("Not the expected type").await, - format!("This expression is not a {}", self.typ.name()), - [self.pos.clone()], - ) + pub fn mk_err(&self, ctx: &Ctx) -> OrcErr { + ctx.mk_err("Not the expected type", format!("This expression is not a {}", self.typ.name()), [ + self.pos.clone(), + ]) } } @@ -329,10 +328,10 @@ impl Format for AtomFactory { } } -pub async fn err_not_callable(i: &Interner) -> OrcErrv { - mk_errv_floating(i.i("This atom is not callable").await, "Attempted to apply value as function") +pub fn err_not_callable(cx: &Ctx) -> OrcErr { + cx.mk_err_floating("This atom is not callable", "Attempted to apply value as function") } -pub async fn err_not_command(i: &Interner) -> OrcErrv { - mk_errv_floating(i.i("This atom is not a command").await, "Settled on an inactionable value") +pub fn err_not_command(cx: &Ctx) -> OrcErr { + cx.mk_err_floating("This atom is not a command", "Settled on an inactionable value") } diff --git a/orchid-extension/src/conv.rs b/orchid-extension/src/conv.rs index 5b49328..9dd9455 100644 --- a/orchid-extension/src/conv.rs +++ b/orchid-extension/src/conv.rs @@ -1,7 +1,7 @@ use std::future::Future; use never::Never; -use orchid_base::error::{OrcErrv, OrcRes, mk_errv}; +use orchid_base::error::{OrcErrv, OrcRes, mk_err}; use orchid_base::interner::Interner; use orchid_base::location::Pos; @@ -25,11 +25,11 @@ impl TryFromExpr for (T, U) { } async fn err_not_atom(pos: Pos, i: &Interner) -> OrcErrv { - mk_errv(i.i("Expected an atom").await, "This expression is not an atom", [pos]) + mk_err(i.i("Expected an atom").await, "This expression is not an atom", [pos]) } async fn err_type(pos: Pos, i: &Interner) -> OrcErrv { - mk_errv(i.i("Type error").await, "The atom is a different type than expected", [pos]) + mk_err(i.i("Type error").await, "The atom is a different type than expected", [pos]) } impl TryFromExpr for ForeignAtom { diff --git a/orchid-extension/src/entrypoint.rs b/orchid-extension/src/entrypoint.rs index 5d5699d..a2b37f5 100644 --- a/orchid-extension/src/entrypoint.rs +++ b/orchid-extension/src/entrypoint.rs @@ -49,7 +49,7 @@ impl ExtensionData { } pub enum MemberRecord { - Gen(Vec>, LazyMemberFactory), + Gen(Vec, LazyMemberFactory), Res, } diff --git a/orchid-extension/src/interner.rs b/orchid-extension/src/interner.rs new file mode 100644 index 0000000..2a10827 --- /dev/null +++ b/orchid-extension/src/interner.rs @@ -0,0 +1,7 @@ +use orchid_base::interner::{ApiStrTok, ApiStrvTok, IStr}; + +pub struct ExtIStr(ApiStrTok, Rc); +impl Deref for ExtIStr {} +pub struct ExtIStrv(ApiStrvTok, Rc>); + +pub struct ExtInterner {} diff --git a/orchid-extension/src/lexer.rs b/orchid-extension/src/lexer.rs index b41c1b2..e698126 100644 --- a/orchid-extension/src/lexer.rs +++ b/orchid-extension/src/lexer.rs @@ -4,7 +4,7 @@ use std::ops::RangeInclusive; use futures::FutureExt; use futures::future::LocalBoxFuture; -use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_errv}; +use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_err}; use orchid_base::interner::{Interner, Tok}; use orchid_base::location::{Pos, SrcRange}; use orchid_base::name::Sym; @@ -17,27 +17,27 @@ use crate::parser::PTokTree; use crate::system::SysCtx; use crate::tree::GenTokTree; -pub async fn ekey_cascade(i: &Interner) -> Tok { +pub async fn ekey_cascade(i: &Interner) -> IStr { i.i("An error cascading from a recursive call").await } -pub async fn ekey_not_applicable(i: &Interner) -> Tok { +pub async fn ekey_not_applicable(i: &Interner) -> IStr { i.i("Pseudo-error to communicate that the current branch in a dispatch doesn't apply").await } const MSG_INTERNAL_ERROR: &str = "This error is a sentinel for the extension library.\ it should not be emitted by the extension."; pub async fn err_cascade(i: &Interner) -> OrcErrv { - mk_errv(ekey_cascade(i).await, MSG_INTERNAL_ERROR, [Pos::None]) + mk_err(ekey_cascade(i).await, MSG_INTERNAL_ERROR, [Pos::None]) } pub async fn err_not_applicable(i: &Interner) -> OrcErrv { - mk_errv(ekey_not_applicable(i).await, MSG_INTERNAL_ERROR, [Pos::None]) + mk_err(ekey_not_applicable(i).await, MSG_INTERNAL_ERROR, [Pos::None]) } pub struct LexContext<'a> { pub(crate) exprs: &'a BorrowedExprStore, pub ctx: SysCtx, - pub text: &'a Tok, + pub text: &'a IStr, pub id: api::ParsId, pub pos: u32, pub(crate) src: Sym, diff --git a/orchid-extension/src/lib.rs b/orchid-extension/src/lib.rs index 8e16689..8652376 100644 --- a/orchid-extension/src/lib.rs +++ b/orchid-extension/src/lib.rs @@ -11,6 +11,7 @@ pub mod func_atom; pub mod gen_expr; pub mod lexer; // pub mod msg; +mod interner; pub mod other_system; pub mod parser; pub mod reflection; diff --git a/orchid-extension/src/parser.rs b/orchid-extension/src/parser.rs index 8494123..d87a8d8 100644 --- a/orchid-extension/src/parser.rs +++ b/orchid-extension/src/parser.rs @@ -115,7 +115,7 @@ impl ParsedLine { sr: &SrcRange, comments: impl IntoIterator, exported: bool, - name: Tok, + name: IStr, f: F, ) -> Self { let cb = Box::new(|ctx| async move { f(ctx).await.to_expr().await }.boxed_local()); @@ -127,7 +127,7 @@ impl ParsedLine { sr: &SrcRange, comments: impl IntoIterator, exported: bool, - name: &Tok, + name: &IStr, use_prelude: bool, lines: impl IntoIterator, ) -> Self { @@ -175,7 +175,7 @@ pub enum ParsedLineKind { } pub struct ParsedMem { - pub name: Tok, + pub name: IStr, pub exported: bool, pub kind: ParsedMemKind, } diff --git a/orchid-extension/src/reflection.rs b/orchid-extension/src/reflection.rs index 1d000f3..f361b1b 100644 --- a/orchid-extension/src/reflection.rs +++ b/orchid-extension/src/reflection.rs @@ -32,7 +32,7 @@ pub struct ReflModData { inferred: Mutex, path: VPath, ctx: WeakSysCtx, - members: MemoMap, ReflMem>, + members: MemoMap, } #[derive(Clone)] @@ -41,7 +41,7 @@ impl ReflMod { fn ctx(&self) -> SysCtx { self.0.ctx.upgrade().expect("ReflectedModule accessed after context drop") } - pub fn path(&self) -> &[Tok] { &self.0.path[..] } + pub fn path(&self) -> &[IStr] { &self.0.path[..] } pub fn is_root(&self) -> bool { self.0.path.is_empty() } async fn try_populate(&self) -> Result<(), api::LsModuleError> { let ctx = self.ctx(); @@ -70,7 +70,7 @@ impl ReflMod { } Ok(()) } - pub async fn get_child(&self, key: &Tok) -> Option { + pub async fn get_child(&self, key: &IStr) -> Option { let inferred_g = self.0.inferred.lock().await; if let Some(mem) = self.0.members.get(key) { return Some(mem.clone()); @@ -88,7 +88,7 @@ impl ReflMod { } self.0.members.get(key).cloned() } - pub async fn get_by_path(&self, path: &[Tok]) -> Result { + pub async fn get_by_path(&self, path: &[IStr]) -> Result { let ctx = self.ctx(); let (next, tail) = path.split_first().expect("Attempted to walk by empty path"); let inferred_g = self.0.inferred.lock().await; diff --git a/orchid-extension/src/tree.rs b/orchid-extension/src/tree.rs index 89b4dcb..6829785 100644 --- a/orchid-extension/src/tree.rs +++ b/orchid-extension/src/tree.rs @@ -206,21 +206,21 @@ impl MemKind { pub trait TreeIntoApiCtx { fn sys(&self) -> SysCtx; fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId; - fn push_path(&mut self, seg: Tok) -> impl TreeIntoApiCtx; + fn push_path(&mut self, seg: IStr) -> impl TreeIntoApiCtx; fn req(&self) -> &impl ReqHandlish; } pub struct TreeIntoApiCtxImpl<'a, 'b, RH: ReqHandlish> { pub sys: SysCtx, - pub basepath: &'a [Tok], - pub path: Substack<'a, Tok>, + pub basepath: &'a [IStr], + pub path: Substack<'a, IStr>, pub lazy_members: &'b mut HashMap, pub req: &'a RH, } impl TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> { fn sys(&self) -> SysCtx { self.sys.clone() } - fn push_path(&mut self, seg: Tok) -> impl TreeIntoApiCtx { + fn push_path(&mut self, seg: IStr) -> impl TreeIntoApiCtx { TreeIntoApiCtxImpl { req: self.req, lazy_members: self.lazy_members, diff --git a/orchid-host/src/atom.rs b/orchid-host/src/atom.rs index 5487008..c08eead 100644 --- a/orchid-host/src/atom.rs +++ b/orchid-host/src/atom.rs @@ -73,7 +73,7 @@ impl AtomHand { pub fn sys(&self) -> &System { &self.0.owner } #[must_use] pub fn ext(&self) -> &Extension { self.sys().ext() } - pub async fn req(&self, key: api::TStrv, req: Vec) -> Option> { + pub async fn req(&self, key: api::TVec, req: Vec) -> Option> { self.0.owner.reqnot().request(api::Fwded(self.0.api_ref(), key, req)).await } #[must_use] diff --git a/orchid-host/src/dealias.rs b/orchid-host/src/dealias.rs index 041aeec..b312f5c 100644 --- a/orchid-host/src/dealias.rs +++ b/orchid-host/src/dealias.rs @@ -1,6 +1,6 @@ use hashbrown::HashSet; use itertools::Itertools; -use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_errv}; +use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_err}; use orchid_base::interner::{Interner, Tok}; use orchid_base::location::Pos; use orchid_base::name::VName; @@ -30,7 +30,7 @@ impl AbsPathError { format!("{path} is leading outside the root."), ), }; - mk_errv(descr, msg, [pos]) + mk_err(descr, msg, [pos]) } } @@ -42,8 +42,8 @@ impl AbsPathError { /// if the relative path contains as many or more `super` segments than the /// length of the absolute path. pub async fn absolute_path( - mut cwd: &[Tok], - mut rel: &[Tok], + mut cwd: &[IStr], + mut rel: &[IStr], i: &Interner, ) -> Result { let i_self = i.i("self").await; @@ -67,13 +67,13 @@ pub struct DealiasCtx<'a> { } pub async fn resolv_glob( - cwd: &[Tok], + cwd: &[IStr], root: &Mod, - abs_path: &[Tok], + abs_path: &[IStr], pos: Pos, i: &Interner, ctx: &mut Mod::Ctx<'_>, -) -> OrcRes>> { +) -> 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(abs_path.len().min(coprefix_len + 1)); let fst_diff = @@ -87,7 +87,7 @@ pub async fn resolv_glob( ChildErrorKind::Missing => ("Invalid import path", format!("{path} not found")), ChildErrorKind::Private => ("Import inaccessible", format!("{path} is private")), }; - return Err(mk_errv(i.i(tk).await, msg, [pos])); + return Err(mk_err(i.i(tk).await, msg, [pos])); }, }; Ok(target_module.children(coprefix_len < abs_path.len())) @@ -98,11 +98,11 @@ pub type ChildResult<'a, T> = Result<&'a T, ChildErrorKind>; pub trait Tree { type Ctx<'a>; #[must_use] - fn children(&self, public_only: bool) -> HashSet>; + fn children(&self, public_only: bool) -> HashSet; #[must_use] fn child( &self, - key: Tok, + key: IStr, public_only: bool, ctx: &mut Self::Ctx<'_>, ) -> impl Future>; @@ -133,7 +133,7 @@ pub struct ChildError { pub async fn walk<'a, T: Tree>( root: &'a T, public_only: bool, - path: impl IntoIterator>, + path: impl IntoIterator, ctx: &mut T::Ctx<'_>, ) -> Result<&'a T, ChildError> { let mut cur = root; diff --git a/orchid-host/src/extension.rs b/orchid-host/src/extension.rs index 2a5d679..6a11f04 100644 --- a/orchid-host/src/extension.rs +++ b/orchid-host/src/extension.rs @@ -260,7 +260,7 @@ impl Extension { } pub(crate) async fn lex_req>>( &self, - source: Tok, + source: IStr, src: Sym, pos: u32, sys: api::SysId, diff --git a/orchid-host/src/lex.rs b/orchid-host/src/lex.rs index 5786a14..a98ab8c 100644 --- a/orchid-host/src/lex.rs +++ b/orchid-host/src/lex.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use futures::FutureExt; use futures::lock::Mutex; -use orchid_base::error::{OrcErrv, OrcRes, mk_errv}; +use orchid_base::error::{OrcErrv, OrcRes, mk_err}; use orchid_base::interner::Tok; use orchid_base::location::SrcRange; use orchid_base::name::Sym; @@ -17,7 +17,7 @@ use crate::system::System; pub struct LexCtx<'a> { pub systems: &'a [System], - pub source: &'a Tok, + pub source: &'a IStr, pub path: &'a Sym, pub tail: &'a str, pub sub_trees: &'a mut Vec, @@ -105,7 +105,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes { ParsTok::NS(ctx.ctx.i.i(name).await, Box::new(body)) } else if ctx.strip_prefix("--[") { let Some((cmt, tail)) = ctx.tail.split_once("]--") else { - return Err(mk_errv( + return Err(mk_err( ctx.ctx.i.i("Unterminated block comment").await, "This block comment has no ending ]--", [SrcRange::new(start..start + 3, ctx.path)], @@ -128,7 +128,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes { ctx.trim_ws(); while !ctx.strip_char(*rp) { if ctx.tail.is_empty() { - return Err(mk_errv( + return Err(mk_err( ctx.ctx.i.i("unclosed paren").await, format!("this {lp} has no matching {rp}"), [SrcRange::new(start..start + 1, ctx.path)], @@ -178,7 +178,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes { } else if ctx.tail.starts_with(op_char) { ParsTok::Name(ctx.ctx.i.i(ctx.get_start_matches(op_char)).await) } else { - return Err(mk_errv( + return Err(mk_err( ctx.ctx.i.i("Unrecognized character").await, "The following syntax is meaningless.", [SrcRange::new(start..start + 1, ctx.path)], @@ -188,12 +188,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes { Ok(ParsTokTree { tok, sr: SrcRange::new(start..ctx.get_pos(), ctx.path) }) } -pub async fn lex( - text: Tok, - path: Sym, - systems: &[System], - ctx: &Ctx, -) -> OrcRes> { +pub async fn lex(text: IStr, path: Sym, systems: &[System], ctx: &Ctx) -> OrcRes> { let mut sub_trees = Vec::new(); let mut ctx = LexCtx { source: &text, sub_trees: &mut sub_trees, tail: &text[..], systems, path: &path, ctx }; diff --git a/orchid-host/src/parse.rs b/orchid-host/src/parse.rs index 92d6c79..b24a5bf 100644 --- a/orchid-host/src/parse.rs +++ b/orchid-host/src/parse.rs @@ -1,6 +1,6 @@ use futures::future::join_all; use itertools::Itertools; -use orchid_base::error::{OrcRes, Reporter, mk_errv}; +use orchid_base::error::{OrcRes, Reporter, mk_err}; use orchid_base::format::fmt; use orchid_base::interner::{Interner, Tok}; use orchid_base::name::Sym; @@ -47,7 +47,7 @@ pub trait HostParseCtx: ParseCtx { pub async fn parse_items( ctx: &impl HostParseCtx, - path: Substack<'_, Tok>, + path: Substack<'_, IStr>, items: ParsSnippet<'_>, ) -> OrcRes> { let lines = line_items(ctx, items).await; @@ -58,7 +58,7 @@ pub async fn parse_items( pub async fn parse_item( ctx: &impl HostParseCtx, - path: Substack<'_, Tok>, + path: Substack<'_, IStr>, comments: Vec, item: ParsSnippet<'_>, ) -> OrcRes> { @@ -67,7 +67,7 @@ pub async fn parse_item( n if *n == ctx.i().i("export").await => match try_pop_no_fluff(ctx, postdisc).await? { Parsed { output: TokTree { tok: Token::Name(n), .. }, tail } => parse_exportable_item(ctx, path, comments, true, n.clone(), tail).await, - Parsed { output, tail: _ } => Err(mk_errv( + Parsed { output, tail: _ } => Err(mk_err( ctx.i().i("Malformed export").await, "`export` can either prefix other lines or list names inside ( )", [output.sr()], @@ -83,11 +83,10 @@ pub async fn parse_item( }, n => parse_exportable_item(ctx, path, comments, false, n.clone(), postdisc).await, }, - Some(_) => Err(mk_errv( - ctx.i().i("Expected a line type").await, - "All lines must begin with a keyword", - [item.sr()], - )), + Some(_) => + Err(mk_err(ctx.i().i("Expected a line type").await, "All lines must begin with a keyword", [ + item.sr(), + ])), None => unreachable!("These lines are filtered and aggregated in earlier stages"), } } @@ -103,10 +102,10 @@ pub async fn parse_import<'a>( pub async fn parse_exportable_item<'a>( ctx: &impl HostParseCtx, - path: Substack<'_, Tok>, + path: Substack<'_, IStr>, comments: Vec, exported: bool, - discr: Tok, + discr: IStr, tail: ParsSnippet<'a>, ) -> OrcRes> { let kind = if discr == ctx.i().i("mod").await { @@ -121,7 +120,7 @@ pub async fn parse_exportable_item<'a>( .await; } else { let ext_lines = ctx.systems().flat_map(System::line_types).join(", "); - return Err(mk_errv( + return Err(mk_err( ctx.i().i("Unrecognized line type").await, format!("Line types are: mod, {ext_lines}"), [tail.prev().sr()], @@ -132,13 +131,13 @@ pub async fn parse_exportable_item<'a>( pub async fn parse_module<'a>( ctx: &impl HostParseCtx, - path: Substack<'_, Tok>, + path: Substack<'_, IStr>, tail: ParsSnippet<'a>, -) -> OrcRes<(Tok, ParsedModule)> { +) -> OrcRes<(IStr, ParsedModule)> { let (name, tail) = match try_pop_no_fluff(ctx, tail).await? { Parsed { output: TokTree { tok: Token::Name(n), .. }, tail } => (n.clone(), tail), Parsed { output, .. } => { - return Err(mk_errv( + return Err(mk_err( ctx.i().i("Missing module name").await, format!("A name was expected, {} was found", fmt(output, ctx.i()).await), [output.sr()], @@ -148,7 +147,7 @@ pub async fn parse_module<'a>( let Parsed { output, tail: surplus } = try_pop_no_fluff(ctx, tail).await?; expect_end(ctx, surplus).await?; let Some(body) = output.as_s(Paren::Round) else { - return Err(mk_errv( + return Err(mk_err( ctx.i().i("Expected module body").await, format!("A ( block ) was expected, {} was found", fmt(output, ctx.i()).await), [output.sr()], diff --git a/orchid-host/src/parsed.rs b/orchid-host/src/parsed.rs index bcb76b6..439502a 100644 --- a/orchid-host/src/parsed.rs +++ b/orchid-host/src/parsed.rs @@ -69,14 +69,14 @@ impl Format for Item { } pub struct ParsedMember { - pub name: Tok, + pub name: IStr, pub exported: bool, pub kind: ParsedMemberKind, } impl ParsedMember { #[must_use] - pub fn name(&self) -> Tok { self.name.clone() } - pub fn new(exported: bool, name: Tok, kind: impl Into) -> Self { + pub fn name(&self) -> IStr { self.name.clone() } + pub fn new(exported: bool, name: IStr, kind: impl Into) -> Self { Self { exported, name, kind: kind.into() } } } @@ -90,14 +90,14 @@ impl Debug for ParsedMember { } pub(crate) type ParsedExprCallback = - Rc Fn(&'a [Tok]) -> LocalBoxFuture<'a, Expr>>; + Rc Fn(&'a [IStr]) -> LocalBoxFuture<'a, Expr>>; pub struct ParsedExpr { pub(crate) debug: String, pub(crate) callback: ParsedExprCallback, } impl ParsedExpr { - pub async fn run(self, imported_names: &[Tok]) -> Expr { + pub async fn run(self, imported_names: &[IStr]) -> Expr { (self.callback)(imported_names).await } } @@ -116,7 +116,7 @@ impl From for ParsedMemberKind { #[derive(Debug, Default)] pub struct ParsedModule { - pub exports: Vec>, + pub exports: Vec, pub items: Vec, pub use_prelude: bool, } @@ -142,7 +142,7 @@ impl ParsedModule { (self.items.iter()) .filter_map(|it| if let ItemKind::Import(i) = &it.kind { Some(i) } else { None }) } - pub fn default_item(self, name: Tok, sr: SrcRange) -> Item { + pub fn default_item(self, name: IStr, sr: SrcRange) -> Item { let mem = ParsedMember { exported: true, name, kind: ParsedMemberKind::Mod(self) }; Item { comments: vec![], sr, kind: ItemKind::Member(mem) } } @@ -151,7 +151,7 @@ impl Tree for ParsedModule { type Ctx<'a> = (); async fn child( &self, - key: Tok, + key: IStr, public_only: bool, (): &mut Self::Ctx<'_>, ) -> ChildResult<'_, Self> { @@ -169,7 +169,7 @@ impl Tree for ParsedModule { } ChildResult::Err(ChildErrorKind::Missing) } - fn children(&self, public_only: bool) -> HashSet> { + fn children(&self, public_only: bool) -> HashSet { let mut public: HashSet<_> = self.exports.iter().cloned().collect(); if !public_only { public.extend( @@ -198,11 +198,11 @@ impl Format for ParsedModule { /// point to a module and rule_loc selects a macro rule within that module #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ConstPath { - steps: Tok>>, + steps: Tok>, } impl ConstPath { #[must_use] - pub fn to_const(steps: Tok>>) -> Self { Self { steps } } + pub fn to_const(steps: Tok>) -> Self { Self { steps } } } pub async fn tt_to_api(exprs: &mut ExprStore, subtree: ParsTokTree) -> api::TokenTree { diff --git a/orchid-host/src/sys_parser.rs b/orchid-host/src/sys_parser.rs index 9805498..2a10e45 100644 --- a/orchid-host/src/sys_parser.rs +++ b/orchid-host/src/sys_parser.rs @@ -23,7 +23,7 @@ pub struct Parser { pub(crate) system: System, pub(crate) idx: u16, } -type ModPath<'a> = Substack<'a, Tok>; +type ModPath<'a> = Substack<'a, IStr>; impl Parser { pub async fn parse( @@ -80,8 +80,8 @@ struct ConvCtx<'a> { } async fn conv( parsed_v: Vec, - module: Substack<'_, Tok>, - callback: &'_ mut impl AsyncFnMut(Substack<'_, Tok>, Vec) -> OrcRes>, + module: Substack<'_, IStr>, + callback: &'_ mut impl AsyncFnMut(Substack<'_, IStr>, Vec) -> OrcRes>, ctx: &mut ConvCtx<'_>, ) -> OrcRes> { let mut items = Vec::new(); diff --git a/orchid-host/src/system.rs b/orchid-host/src/system.rs index a1019df..0cdd19d 100644 --- a/orchid-host/src/system.rs +++ b/orchid-host/src/system.rs @@ -10,7 +10,7 @@ use hashbrown::HashMap; use itertools::Itertools; use memo_map::MemoMap; use orchid_base::char_filter::char_filter_match; -use orchid_base::error::{OrcRes, mk_errv_floating}; +use orchid_base::error::{OrcRes, mk_err_floating}; use orchid_base::format::{FmtCtx, FmtUnit, Format}; use orchid_base::interner::{Interner, Tok}; use orchid_base::iter_utils::IteratorPrint; @@ -35,7 +35,7 @@ pub(crate) struct SystemInstData { decl_id: api::SysDeclId, lex_filter: api::CharFilter, id: api::SysId, - line_types: Vec>, + line_types: Vec, prelude: Vec, owned_atoms: RwLock>, pub(crate) const_paths: MemoMap, @@ -88,7 +88,7 @@ impl System { /// [Self::can_lex] was called and returned true. pub async fn lex>>( &self, - source: Tok, + source: IStr, src: Sym, pos: u32, r: impl FnMut(u32) -> F, @@ -96,12 +96,12 @@ impl System { self.0.ext.lex_req(source, src, pos, self.id(), r).await } #[must_use] - pub fn get_parser(&self, ltyp: Tok) -> Option { + pub fn get_parser(&self, ltyp: IStr) -> Option { (self.0.line_types.iter().enumerate()) .find(|(_, txt)| *txt == <yp) .map(|(idx, _)| Parser { idx: idx as u16, system: self.clone() }) } - pub fn line_types(&self) -> impl Iterator> + '_ { self.0.line_types.iter() } + pub fn line_types(&self) -> impl Iterator + '_ { self.0.line_types.iter() } #[must_use] pub async fn request(&self, req: Vec) -> Vec { @@ -130,7 +130,7 @@ impl System { pub(crate) async fn name_resolver( &self, orig: api::ParsedConstId, - ) -> impl AsyncFnMut(&[Tok]) -> OrcRes + use<> { + ) -> impl AsyncFnMut(&[IStr]) -> OrcRes + use<> { let root = self.0.ctx.root.read().await.upgrade().expect("find_names when root not in context"); let orig = self.0.const_paths.get(&orig).expect("origin for find_names invalid").clone(); let ctx = self.0.ctx.clone(); @@ -147,7 +147,7 @@ impl System { match cmod.imports.get(selector) { Some(Ok(dest)) => return Ok(dest.target.to_vname().suffix(tail.iter().cloned())), Some(Err(dests)) => - return Err(mk_errv_floating( + return Err(mk_err_floating( ctx.i.i("Ambiguous name").await, format!( "{selector} could refer to {}", @@ -159,7 +159,7 @@ impl System { if tail.is_empty() { return Ok(VPath::new(cwd.iter().cloned()).name_with_suffix(selector.clone())); } - Err(mk_errv_floating( + Err(mk_err_floating( ctx.i.i("Invalid name").await, format!("{selector} doesn't refer to a module"), )) diff --git a/orchid-host/src/tree.rs b/orchid-host/src/tree.rs index 0821bbb..b973d34 100644 --- a/orchid-host/src/tree.rs +++ b/orchid-host/src/tree.rs @@ -12,7 +12,7 @@ use hashbrown::hash_map::Entry; use itertools::Itertools; use memo_map::MemoMap; use orchid_base::clone; -use orchid_base::error::{OrcRes, Reporter, mk_errv}; +use orchid_base::error::{OrcRes, Reporter, mk_err}; use orchid_base::interner::Tok; use orchid_base::location::{CodeGenInfo, Pos}; use orchid_base::name::{NameLike, Sym, VPath}; @@ -109,7 +109,7 @@ impl Root { return Ok(val.clone()); } match module { - Ok(_) => Err(mk_errv( + Ok(_) => Err(mk_err( ctx.i.i("module used as constant").await, format!("{name} is a module, not a constant"), [pos], @@ -117,7 +117,7 @@ impl Root { Err(e) => match e.kind { ChildErrorKind::Private => panic!("public_only is false"), ChildErrorKind::Constant => panic!("Tree refers to constant not in table"), - ChildErrorKind::Missing => Err(mk_errv( + ChildErrorKind::Missing => Err(mk_err( ctx.i.i("Constant does not exist").await, format!("{name} does not refer to a constant"), [pos], @@ -144,11 +144,11 @@ impl Default for WeakRoot { pub struct TreeFromApiCtx<'a> { pub sys: &'a System, pub consts: &'a MemoMap, - pub path: Tok>>, + pub path: Tok>, } impl<'a> TreeFromApiCtx<'a> { #[must_use] - pub async fn push<'c>(&'c self, name: Tok) -> TreeFromApiCtx<'c> { + pub async fn push<'c>(&'c self, name: IStr) -> TreeFromApiCtx<'c> { let path = self.sys.ctx().i.i(&self.path.iter().cloned().chain([name]).collect_vec()).await; TreeFromApiCtx { path, consts: self.consts, sys: self.sys } } @@ -162,8 +162,8 @@ pub struct ResolvedImport { #[derive(Clone, Default)] pub struct Module { - pub imports: HashMap, Result>>, - pub members: HashMap, Rc>, + pub imports: HashMap>>, + pub members: HashMap>, } impl Module { #[must_use] @@ -268,7 +268,7 @@ impl Module { } } else { for item in values { - ctx.rep.report(mk_errv( + ctx.rep.report(mk_err( conflicting_imports_msg.clone(), format!("{key} is imported multiple times from different modules"), [item.sr.pos()], @@ -298,7 +298,7 @@ impl Module { let Ok(import) = value else { continue }; if import.target.strip_prefix(&path[..]).is_some_and(|t| t.starts_with(slice::from_ref(key))) { - ctx.rep.report(mk_errv( + ctx.rep.report(mk_err( self_referential_msg.clone(), format!("import {} points to itself or a path within itself", &import.target), [import.pos.clone()], @@ -396,7 +396,7 @@ impl Tree for Module { type Ctx<'a> = (Ctx, &'a MemoMap); async fn child( &self, - key: Tok, + key: IStr, public_only: bool, (ctx, consts): &mut Self::Ctx<'_>, ) -> crate::dealias::ChildResult<'_, Self> { @@ -411,7 +411,7 @@ impl Tree for Module { MemberKind::Const => Err(ChildErrorKind::Constant), } } - fn children(&self, public_only: bool) -> hashbrown::HashSet> { + fn children(&self, public_only: bool) -> hashbrown::HashSet { self.members.iter().filter(|(_, v)| !public_only || v.public).map(|(k, _)| k.clone()).collect() } } diff --git a/orchid-std/src/macros/let_line.rs b/orchid-std/src/macros/let_line.rs index d0d884c..6e645b9 100644 --- a/orchid-std/src/macros/let_line.rs +++ b/orchid-std/src/macros/let_line.rs @@ -39,7 +39,7 @@ impl Parser for LetLine { let rep = Reporter::new(); let dealiased = dealias_mac_v(aliased, &ctx, &rep).await; let macro_input = MacTok::S(Paren::Round, dealiased).at(sr.pos()); - if let Some(e) = rep.errv() { + if let Some(e) = rep.res() { return Err(e); } Ok(call([ diff --git a/orchid-std/src/macros/macro_lib.rs b/orchid-std/src/macros/macro_lib.rs index e2507bd..38412fc 100644 --- a/orchid-std/src/macros/macro_lib.rs +++ b/orchid-std/src/macros/macro_lib.rs @@ -40,7 +40,7 @@ pub fn gen_macro_lib() -> Vec { fun(true, "lower", |tpl: TypAtom| async move { let ctx = LowerCtx { sys: tpl.untyped.ctx().clone(), rep: &Reporter::new() }; let res = own(tpl).await.lower(ctx, Substack::Bottom).await; - if let Some(e) = Reporter::new().errv() { Err(e) } else { Ok(res) } + if let Some(e) = Reporter::new().res() { Err(e) } else { Ok(res) } }), fun(true, "resolve_recur", |state: TypAtom, tpl: TypAtom| async move { exec("macros::resolve_recur", async move |mut h| { diff --git a/orchid-std/src/macros/macro_line.rs b/orchid-std/src/macros/macro_line.rs index 03dc51a..47dbeff 100644 --- a/orchid-std/src/macros/macro_line.rs +++ b/orchid-std/src/macros/macro_line.rs @@ -7,7 +7,7 @@ use futures::{StreamExt, stream}; use hashbrown::{HashMap, HashSet}; use itertools::Itertools; use never::Never; -use orchid_base::error::{OrcRes, Reporter, mk_errv}; +use orchid_base::error::{OrcRes, Reporter, mk_err}; use orchid_base::interner::Tok; use orchid_base::location::Pos; use orchid_base::name::Sym; @@ -40,7 +40,7 @@ impl Parser for MacroLine { line: PSnippet<'a>, ) -> OrcRes> { if exported { - return Err(mk_errv( + return Err(mk_err( ctx.i().i("macros are always exported").await, "The export keyword is forbidden here to avoid confusion\n\ because macros are exported by default", @@ -94,7 +94,7 @@ impl Parser for MacroLine { } } let Some(macro_name) = keywords.keys().next().cloned() else { - return Err(mk_errv( + return Err(mk_err( ctx.i().i("macro with no keywords").await, "Macros must define at least one macro of their own.", [kw_line.tail.sr()], @@ -109,7 +109,7 @@ impl Parser for MacroLine { let Parsed { tail, .. } = expect_tok(&ctx, line.tail, ctx.i().i("rule").await).await?; let arrow_token = ctx.i().i("=>").await; let Some((pattern, body)) = tail.split_once(|tok| tok.is_kw(arrow_token.clone())) else { - ctx.rep().report(mk_errv( + ctx.rep().report(mk_err( ctx.i().i("Missing => in rule").await, "Rule lines are of the form `rule ...pattern => ...body`", [line.tail.sr()], @@ -137,7 +137,7 @@ impl Parser for MacroLine { let rep = Reporter::new(); let body = dealias_mac_v(body_mactree, &ctx, &rep).await; let macro_input = MacTok::S(Paren::Round, body).at(body_sr.pos()); - if let Some(e) = rep.errv() { + if let Some(e) = rep.res() { return Err(e); } Ok(call([ @@ -199,7 +199,7 @@ pub struct MacroData { pub module: Sym, pub prio: Option, pub rules: Vec, - pub own_kws: Vec>, + pub own_kws: Vec, } #[derive(Clone, Debug)] @@ -210,8 +210,8 @@ pub struct Rule { pub pos: Pos, pub pattern: Matcher, pub glossary: HashSet, - pub placeholders: Vec>, - pub body_name: Tok, + pub placeholders: Vec, + pub body_name: IStr, } #[derive(Debug)] pub enum Matcher { diff --git a/orchid-std/src/macros/mactree.rs b/orchid-std/src/macros/mactree.rs index 519c5ab..bb97d02 100644 --- a/orchid-std/src/macros/mactree.rs +++ b/orchid-std/src/macros/mactree.rs @@ -6,7 +6,7 @@ use futures::FutureExt; use futures::future::join_all; use hashbrown::HashSet; use itertools::Itertools; -use orchid_base::error::{OrcErrv, Reporter, mk_errv}; +use orchid_base::error::{OrcErrv, Reporter, mk_err}; use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt}; use orchid_base::interner::Tok; use orchid_base::location::Pos; @@ -42,7 +42,7 @@ impl MacTree { MacTok::Bottom(e) => bot(e.clone()), MacTok::Lambda(arg, body) => { let MacTok::Name(name) = &*arg.tok else { - let err = mk_errv( + let err = mk_err( ctx.sys.i().i("Syntax error after macros").await, "This token ends up as a binding, consider replacing it with a name", [arg.pos()], @@ -57,7 +57,7 @@ impl MacTree { Some((i, _)) => arg((args.len() - i) as u64), }, MacTok::Ph(ph) => { - let err = mk_errv( + let err = mk_err( ctx.sys.i().i("Placeholder in value").await, format!("Placeholder {ph} is only supported in macro patterns"), [self.pos()], @@ -67,7 +67,7 @@ impl MacTree { }, MacTok::S(Paren::Round, body) => call(lower_v(body, ctx, args).await), MacTok::S(..) => { - let err = mk_errv( + let err = mk_err( ctx.sys.i().i("[] or {} after macros").await, format!("{} didn't match any macro", fmt(self, ctx.sys.i()).await), [self.pos()], @@ -166,7 +166,7 @@ pub async fn mtreev_fmt<'b>( #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Ph { - pub name: Tok, + pub name: IStr, pub kind: PhKind, } impl Display for Ph { diff --git a/orchid-std/src/macros/mactree_lexer.rs b/orchid-std/src/macros/mactree_lexer.rs index 7de0dda..fd068db 100644 --- a/orchid-std/src/macros/mactree_lexer.rs +++ b/orchid-std/src/macros/mactree_lexer.rs @@ -1,7 +1,7 @@ use std::ops::RangeInclusive; use futures::FutureExt; -use orchid_base::error::{OrcRes, mk_errv}; +use orchid_base::error::{OrcRes, mk_err}; use orchid_base::parse::ParseCtx; use orchid_base::sym; use orchid_base::tokens::PARENS; @@ -55,7 +55,7 @@ impl Lexer for MacTreeLexer { if let Some(tail3) = tail2.strip_prefix(*rp) { break Ok((tail3, MacTok::S(*paren, items).at(ctx.pos_tt(tail, tail3).pos()))); } else if tail2.is_empty() { - return Err(mk_errv( + return Err(mk_err( ctx.i().i("Unclosed block").await, format!("Expected closing {rp}"), [ctx.pos_lt(1, tail)], diff --git a/orchid-std/src/macros/recur_state.rs b/orchid-std/src/macros/recur_state.rs index 69a38eb..986d638 100644 --- a/orchid-std/src/macros/recur_state.rs +++ b/orchid-std/src/macros/recur_state.rs @@ -11,7 +11,7 @@ use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant}; #[derive(Clone, PartialEq, Eq, Hash)] pub struct RulePath { pub module: Sym, - pub main_kw: Tok, + pub main_kw: IStr, pub rule: u32, } impl RulePath { diff --git a/orchid-std/src/macros/resolve.rs b/orchid-std/src/macros/resolve.rs index 633f9ab..5a2f288 100644 --- a/orchid-std/src/macros/resolve.rs +++ b/orchid-std/src/macros/resolve.rs @@ -1,7 +1,7 @@ use futures::FutureExt; use hashbrown::HashMap; use itertools::Itertools; -use orchid_base::error::mk_errv; +use orchid_base::error::mk_err; use orchid_base::location::Pos; use orchid_base::name::Sym; use orchid_base::sym; @@ -91,7 +91,7 @@ async fn mk_body_call( let rule_path = RulePath { module: mac.0.module.clone(), main_kw: mac.0.own_kws[0].clone(), rule: rule.index }; let Some(new_recur) = recur.push(rule_path.clone()) else { - return bot(mk_errv( + return bot(mk_err( ctx.i().i("Circular macro dependency").await, format!("The definition of {rule_path} is circular"), [rule.pos.clone()], diff --git a/orchid-std/src/macros/rule/build.rs b/orchid-std/src/macros/rule/build.rs index fc434e8..fadc3af 100644 --- a/orchid-std/src/macros/rule/build.rs +++ b/orchid-std/src/macros/rule/build.rs @@ -1,7 +1,7 @@ use futures::FutureExt; use futures::future::join_all; use itertools::Itertools; -use orchid_base::error::{OrcRes, mk_errv}; +use orchid_base::error::{OrcRes, mk_err}; use orchid_base::interner::{Interner, Tok}; use orchid_base::join_ok; use orchid_base::side::Side; @@ -11,7 +11,7 @@ use super::vec_attrs::vec_attrs; use crate::macros::mactree::{Ph, PhKind}; use crate::macros::{MacTok, MacTree}; -pub type MaxVecSplit<'a> = (&'a [MacTree], (Tok, u8, bool), &'a [MacTree]); +pub type MaxVecSplit<'a> = (&'a [MacTree], (IStr, u8, bool), &'a [MacTree]); /// Derive the details of the central vectorial and the two sides from a /// slice of Expr's @@ -124,7 +124,7 @@ async fn mk_scalar(pattern: &MacTree, i: &Interner) -> OrcRes { }, MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body, i).boxed_local().await?)), MacTok::Lambda(..) => - return Err(mk_errv( + return Err(mk_err( i.i("Lambda in matcher").await, "Lambdas can't be matched for, only generated in templates", [pattern.pos()], diff --git a/orchid-std/src/macros/rule/matcher.rs b/orchid-std/src/macros/rule/matcher.rs index 27b8f8e..774fe3b 100644 --- a/orchid-std/src/macros/rule/matcher.rs +++ b/orchid-std/src/macros/rule/matcher.rs @@ -18,7 +18,7 @@ use crate::macros::{MacTok, MacTree}; pub struct NamedMatcher { inner: AnyMatcher, head: Sym, - after_tok: Tok, + after_tok: IStr, } impl NamedMatcher { pub async fn new(pattern: &[MacTree], i: &Interner) -> OrcRes { diff --git a/orchid-std/src/macros/rule/shared.rs b/orchid-std/src/macros/rule/shared.rs index 32bee70..8cc0910 100644 --- a/orchid-std/src/macros/rule/shared.rs +++ b/orchid-std/src/macros/rule/shared.rs @@ -11,12 +11,12 @@ use orchid_base::tokens::{PARENS, Paren}; pub enum ScalMatcher { Name(Sym), S(Paren, Box), - Placeh { key: Tok }, + Placeh { key: IStr }, } pub enum VecMatcher { Placeh { - key: Tok, + key: IStr, nonzero: bool, }, Scan { @@ -41,7 +41,7 @@ pub enum VecMatcher { /// the length of matches on either side. /// /// Vectorial keys that appear on either side, in priority order - key_order: Vec>, + key_order: Vec, }, } diff --git a/orchid-std/src/macros/rule/state.rs b/orchid-std/src/macros/rule/state.rs index a850268..61f36f8 100644 --- a/orchid-std/src/macros/rule/state.rs +++ b/orchid-std/src/macros/rule/state.rs @@ -30,11 +30,11 @@ pub enum StateEntry<'a> { } #[derive(Clone, Debug)] pub struct MatchState<'a> { - placeholders: HashMap, StateEntry<'a>>, + placeholders: HashMap>, name_posv: HashMap>, } impl<'a> MatchState<'a> { - pub fn from_ph(key: Tok, entry: StateEntry<'a>) -> Self { + pub fn from_ph(key: IStr, entry: StateEntry<'a>) -> Self { Self { placeholders: HashMap::from([(key, entry)]), name_posv: HashMap::new() } } pub fn combine(self, s: Self) -> Self { @@ -45,7 +45,7 @@ impl<'a> MatchState<'a> { }), } } - pub fn ph_len(&self, key: &Tok) -> Option { + pub fn ph_len(&self, key: &IStr) -> Option { match self.placeholders.get(key)? { StateEntry::Vec(slc) => Some(slc.len()), _ => None, @@ -54,8 +54,8 @@ impl<'a> MatchState<'a> { pub fn from_name(name: Sym, location: Pos) -> Self { Self { name_posv: HashMap::from([(name, vec![location])]), placeholders: HashMap::new() } } - pub fn get(&self, key: &Tok) -> Option<&StateEntry<'a>> { self.placeholders.get(key) } - pub fn remove(&mut self, name: Tok) -> Option> { + pub fn get(&self, key: &IStr) -> Option<&StateEntry<'a>> { self.placeholders.get(key) } + pub fn remove(&mut self, name: IStr) -> Option> { self.placeholders.remove(&name) } pub fn mk_owned(self) -> OwnedState { @@ -85,10 +85,10 @@ pub enum OwnedEntry { Scalar(MacTree), } pub struct OwnedState { - placeholders: HashMap, OwnedEntry>, + placeholders: HashMap, name_posv: HashMap>, } impl OwnedState { - pub fn get(&self, key: &Tok) -> Option<&OwnedEntry> { self.placeholders.get(key) } + pub fn get(&self, key: &IStr) -> Option<&OwnedEntry> { self.placeholders.get(key) } pub fn positions(&self, name: &Sym) -> &[Pos] { self.name_posv.get(name).map_or(&[], |v| &v[..]) } } diff --git a/orchid-std/src/macros/rule/vec_attrs.rs b/orchid-std/src/macros/rule/vec_attrs.rs index ddb9900..2c541ce 100644 --- a/orchid-std/src/macros/rule/vec_attrs.rs +++ b/orchid-std/src/macros/rule/vec_attrs.rs @@ -6,7 +6,7 @@ use crate::macros::{MacTok, MacTree}; /// Returns the name, priority and at_least_one of the expression if it is /// a vectorial placeholder #[must_use] -pub fn vec_attrs(expr: &MacTree) -> Option<(Tok, u8, bool)> { +pub fn vec_attrs(expr: &MacTree) -> Option<(IStr, u8, bool)> { match (*expr.tok).clone() { MacTok::Ph(Ph { kind: PhKind::Vector { priority, at_least_one }, name }) => Some((name, priority, at_least_one)), diff --git a/orchid-std/src/std/string/str_atom.rs b/orchid-std/src/std/string/str_atom.rs index 8f828e1..1782091 100644 --- a/orchid-std/src/std/string/str_atom.rs +++ b/orchid-std/src/std/string/str_atom.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use futures::AsyncWrite; use orchid_api_derive::Coding; use orchid_api_traits::{Encode, Request}; -use orchid_base::error::{OrcRes, mk_errv}; +use orchid_base::error::{OrcRes, mk_err}; use orchid_base::format::{FmtCtx, FmtUnit}; use orchid_base::interner::Tok; use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TypAtom}; @@ -58,13 +58,13 @@ impl OwnedAtom for StrAtom { } #[derive(Debug, Clone)] -pub struct IntStrAtom(Tok); +pub struct IntStrAtom(IStr); impl Atomic for IntStrAtom { type Variant = OwnedVariant; type Data = orchid_api::TStr; } -impl From> for IntStrAtom { - fn from(value: Tok) -> Self { Self(value) } +impl From for IntStrAtom { + fn from(value: IStr) -> Self { Self(value) } } impl OwnedAtom for IntStrAtom { type Refs = (); @@ -109,7 +109,7 @@ impl TryFromExpr for OrcString { let ctx = expr.ctx(); match TypAtom::::try_from_expr(expr).await { Ok(t) => Ok(OrcString { ctx: t.untyped.ctx().clone(), kind: OrcStringKind::Int(t) }), - Err(e) => Err(mk_errv(ctx.i().i("A string was expected").await, "", e.pos_iter())), + Err(e) => Err(mk_err(ctx.i().i("A string was expected").await, "", e.pos_iter())), } } } diff --git a/orchid-std/src/std/string/str_lexer.rs b/orchid-std/src/std/string/str_lexer.rs index 5acc40f..1f2d7d4 100644 --- a/orchid-std/src/std/string/str_lexer.rs +++ b/orchid-std/src/std/string/str_lexer.rs @@ -1,5 +1,5 @@ use itertools::Itertools; -use orchid_base::error::{OrcErr, OrcErrv, OrcRes, mk_errv}; +use orchid_base::error::{OrcErr, OrcErrv, OrcRes, mk_err}; use orchid_base::interner::Interner; use orchid_base::location::SrcRange; use orchid_base::name::Sym; @@ -36,7 +36,7 @@ impl StringError { /// Convert into project error for reporting pub async fn into_proj(self, path: &Sym, pos: u32, i: &Interner) -> OrcErrv { let start = pos + self.pos; - mk_errv( + mk_err( i.i("Failed to parse string").await, match self.kind { StringErrorKind::NotHex => "Expected a hex digit", @@ -144,7 +144,7 @@ impl Lexer for StringLexer { tail = ch.as_str(); } else { let range = ctx.pos(all)..ctx.pos(""); - return Err(mk_errv( + return Err(mk_err( ctx.i().i("No string end").await, "String never terminated with \"", [SrcRange::new(range.clone(), ctx.src())], diff --git a/orcx/src/main.rs b/orcx/src/main.rs index bb3ac80..4802c58 100644 --- a/orcx/src/main.rs +++ b/orcx/src/main.rs @@ -131,7 +131,7 @@ async fn main() -> io::Result { }; let snip = Snippet::new(first, &lexemes); let ptree = parse_items(&pctx, Substack::Bottom, snip).await.unwrap(); - if let Some(errv) = reporter.errv() { + if let Some(errv) = reporter.res() { eprintln!("{errv}"); *exit_code1.borrow_mut() = ExitCode::FAILURE; return; diff --git a/orcx/src/parse_folder.rs b/orcx/src/parse_folder.rs index 799c955..17f89ca 100644 --- a/orcx/src/parse_folder.rs +++ b/orcx/src/parse_folder.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use futures::FutureExt; use itertools::Itertools; -use orchid_base::error::{OrcRes, Reporter, async_io_err, mk_errv, os_str_to_string}; +use orchid_base::error::{OrcRes, Reporter, async_io_err, mk_err, os_str_to_string}; use orchid_base::location::SrcRange; use orchid_base::name::Sym; use orchid_base::parse::Snippet; @@ -30,7 +30,7 @@ pub async fn parse_folder( let sr = SrcRange::new(0..0, &ns); if path.is_dir() { let Some(name_os) = path.file_name() else { - return Err(mk_errv( + return Err(mk_err( ctx.i.i("Could not read directory name").await, format!("Path {} ends in ..", path.to_string_lossy()), [sr],