forked from Orchid/orchid
Initial extension asynchronization efforts.
This commit is contained in:
@@ -6,4 +6,7 @@ macro_rules! clone {
|
||||
$body
|
||||
}
|
||||
);
|
||||
($($n:ident),+) => {
|
||||
$( let $n = $n.clone(); )+
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use futures::future::join_all;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::api;
|
||||
use crate::interner::Tok;
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::location::Pos;
|
||||
|
||||
/// A point of interest in resolving the error, such as the point where
|
||||
@@ -22,10 +22,10 @@ impl ErrPos {
|
||||
pub fn new(msg: &str, position: Pos) -> Self {
|
||||
Self { message: Some(Arc::new(msg.to_string())), position }
|
||||
}
|
||||
async fn from_api(api: &api::ErrLocation) -> Self {
|
||||
async fn from_api(api: &api::ErrLocation, i: &Interner) -> Self {
|
||||
Self {
|
||||
message: Some(api.message.clone()).filter(|s| !s.is_empty()),
|
||||
position: Pos::from_api(&api.location).await,
|
||||
position: Pos::from_api(&api.location, i).await,
|
||||
}
|
||||
}
|
||||
fn to_api(&self) -> api::ErrLocation {
|
||||
@@ -53,11 +53,11 @@ impl OrcErr {
|
||||
locations: self.positions.iter().map(ErrPos::to_api).collect(),
|
||||
}
|
||||
}
|
||||
async fn from_api(api: &api::OrcError) -> Self {
|
||||
async fn from_api(api: &api::OrcError, i: &Interner) -> Self {
|
||||
Self {
|
||||
description: Tok::from_api(api.description).await,
|
||||
description: Tok::from_api(api.description, i).await,
|
||||
message: api.message.clone(),
|
||||
positions: join_all(api.locations.iter().map(ErrPos::from_api)).await,
|
||||
positions: join_all(api.locations.iter().map(|e| ErrPos::from_api(e, i))).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,11 @@ impl OrcErrv {
|
||||
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>) -> Self {
|
||||
Self(join_all(api.into_iter().map(OrcErr::from_api)).await)
|
||||
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 {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::future::Future;
|
||||
use std::hash::BuildHasher as _;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU64;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex, MutexGuard, atomic};
|
||||
use std::{fmt, hash, mem};
|
||||
use std::sync::atomic;
|
||||
use std::{fmt, hash};
|
||||
|
||||
use async_once_cell::Lazy;
|
||||
use async_std::sync::Mutex;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use itertools::Itertools as _;
|
||||
use orchid_api_traits::Request;
|
||||
@@ -29,9 +28,9 @@ pub struct Tok<T: Interned> {
|
||||
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: &mut Interner) -> Self
|
||||
pub async fn from_api<M>(marker: M, i: &Interner) -> Self
|
||||
where M: InternMarker<Interned = T> {
|
||||
i.deintern(marker).await
|
||||
i.ex(marker).await
|
||||
}
|
||||
pub fn rc(&self) -> Rc<T> { self.data.clone() }
|
||||
}
|
||||
@@ -67,7 +66,7 @@ impl<T: Interned + fmt::Debug> fmt::Debug for Tok<T> {
|
||||
pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable<Interned = Self> {
|
||||
type Marker: InternMarker<Interned = Self> + Sized;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
self: Rc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> impl Future<Output = Self::Marker>;
|
||||
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
|
||||
@@ -75,15 +74,13 @@ pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable<Interned =
|
||||
|
||||
pub trait Internable: fmt::Debug {
|
||||
type Interned: Interned;
|
||||
fn get_owned(&self) -> Arc<Self::Interned>;
|
||||
fn get_owned(&self) -> Rc<Self::Interned>;
|
||||
}
|
||||
|
||||
pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash + Sized {
|
||||
type Interned: Interned<Marker = Self>;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> impl Future<Output = Tok<Self::Interned>>;
|
||||
/// 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;
|
||||
}
|
||||
@@ -91,63 +88,61 @@ pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash +
|
||||
impl Interned for String {
|
||||
type Marker = api::TStr;
|
||||
async fn intern(
|
||||
self: Arc<Self>,
|
||||
self: Rc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStr(self)).await
|
||||
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,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
Tok::new(req.request(api::ExternStr(self)).await, self)
|
||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||
Tok::new(Rc::new(i.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) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
|
||||
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
|
||||
}
|
||||
impl Internable for String {
|
||||
type Interned = String;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_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: Arc<Self>,
|
||||
self: Rc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStrv(Arc::new(self.iter().map(|t| t.to_api()).collect()))).await
|
||||
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,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
let rep = req.request(api::ExternStrv(self)).await;
|
||||
let data = futures::future::join_all(rep.iter().map(|m| deintern(*m))).await;
|
||||
Tok::new(Arc::new(data), self)
|
||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||
let rep = i.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) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
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) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
||||
}
|
||||
// impl Internable for Vec<api::TStr> {
|
||||
// type Interned = Vec<Tok<String>>;
|
||||
@@ -167,14 +162,14 @@ const BASE_RC: usize = 3;
|
||||
|
||||
#[test]
|
||||
fn base_rc_correct() {
|
||||
let tok = Tok::new(Arc::new("foo".to_string()), api::TStr(1.try_into().unwrap()));
|
||||
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!(Arc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
|
||||
assert_eq!(Rc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
|
||||
}
|
||||
|
||||
pub struct Bimap<T: Interned> {
|
||||
intern: HashMap<Arc<T>, Tok<T>>,
|
||||
intern: HashMap<Rc<T>, Tok<T>>,
|
||||
by_id: HashMap<T::Marker, Tok<T>>,
|
||||
}
|
||||
impl<T: Interned> Bimap<T> {
|
||||
@@ -194,7 +189,7 @@ impl<T: Interned> Bimap<T> {
|
||||
|
||||
pub fn sweep_replica(&mut self) -> Vec<T::Marker> {
|
||||
(self.intern)
|
||||
.extract_if(|k, _| Arc::strong_count(k) == BASE_RC)
|
||||
.extract_if(|k, _| Rc::strong_count(k) == BASE_RC)
|
||||
.map(|(_, v)| {
|
||||
self.by_id.remove(&v.to_api());
|
||||
v.to_api()
|
||||
@@ -203,7 +198,7 @@ impl<T: Interned> Bimap<T> {
|
||||
}
|
||||
|
||||
pub fn sweep_master(&mut self, retained: HashSet<T::Marker>) {
|
||||
self.intern.retain(|k, v| BASE_RC < Arc::strong_count(k) || retained.contains(&v.to_api()))
|
||||
self.intern.retain(|k, v| BASE_RC < Rc::strong_count(k) || retained.contains(&v.to_api()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,58 +218,59 @@ pub struct TypedInterners {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
interners: TypedInterners,
|
||||
interners: Mutex<TypedInterners>,
|
||||
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
||||
}
|
||||
impl Interner {
|
||||
pub fn new_master() -> Self { Self::default() }
|
||||
pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) -> Self {
|
||||
Self {
|
||||
master: Some(Box::new(req)),
|
||||
interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() },
|
||||
}
|
||||
Self { master: Some(Box::new(req)), interners: Mutex::default() }
|
||||
}
|
||||
pub async fn intern<T: Interned>(
|
||||
&mut self,
|
||||
t: &(impl Internable<Interned = T> + ?Sized),
|
||||
) -> Tok<T> {
|
||||
/// 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 job = format!("{t:?} in {}", if self.master.is_some() { "replica" } else { "master" });
|
||||
eprintln!("Interning {job}");
|
||||
let typed = T::bimap(&mut self.interners);
|
||||
let mut g = self.interners.lock().await;
|
||||
let typed = T::bimap(&mut g);
|
||||
if let Some(tok) = typed.by_value(&data) {
|
||||
return tok;
|
||||
}
|
||||
let marker = match &mut self.master {
|
||||
let marker = match &self.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 self.interners).insert(tok.clone());
|
||||
T::bimap(&mut g).insert(tok.clone());
|
||||
eprintln!("Interned {job}");
|
||||
tok
|
||||
}
|
||||
async fn deintern<M: InternMarker>(&mut self, marker: M) -> Tok<M::Interned> {
|
||||
if let Some(tok) = M::Interned::bimap(&mut self.interners).by_marker(marker) {
|
||||
/// Extern an identifier; query the data it represents if not known locally
|
||||
async fn ex<M: InternMarker>(&self, marker: M) -> Tok<M::Interned> {
|
||||
if let Some(tok) = M::Interned::bimap(&mut *self.interners.lock().await).by_marker(marker) {
|
||||
return tok;
|
||||
}
|
||||
let master = self.master.as_mut().expect("ID not in local interner and this is master");
|
||||
let token = marker.resolve(&**master).await;
|
||||
M::Interned::bimap(&mut self.interners).insert(token.clone());
|
||||
assert!(self.master.is_some(), "ID not in local interner and this is master");
|
||||
let token = marker.resolve(self).await;
|
||||
M::Interned::bimap(&mut *self.interners.lock().await).insert(token.clone());
|
||||
token
|
||||
}
|
||||
pub fn sweep_replica(&mut self) -> api::Retained {
|
||||
pub async fn sweep_replica(&self) -> api::Retained {
|
||||
assert!(self.master.is_some(), "Not a replica");
|
||||
api::Retained {
|
||||
strings: self.interners.strings.sweep_replica(),
|
||||
vecs: self.interners.vecs.sweep_replica(),
|
||||
}
|
||||
let mut g = self.interners.lock().await;
|
||||
api::Retained { strings: g.strings.sweep_replica(), vecs: g.vecs.sweep_replica() }
|
||||
}
|
||||
pub fn sweep_master(&mut self, retained: api::Retained) {
|
||||
pub async fn sweep_master(&self, retained: api::Retained) {
|
||||
assert!(self.master.is_none(), "Not master");
|
||||
self.interners.strings.sweep_master(retained.strings.into_iter().collect());
|
||||
self.interners.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||
let mut g = self.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.master.is_none())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,11 +293,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_i() {
|
||||
let _: Tok<String> = spin_on(intern!(str: "foo"));
|
||||
let _: Tok<Vec<Tok<String>>> = spin_on(intern!([Tok<String>]: &[
|
||||
spin_on(intern!(str: "bar")),
|
||||
spin_on(intern!(str: "baz"))
|
||||
]));
|
||||
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"))]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -6,9 +6,9 @@ use std::ops::Range;
|
||||
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::name::Sym;
|
||||
use crate::{api, intern, match_mapping, sym};
|
||||
use crate::{api, match_mapping, sym};
|
||||
|
||||
trait_set! {
|
||||
pub trait GetSrc = FnMut(&Sym) -> Tok<String>;
|
||||
@@ -36,12 +36,12 @@ impl Pos {
|
||||
other => format!("{other:?}"),
|
||||
}
|
||||
}
|
||||
pub async fn from_api(api: &api::Location) -> Self {
|
||||
pub async fn from_api(api: &api::Location, i: &Interner) -> Self {
|
||||
match_mapping!(api, api::Location => Pos {
|
||||
None, Inherit, SlotTarget,
|
||||
Range(r.clone()),
|
||||
Gen(cgi => CodeGenInfo::from_api(cgi).await),
|
||||
SourceRange(sr => SourceRange::from_api(sr).await)
|
||||
Gen(cgi => CodeGenInfo::from_api(cgi, i).await),
|
||||
SourceRange(sr => SourceRange::from_api(sr, i).await)
|
||||
})
|
||||
}
|
||||
pub fn to_api(&self) -> api::Location {
|
||||
@@ -67,7 +67,7 @@ impl SourceRange {
|
||||
}
|
||||
/// Create a dud [SourceRange] for testing. Its value is unspecified and
|
||||
/// volatile.
|
||||
pub async fn mock() -> Self { Self { range: 0..1, path: sym!(test).await } }
|
||||
pub async fn mock(i: &Interner) -> Self { Self { range: 0..1, path: sym!(test; i).await } }
|
||||
/// Path the source text was loaded from
|
||||
pub fn path(&self) -> Sym { self.path.clone() }
|
||||
/// Byte range
|
||||
@@ -92,8 +92,8 @@ impl SourceRange {
|
||||
}
|
||||
}
|
||||
pub fn zw(path: Sym, pos: u32) -> Self { Self { path, range: pos..pos } }
|
||||
async fn from_api(api: &api::SourceRange) -> Self {
|
||||
Self { path: Sym::from_api(api.path).await, range: api.range.clone() }
|
||||
async fn from_api(api: &api::SourceRange, i: &Interner) -> Self {
|
||||
Self { path: Sym::from_api(api.path, i).await, range: api.range.clone() }
|
||||
}
|
||||
fn to_api(&self) -> api::SourceRange {
|
||||
api::SourceRange { path: self.path.to_api(), range: self.range.clone() }
|
||||
@@ -110,19 +110,19 @@ pub struct CodeGenInfo {
|
||||
}
|
||||
impl CodeGenInfo {
|
||||
/// A codegen marker with no user message and parameters
|
||||
pub async fn new_short(generator: Sym) -> Self {
|
||||
Self { generator, details: intern!(str: "").await }
|
||||
pub async fn new_short(generator: Sym, i: &Interner) -> Self {
|
||||
Self { generator, details: i.i("").await }
|
||||
}
|
||||
/// A codegen marker with a user message or parameters
|
||||
pub async fn new_details(generator: Sym, details: impl AsRef<str>) -> Self {
|
||||
Self { generator, details: intern(details.as_ref()).await }
|
||||
pub async fn new_details(generator: Sym, details: impl AsRef<str>, i: &Interner) -> Self {
|
||||
Self { generator, details: i.i(details.as_ref()).await }
|
||||
}
|
||||
/// Syntactic location
|
||||
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
|
||||
pub async fn from_api(api: &api::CodeGenInfo) -> Self {
|
||||
pub async fn from_api(api: &api::CodeGenInfo, i: &Interner) -> Self {
|
||||
Self {
|
||||
generator: Sym::from_api(api.generator).await,
|
||||
details: Tok::from_api(api.details).await,
|
||||
generator: Sym::from_api(api.generator, i).await,
|
||||
details: Tok::from_api(api.details, i).await,
|
||||
}
|
||||
}
|
||||
pub fn to_api(&self) -> api::CodeGenInfo {
|
||||
|
||||
@@ -3,11 +3,12 @@ use std::sync::Arc;
|
||||
|
||||
use async_std::stream;
|
||||
use async_std::sync::Mutex;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::interner::Interner;
|
||||
use crate::location::Pos;
|
||||
use crate::name::Sym;
|
||||
use crate::tree::{Paren, Ph};
|
||||
@@ -20,7 +21,7 @@ impl MacroSlot<'_> {
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
pub trait MacroAtomToApi<A> = FnMut(&A) -> api::MacroToken;
|
||||
pub trait MacroAtomToApi<A> = for<'a> FnMut(&'a A) -> LocalBoxFuture<'a, api::MacroToken>;
|
||||
pub trait MacroAtomFromApi<'a, A> = FnMut(&api::Atom) -> MTok<'a, A>;
|
||||
}
|
||||
|
||||
@@ -33,14 +34,18 @@ impl<'a, A> MTree<'a, A> {
|
||||
pub(crate) async fn from_api(
|
||||
api: &api::MacroTree,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
i: &Interner,
|
||||
) -> Self {
|
||||
Self {
|
||||
pos: Pos::from_api(&api.location).await,
|
||||
tok: Arc::new(MTok::from_api(&api.token, do_atom).await),
|
||||
pos: Pos::from_api(&api.location, i).await,
|
||||
tok: Arc::new(MTok::from_api(&api.token, do_atom, i).await),
|
||||
}
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroTree {
|
||||
api::MacroTree { location: self.pos.to_api(), token: self.tok.to_api(do_atom) }
|
||||
pub(crate) async fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroTree {
|
||||
api::MacroTree {
|
||||
location: self.pos.to_api(),
|
||||
token: self.tok.to_api(do_atom).boxed_local().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,29 +67,30 @@ impl<'a, A> MTok<'a, A> {
|
||||
pub(crate) async fn from_api(
|
||||
api: &api::MacroToken,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
i: &Interner,
|
||||
) -> Self {
|
||||
match_mapping!(&api, api::MacroToken => MTok::<'a, A> {
|
||||
Lambda(x => mtreev_from_api(x, do_atom).await, b => mtreev_from_api(b, do_atom).await),
|
||||
Name(t => Sym::from_api(*t).await),
|
||||
Lambda(x => mtreev_from_api(x, do_atom, i).await, b => mtreev_from_api(b, do_atom, i).await),
|
||||
Name(t => Sym::from_api(*t, i).await),
|
||||
Slot(tk => MacroSlot(*tk, PhantomData)),
|
||||
S(p.clone(), b => mtreev_from_api(b, do_atom).await),
|
||||
Ph(ph => Ph::from_api(ph).await),
|
||||
S(p.clone(), b => mtreev_from_api(b, do_atom, i).await),
|
||||
Ph(ph => Ph::from_api(ph, i).await),
|
||||
} {
|
||||
api::MacroToken::Atom(a) => do_atom(a)
|
||||
})
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroToken {
|
||||
fn sink(n: &Never) -> api::MacroToken { match *n {} }
|
||||
pub(crate) async fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroToken {
|
||||
fn sink<T>(n: &Never) -> LocalBoxFuture<'_, T> { match *n {} }
|
||||
match_mapping!(&self, MTok => api::MacroToken {
|
||||
Lambda(x => mtreev_to_api(x, do_atom), b => mtreev_to_api(b, do_atom)),
|
||||
Lambda(x => mtreev_to_api(x, do_atom).await, b => mtreev_to_api(b, do_atom).await),
|
||||
Name(t.tok().to_api()),
|
||||
Ph(ph.to_api()),
|
||||
S(p.clone(), b => mtreev_to_api(b, do_atom)),
|
||||
S(p.clone(), b => mtreev_to_api(b, do_atom).await),
|
||||
Slot(tk.0.clone()),
|
||||
} {
|
||||
MTok::Ref(r) => r.to_api(&mut sink),
|
||||
MTok::Done(t) => t.to_api(do_atom),
|
||||
MTok::Atom(a) => do_atom(a),
|
||||
MTok::Ref(r) => r.to_api(&mut sink).boxed_local().await,
|
||||
MTok::Done(t) => t.to_api(do_atom).boxed_local().await,
|
||||
MTok::Atom(a) => do_atom(a).await,
|
||||
})
|
||||
}
|
||||
pub fn at(self, pos: Pos) -> MTree<'a, A> { MTree { pos, tok: Arc::new(self) } }
|
||||
@@ -93,17 +99,24 @@ impl<'a, A> MTok<'a, A> {
|
||||
pub async fn mtreev_from_api<'a, 'b, A>(
|
||||
api: impl IntoIterator<Item = &'b api::MacroTree>,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
i: &Interner,
|
||||
) -> Vec<MTree<'a, A>> {
|
||||
let do_atom_lk = Mutex::new(do_atom);
|
||||
stream::from_iter(api)
|
||||
.then(|api| async { MTree::from_api(api, &mut *do_atom_lk.lock().await).boxed_local().await })
|
||||
.then(|api| async {
|
||||
MTree::from_api(api, &mut *do_atom_lk.lock().await, i).boxed_local().await
|
||||
})
|
||||
.collect()
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn mtreev_to_api<'a: 'b, 'b, A: 'b>(
|
||||
pub async fn mtreev_to_api<'a: 'b, 'b, A: 'b>(
|
||||
v: impl IntoIterator<Item = &'b MTree<'a, A>>,
|
||||
do_atom: &mut impl MacroAtomToApi<A>,
|
||||
) -> Vec<api::MacroTree> {
|
||||
v.into_iter().map(|t| t.to_api(do_atom)).collect_vec()
|
||||
let mut out = Vec::new();
|
||||
for t in v {
|
||||
out.push(t.to_api(do_atom).await);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/// match_mapping!(self, ThisType => OtherType {
|
||||
/// EmptyVariant,
|
||||
/// TupleVariant(foo => intern(foo), bar.clone()),
|
||||
/// StructVariant{ a.to_api(), b => b.}
|
||||
/// StructVariant{ a.to_api(), b }
|
||||
/// })
|
||||
/// ```
|
||||
#[macro_export]
|
||||
@@ -69,6 +69,9 @@ macro_rules! match_mapping {
|
||||
$($prefix)::* :: $variant { $($names),* }
|
||||
};
|
||||
(@PAT_MUNCH $ctx:tt $names:tt $(,)? ) => { match_mapping!($ctx $names) };
|
||||
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@PAT_MUNCH $ctx ($($names)* $name) $($tail)*)
|
||||
};
|
||||
(@PAT_MUNCH $ctx:tt ($($names:ident)*) * $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@PAT_MUNCH $ctx ($($names)* $name) $($tail)*)
|
||||
};
|
||||
@@ -94,6 +97,9 @@ macro_rules! match_mapping {
|
||||
(@VAL $prefix:tt { $($fields:tt)* }) => {
|
||||
match_mapping!(@VAL_MUNCH ({} $prefix) () $($fields)* , )
|
||||
};
|
||||
(@VAL_MUNCH $ctx:tt ($($prefix:tt)*) $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@VAL_MUNCH $ctx ($($prefix)* ($name ($name)) ) $($tail)*)
|
||||
};
|
||||
(@VAL_MUNCH $ctx:tt ($($prefix:tt)*) * $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@VAL_MUNCH $ctx ($($prefix)* ($name (* $name)) ) $($tail)*)
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ use itertools::Itertools;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::interner::{InternMarker, Tok, intern};
|
||||
use crate::interner::{InternMarker, Interner, Tok};
|
||||
|
||||
trait_set! {
|
||||
/// Traits that all name iterators should implement
|
||||
@@ -174,8 +174,8 @@ impl VPath {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Partition the string by `::` namespace separators
|
||||
pub async fn parse(s: &str) -> Self {
|
||||
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(intern)).await })
|
||||
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 })
|
||||
}
|
||||
/// Walk over the segments
|
||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||
@@ -195,14 +195,15 @@ impl VPath {
|
||||
}
|
||||
|
||||
/// Convert a fs path to a vpath
|
||||
pub async fn from_path(path: &Path, ext: &str) -> Option<(Self, bool)> {
|
||||
async fn to_vpath(p: &Path) -> Option<VPath> {
|
||||
let tok_opt_v = join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(intern)))).await;
|
||||
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;
|
||||
tok_opt_v.into_iter().collect::<Option<_>>().map(VPath)
|
||||
}
|
||||
match path.extension().map(|s| s.to_str()) {
|
||||
Some(Some(s)) if s == ext => Some((to_vpath(&path.with_extension("")).await?, true)),
|
||||
None => Some((to_vpath(path).await?, false)),
|
||||
Some(Some(s)) if s == ext => Some((to_vpath(&path.with_extension(""), i).await?, true)),
|
||||
None => Some((to_vpath(path, i).await?, false)),
|
||||
Some(_) => None,
|
||||
}
|
||||
}
|
||||
@@ -259,8 +260,11 @@ impl VName {
|
||||
let data: Vec<_> = items.into_iter().collect();
|
||||
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
|
||||
}
|
||||
pub async fn deintern(name: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
|
||||
Self::new(join_all(name.into_iter().map(Tok::from_api)).await)
|
||||
pub async fn deintern(
|
||||
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)
|
||||
}
|
||||
/// Unwrap the enclosed vector
|
||||
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
|
||||
@@ -270,7 +274,7 @@ impl VName {
|
||||
/// must never be empty.
|
||||
pub fn vec_mut(&mut self) -> &mut Vec<Tok<String>> { &mut self.0 }
|
||||
/// Intern the name and return a [Sym]
|
||||
pub async fn to_sym(&self) -> Sym { Sym(intern(&self.0[..]).await) }
|
||||
pub async fn to_sym(&self, i: &Interner) -> Sym { Sym(i.i(&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() }
|
||||
/// Prepend the segments to this name
|
||||
@@ -284,8 +288,12 @@ impl VName {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Read a `::` separated namespaced name
|
||||
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s).await) }
|
||||
pub async fn literal(s: &'static str) -> Self { Self::parse(s).await.expect("empty literal !?") }
|
||||
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
|
||||
Self::new(VPath::parse(s, i).await)
|
||||
}
|
||||
pub async fn literal(s: &'static str, i: &Interner) -> Self {
|
||||
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() }
|
||||
}
|
||||
@@ -341,13 +349,16 @@ pub struct Sym(Tok<Vec<Tok<String>>>);
|
||||
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>>) -> Result<Self, EmptyNameError> {
|
||||
pub async fn new(
|
||||
v: impl IntoIterator<Item = Tok<String>>,
|
||||
i: &Interner,
|
||||
) -> Result<Self, EmptyNameError> {
|
||||
let items = v.into_iter().collect_vec();
|
||||
Self::from_tok(intern(&items[..]).await)
|
||||
Self::from_tok(i.i(&items).await)
|
||||
}
|
||||
/// Read a `::` separated namespaced name.
|
||||
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(intern(&VName::parse(s).await?.into_vec()[..]).await))
|
||||
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(i.i(&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> {
|
||||
@@ -359,8 +370,8 @@ impl Sym {
|
||||
pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() }
|
||||
/// Extern the sym for editing
|
||||
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
|
||||
pub async fn from_api(marker: api::TStrv) -> Sym {
|
||||
Self::from_tok(Tok::from_api(marker).await).expect("Empty sequence found for serialized Sym")
|
||||
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 fn to_api(&self) -> api::TStrv { self.tok().to_api() }
|
||||
}
|
||||
@@ -439,11 +450,11 @@ impl NameLike for VName {}
|
||||
/// cloning the token.
|
||||
#[macro_export]
|
||||
macro_rules! sym {
|
||||
($seg1:tt $( :: $seg:tt)*) => { async {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||
$crate::name::Sym::from_tok(
|
||||
$crate::intern!([$crate::interner::Tok<String>]: &[
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )*
|
||||
$i.i(&[
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )*
|
||||
])
|
||||
.await
|
||||
).unwrap()
|
||||
@@ -457,10 +468,10 @@ macro_rules! sym {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vname {
|
||||
($seg1:tt $( :: $seg:tt)*) => { async {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||
$crate::name::VName::new([
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )*
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )*
|
||||
]).unwrap()
|
||||
} };
|
||||
}
|
||||
@@ -470,10 +481,10 @@ macro_rules! vname {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vpath {
|
||||
($seg1:tt $( :: $seg:tt)+) => { async {
|
||||
($seg1:tt $( :: $seg:tt)+ ; $i:expr) => { async {
|
||||
$crate::name::VPath(vec![
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )+
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )+
|
||||
])
|
||||
} };
|
||||
() => {
|
||||
@@ -481,46 +492,6 @@ macro_rules! vpath {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a &[PathSlice] literal.
|
||||
///
|
||||
/// The components are interned much like in [sym]
|
||||
#[macro_export]
|
||||
macro_rules! with_path_slice {
|
||||
(@UNIT $tt:tt) => { () };
|
||||
($seg1:tt $( :: $seg:tt)* in $expr:expr) => { {
|
||||
use std::future::Future;
|
||||
use std::ops::Deref as _;
|
||||
use std::pin::Pin;
|
||||
|
||||
const fn count_helper<const N: usize>(_: [(); N]) -> usize { N }
|
||||
|
||||
type Output = [Tok<String>; const {
|
||||
count_helper([() $(, $crate::with_path_slice!(@UNIT $seg))*])
|
||||
}];
|
||||
type InternFuture = Pin<Box<dyn Future<Output = Output>>>;
|
||||
thread_local! {
|
||||
static VALUE: Pin<std::rc::Rc<async_once_cell::Lazy<Output, InternFuture>>> =
|
||||
std::rc::Rc::pin(async_once_cell::Lazy::new(Box::pin(async {
|
||||
[
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )+
|
||||
]
|
||||
})));
|
||||
}
|
||||
VALUE.with(|v| $crate::clone!(v; async move {
|
||||
let expr = $expr;
|
||||
let result = v.as_ref().await;
|
||||
let ps: &PathSlice = $crate::name::PathSlice::new(&result.deref()[..]);
|
||||
(expr)(ps).await
|
||||
}))
|
||||
|
||||
} };
|
||||
($expr:expr) => {
|
||||
let expr = $expr;
|
||||
(expr)($crate::name::PathSlice::new(&[]))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::borrow::Borrow;
|
||||
@@ -528,13 +499,14 @@ mod test {
|
||||
use test_executors::spin_on;
|
||||
|
||||
use super::{PathSlice, Sym, VName};
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::name::VPath;
|
||||
|
||||
#[test]
|
||||
fn recur() {
|
||||
spin_on(async {
|
||||
let myname = vname!(foo::bar).await;
|
||||
let i = Interner::new_master();
|
||||
let myname = vname!(foo::bar; i).await;
|
||||
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||
let _borrowed_pathslice: &PathSlice = myname.borrow();
|
||||
let _deref_pathslice: &PathSlice = &myname;
|
||||
@@ -545,25 +517,19 @@ mod test {
|
||||
#[test]
|
||||
fn literals() {
|
||||
spin_on(async {
|
||||
let i = Interner::new_master();
|
||||
assert_eq!(
|
||||
sym!(foo::bar::baz).await,
|
||||
Sym::new([intern("foo").await, intern("bar").await, intern("baz").await]).await.unwrap()
|
||||
sym!(foo::bar::baz; i).await,
|
||||
Sym::new([i.i("foo").await, i.i("bar").await, i.i("baz").await], &i).await.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vname!(foo::bar::baz).await,
|
||||
VName::new([intern("foo").await, intern("bar").await, intern("baz").await]).unwrap()
|
||||
vname!(foo::bar::baz; i).await,
|
||||
VName::new([i.i("foo").await, i.i("bar").await, i.i("baz").await]).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vpath!(foo::bar::baz).await,
|
||||
VPath::new([intern("foo").await, intern("bar").await, intern("baz").await])
|
||||
vpath!(foo::bar::baz; i).await,
|
||||
VPath::new([i.i("foo").await, i.i("bar").await, i.i("baz").await])
|
||||
);
|
||||
with_path_slice!(foo::bar::baz in |val| async move {
|
||||
assert_eq!(
|
||||
val,
|
||||
PathSlice::new(&[intern("foo").await, intern("bar").await, intern("baz").await])
|
||||
);
|
||||
})
|
||||
.await
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use ordered_float::NotNan;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use crate::error::{OrcErr, mk_err};
|
||||
use crate::intern;
|
||||
use crate::interner::Interner;
|
||||
use crate::location::Pos;
|
||||
|
||||
/// A number, either floating point or unsigned int, parsed by Orchid.
|
||||
@@ -63,9 +63,9 @@ pub struct NumError {
|
||||
pub kind: NumErrorKind,
|
||||
}
|
||||
|
||||
pub async fn num_to_err(NumError { kind, range }: NumError, offset: u32) -> OrcErr {
|
||||
pub async fn num_to_err(NumError { kind, range }: NumError, offset: u32, i: &Interner) -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "Failed to parse number").await,
|
||||
i.i("Failed to parse number").await,
|
||||
match kind {
|
||||
NumErrorKind::NaN => "NaN emerged during parsing",
|
||||
NumErrorKind::InvalidDigit => "non-digit character encountered",
|
||||
|
||||
@@ -4,12 +4,12 @@ use std::ops::{Deref, Range};
|
||||
use futures::future::join_all;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::api;
|
||||
use crate::error::{OrcRes, Reporter, mk_err, mk_errv};
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::interner::{Internable, Interned, Interner, Tok};
|
||||
use crate::location::Pos;
|
||||
use crate::name::VPath;
|
||||
use crate::tree::{AtomRepr, ExtraTok, Paren, TokTree, Token};
|
||||
use crate::{api, intern};
|
||||
|
||||
pub fn name_start(c: char) -> bool { c.is_alphabetic() || c == '_' }
|
||||
pub fn name_char(c: char) -> bool { name_start(c) || c.is_numeric() }
|
||||
@@ -20,15 +20,24 @@ pub fn unrep_space(c: char) -> bool { c.is_whitespace() && !"\r\n".contains(c) }
|
||||
pub struct Snippet<'a, 'b, A: AtomRepr, X: ExtraTok> {
|
||||
prev: &'a TokTree<'b, A, X>,
|
||||
cur: &'a [TokTree<'b, A, X>],
|
||||
interner: &'a Interner,
|
||||
}
|
||||
impl<'a, 'b, A: AtomRepr, X: ExtraTok> Snippet<'a, 'b, A, X> {
|
||||
pub fn new(prev: &'a TokTree<'b, A, X>, cur: &'a [TokTree<'b, A, X>]) -> Self {
|
||||
Self { prev, cur }
|
||||
pub fn new(
|
||||
prev: &'a TokTree<'b, A, X>,
|
||||
cur: &'a [TokTree<'b, A, X>],
|
||||
interner: &'a Interner,
|
||||
) -> Self {
|
||||
Self { prev, cur, interner }
|
||||
}
|
||||
pub async fn i<T: Interned>(&self, arg: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
|
||||
self.interner.i(arg).await
|
||||
}
|
||||
pub fn split_at(self, pos: u32) -> (Self, Self) {
|
||||
let fst = Self { prev: self.prev, cur: &self.cur[..pos as usize] };
|
||||
let Self { prev, cur, interner } = self;
|
||||
let fst = Self { prev, cur: &cur[..pos as usize], interner };
|
||||
let new_prev = if pos == 0 { self.prev } else { &self.cur[pos as usize - 1] };
|
||||
let snd = Self { prev: new_prev, cur: &self.cur[pos as usize..] };
|
||||
let snd = Self { prev: new_prev, cur: &self.cur[pos as usize..], interner };
|
||||
(fst, snd)
|
||||
}
|
||||
pub fn find_idx(self, mut f: impl FnMut(&Token<'b, A, X>) -> bool) -> Option<u32> {
|
||||
@@ -101,8 +110,8 @@ impl Comment {
|
||||
pub fn to_api(&self) -> api::Comment {
|
||||
api::Comment { location: self.pos.to_api(), text: self.text.to_api() }
|
||||
}
|
||||
pub async fn from_api(api: &api::Comment) -> Self {
|
||||
Self { pos: Pos::from_api(&api.location).await, text: Tok::from_api(api.text).await }
|
||||
pub async fn from_api(api: &api::Comment, i: &Interner) -> Self {
|
||||
Self { pos: Pos::from_api(&api.location, i).await, text: Tok::from_api(api.text, i).await }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +133,7 @@ pub async fn line_items<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
let comments = join_all(comments.drain(..).chain(cmts.cur).map(|t| async {
|
||||
match &t.tok {
|
||||
Token::Comment(c) =>
|
||||
Comment { text: intern(&**c).await, pos: Pos::Range(t.range.clone()) },
|
||||
Comment { text: tail.i(&**c).await, pos: Pos::Range(t.range.clone()) },
|
||||
_ => unreachable!("All are comments checked above"),
|
||||
}
|
||||
}))
|
||||
@@ -141,18 +150,17 @@ pub async fn try_pop_no_fluff<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
) -> ParseRes<'a, 'b, &'a TokTree<'b, A, X>, A, X> {
|
||||
match snip.skip_fluff().pop_front() {
|
||||
Some((output, tail)) => Ok(Parsed { output, tail }),
|
||||
None =>
|
||||
Err(mk_errv(intern!(str: "Unexpected end").await, "Pattern ends abruptly", [Pos::Range(
|
||||
snip.pos(),
|
||||
)
|
||||
.into()])),
|
||||
None => Err(mk_errv(snip.i("Unexpected end").await, "Pattern ends abruptly", [Pos::Range(
|
||||
snip.pos(),
|
||||
)
|
||||
.into()])),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn expect_end(snip: Snippet<'_, '_, impl AtomRepr, impl ExtraTok>) -> OrcRes<()> {
|
||||
match snip.skip_fluff().get(0) {
|
||||
Some(surplus) => Err(mk_errv(
|
||||
intern!(str: "Extra code after end of line").await,
|
||||
snip.i("Extra code after end of line").await,
|
||||
"Code found after the end of the line",
|
||||
[Pos::Range(surplus.range.clone()).into()],
|
||||
)),
|
||||
@@ -168,7 +176,7 @@ pub async fn expect_tok<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
match &head.tok {
|
||||
Token::Name(n) if *n == tok => Ok(Parsed { output: (), tail }),
|
||||
t => Err(mk_errv(
|
||||
intern!(str: "Expected specific keyword").await,
|
||||
snip.i("Expected specific keyword").await,
|
||||
format!("Expected {tok} but found {t}"),
|
||||
[Pos::Range(head.range.clone()).into()],
|
||||
)),
|
||||
@@ -192,11 +200,11 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
ctx: &impl Reporter,
|
||||
tail: Snippet<'a, 'b, A, X>,
|
||||
) -> ParseRes<'a, 'b, Vec<(Vec<Tok<String>>, Option<Tok<String>>, Pos)>, A, X> {
|
||||
let comma = intern!(str: ",").await;
|
||||
let globstar = intern!(str: "*").await;
|
||||
let comma = tail.i(",").await;
|
||||
let globstar = tail.i("*").await;
|
||||
let Some((name, tail)) = tail.skip_fluff().pop_front() else {
|
||||
return Err(mk_errv(
|
||||
intern!(str: "Expected name").await,
|
||||
tail.i("Expected name").await,
|
||||
"Expected a name, a list of names, or a globstar.",
|
||||
[Pos::Range(tail.pos()).into()],
|
||||
));
|
||||
@@ -204,10 +212,9 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
if let Some((Token::NS, tail)) = tail.skip_fluff().pop_front().map(|(tt, s)| (&tt.tok, s)) {
|
||||
let n = match &name.tok {
|
||||
Token::Name(n) if n.starts_with(name_start) => Ok(n),
|
||||
_ =>
|
||||
Err(mk_err(intern!(str: "Unexpected name prefix").await, "Only names can precede ::", [
|
||||
Pos::Range(name.range.clone()).into(),
|
||||
])),
|
||||
_ => Err(mk_err(tail.i("Unexpected name prefix").await, "Only names can precede ::", [
|
||||
Pos::Range(name.range.clone()).into(),
|
||||
])),
|
||||
};
|
||||
match (Box::pin(rec(ctx, tail)).await, n) {
|
||||
(Err(ev), n) => Err(ev.extended(n.err())),
|
||||
@@ -227,7 +234,7 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
n if *n == globstar => None,
|
||||
n if n.starts_with(op_char) => {
|
||||
return Err(mk_errv(
|
||||
intern!(str: "Unescaped operator in multiname").await,
|
||||
tail.i("Unescaped operator in multiname").await,
|
||||
"Operators in multinames should be enclosed in []",
|
||||
[Pos::Range(name.range.clone()).into()],
|
||||
));
|
||||
@@ -244,7 +251,7 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
ok.push((vec![], Some(n.clone()), Pos::Range(tt.range.clone()))),
|
||||
Token::BR | Token::Comment(_) => (),
|
||||
_ => ctx.report(mk_err(
|
||||
intern!(str: "Non-operator in escapement in multiname").await,
|
||||
tail.i("Non-operator in escapement in multiname").await,
|
||||
"In multinames, [] functions as a literal name list reserved for operators",
|
||||
[Pos::Range(name.range.clone()).into()],
|
||||
)),
|
||||
@@ -254,14 +261,14 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
},
|
||||
Token::S(Paren::Round, b) => {
|
||||
let mut ok = Vec::new();
|
||||
let body = Snippet::new(name, b);
|
||||
let body = Snippet::new(name, b, tail.interner);
|
||||
for csent in body.split(|n| matches!(n, Token::Name(n) if *n == comma)) {
|
||||
match Box::pin(rec(ctx, csent)).await {
|
||||
Err(e) => ctx.report(e),
|
||||
Ok(Parsed { output, tail }) => match tail.get(0) {
|
||||
None => ok.extend(output),
|
||||
Some(t) => ctx.report(mk_err(
|
||||
intern!(str: "Unexpected token in multiname group").await,
|
||||
tail.i("Unexpected token in multiname group").await,
|
||||
"Unexpected token. Likely missing a :: or , or wanted [] instead of ()",
|
||||
[Pos::Range(t.range.clone()).into()],
|
||||
)),
|
||||
@@ -272,7 +279,7 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
},
|
||||
t => {
|
||||
return Err(mk_errv(
|
||||
intern!(str: "Unrecognized name end").await,
|
||||
tail.i("Unrecognized name end").await,
|
||||
format!("Names cannot end with {t} tokens"),
|
||||
[Pos::Range(name.range.clone()).into()],
|
||||
));
|
||||
|
||||
@@ -38,7 +38,11 @@ fn get_id(message: &[u8]) -> (u64, &[u8]) {
|
||||
}
|
||||
|
||||
pub trait ReqHandlish {
|
||||
fn defer_drop(&self, val: impl Any + 'static);
|
||||
fn defer_drop(&self, val: impl Any + 'static)
|
||||
where Self: Sized {
|
||||
self.defer_drop_objsafe(Box::new(val));
|
||||
}
|
||||
fn defer_drop_objsafe(&self, val: Box<dyn Any>);
|
||||
}
|
||||
|
||||
#[derive(destructure)]
|
||||
@@ -77,7 +81,7 @@ impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
|
||||
}
|
||||
}
|
||||
impl<MS: MsgSet> ReqHandlish for RequestHandle<'_, MS> {
|
||||
fn defer_drop(&self, val: impl Any) { self.defer_drop.borrow_mut().push(Box::new(val)) }
|
||||
fn defer_drop_objsafe(&self, val: Box<dyn Any>) { self.defer_drop.borrow_mut().push(val); }
|
||||
}
|
||||
impl<MS: MsgSet> Drop for RequestHandle<'_, MS> {
|
||||
fn drop(&mut self) {
|
||||
@@ -212,6 +216,7 @@ impl<T: MsgSet> Clone for ReqNot<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_std::sync::Mutex;
|
||||
@@ -270,8 +275,8 @@ mod test {
|
||||
#[test]
|
||||
fn request() {
|
||||
spin_on(async {
|
||||
let receiver = Arc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
|
||||
let sender = Arc::new(ReqNot::<TestMsgSet>::new(
|
||||
let receiver = Rc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
|
||||
let sender = Rc::new(ReqNot::<TestMsgSet>::new(
|
||||
clone!(receiver; move |d, _| clone!(receiver; Box::pin(async move {
|
||||
receiver.lock().await.as_ref().unwrap().receive(d).await
|
||||
}))),
|
||||
|
||||
@@ -9,14 +9,15 @@ use std::sync::Arc;
|
||||
pub use api::PhKind;
|
||||
use async_std::stream;
|
||||
use async_std::sync::Mutex;
|
||||
use futures::StreamExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use ordered_float::NotNan;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::error::OrcErrv;
|
||||
use crate::interner::Tok;
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::location::Pos;
|
||||
use crate::name::PathSlice;
|
||||
use crate::parse::Snippet;
|
||||
@@ -26,6 +27,8 @@ use crate::{api, match_mapping};
|
||||
trait_set! {
|
||||
pub trait RecurCB<'a, A: AtomRepr, X: ExtraTok> = Fn(TokTree<'a, A, X>) -> TokTree<'a, A, X>;
|
||||
pub trait ExtraTok = Display + Clone + fmt::Debug;
|
||||
pub trait RefDoExtra<X> =
|
||||
for<'b> FnMut(&'b X, Range<u32>) -> LocalBoxFuture<'b, api::TokenTree>;
|
||||
}
|
||||
|
||||
pub fn recur<'a, A: AtomRepr, X: ExtraTok>(
|
||||
@@ -72,41 +75,38 @@ pub struct TokTree<'a, A: AtomRepr, X: ExtraTok> {
|
||||
pub tok: Token<'a, A, X>,
|
||||
pub range: Range<u32>,
|
||||
}
|
||||
impl<'a, A: AtomRepr, X: ExtraTok> TokTree<'a, A, X> {
|
||||
pub async fn from_api(tt: &api::TokenTree, ctx: &mut A::Ctx) -> Self {
|
||||
let tok = match_mapping!(&tt.token, api::Token => Token::<'a, A, X> {
|
||||
impl<'b, A: AtomRepr, X: ExtraTok> TokTree<'b, A, X> {
|
||||
pub async fn from_api(tt: &api::TokenTree, ctx: &mut A::Ctx, i: &Interner) -> Self {
|
||||
let tok = match_mapping!(&tt.token, api::Token => Token::<'b, A, X> {
|
||||
BR, NS,
|
||||
Atom(a => A::from_api(a, Pos::Range(tt.range.clone()), ctx)),
|
||||
Bottom(e => OrcErrv::from_api(e).await),
|
||||
LambdaHead(arg => ttv_from_api(arg, ctx).await),
|
||||
Name(n => Tok::from_api(*n).await),
|
||||
S(*par, b => ttv_from_api(b, ctx).await),
|
||||
Bottom(e => OrcErrv::from_api(e, i).await),
|
||||
LambdaHead(arg => ttv_from_api(arg, ctx, i).await),
|
||||
Name(n => Tok::from_api(*n, i).await),
|
||||
S(*par, b => ttv_from_api(b, ctx, i).await),
|
||||
Comment(c.clone()),
|
||||
Slot(id => TokHandle::new(*id)),
|
||||
Ph(ph => Ph::from_api(ph).await),
|
||||
Ph(ph => Ph::from_api(ph, i).await),
|
||||
Macro(*prio)
|
||||
});
|
||||
Self { range: tt.range.clone(), tok }
|
||||
}
|
||||
|
||||
pub fn to_api(
|
||||
&self,
|
||||
do_extra: &mut impl FnMut(&X, Range<u32>) -> api::TokenTree,
|
||||
) -> api::TokenTree {
|
||||
pub async fn to_api(&self, do_extra: &mut impl RefDoExtra<X>) -> api::TokenTree {
|
||||
let token = match_mapping!(&self.tok, Token => api::Token {
|
||||
Atom(a.to_api()),
|
||||
BR,
|
||||
NS,
|
||||
Bottom(e.to_api()),
|
||||
Comment(c.clone()),
|
||||
LambdaHead(arg => ttv_to_api(arg, do_extra)),
|
||||
LambdaHead(arg => ttv_to_api(arg, do_extra).boxed_local().await),
|
||||
Name(n.to_api()),
|
||||
Slot(tt.ticket()),
|
||||
S(*p, b => ttv_to_api(b, do_extra)),
|
||||
S(*p, b => ttv_to_api(b, do_extra).boxed_local().await),
|
||||
Ph(ph.to_api()),
|
||||
Macro(*prio),
|
||||
} {
|
||||
Token::X(x) => return do_extra(x, self.range.clone())
|
||||
Token::X(x) => return do_extra(x, self.range.clone()).await
|
||||
});
|
||||
api::TokenTree { range: self.range.clone(), token }
|
||||
}
|
||||
@@ -137,8 +137,8 @@ impl<'a, A: AtomRepr, X: ExtraTok> TokTree<'a, A, X> {
|
||||
pub fn as_name(&self) -> Option<Tok<String>> {
|
||||
if let Token::Name(n) = &self.tok { Some(n.clone()) } else { None }
|
||||
}
|
||||
pub fn as_s(&self, par: Paren) -> Option<Snippet<'_, 'a, A, X>> {
|
||||
self.tok.as_s(par).map(|slc| Snippet::new(self, slc))
|
||||
pub fn as_s<'a>(&'a self, par: Paren, i: &'a Interner) -> Option<Snippet<'a, 'b, A, X>> {
|
||||
self.tok.as_s(par).map(|slc| Snippet::new(self, slc, i))
|
||||
}
|
||||
pub fn lambda(arg: Vec<Self>, mut body: Vec<Self>) -> Self {
|
||||
let arg_range = ttv_range(&arg);
|
||||
@@ -155,22 +155,27 @@ impl<A: AtomRepr, X: ExtraTok> Display for TokTree<'_, A, X> {
|
||||
pub async fn ttv_from_api<A: AtomRepr, X: ExtraTok>(
|
||||
tokv: impl IntoIterator<Item: Borrow<api::TokenTree>>,
|
||||
ctx: &mut A::Ctx,
|
||||
i: &Interner,
|
||||
) -> Vec<TokTree<'static, A, X>> {
|
||||
let ctx_lk = Mutex::new(ctx);
|
||||
stream::from_iter(tokv.into_iter())
|
||||
.then(|t| async {
|
||||
let t = t;
|
||||
TokTree::<A, X>::from_api(t.borrow(), *ctx_lk.lock().await).await
|
||||
TokTree::<A, X>::from_api(t.borrow(), *ctx_lk.lock().await, i).await
|
||||
})
|
||||
.collect()
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn ttv_to_api<'a, A: AtomRepr, X: ExtraTok>(
|
||||
pub async fn ttv_to_api<'a, A: AtomRepr, X: ExtraTok>(
|
||||
tokv: impl IntoIterator<Item: Borrow<TokTree<'a, A, X>>>,
|
||||
do_extra: &mut impl FnMut(&X, Range<u32>) -> api::TokenTree,
|
||||
do_extra: &mut impl RefDoExtra<X>,
|
||||
) -> Vec<api::TokenTree> {
|
||||
tokv.into_iter().map(|tok| Borrow::<TokTree<A, X>>::borrow(&tok).to_api(do_extra)).collect_vec()
|
||||
let mut output = Vec::new();
|
||||
for tok in tokv {
|
||||
output.push(Borrow::<TokTree<A, X>>::borrow(&tok).to_api(do_extra).await)
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn ttv_into_api<'a, A: AtomRepr, X: ExtraTok>(
|
||||
@@ -307,8 +312,8 @@ pub struct Ph {
|
||||
pub kind: PhKind,
|
||||
}
|
||||
impl Ph {
|
||||
pub async fn from_api(api: &api::Placeholder) -> Self {
|
||||
Self { name: Tok::from_api(api.name).await, kind: api.kind }
|
||||
pub async fn from_api(api: &api::Placeholder, i: &Interner) -> Self {
|
||||
Self { name: Tok::from_api(api.name, i).await, kind: api.kind }
|
||||
}
|
||||
pub fn to_api(&self) -> api::Placeholder {
|
||||
api::Placeholder { name: self.name.to_api(), kind: self.kind }
|
||||
|
||||
Reference in New Issue
Block a user