Compare commits

...

2 Commits

Author SHA1 Message Date
cd1d640174 Temporary commit to try fix halting 2025-09-14 13:29:35 +02:00
ee45dbd28e Hide todos in the legacy folder 2025-09-09 16:37:37 +02:00
60 changed files with 1095 additions and 778 deletions

View File

@@ -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<u8>;
@@ -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<u8>);
pub struct Fwded(pub Atom, pub TVec, pub Vec<u8>);
impl Request for Fwded {
type Response = Option<Vec<u8>>;
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
#[extends(ExtHostReq)]
pub struct Fwd(pub Atom, pub TStrv, pub Vec<u8>);
pub struct Fwd(pub Atom, pub TVec, pub Vec<u8>);
impl Request for Fwd {
type Response = Option<Vec<u8>>;
}

View File

@@ -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<OrcError>),
}

View File

@@ -47,7 +47,7 @@ impl Request for ExternStr {
#[extends(IntReq, ExtHostReq)]
pub struct InternStrv(pub Vec<TStr>);
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<TStr>;
}
@@ -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<TStr>,
pub vecs: Vec<TStrv>,
pub vecs: Vec<TVec>,
}

View File

@@ -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<OrcResult<LexedExpr>>;

View File

@@ -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<u32>,
}
#[derive(Clone, Debug, Coding)]
pub struct CodeGenInfo {
pub generator: TStrv,
pub generator: TVec,
pub details: TStr,
}

View File

@@ -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<Comment>,
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<TStrv>,
pub names: Vec<TVec>,
}
impl Request for ResolveNames {
type Response = Vec<OrcResult<TStrv>>;
type Response = Vec<OrcResult<TVec>>;
}

View File

@@ -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<TStr>,
pub const_root: HashMap<TStr, MemberKind>,
pub prelude: Vec<TStrv>,
pub prelude: Vec<TVec>,
}
#[derive(Clone, Debug, Coding, Hierarchy)]

View File

@@ -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<ModuleInfo, LsModuleError>;
}

View File

@@ -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]

28
orchid-base/src/ctx.rs Normal file
View File

@@ -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<Rc<dyn DynClient>>;
fn msg_set_type(&self) -> TypeId;
}
pub struct Ctx(Rc<dyn CtxDyn>);
impl Ctx {
pub fn i(&self) -> Interner { self.0.i() }
pub fn rep(&self) -> &Reporter { self.0.rep() }
pub fn client<T: MsgSet>(&self) -> Client<T> {
let Some(dyn_client) = self.0.client(TypeId::of::<T>()) else {
panic!("Incorrect message set {} passed", type_name::<T>());
};
Client(dyn_client, PhantomData)
}
}

View File

@@ -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<String>,
struct SingleError {
pub description: IStr,
pub message: Arc<String>,
pub positions: Vec<ErrPos>,
}
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<Tok<String>> for OrcErr {
fn eq(&self, other: &Tok<String>) -> bool { self.description == *other }
}
impl From<OrcErr> for Vec<OrcErr> {
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<OwnedOrcErr>,
futures: Mutex<Vec<Pin<Box<dyn Future<Output = OwnedOrcErr>>>>>,
}
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<Pin<Box<dyn Future<Output = OwnedOrcErr>>>> {
match self.singles.into_inner() {
Some(val) => vec![Box::pin(ready(val))],
None => self.futures.into_inner(),
}
}
}
impl From<OwnedOrcErr> for OrcErr {
fn from(value: OwnedOrcErr) -> Self {
Self { singles: OnceCell::from(value), futures: Mutex::new(vec![]) }
}
}
impl<T: Future<Output = OrcErr> + 'static> From<T> 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<SingleError>);
impl OwnedOrcErr {
pub fn to_api(&self) -> Vec<api::OrcError> {
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<Item = &api::OrcError>, 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<OrcErr>);
impl OrcErrv {
pub fn new(errors: impl IntoIterator<Item = OrcErr>) -> Result<Self, EmptyErrv> {
let v = errors.into_iter().collect_vec();
if v.is_empty() { Err(EmptyErrv) } else { Ok(Self(v)) }
}
#[must_use]
pub fn extended<T>(mut self, errors: impl IntoIterator<Item = T>) -> Self
where Self: Extend<T> {
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<Self> {
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<Item = ErrPos> + '_ {
self.0.iter().flat_map(|e| e.positions.iter().cloned())
}
pub fn to_api(&self) -> Vec<api::OrcError> { self.0.iter().map(OrcErr::to_api).collect() }
pub async fn from_api<'a>(
api: impl IntoIterator<Item = &'a api::OrcError>,
i: &Interner,
) -> Self {
Self(join_all(api.into_iter().map(|e| OrcErr::from_api(e, i))).await)
}
}
impl From<OrcErr> 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<OrcErr> for OrcErrv {
fn extend<T: IntoIterator<Item = OrcErr>>(&mut self, iter: T) { self.0.extend(iter) }
}
impl Extend<OrcErrv> for OrcErrv {
fn extend<T: IntoIterator<Item = OrcErrv>>(&mut self, iter: T) {
self.0.extend(iter.into_iter().flatten())
}
}
impl IntoIterator for OrcErrv {
type IntoIter = std::vec::IntoIter<OrcErr>;
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<T> = Result<T, OrcErrv>;
pub type OrcRes<T> = Result<T, OrcErr>;
pub fn join_ok<T, U>(left: OrcRes<T>, right: OrcRes<U>) -> OrcRes<(T, U)> {
match (left, right) {
@@ -191,62 +222,80 @@ macro_rules! join_ok {
(@VALUES) => { Ok(()) };
}
pub fn mk_errv_floating(description: Tok<String>, message: impl AsRef<str>) -> OrcErrv {
mk_errv::<Pos>(description, message, [])
}
pub fn mk_errv<I: Into<ErrPos>>(
description: Tok<String>,
message: impl AsRef<str>,
posv: impl IntoIterator<Item = I>,
) -> 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<str> + 'static,
message: impl AsRef<str> + 'static,
) -> OrcErr {
self.mk_err::<Pos>(description, message, [])
}
.into()
}
pub async fn async_io_err<I: Into<ErrPos>>(
err: std::io::Error,
i: &Interner,
posv: impl IntoIterator<Item = I>,
) -> OrcErrv {
mk_errv(i.i(&err.kind().to_string()).await, err.to_string(), posv)
}
pub async fn os_str_to_string<'a, I: Into<ErrPos>>(
str: &'a OsStr,
i: &Interner,
posv: impl IntoIterator<Item = I>,
) -> OrcRes<&'a str> {
match str.to_str() {
Some(str) => Ok(str),
None => Err(mk_errv(
i.i("Non-unicode string").await,
format!("{str:?} is not representable as unicode"),
posv,
)),
pub fn mk_err<I: Into<ErrPos>>(
&self,
description: impl AsRef<str> + 'static,
message: impl AsRef<str> + 'static,
posv: impl IntoIterator<Item = I> + '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<I: Into<ErrPos>>(
&self,
err: std::io::Error,
posv: impl IntoIterator<Item = I> + 'static,
) -> OrcErr {
self.mk_err(err.kind().to_string(), err.to_string(), posv)
}
pub fn os_str_to_string<'a, I: Into<ErrPos>>(
&self,
str: &'a OsStr,
posv: impl IntoIterator<Item = I> + '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<Vec<OrcErr>>,
errors: RefCell<Option<OrcErr>>,
}
impl Reporter {
pub fn report(&self, e: impl Into<OrcErrv>) { self.errors.borrow_mut().extend(e.into()) }
pub fn new() -> Self { Self { errors: RefCell::new(vec![]) } }
pub fn errv(self) -> Option<OrcErrv> { OrcErrv::new(self.errors.into_inner()).ok() }
pub fn merge<T>(self, res: OrcRes<T>) -> OrcRes<T> {
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<OrcErr>) {
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<T>(self, res: OrcRes<T>) -> OrcRes<T> {
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 {

View File

@@ -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>(T);
// /// Clippy crashes while verifying `Tok: Sized` without this and I cba to
// create /// a minimal example
// #[derive(Clone)]
// struct ForceSized<T>(T);
#[derive(Clone)]
pub struct Tok<T: Interned> {
data: Rc<T>,
marker: ForceSized<T::Marker>,
}
impl<T: Interned> Tok<T> {
pub fn new(data: Rc<T>, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } }
pub fn to_api(&self) -> T::Marker { self.marker.0 }
pub async fn from_api<M>(marker: M, i: &Interner) -> Self
where M: InternMarker<Interned = T> {
i.ex(marker).await
}
pub fn rc(&self) -> Rc<T> { self.data.clone() }
}
impl<T: Interned> Deref for Tok<T> {
type Target = T;
// #[derive(Clone)]
// pub struct Tok<T: Interned> {
// data: Rc<T>,
// marker: ForceSized<T::Marker>,
// }
// impl<T: Interned> Tok<T> {
// pub fn new(data: Rc<T>, marker: T::Marker) -> Self { Self { data, marker:
// ForceSized(marker) } } pub fn to_api(&self) -> T::Marker { self.marker.0 }
// pub async fn from_api<M>(marker: M, i: &Interner) -> Self
// where M: InternMarker<Interned = T> {
// i.ex(marker).await
// }
// pub fn rc(&self) -> Rc<T> { self.data.clone() }
// }
// impl<T: Interned> Deref for Tok<T> {
// type Target = T;
fn deref(&self) -> &Self::Target { self.data.as_ref() }
}
impl<T: Interned> Ord for Tok<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.to_api().cmp(&other.to_api()) }
}
impl<T: Interned> PartialOrd for Tok<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
}
impl<T: Interned> Eq for Tok<T> {}
impl<T: Interned> PartialEq for Tok<T> {
fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() }
}
impl<T: Interned> hash::Hash for Tok<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.to_api().hash(state) }
}
impl<T: Interned + fmt::Display> fmt::Display for Tok<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &*self.data)
}
}
impl<T: Interned + fmt::Debug> fmt::Debug for Tok<T> {
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<T: Interned> Ord for Tok<T> {
// fn cmp(&self, other: &Self) -> std::cmp::Ordering {
// self.to_api().cmp(&other.to_api()) } }
// impl<T: Interned> PartialOrd for Tok<T> {
// fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
// Some(self.cmp(other)) } }
// impl<T: Interned> Eq for Tok<T> {}
// impl<T: Interned> PartialEq for Tok<T> {
// fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() }
// }
// impl<T: Interned> hash::Hash for Tok<T> {
// fn hash<H: hash::Hasher>(&self, state: &mut H) { self.to_api().hash(state) }
// }
// impl<T: Interned + fmt::Display> fmt::Display for Tok<T> {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(f, "{}", &*self.data)
// }
// }
// impl<T: Interned + fmt::Debug> fmt::Debug for Tok<T> {
// 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<Interned = Self> {
type Marker: InternMarker<Interned = Self> + Sized;
fn intern(
self: Rc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> impl Future<Output = Self::Marker>;
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
}
// pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug +
// Internable<Interned = Self> { type Marker: InternMarker<Interned = Self> +
// Sized; fn intern(
// self: Rc<Self>,
// req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
// ) -> impl Future<Output = Self::Marker>;
// fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
// }
pub trait Internable: fmt::Debug {
type Interned: Interned;
fn get_owned(&self) -> Rc<Self::Interned>;
}
// pub trait Internable: fmt::Debug {
// type Interned: Interned;
// fn get_owned(&self) -> Rc<Self::Interned>;
// }
pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash + Sized {
type Interned: Interned<Marker = Self>;
/// Only called on replicas
fn resolve(self, i: &Interner) -> impl Future<Output = Tok<Self::Interned>>;
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<Marker = Self>;
// /// Only called on replicas
// fn resolve(self, i: &Interner) -> impl Future<Output = Tok<Self::Interned>>;
// fn get_id(self) -> NonZeroU64;
// fn from_id(id: NonZeroU64) -> Self;
// }
impl Interned for String {
type Marker = api::TStr;
async fn intern(
self: Rc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker {
req.request(api::InternStr(self.to_string())).await
}
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.strings }
}
impl InternMarker for api::TStr {
type Interned = String;
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
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<Self::Interned> { Rc::new(self.to_string()) }
}
impl Internable for String {
type Interned = String;
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
}
// impl Interned for String {
// type Marker = api::TStr;
// async fn intern(
// self: Rc<Self>,
// req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
// ) -> Self::Marker {
// req.request(api::InternStr(self.to_string())).await
// }
// fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut
// interners.strings } }
// impl InternMarker for api::TStr {
// type Interned = String;
// async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
// 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<Self::Interned> { Rc::new(self.to_string()) }
// }
// impl Internable for String {
// type Interned = String;
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
// }
impl Interned for Vec<Tok<String>> {
type Marker = api::TStrv;
async fn intern(
self: Rc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker {
req.request(api::InternStrv(self.iter().map(|t| t.to_api()).collect())).await
}
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.vecs }
}
impl InternMarker for api::TStrv {
type Interned = Vec<Tok<String>>;
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
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<String>] {
type Interned = Vec<Tok<String>>;
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
}
impl<const N: usize> Internable for [Tok<String>; N] {
type Interned = Vec<Tok<String>>;
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
}
impl Internable for Vec<Tok<String>> {
type Interned = Vec<Tok<String>>;
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
}
// impl Interned for Vec<IStr> {
// type Marker = api::TStrv;
// async fn intern(
// self: Rc<Self>,
// req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
// ) -> Self::Marker {
// req.request(api::InternStrv(self.iter().map(|t|
// t.to_api()).collect())).await }
// fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut
// interners.vecs } }
// impl InternMarker for api::TStrv {
// type Interned = Vec<IStr>;
// async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
// 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<IStr>;
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
// }
// impl<const N: usize> Internable for [IStr; N] {
// type Interned = Vec<IStr>;
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
// }
// impl Internable for Vec<IStr> {
// type Interned = Vec<IStr>;
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
// }
// impl Internable for Vec<api::TStr> {
// type Interned = Vec<Tok<String>>;
// type Interned = Vec<IStr>;
// fn get_owned(&self) -> Arc<Self::Interned> {
// Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
// }
// }
// impl Internable for [api::TStr] {
// type Interned = Vec<Tok<String>>;
// type Interned = Vec<IStr>;
// fn get_owned(&self) -> Arc<Self::Interned> {
// 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<dyn $trait>);
impl $type {
pub fn new<T: $trait + 'static>(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<Target = $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<std::cmp::Ordering> { Some(self.cmp(other)) }
}
impl Hash for $type {
fn hash<H: hash::Hasher>(&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<T: Interned> {
intern: HashMap<Rc<T>, Tok<T>>,
by_id: HashMap<T::Marker, Tok<T>>,
}
impl<T: Interned> Bimap<T> {
pub fn insert(&mut self, token: Tok<T>) {
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<Tok<T>> { self.by_id.get(&marker).cloned() }
pub fn by_value<Q: Eq + hash::Hash>(&self, q: &Q) -> Option<Tok<T>>
where T: Borrow<Q> {
(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<T::Marker> {
(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<T::Marker>) {
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<T: Interned> Default for Bimap<T> {
fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() } }
}
token_def!(IVec, IVecDyn, [IStr], api::TVec, "IVec");
pub trait UpComm {
fn up<R: Request>(&self, req: R) -> R::Response;
}
#[derive(Default)]
pub struct TypedInterners {
strings: Bimap<String>,
vecs: Bimap<Vec<Tok<String>>>,
}
#[derive(Default)]
pub struct InternerData {
interners: Mutex<TypedInterners>,
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
}
#[derive(Clone, Default)]
pub struct Interner(Rc<InternerData>);
#[derive(Clone)]
pub struct Interner(Rc<dyn InternerDyn>);
impl Interner {
pub fn new_master() -> Self { Self::default() }
pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) -> Self {
Self(Rc::new(InternerData { master: Some(Box::new(req)), interners: Mutex::default() }))
pub fn new<T: InternerDyn + 'static>(t: T) -> Self { Self(Rc::new(t) as _) }
pub async fn is(&self, s: &(impl Borrow<str> + ?Sized)) -> IStr {
IStr(self.0.is(s.borrow()).await)
}
/// Intern some data; query its identifier if not known locally
pub async fn i<T: Interned>(&self, t: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
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<M: InternMarker>(&self, marker: M) -> Tok<M::Interned> {
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<Rc<dyn IStrDyn>>;
fn iv(&self, v: &[IStr]) -> LocalBoxFuture<Rc<dyn IVecDyn>>;
fn es(&self, m: api::TStr) -> LocalBoxFuture<Rc<dyn IStrDyn>>;
fn ev(&self, m: api::TVec) -> LocalBoxFuture<Rc<dyn IVecDyn>>;
}
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<String> = spin_on(i.i("foo"));
let _: Tok<Vec<Tok<String>>> = 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<IStr>);
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<String, NonZeroU64>,
HashMap<NonZeroU64, Rc<DummyIStr>>,
HashMap<NonZeroU64, Rc<DummyIStrv>>,
)>,
AsyncMonitor<InternerEvent>,
);
pub enum InternerEvent {
ExternStr(Rc<DummyIStr>),
ExternVec(Rc<DummyIStrv>),
InternStr { token: Rc<DummyIStr>, new: bool },
InternVec { token: Rc<DummyIStrv>, new: bool },
}
impl DummyInterner {
pub fn new(monitor: AsyncMonitor<InternerEvent>) -> Interner {
Interner(Rc::new(Self(RefCell::default(), monitor)))
}
}
impl InternerDyn for DummyInterner {
fn es(&self, m: api::TStr) -> LocalBoxFuture<Rc<dyn IStrDyn>> {
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<dyn IStrDyn>
})
}
fn ev(&self, m: api::TVec) -> LocalBoxFuture<Rc<dyn IVecDyn>> {
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<dyn IVecDyn>
})
}
fn is(&self, s: &str) -> LocalBoxFuture<Rc<dyn IStrDyn>> {
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<Rc<dyn IVecDyn>> {
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<K, V, Tok> {
// intern: HashMap<V, Tok>,
// by_id: HashMap<K, Tok>,
// }
// impl<K> Bimap<T> {
// pub fn insert(&mut self, token: Tok<T>) {
// 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<Tok<T>> {
// self.by_id.get(&marker).cloned() }
// pub fn by_value<Q: Eq + hash::Hash>(&self, q: &Q) -> Option<Tok<T>>
// where T: Borrow<Q> {
// (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<T::Marker> {
// (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<T::Marker>) {
// self.intern.retain(|k, v| BASE_RC < Rc::strong_count(k) ||
// retained.contains(&v.to_api())) }
// }
// impl<T: Interned> Default for Bimap<T> {
// fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new()
// } } }
// pub trait UpComm {
// fn up<R: Request>(&self, req: R) -> R::Response;
// }
// #[derive(Default)]
// pub struct TypedInterners {
// strings: Bimap<String>,
// vecs: Bimap<Vec<IStr>>,
// }
// #[derive(Default)]
// pub struct InternerData {
// interners: Mutex<TypedInterners>,
// master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
// }
// #[derive(Clone, Default)]
// pub struct Interner(Rc<InternerData>);
// impl Interner {
// pub fn new_master() -> Self { Self::default() }
// pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + '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<T: Interned>(&self, t: &(impl Internable<Interned = T> +
// ?Sized)) -> Tok<T> { 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<M: InternMarker>(&self, marker: M) -> Tok<M::Interned> {
// 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<Vec<IStr>> = 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:?}")
// })
// }
// }

View File

@@ -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;

View File

@@ -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<String>;
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<String>,
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<str>, 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() }

View File

@@ -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<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
pub trait NameIter = Iterator<Item = IStr> + 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<Tok<String>>);
pub struct VPath(Vec<IStr>);
impl VPath {
/// Collect segments into a vector
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Self {
Self(items.into_iter().collect())
}
pub fn new(items: impl IntoIterator<Item = IStr>) -> 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<Item = Tok<String>>) -> Self {
pub fn prefix(self, items: impl IntoIterator<Item = IStr>) -> Self {
Self(items.into_iter().chain(self.0).collect())
}
/// Append some tokens to the path
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
pub fn suffix(self, items: impl IntoIterator<Item = IStr>) -> 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<Item = &'_ str> {
Box::new(self.0.iter().map(|s| s.as_str()))
}
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> { self.0.iter().map(|s| s.as_ref()) }
/// Try to convert into non-empty version
pub fn into_name(self) -> Result<VName, EmptyNameError> { 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<String>) -> 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<String>) -> 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<VPath> {
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::<Option<_>>().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<Tok<String>> for VPath {
fn from_iter<T: IntoIterator<Item = Tok<String>>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
impl FromIterator<IStr> for VPath {
fn from_iter<T: IntoIterator<Item = IStr>>(iter: T) -> Self { Self(iter.into_iter().collect()) }
}
impl IntoIterator for VPath {
type Item = Tok<String>;
type Item = IStr;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
impl Borrow<[Tok<String>]> for VPath {
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
impl Borrow<[IStr]> for VPath {
fn borrow(&self) -> &[IStr] { &self.0[..] }
}
impl Deref for VPath {
type Target = [Tok<String>];
type Target = [IStr];
fn deref(&self) -> &Self::Target { self.borrow() }
}
impl<T> Index<T> for VPath
where [Tok<String>]: Index<T>
where [IStr]: Index<T>
{
type Output = <[Tok<String>] as Index<T>>::Output;
type Output = <[IStr] as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &Borrow::<[Tok<String>]>::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<String>]: Index<T>
/// See also [Sym] for the immutable representation, and [VPath] for possibly
/// empty values
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct VName(Vec<Tok<String>>);
pub struct VName(Vec<IStr>);
impl VName {
/// Assert that the sequence isn't empty and wrap it in [VName] to represent
/// this invariant
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
pub fn new(items: impl IntoIterator<Item = IStr>) -> Result<Self, EmptyNameError> {
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<Item = api::TStr>,
i: &Interner,
) -> Result<Self, EmptyNameError> {
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<Tok<String>> { self.0 }
pub fn into_vec(self) -> Vec<IStr> { self.0 }
/// Get a reference to the enclosed vector
pub fn vec(&self) -> &Vec<Tok<String>> { &self.0 }
pub fn vec(&self) -> &Vec<IStr> { &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<Tok<String>> { &mut self.0 }
pub fn vec_mut(&mut self) -> &mut Vec<IStr> { &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<Tok<String>> { self.0.iter().exactly_one().ok().cloned() }
pub fn as_root(&self) -> Option<IStr> { 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<Item = Tok<String>>) -> Self {
pub fn prefix(self, items: impl IntoIterator<Item = IStr>) -> 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<Item = Tok<String>>) -> Self {
pub fn suffix(self, items: impl IntoIterator<Item = IStr>) -> 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<Item = Tok<String>> + '_ { self.0.iter().cloned() }
pub fn iter(&self) -> impl Iterator<Item = IStr> + '_ { 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<String>;
type Item = IStr;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
impl<T> Index<T> for VName
where [Tok<String>]: Index<T>
where [IStr]: Index<T>
{
type Output = <[Tok<String>] as Index<T>>::Output;
type Output = <[IStr] as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
}
impl Borrow<[Tok<String>]> for VName {
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
impl Borrow<[IStr]> for VName {
fn borrow(&self) -> &[IStr] { self.0.borrow() }
}
impl Deref for VName {
type Target = [Tok<String>];
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<String>]> for VName {
impl TryFrom<&[IStr]> for VName {
type Error = EmptyNameError;
fn try_from(value: &[Tok<String>]) -> Result<Self, Self::Error> {
Self::new(value.iter().cloned())
}
fn try_from(value: &[IStr]) -> Result<Self, Self::Error> { Self::new(value.iter().cloned()) }
}
/// An interned representation of a namespaced identifier.
@@ -206,36 +198,36 @@ impl TryFrom<&[Tok<String>]> for VName {
///
/// See also [VName]
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct Sym(Tok<Vec<Tok<String>>>);
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<Item = Tok<String>>,
v: impl IntoIterator<Item = IStr>,
i: &Interner,
) -> Result<Self, EmptyNameError> {
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<Self, EmptyNameError> {
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<Vec<Tok<String>>>) -> Result<Self, EmptyNameError> {
pub fn from_tok(t: IVec) -> Result<Self, EmptyNameError> {
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
}
/// Grab the interner token
pub fn tok(&self) -> Tok<Vec<Tok<String>>> { 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<Item = Tok<String>>, i: &Interner) -> Sym {
pub fn to_api(&self) -> api::TVec { self.tok().to_api() }
pub async fn suffix(&self, tokv: impl IntoIterator<Item = IStr>, i: &Interner) -> Sym {
Self::new(self.0.iter().cloned().chain(tokv), i).await.unwrap()
}
}
@@ -248,17 +240,17 @@ impl fmt::Display for Sym {
}
}
impl<T> Index<T> for Sym
where [Tok<String>]: Index<T>
where [IStr]: Index<T>
{
type Output = <[Tok<String>] as Index<T>>::Output;
type Output = <[IStr] as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
}
impl Borrow<[Tok<String>]> for Sym {
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
impl Borrow<[IStr]> for Sym {
fn borrow(&self) -> &[IStr] { &self.0[..] }
}
impl Deref for Sym {
type Target = [Tok<String>];
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<String>]>
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<[IStr]>
{
/// Convert into held slice
fn as_slice(&self) -> &[Tok<String>] { Borrow::<[Tok<String>]>::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<Item = &'_ str> + '_ {
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<String>, &[Tok<String>]) {
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<String>, &[Tok<String>]) {
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<String> { self.split_first_seg().0 }
fn first_seg(&self) -> IStr { self.split_first_seg().0 }
/// Get the last element
fn last_seg(&self) -> Tok<String> { 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<String>] = myname.borrow();
let _deref_pathslice: &[Tok<String>] = &myname;
let _as_slice_out: &[Tok<String>] = 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])
);
})
}

View File

@@ -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",

View File

@@ -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<A: ExprRepr, X: ExtraTok> Format for Snippet<'_, A, X> {
#[derive(Clone, Debug)]
pub struct Comment {
pub text: Tok<String>,
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<impl ExprRepr, impl ExtraTok>, i: &Interner) -> Option<Self> {
pub async fn from_tk(tk: &TokTree<impl ExprRepr, impl ExtraTok>, cx: &Ctx) -> Option<Self> {
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<R: ExprRepr, X: ExtraTok>(&self) -> TokTree<R, X> {
TokTree { tok: Token::Comment(self.text.rc().clone()), sr: self.sr.clone() }
pub fn to_tk<A: ExprRepr, X: ExtraTok>(&self) -> TokTree<A, X> {
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<Parsed<'a, Vec<Comment>, 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>, 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<String>,
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<A: ExprRepr, X: ExtraTok>(
ctx: &impl ParseCtx,
ctx: &Ctx,
tok: &TokTree<A, X>,
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<Parsed<'a, T, H, X>>;
pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
ctx: &impl ParseCtx,
ctx: &Ctx,
tail: Snippet<'a, A, X>,
) -> ParseRes<'a, Vec<Import>, 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<A: ExprRepr, X: ExtraTok>(
tt: &TokTree<A, X>,
ctx: &impl ParseCtx,
) -> OrcRes<Vec<(Vec<Tok<String>>, Option<Tok<String>>, SrcRange)>> {
ctx: &Ctx,
) -> OrcRes<Vec<(Vec<IStr>, Option<IStr>, 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<Tok<String>>,
pub name: Option<IStr>,
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<String>) -> 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("*"))
}
}

View File

@@ -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<Self>) -> Pin<Box<dyn Future<Output = Box<dyn DynResponseHandle>>>>;
}
/// 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<Self>) -> Pin<Box<dyn Future<Output = ()>>>;
}
/// 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<Self>) -> Pin<Box<dyn Future<Output = ()>>>;
}
pub trait DynClient {
fn request(&self) -> Pin<Box<dyn Future<Output = Box<dyn DynRequestWriter>>>>;
fn notif(&self) -> Pin<Box<dyn Future<Output = Box<dyn DynNotifWriter>>>>;
}
pub struct Client<T: MsgSet>(pub(crate) Rc<dyn DynClient>, pub(crate) PhantomData<T>);
impl<T: MsgSet> Client<T> {
pub async fn notify<Notif: Into<<T::Out as Channel>::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: Request + Into<<T::Out as Channel>::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<u64, Box<dyn FnOnce(&mut dyn AsyncBufRead)>>,
sender: Pin<Box<dyn AsyncWrite>>,
receiver: Pin<Box<dyn AsyncBufRead>>,
}
pub enum ServerEvent<T: MsgSet> {
Notif(<T::In as Channel>::Notif),
Req(RequestHandle<T>, <T::In as Channel>::Req),
}
pub async fn run_duplex_server<T: MsgSet>(
sender: Pin<Box<dyn AsyncWrite>>,
receiver: Pin<Box<dyn AsyncBufRead>>,
) -> (impl Stream<Item = ServerEvent<T>>, Client<T>) {
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<Mutex<DuplexServerState>>);
impl DuplexServer {
pub fn receive(msg: )
}
trait_set! {
pub trait SendFn<T: MsgSet> =
for<'a> FnMut(&'a [u8], ReqNot<T>) -> LocalBoxFuture<'a, ()>
@@ -52,11 +120,10 @@ impl ReqHandlish for &'_ dyn ReqHandlish {
}
#[derive(destructure)]
pub struct RequestHandle<'a, MS: MsgSet> {
pub struct RequestHandle<MS: MsgSet> {
defer_drop: RefCell<Vec<Box<dyn Any>>>,
fulfilled: AtomicBool,
id: u64,
_reqlt: PhantomData<&'a mut ()>,
parent: ReqNot<MS>,
}
impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
@@ -89,7 +156,7 @@ impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
impl<MS: MsgSet> ReqHandlish for RequestHandle<'_, MS> {
fn defer_drop_objsafe(&self, val: Box<dyn Any>) { self.defer_drop.borrow_mut().push(val); }
}
impl<MS: MsgSet> Drop for RequestHandle<'_, MS> {
impl<MS: MsgSet> Drop for RequestHandle<MS> {
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<T: MsgSet> ReqNot<T> {
notif: impl NotifFn<T>,
req: impl ReqFn<T>,
) -> Self {
Self(
let this = Self(
Arc::new(Mutex::new(ReqNotData {
id: 1,
send: Box::new(send),
@@ -132,7 +199,13 @@ impl<T: MsgSet> ReqNot<T> {
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

View File

@@ -0,0 +1,23 @@
#![cfg(any(feature = "mocks", test))]
use std::future::ready;
use std::pin::Pin;
use std::rc::Rc;
pub struct AsyncMonitor<E: 'static>(Rc<dyn Fn(E) -> Pin<Box<dyn Future<Output = ()>>>>);
impl<E: 'static> AsyncMonitor<E> {
pub fn new<F: AsyncFn(E) -> () + '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<E: 'static> Default for AsyncMonitor<E> {
fn default() -> Self { Self(Rc::new(|_| Box::pin(ready(())))) }
}
impl<E: 'static> Clone for AsyncMonitor<E> {
fn clone(&self) -> Self { Self(self.0.clone()) }
}

View File

@@ -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<H: ExprRepr, X: ExtraTok> TokTree<H, X> {
let pos = SrcRange::new(tt.range.clone(), src);
let tok = match_mapping!(&tt.token, api::Token => Token::<H, X> {
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<H: ExprRepr, X: ExtraTok> TokTree<H, X> {
api::TokenTree { range: self.sr.range.clone(), token }
}
pub fn is_kw(&self, tk: Tok<String>) -> bool { self.tok.is_kw(tk) }
pub fn as_name(&self) -> Option<Tok<String>> {
pub fn is_kw(&self, tk: IStr) -> bool { self.tok.is_kw(tk) }
pub fn as_name(&self) -> Option<IStr> {
if let Token::Name(n) = &self.tok { Some(n.clone()) } else { None }
}
pub fn as_multiname(&self) -> Result<VName, &TokTree<H, X>> {
@@ -245,9 +245,9 @@ pub enum Token<H: ExprRepr, X: ExtraTok> {
/// stretches to the end of the enclosing parens or the end of the const line
LambdaHead(Box<TokTree<H, X>>),
/// A binding, operator, or a segment of a namespaced::name
Name(Tok<String>),
Name(IStr),
/// A namespace prefix, like `my_ns::` followed by a token
NS(Tok<String>, Box<TokTree<H, X>>),
NS(IStr, Box<TokTree<H, X>>),
/// A line break
BR,
/// `()`, `[]`, or `{}`
@@ -259,11 +259,11 @@ pub enum Token<H: ExprRepr, X: ExtraTok> {
/// 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<H: ExprRepr, X: ExtraTok> Token<H, X> {
pub fn at(self, sr: SrcRange) -> TokTree<H, X> { TokTree { sr, tok: self } }
pub fn is_kw(&self, tk: Tok<String>) -> 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<H, X>]> {
match self {
Self::S(p, b) if *p == par => Some(b),
@@ -275,8 +275,7 @@ impl<H: ExprRepr, X: ExtraTok> Format for Token<H, X> {
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<Variants>: Rc::new(Variants::default().bounded("\\{0b}.")))

View File

@@ -13,13 +13,13 @@ pub enum Loaded {
Code(Arc<String>),
/// Conceptually equivalent to the list of *.orc files in a folder, without
/// the extension
Collection(Arc<Vec<Tok<String>>>),
Collection(Arc<Vec<IStr>>),
}
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<Item = Tok<String>>) -> Self {
pub fn collection(items: impl IntoIterator<Item = IStr>) -> 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<String>], 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<String>]) -> Option<String>;
fn display(&self, path: &[IStr]) -> Option<String>;
/// Convert the FS handler into a type-erased version of itself for packing in
/// a tree.
fn rc(self) -> Rc<dyn VirtFS>
@@ -81,15 +81,15 @@ pub trait VirtFS {
}
impl VirtFS for &dyn VirtFS {
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
(*self).get(path, full_path)
}
fn display(&self, path: &[Tok<String>]) -> Option<String> { (*self).display(path) }
fn display(&self, path: &[IStr]) -> Option<String> { (*self).display(path) }
}
impl<T: VirtFS + ?Sized> VirtFS for Rc<T> {
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
(**self).get(path, full_path)
}
fn display(&self, path: &[Tok<String>]) -> Option<String> { (**self).display(path) }
fn display(&self, path: &[IStr]) -> Option<String> { (**self).display(path) }
}

View File

@@ -32,7 +32,7 @@ impl<'a> Combine for &'a dyn VirtFS {
pub type DeclTree = ModEntry<Rc<dyn VirtFS>, (), ()>;
impl VirtFS for DeclTree {
fn get(&self, path: &[Tok<String>], 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<String>]) -> Option<String> {
fn display(&self, path: &[IStr]) -> Option<String> {
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<String>]) -> Option<String> { None }
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
fn display(&self, _: &[IStr]) -> Option<String> { 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<String>]) -> Option<String> { None }
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
fn display(&self, _: &[IStr]) -> Option<String> { 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())
}

View File

@@ -99,14 +99,14 @@ impl DirNode {
}
}
fn mk_pathbuf(&self, path: &[Tok<String>]) -> 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<String>], 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<String>]) -> Option<String> {
fn display(&self, path: &[IStr]) -> Option<String> {
let pathbuf = self.mk_pathbuf(path).with_extension(self.ext());
Some(pathbuf.to_string_lossy().to_string())
}

View File

@@ -56,7 +56,7 @@ impl EmbeddedFS {
}
impl VirtFS for EmbeddedFS {
fn get(&self, path: &[Tok<String>], 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<String>]) -> Option<String> {
fn display(&self, path: &[IStr]) -> Option<String> {
let Self { gen, suffix, .. } = self;
Some(format!("{}{suffix} in {gen}", path.iter().join("/")))
}

View File

@@ -21,18 +21,18 @@ impl<'a> PrefixFS<'a> {
add: VPath::parse(add.as_ref()),
}
}
fn proc_path(&self, path: &[Tok<String>]) -> Option<Vec<Tok<String>>> {
fn proc_path(&self, path: &[IStr]) -> Option<Vec<IStr>> {
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<String>], 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<String>]) -> Option<String> {
fn display(&self, path: &[IStr]) -> Option<String> {
self.wrapped.display(&self.proc_path(path)?)
}
}

View File

@@ -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")
}

View File

@@ -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<T: TryFromExpr, U: TryFromExpr> 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 {

View File

@@ -49,7 +49,7 @@ impl ExtensionData {
}
pub enum MemberRecord {
Gen(Vec<Tok<String>>, LazyMemberFactory),
Gen(Vec<IStr>, LazyMemberFactory),
Res,
}

View File

@@ -0,0 +1,7 @@
use orchid_base::interner::{ApiStrTok, ApiStrvTok, IStr};
pub struct ExtIStr(ApiStrTok, Rc<String>);
impl Deref for ExtIStr {}
pub struct ExtIStrv(ApiStrvTok, Rc<Vec<IStr>>);
pub struct ExtInterner {}

View File

@@ -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<String> {
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<String> {
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<String>,
pub text: &'a IStr,
pub id: api::ParsId,
pub pos: u32,
pub(crate) src: Sym,

View File

@@ -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;

View File

@@ -115,7 +115,7 @@ impl ParsedLine {
sr: &SrcRange,
comments: impl IntoIterator<Item = &'a Comment>,
exported: bool,
name: Tok<String>,
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<Item = &'a Comment>,
exported: bool,
name: &Tok<String>,
name: &IStr,
use_prelude: bool,
lines: impl IntoIterator<Item = ParsedLine>,
) -> Self {
@@ -175,7 +175,7 @@ pub enum ParsedLineKind {
}
pub struct ParsedMem {
pub name: Tok<String>,
pub name: IStr,
pub exported: bool,
pub kind: ParsedMemKind,
}

View File

@@ -32,7 +32,7 @@ pub struct ReflModData {
inferred: Mutex<bool>,
path: VPath,
ctx: WeakSysCtx,
members: MemoMap<Tok<String>, ReflMem>,
members: MemoMap<IStr, ReflMem>,
}
#[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<String>] { &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<String>) -> Option<ReflMem> {
pub async fn get_child(&self, key: &IStr) -> Option<ReflMem> {
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<String>]) -> Result<ReflMem, InvalidPathError> {
pub async fn get_by_path(&self, path: &[IStr]) -> Result<ReflMem, InvalidPathError> {
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;

View File

@@ -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<String>) -> 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<String>],
pub path: Substack<'a, Tok<String>>,
pub basepath: &'a [IStr],
pub path: Substack<'a, IStr>,
pub lazy_members: &'b mut HashMap<api::TreeId, MemberRecord>,
pub req: &'a RH,
}
impl<RH: ReqHandlish> TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> {
fn sys(&self) -> SysCtx { self.sys.clone() }
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
fn push_path(&mut self, seg: IStr) -> impl TreeIntoApiCtx {
TreeIntoApiCtxImpl {
req: self.req,
lazy_members: self.lazy_members,

View File

@@ -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<u8>) -> Option<Vec<u8>> {
pub async fn req(&self, key: api::TVec, req: Vec<u8>) -> Option<Vec<u8>> {
self.0.owner.reqnot().request(api::Fwded(self.0.api_ref(), key, req)).await
}
#[must_use]

View File

@@ -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<String>],
mut rel: &[Tok<String>],
mut cwd: &[IStr],
mut rel: &[IStr],
i: &Interner,
) -> Result<VName, AbsPathError> {
let i_self = i.i("self").await;
@@ -67,13 +67,13 @@ pub struct DealiasCtx<'a> {
}
pub async fn resolv_glob<Mod: Tree>(
cwd: &[Tok<String>],
cwd: &[IStr],
root: &Mod,
abs_path: &[Tok<String>],
abs_path: &[IStr],
pos: Pos,
i: &Interner,
ctx: &mut Mod::Ctx<'_>,
) -> OrcRes<HashSet<Tok<String>>> {
) -> OrcRes<HashSet<IStr>> {
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<Mod: Tree>(
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<Tok<String>>;
fn children(&self, public_only: bool) -> HashSet<IStr>;
#[must_use]
fn child(
&self,
key: Tok<String>,
key: IStr,
public_only: bool,
ctx: &mut Self::Ctx<'_>,
) -> impl Future<Output = ChildResult<'_, Self>>;
@@ -133,7 +133,7 @@ pub struct ChildError {
pub async fn walk<'a, T: Tree>(
root: &'a T,
public_only: bool,
path: impl IntoIterator<Item = Tok<String>>,
path: impl IntoIterator<Item = IStr>,
ctx: &mut T::Ctx<'_>,
) -> Result<&'a T, ChildError> {
let mut cur = root;

View File

@@ -260,7 +260,7 @@ impl Extension {
}
pub(crate) async fn lex_req<F: Future<Output = Option<api::SubLexed>>>(
&self,
source: Tok<String>,
source: IStr,
src: Sym,
pos: u32,
sys: api::SysId,

View File

@@ -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<String>,
pub source: &'a IStr,
pub path: &'a Sym,
pub tail: &'a str,
pub sub_trees: &'a mut Vec<Expr>,
@@ -105,7 +105,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
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<ParsTokTree> {
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<ParsTokTree> {
} 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<ParsTokTree> {
Ok(ParsTokTree { tok, sr: SrcRange::new(start..ctx.get_pos(), ctx.path) })
}
pub async fn lex(
text: Tok<String>,
path: Sym,
systems: &[System],
ctx: &Ctx,
) -> OrcRes<Vec<ParsTokTree>> {
pub async fn lex(text: IStr, path: Sym, systems: &[System], ctx: &Ctx) -> OrcRes<Vec<ParsTokTree>> {
let mut sub_trees = Vec::new();
let mut ctx =
LexCtx { source: &text, sub_trees: &mut sub_trees, tail: &text[..], systems, path: &path, ctx };

View File

@@ -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<String>>,
path: Substack<'_, IStr>,
items: ParsSnippet<'_>,
) -> OrcRes<Vec<Item>> {
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<String>>,
path: Substack<'_, IStr>,
comments: Vec<Comment>,
item: ParsSnippet<'_>,
) -> OrcRes<Vec<Item>> {
@@ -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<String>>,
path: Substack<'_, IStr>,
comments: Vec<Comment>,
exported: bool,
discr: Tok<String>,
discr: IStr,
tail: ParsSnippet<'a>,
) -> OrcRes<Vec<Item>> {
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<String>>,
path: Substack<'_, IStr>,
tail: ParsSnippet<'a>,
) -> OrcRes<(Tok<String>, 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()],

View File

@@ -69,14 +69,14 @@ impl Format for Item {
}
pub struct ParsedMember {
pub name: Tok<String>,
pub name: IStr,
pub exported: bool,
pub kind: ParsedMemberKind,
}
impl ParsedMember {
#[must_use]
pub fn name(&self) -> Tok<String> { self.name.clone() }
pub fn new(exported: bool, name: Tok<String>, kind: impl Into<ParsedMemberKind>) -> Self {
pub fn name(&self) -> IStr { self.name.clone() }
pub fn new(exported: bool, name: IStr, kind: impl Into<ParsedMemberKind>) -> Self {
Self { exported, name, kind: kind.into() }
}
}
@@ -90,14 +90,14 @@ impl Debug for ParsedMember {
}
pub(crate) type ParsedExprCallback =
Rc<dyn for<'a> Fn(&'a [Tok<String>]) -> LocalBoxFuture<'a, Expr>>;
Rc<dyn for<'a> 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<String>]) -> Expr {
pub async fn run(self, imported_names: &[IStr]) -> Expr {
(self.callback)(imported_names).await
}
}
@@ -116,7 +116,7 @@ impl From<ParsedModule> for ParsedMemberKind {
#[derive(Debug, Default)]
pub struct ParsedModule {
pub exports: Vec<Tok<String>>,
pub exports: Vec<IStr>,
pub items: Vec<Item>,
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<String>, 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<String>,
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<Tok<String>> {
fn children(&self, public_only: bool) -> HashSet<IStr> {
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<Vec<Tok<String>>>,
steps: Tok<Vec<IStr>>,
}
impl ConstPath {
#[must_use]
pub fn to_const(steps: Tok<Vec<Tok<String>>>) -> Self { Self { steps } }
pub fn to_const(steps: Tok<Vec<IStr>>) -> Self { Self { steps } }
}
pub async fn tt_to_api(exprs: &mut ExprStore, subtree: ParsTokTree) -> api::TokenTree {

View File

@@ -23,7 +23,7 @@ pub struct Parser {
pub(crate) system: System,
pub(crate) idx: u16,
}
type ModPath<'a> = Substack<'a, Tok<String>>;
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<api::ParsedLine>,
module: Substack<'_, Tok<String>>,
callback: &'_ mut impl AsyncFnMut(Substack<'_, Tok<String>>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
module: Substack<'_, IStr>,
callback: &'_ mut impl AsyncFnMut(Substack<'_, IStr>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
ctx: &mut ConvCtx<'_>,
) -> OrcRes<Vec<Item>> {
let mut items = Vec::new();

View File

@@ -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<Tok<String>>,
line_types: Vec<IStr>,
prelude: Vec<Sym>,
owned_atoms: RwLock<HashMap<api::AtomId, WeakAtomHand>>,
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
@@ -88,7 +88,7 @@ impl System {
/// [Self::can_lex] was called and returned true.
pub async fn lex<F: Future<Output = Option<api::SubLexed>>>(
&self,
source: Tok<String>,
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<String>) -> Option<Parser> {
pub fn get_parser(&self, ltyp: IStr) -> Option<Parser> {
(self.0.line_types.iter().enumerate())
.find(|(_, txt)| *txt == &ltyp)
.map(|(idx, _)| Parser { idx: idx as u16, system: self.clone() })
}
pub fn line_types(&self) -> impl Iterator<Item = &Tok<String>> + '_ { self.0.line_types.iter() }
pub fn line_types(&self) -> impl Iterator<Item = &IStr> + '_ { self.0.line_types.iter() }
#[must_use]
pub async fn request(&self, req: Vec<u8>) -> Vec<u8> {
@@ -130,7 +130,7 @@ impl System {
pub(crate) async fn name_resolver(
&self,
orig: api::ParsedConstId,
) -> impl AsyncFnMut(&[Tok<String>]) -> OrcRes<VName> + use<> {
) -> impl AsyncFnMut(&[IStr]) -> OrcRes<VName> + 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"),
))

View File

@@ -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<Sym, Expr>,
pub path: Tok<Vec<Tok<String>>>,
pub path: Tok<Vec<IStr>>,
}
impl<'a> TreeFromApiCtx<'a> {
#[must_use]
pub async fn push<'c>(&'c self, name: Tok<String>) -> 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<Tok<String>, Result<ResolvedImport, Vec<ResolvedImport>>>,
pub members: HashMap<Tok<String>, Rc<Member>>,
pub imports: HashMap<IStr, Result<ResolvedImport, Vec<ResolvedImport>>>,
pub members: HashMap<IStr, Rc<Member>>,
}
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<Sym, Expr>);
async fn child(
&self,
key: Tok<String>,
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<Tok<String>> {
fn children(&self, public_only: bool) -> hashbrown::HashSet<IStr> {
self.members.iter().filter(|(_, v)| !public_only || v.public).map(|(k, _)| k.clone()).collect()
}
}

View File

@@ -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([

View File

@@ -40,7 +40,7 @@ pub fn gen_macro_lib() -> Vec<GenMember> {
fun(true, "lower", |tpl: TypAtom<MacTree>| 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<RecurState>, tpl: TypAtom<MacTree>| async move {
exec("macros::resolve_recur", async move |mut h| {

View File

@@ -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<Vec<ParsedLine>> {
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<u64>,
pub rules: Vec<Rule>,
pub own_kws: Vec<Tok<String>>,
pub own_kws: Vec<IStr>,
}
#[derive(Clone, Debug)]
@@ -210,8 +210,8 @@ pub struct Rule {
pub pos: Pos,
pub pattern: Matcher,
pub glossary: HashSet<Sym>,
pub placeholders: Vec<Tok<String>>,
pub body_name: Tok<String>,
pub placeholders: Vec<IStr>,
pub body_name: IStr,
}
#[derive(Debug)]
pub enum Matcher {

View File

@@ -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<String>,
pub name: IStr,
pub kind: PhKind,
}
impl Display for Ph {

View File

@@ -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)],

View File

@@ -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<String>,
pub main_kw: IStr,
pub rule: u32,
}
impl RulePath {

View File

@@ -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()],

View File

@@ -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<String>, 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<ScalMatcher> {
},
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()],

View File

@@ -18,7 +18,7 @@ use crate::macros::{MacTok, MacTree};
pub struct NamedMatcher {
inner: AnyMatcher,
head: Sym,
after_tok: Tok<String>,
after_tok: IStr,
}
impl NamedMatcher {
pub async fn new(pattern: &[MacTree], i: &Interner) -> OrcRes<Self> {

View File

@@ -11,12 +11,12 @@ use orchid_base::tokens::{PARENS, Paren};
pub enum ScalMatcher {
Name(Sym),
S(Paren, Box<AnyMatcher>),
Placeh { key: Tok<String> },
Placeh { key: IStr },
}
pub enum VecMatcher {
Placeh {
key: Tok<String>,
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<Tok<String>>,
key_order: Vec<IStr>,
},
}

View File

@@ -30,11 +30,11 @@ pub enum StateEntry<'a> {
}
#[derive(Clone, Debug)]
pub struct MatchState<'a> {
placeholders: HashMap<Tok<String>, StateEntry<'a>>,
placeholders: HashMap<IStr, StateEntry<'a>>,
name_posv: HashMap<Sym, Vec<Pos>>,
}
impl<'a> MatchState<'a> {
pub fn from_ph(key: Tok<String>, 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<String>) -> Option<usize> {
pub fn ph_len(&self, key: &IStr) -> Option<usize> {
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<String>) -> Option<&StateEntry<'a>> { self.placeholders.get(key) }
pub fn remove(&mut self, name: Tok<String>) -> Option<StateEntry<'a>> {
pub fn get(&self, key: &IStr) -> Option<&StateEntry<'a>> { self.placeholders.get(key) }
pub fn remove(&mut self, name: IStr) -> Option<StateEntry<'a>> {
self.placeholders.remove(&name)
}
pub fn mk_owned(self) -> OwnedState {
@@ -85,10 +85,10 @@ pub enum OwnedEntry {
Scalar(MacTree),
}
pub struct OwnedState {
placeholders: HashMap<Tok<String>, OwnedEntry>,
placeholders: HashMap<IStr, OwnedEntry>,
name_posv: HashMap<Sym, Vec<Pos>>,
}
impl OwnedState {
pub fn get(&self, key: &Tok<String>) -> 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[..]) }
}

View File

@@ -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<String>, 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)),

View File

@@ -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<String>);
pub struct IntStrAtom(IStr);
impl Atomic for IntStrAtom {
type Variant = OwnedVariant;
type Data = orchid_api::TStr;
}
impl From<Tok<String>> for IntStrAtom {
fn from(value: Tok<String>) -> Self { Self(value) }
impl From<IStr> 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::<IntStrAtom>::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())),
}
}
}

View File

@@ -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())],

View File

@@ -55,6 +55,10 @@
],
"rust-analyzer.showUnlinkedFileNotification": false,
"swissknife.notesEnabled": false,
"todo-tree.filtering.excludeGlobs": [
"**/node_modules/*/**",
"orchidlang/**"
]
},
"extensions": {
"recommendations": [

View File

@@ -131,7 +131,7 @@ async fn main() -> io::Result<ExitCode> {
};
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;

View File

@@ -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],