Updated everything and moved to hard tab indentation

This commit is contained in:
2025-01-08 19:20:34 +01:00
parent 7cdfe7e3c4
commit 52c8d1c95a
100 changed files with 5949 additions and 5998 deletions

View File

@@ -3,27 +3,27 @@ use std::ops::Deref;
use std::sync::Arc;
pub enum ArcCow<'a, T: ?Sized + ToOwned> {
Borrowed(&'a T),
Owned(Arc<T::Owned>),
Borrowed(&'a T),
Owned(Arc<T::Owned>),
}
impl<T: ?Sized + ToOwned> ArcCow<'_, T> {
pub fn owned(value: T::Owned) -> Self { Self::Owned(Arc::new(value)) }
pub fn owned(value: T::Owned) -> Self { Self::Owned(Arc::new(value)) }
}
impl<T: ?Sized + ToOwned> Clone for ArcCow<'_, T> {
fn clone(&self) -> Self {
match self {
Self::Borrowed(r) => Self::Borrowed(r),
Self::Owned(b) => Self::Owned(b.clone()),
}
}
fn clone(&self) -> Self {
match self {
Self::Borrowed(r) => Self::Borrowed(r),
Self::Owned(b) => Self::Owned(b.clone()),
}
}
}
impl<T: ?Sized + ToOwned> Deref for ArcCow<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Borrowed(t) => t,
Self::Owned(b) => b.as_ref().borrow(),
}
}
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Borrowed(t) => t,
Self::Owned(b) => b.as_ref().borrow(),
}
}
}

View File

@@ -8,54 +8,54 @@ use crate::api;
pub type CRange = RangeInclusive<char>;
pub trait ICFilter: fmt::Debug {
fn ranges(&self) -> &[RangeInclusive<char>];
fn ranges(&self) -> &[RangeInclusive<char>];
}
impl ICFilter for [RangeInclusive<char>] {
fn ranges(&self) -> &[RangeInclusive<char>] { self }
fn ranges(&self) -> &[RangeInclusive<char>] { self }
}
impl ICFilter for api::CharFilter {
fn ranges(&self) -> &[RangeInclusive<char>] { &self.0 }
fn ranges(&self) -> &[RangeInclusive<char>] { &self.0 }
}
fn try_merge_char_ranges(left: CRange, right: CRange) -> Result<CRange, (CRange, CRange)> {
match *left.end() as u32 + 1 < *right.start() as u32 {
true => Err((left, right)),
false => Ok(*left.start()..=*right.end()),
}
match *left.end() as u32 + 1 < *right.start() as u32 {
true => Err((left, right)),
false => Ok(*left.start()..=*right.end()),
}
}
/// Process the character ranges to make them adhere to the structural
/// requirements of [CharFilter]
pub fn mk_char_filter(items: impl IntoIterator<Item = CRange>) -> api::CharFilter {
api::CharFilter(
(items.into_iter())
.filter(|r| *r.start() as u32 <= *r.end() as u32)
.sorted_by_key(|r| *r.start() as u32)
.coalesce(try_merge_char_ranges)
.collect_vec(),
)
api::CharFilter(
(items.into_iter())
.filter(|r| *r.start() as u32 <= *r.end() as u32)
.sorted_by_key(|r| *r.start() as u32)
.coalesce(try_merge_char_ranges)
.collect_vec(),
)
}
/// Decide whether a char filter matches a character via binary search
pub fn char_filter_match(cf: &(impl ICFilter + ?Sized), c: char) -> bool {
match cf.ranges().binary_search_by_key(&c, |l| *l.end()) {
Ok(_) => true, // c is the end of a range
Err(i) if i == cf.ranges().len() => false, // all ranges end before c
Err(i) => cf.ranges()[i].contains(&c), /* c between cf.0[i-1]?.end and cf.0[i].end,
* check [i] */
}
match cf.ranges().binary_search_by_key(&c, |l| *l.end()) {
Ok(_) => true, // c is the end of a range
Err(i) if i == cf.ranges().len() => false, // all ranges end before c
Err(i) => cf.ranges()[i].contains(&c), /* c between cf.0[i-1]?.end and cf.0[i].end,
* check [i] */
}
}
/// Merge two char filters into a filter that matches if either of the
/// constituents would match.
pub fn char_filter_union(
l: &(impl ICFilter + ?Sized),
r: &(impl ICFilter + ?Sized),
l: &(impl ICFilter + ?Sized),
r: &(impl ICFilter + ?Sized),
) -> api::CharFilter {
api::CharFilter(
(l.ranges().iter().merge_by(r.ranges(), |l, r| l.start() <= r.start()))
.cloned()
.coalesce(try_merge_char_ranges)
.collect_vec(),
)
api::CharFilter(
(l.ranges().iter().merge_by(r.ranges(), |l, r| l.start() <= r.start()))
.cloned()
.coalesce(try_merge_char_ranges)
.collect_vec(),
)
}

View File

@@ -6,19 +6,19 @@ use never::Never;
/// variety of types for different purposes. Very broadly, if the operation
/// succeeds, the result should represent _both_ inputs.
pub trait Combine: Sized {
/// Information about the failure
type Error;
/// Information about the failure
type Error;
/// Merge two values into a value that represents both, if this is possible.
fn combine(self, other: Self) -> Result<Self, Self::Error>;
/// Merge two values into a value that represents both, if this is possible.
fn combine(self, other: Self) -> Result<Self, Self::Error>;
}
impl Combine for Never {
type Error = Never;
fn combine(self, _: Self) -> Result<Self, Self::Error> { match self {} }
type Error = Never;
fn combine(self, _: Self) -> Result<Self, Self::Error> { match self {} }
}
impl Combine for () {
type Error = Never;
fn combine(self, (): Self) -> Result<Self, Self::Error> { Ok(()) }
type Error = Never;
fn combine(self, (): Self) -> Result<Self, Self::Error> { Ok(()) }
}

View File

@@ -12,158 +12,158 @@ use crate::location::Pos;
/// processing got stuck, a command that is likely to be incorrect
#[derive(Clone, Debug)]
pub struct ErrPos {
/// The suspected origin
pub position: Pos,
/// Any information about the role of this origin
pub message: Option<Arc<String>>,
/// The suspected origin
pub position: Pos,
/// Any information about the role of this origin
pub message: Option<Arc<String>>,
}
impl ErrPos {
pub fn new(msg: &str, position: Pos) -> Self {
Self { message: Some(Arc::new(msg.to_string())), position }
}
fn from_api(api: &api::ErrLocation) -> Self {
Self {
message: Some(api.message.clone()).filter(|s| !s.is_empty()),
position: Pos::from_api(&api.location),
}
}
fn to_api(&self) -> api::ErrLocation {
api::ErrLocation {
message: self.message.clone().unwrap_or_default(),
location: self.position.to_api(),
}
}
pub fn new(msg: &str, position: Pos) -> Self {
Self { message: Some(Arc::new(msg.to_string())), position }
}
fn from_api(api: &api::ErrLocation) -> Self {
Self {
message: Some(api.message.clone()).filter(|s| !s.is_empty()),
position: Pos::from_api(&api.location),
}
}
fn to_api(&self) -> api::ErrLocation {
api::ErrLocation {
message: self.message.clone().unwrap_or_default(),
location: self.position.to_api(),
}
}
}
impl From<Pos> for ErrPos {
fn from(origin: Pos) -> Self { Self { position: origin, message: None } }
fn from(origin: Pos) -> Self { Self { position: origin, message: None } }
}
#[derive(Clone, Debug)]
pub struct OrcErr {
pub description: Tok<String>,
pub message: Arc<String>,
pub positions: Vec<ErrPos>,
pub description: Tok<String>,
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(),
}
}
fn from_api(api: &api::OrcError) -> Self {
Self {
description: Tok::from_api(api.description),
message: api.message.clone(),
positions: api.locations.iter().map(ErrPos::from_api).collect(),
}
}
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(),
}
}
fn from_api(api: &api::OrcError) -> Self {
Self {
description: Tok::from_api(api.description),
message: api.message.clone(),
positions: api.locations.iter().map(ErrPos::from_api).collect(),
}
}
}
impl Eq for OrcErr {}
impl PartialEq for OrcErr {
fn eq(&self, other: &Self) -> bool { self.description == other.description }
fn eq(&self, other: &Self) -> bool { self.description == other.description }
}
impl From<OrcErr> for Vec<OrcErr> {
fn from(value: OrcErr) -> Self { vec![value] }
fn from(value: OrcErr) -> Self { vec![value] }
}
impl fmt::Display for OrcErr {
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)
}
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)
}
}
#[derive(Clone, Debug)]
pub struct EmptyErrv;
impl fmt::Display for EmptyErrv {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "OrcErrv must not be empty")
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "OrcErrv must not be empty")
}
}
#[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 fn from_api<'a>(api: impl IntoIterator<Item = &'a api::OrcError>) -> Self {
Self(api.into_iter().map(OrcErr::from_api).collect())
}
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 fn from_api<'a>(api: impl IntoIterator<Item = &'a api::OrcError>) -> Self {
Self(api.into_iter().map(OrcErr::from_api).collect())
}
}
impl From<OrcErr> for OrcErrv {
fn from(value: OrcErr) -> Self { Self(vec![value]) }
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()) }
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) }
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())
}
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() }
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"))
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.iter().join("\n"))
}
}
pub type OrcRes<T> = Result<T, OrcErrv>;
pub fn mk_err(
description: Tok<String>,
message: impl AsRef<str>,
posv: impl IntoIterator<Item = ErrPos>,
description: Tok<String>,
message: impl AsRef<str>,
posv: impl IntoIterator<Item = ErrPos>,
) -> OrcErr {
OrcErr {
description,
message: Arc::new(message.as_ref().to_string()),
positions: posv.into_iter().collect(),
}
OrcErr {
description,
message: Arc::new(message.as_ref().to_string()),
positions: posv.into_iter().collect(),
}
}
pub fn mk_errv(
description: Tok<String>,
message: impl AsRef<str>,
posv: impl IntoIterator<Item = ErrPos>,
description: Tok<String>,
message: impl AsRef<str>,
posv: impl IntoIterator<Item = ErrPos>,
) -> OrcErrv {
mk_err(description, message, posv).into()
mk_err(description, message, posv).into()
}
pub trait Reporter {
fn report(&self, e: impl Into<OrcErrv>);
fn report(&self, e: impl Into<OrcErrv>);
}

View File

@@ -1,67 +1,67 @@
//! Multiple-listener-single-delivery event system.
use std::mem;
use std::sync::mpsc::{self, sync_channel};
use std::sync::Mutex;
use std::sync::mpsc::{self, sync_channel};
struct Reply<T, U> {
resub: bool,
outcome: Result<U, T>,
resub: bool,
outcome: Result<U, T>,
}
struct Listener<T, E> {
sink: mpsc::SyncSender<T>,
source: mpsc::Receiver<Reply<T, E>>,
sink: mpsc::SyncSender<T>,
source: mpsc::Receiver<Reply<T, E>>,
}
pub struct Event<T, U> {
listeners: Mutex<Vec<Listener<T, U>>>,
listeners: Mutex<Vec<Listener<T, U>>>,
}
impl<T, U> Event<T, U> {
pub const fn new() -> Self { Self { listeners: Mutex::new(Vec::new()) } }
pub const fn new() -> Self { Self { listeners: Mutex::new(Vec::new()) } }
pub fn dispatch(&self, mut ev: T) -> Option<U> {
let mut listeners = self.listeners.lock().unwrap();
let mut alt_list = Vec::with_capacity(listeners.len());
mem::swap(&mut *listeners, &mut alt_list);
let mut items = alt_list.into_iter();
while let Some(l) = items.next() {
l.sink.send(ev).unwrap();
let Reply { resub, outcome } = l.source.recv().unwrap();
if resub {
listeners.push(l);
}
match outcome {
Ok(res) => {
listeners.extend(items);
return Some(res);
},
Err(next) => {
ev = next;
},
}
}
None
}
pub fn dispatch(&self, mut ev: T) -> Option<U> {
let mut listeners = self.listeners.lock().unwrap();
let mut alt_list = Vec::with_capacity(listeners.len());
mem::swap(&mut *listeners, &mut alt_list);
let mut items = alt_list.into_iter();
while let Some(l) = items.next() {
l.sink.send(ev).unwrap();
let Reply { resub, outcome } = l.source.recv().unwrap();
if resub {
listeners.push(l);
}
match outcome {
Ok(res) => {
listeners.extend(items);
return Some(res);
},
Err(next) => {
ev = next;
},
}
}
None
}
pub fn get_one<V>(&self, mut filter: impl FnMut(&T) -> bool, f: impl FnOnce(T) -> (U, V)) -> V {
let mut listeners = self.listeners.lock().unwrap();
let (sink, request) = sync_channel(0);
let (response, source) = sync_channel(0);
listeners.push(Listener { sink, source });
mem::drop(listeners);
loop {
let t = request.recv().unwrap();
if filter(&t) {
let (u, v) = f(t);
response.send(Reply { resub: false, outcome: Ok(u) }).unwrap();
return v;
}
response.send(Reply { resub: true, outcome: Err(t) }).unwrap();
}
}
pub fn get_one<V>(&self, mut filter: impl FnMut(&T) -> bool, f: impl FnOnce(T) -> (U, V)) -> V {
let mut listeners = self.listeners.lock().unwrap();
let (sink, request) = sync_channel(0);
let (response, source) = sync_channel(0);
listeners.push(Listener { sink, source });
mem::drop(listeners);
loop {
let t = request.recv().unwrap();
if filter(&t) {
let (u, v) = f(t);
response.send(Reply { resub: false, outcome: Ok(u) }).unwrap();
return v;
}
response.send(Reply { resub: true, outcome: Err(t) }).unwrap();
}
}
}
impl<T, U> Default for Event<T, U> {
fn default() -> Self { Self::new() }
fn default() -> Self { Self::new() }
}

View File

@@ -6,45 +6,45 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
use hashbrown::HashMap;
pub struct IdStore<T> {
table: OnceLock<Mutex<HashMap<NonZeroU64, T>>>,
id: AtomicU64,
table: OnceLock<Mutex<HashMap<NonZeroU64, T>>>,
id: AtomicU64,
}
impl<T> IdStore<T> {
pub const fn new() -> Self { Self { table: OnceLock::new(), id: AtomicU64::new(1) } }
pub fn add(&self, t: T) -> IdRecord<'_, T> {
let tbl = self.table.get_or_init(Mutex::default);
let mut tbl_g = tbl.lock().unwrap();
let id: NonZeroU64 = self.id.fetch_add(1, Ordering::Relaxed).try_into().unwrap();
assert!(tbl_g.insert(id, t).is_none(), "atom ID wraparound");
IdRecord(id, tbl_g)
}
pub fn get(&self, id: impl Into<NonZeroU64>) -> Option<IdRecord<'_, T>> {
let tbl = self.table.get_or_init(Mutex::default);
let tbl_g = tbl.lock().unwrap();
let id64 = id.into();
if tbl_g.contains_key(&id64) { Some(IdRecord(id64, tbl_g)) } else { None }
}
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub fn len(&self) -> usize { self.table.get().map(|t| t.lock().unwrap().len()).unwrap_or(0) }
pub const fn new() -> Self { Self { table: OnceLock::new(), id: AtomicU64::new(1) } }
pub fn add(&self, t: T) -> IdRecord<'_, T> {
let tbl = self.table.get_or_init(Mutex::default);
let mut tbl_g = tbl.lock().unwrap();
let id: NonZeroU64 = self.id.fetch_add(1, Ordering::Relaxed).try_into().unwrap();
assert!(tbl_g.insert(id, t).is_none(), "atom ID wraparound");
IdRecord(id, tbl_g)
}
pub fn get(&self, id: impl Into<NonZeroU64>) -> Option<IdRecord<'_, T>> {
let tbl = self.table.get_or_init(Mutex::default);
let tbl_g = tbl.lock().unwrap();
let id64 = id.into();
if tbl_g.contains_key(&id64) { Some(IdRecord(id64, tbl_g)) } else { None }
}
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub fn len(&self) -> usize { self.table.get().map(|t| t.lock().unwrap().len()).unwrap_or(0) }
}
impl<T> Default for IdStore<T> {
fn default() -> Self { Self::new() }
fn default() -> Self { Self::new() }
}
pub struct IdRecord<'a, T>(NonZeroU64, MutexGuard<'a, HashMap<NonZeroU64, T>>);
impl<T> IdRecord<'_, T> {
pub fn id(&self) -> NonZeroU64 { self.0 }
pub fn remove(mut self) -> T { self.1.remove(&self.0).unwrap() }
pub fn id(&self) -> NonZeroU64 { self.0 }
pub fn remove(mut self) -> T { self.1.remove(&self.0).unwrap() }
}
impl<T> Deref for IdRecord<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.1.get(&self.0).expect("Existence checked on construction")
}
type Target = T;
fn deref(&self) -> &Self::Target {
self.1.get(&self.0).expect("Existence checked on construction")
}
}
impl<T> DerefMut for IdRecord<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.1.get_mut(&self.0).expect("Existence checked on construction")
}
fn deref_mut(&mut self) -> &mut Self::Target {
self.1.get_mut(&self.0).expect("Existence checked on construction")
}
}

View File

@@ -2,7 +2,7 @@ use std::borrow::Borrow;
use std::hash::BuildHasher as _;
use std::num::NonZeroU64;
use std::ops::{Deref, DerefMut};
use std::sync::{atomic, Arc, Mutex, MutexGuard};
use std::sync::{Arc, Mutex, MutexGuard, atomic};
use std::{fmt, hash, mem};
use hashbrown::{HashMap, HashSet};
@@ -19,148 +19,149 @@ struct ForceSized<T>(T);
#[derive(Clone)]
pub struct Tok<T: Interned> {
data: Arc<T>,
marker: ForceSized<T::Marker>,
data: Arc<T>,
marker: ForceSized<T::Marker>,
}
impl<T: Interned> Tok<T> {
pub fn new(data: Arc<T>, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } }
pub fn to_api(&self) -> T::Marker { self.marker.0 }
pub fn from_api<M>(marker: M) -> Self where M: InternMarker<Interned = T> {
deintern(marker)
}
pub fn arc(&self) -> Arc<T> { self.data.clone() }
pub fn new(data: Arc<T>, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } }
pub fn to_api(&self) -> T::Marker { self.marker.0 }
pub fn from_api<M>(marker: M) -> Self
where M: InternMarker<Interned = T> {
deintern(marker)
}
pub fn arc(&self) -> Arc<T> { self.data.clone() }
}
impl<T: Interned> Deref for Tok<T> {
type Target = T;
type Target = T;
fn deref(&self) -> &Self::Target { 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()) }
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)) }
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() }
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) }
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)
}
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 fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Token({} -> {:?})", self.to_api().get_id(), self.data.as_ref())
}
}
impl<T: Interned + Encode> Encode for Tok<T> {
fn encode<W: std::io::Write + ?Sized>(&self, write: &mut W) { self.data.encode(write) }
fn encode<W: std::io::Write + ?Sized>(&self, write: &mut W) { self.data.encode(write) }
}
impl<T: Interned + Decode> Decode for Tok<T> {
fn decode<R: std::io::Read + ?Sized>(read: &mut R) -> Self { intern(&T::decode(read)) }
fn decode<R: std::io::Read + ?Sized>(read: &mut R) -> Self { intern(&T::decode(read)) }
}
pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable<Interned = Self> {
type Marker: InternMarker<Interned = Self> + Sized;
fn intern(
self: Arc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker;
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
type Marker: InternMarker<Interned = Self> + Sized;
fn intern(
self: Arc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker;
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
}
pub trait Internable: fmt::Debug {
type Interned: Interned;
fn get_owned(&self) -> Arc<Self::Interned>;
type Interned: Interned;
fn get_owned(&self) -> Arc<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),
) -> Tok<Self::Interned>;
fn get_id(self) -> NonZeroU64;
fn from_id(id: NonZeroU64) -> Self;
type Interned: Interned<Marker = Self>;
fn resolve(
self,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Tok<Self::Interned>;
fn get_id(self) -> NonZeroU64;
fn from_id(id: NonZeroU64) -> Self;
}
impl Interned for String {
type Marker = api::TStr;
fn intern(
self: Arc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker {
req.request(api::InternStr(self))
}
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.strings }
type Marker = api::TStr;
fn intern(
self: Arc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker {
req.request(api::InternStr(self))
}
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.strings }
}
impl InternMarker for api::TStr {
type Interned = String;
fn resolve(
self,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Tok<Self::Interned> {
Tok::new(req.request(api::ExternStr(self)), self)
}
fn get_id(self) -> NonZeroU64 { self.0 }
fn from_id(id: NonZeroU64) -> Self { Self(id) }
type Interned = String;
fn resolve(
self,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Tok<Self::Interned> {
Tok::new(req.request(api::ExternStr(self)), 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()) }
type Interned = String;
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
}
impl Internable for String {
type Interned = String;
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
type Interned = String;
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
}
impl Interned for Vec<Tok<String>> {
type Marker = api::TStrv;
fn intern(
self: Arc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker {
req.request(api::InternStrv(Arc::new(self.iter().map(|t| t.to_api()).collect())))
}
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.vecs }
type Marker = api::TStrv;
fn intern(
self: Arc<Self>,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Self::Marker {
req.request(api::InternStrv(Arc::new(self.iter().map(|t| t.to_api()).collect())))
}
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.vecs }
}
impl InternMarker for api::TStrv {
type Interned = Vec<Tok<String>>;
fn resolve(
self,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Tok<Self::Interned> {
let data =
Arc::new(req.request(api::ExternStrv(self)).iter().map(|m| deintern(*m)).collect_vec());
Tok::new(data, self)
}
fn get_id(self) -> NonZeroU64 { self.0 }
fn from_id(id: NonZeroU64) -> Self { Self(id) }
type Interned = Vec<Tok<String>>;
fn resolve(
self,
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
) -> Tok<Self::Interned> {
let data =
Arc::new(req.request(api::ExternStrv(self)).iter().map(|m| deintern(*m)).collect_vec());
Tok::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()) }
type Interned = Vec<Tok<String>>;
fn get_owned(&self) -> Arc<Self::Interned> { Arc::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()) }
type Interned = Vec<Tok<String>>;
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
}
impl Internable for Vec<api::TStr> {
type Interned = Vec<Tok<String>>;
fn get_owned(&self) -> Arc<Self::Interned> {
Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
}
type Interned = Vec<Tok<String>>;
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>>;
fn get_owned(&self) -> Arc<Self::Interned> {
Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
}
type Interned = Vec<Tok<String>>;
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.
@@ -168,138 +169,138 @@ 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 mut bimap = Bimap::default();
bimap.insert(tok.clone());
assert_eq!(Arc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
let tok = Tok::new(Arc::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");
}
pub struct Bimap<T: Interned> {
intern: HashMap<Arc<T>, Tok<T>>,
by_id: HashMap<T::Marker, Tok<T>>,
intern: HashMap<Arc<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 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_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 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, _| Arc::strong_count(k) == BASE_RC)
.map(|(_, v)| {
self.by_id.remove(&v.to_api());
v.to_api()
})
.collect()
}
pub fn sweep_replica(&mut self) -> Vec<T::Marker> {
(self.intern)
.extract_if(|k, _| Arc::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 < Arc::strong_count(k) || retained.contains(&v.to_api()))
}
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()))
}
}
impl<T: Interned> Default for Bimap<T> {
fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() } }
fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() } }
}
pub trait UpComm {
fn up<R: Request>(&self, req: R) -> R::Response;
fn up<R: Request>(&self, req: R) -> R::Response;
}
#[derive(Default)]
pub struct TypedInterners {
strings: Bimap<String>,
vecs: Bimap<Vec<Tok<String>>>,
strings: Bimap<String>,
vecs: Bimap<Vec<Tok<String>>>,
}
#[derive(Default)]
pub struct Interner {
interners: TypedInterners,
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
interners: TypedInterners,
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
}
static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1);
static INTERNER: Mutex<Option<Interner>> = Mutex::new(None);
pub fn interner() -> impl DerefMut<Target = Interner> {
struct G(MutexGuard<'static, Option<Interner>>);
impl Deref for G {
type Target = Interner;
fn deref(&self) -> &Self::Target { self.0.as_ref().expect("Guard pre-initialized") }
}
impl DerefMut for G {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut().expect("Guard pre-iniitialized")
}
}
let mut g = INTERNER.lock().unwrap();
g.get_or_insert_with(Interner::default);
G(g)
struct G(MutexGuard<'static, Option<Interner>>);
impl Deref for G {
type Target = Interner;
fn deref(&self) -> &Self::Target { self.0.as_ref().expect("Guard pre-initialized") }
}
impl DerefMut for G {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut().expect("Guard pre-iniitialized")
}
}
let mut g = INTERNER.lock().unwrap();
g.get_or_insert_with(Interner::default);
G(g)
}
pub fn init_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) {
let mut g = INTERNER.lock().unwrap();
assert!(g.is_none(), "Attempted to initialize replica interner after first use");
*g = Some(Interner {
master: Some(Box::new(req)),
interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() },
})
let mut g = INTERNER.lock().unwrap();
assert!(g.is_none(), "Attempted to initialize replica interner after first use");
*g = Some(Interner {
master: Some(Box::new(req)),
interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() },
})
}
pub fn intern<T: Interned>(t: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
let data = t.get_owned();
let mut g = interner();
let job = format!("{t:?} in {}", if g.master.is_some() { "replica" } else { "master" });
eprintln!("Interning {job}");
let typed = T::bimap(&mut g.interners);
if let Some(tok) = typed.by_value(&data) {
return tok;
}
let marker = match &mut g.master {
Some(c) => data.clone().intern(&**c),
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.interners).insert(tok.clone());
mem::drop(g);
eprintln!("Interned {job}");
tok
let data = t.get_owned();
let mut g = interner();
let job = format!("{t:?} in {}", if g.master.is_some() { "replica" } else { "master" });
eprintln!("Interning {job}");
let typed = T::bimap(&mut g.interners);
if let Some(tok) = typed.by_value(&data) {
return tok;
}
let marker = match &mut g.master {
Some(c) => data.clone().intern(&**c),
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.interners).insert(tok.clone());
mem::drop(g);
eprintln!("Interned {job}");
tok
}
fn deintern<M: InternMarker>(marker: M) -> Tok<M::Interned> {
let mut g = interner();
if let Some(tok) = M::Interned::bimap(&mut g.interners).by_marker(marker) {
return tok;
}
let master = g.master.as_mut().expect("ID not in local interner and this is master");
let token = marker.resolve(&**master);
M::Interned::bimap(&mut g.interners).insert(token.clone());
token
let mut g = interner();
if let Some(tok) = M::Interned::bimap(&mut g.interners).by_marker(marker) {
return tok;
}
let master = g.master.as_mut().expect("ID not in local interner and this is master");
let token = marker.resolve(&**master);
M::Interned::bimap(&mut g.interners).insert(token.clone());
token
}
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();
into.strings = into.strings.iter().chain(&from.strings).copied().unique().collect();
into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect();
}
pub fn sweep_replica() -> api::Retained {
let mut g = interner();
assert!(g.master.is_some(), "Not a replica");
api::Retained {
strings: g.interners.strings.sweep_replica(),
vecs: g.interners.vecs.sweep_replica(),
}
let mut g = interner();
assert!(g.master.is_some(), "Not a replica");
api::Retained {
strings: g.interners.strings.sweep_replica(),
vecs: g.interners.vecs.sweep_replica(),
}
}
/// Create a thread-local token instance and copy it. This ensures that the
@@ -308,47 +309,47 @@ pub fn sweep_replica() -> api::Retained {
/// expression (i.e. a literal).
#[macro_export]
macro_rules! intern {
($ty:ty : $expr:expr) => {{
thread_local! {
static VALUE: $crate::interner::Tok<<$ty as $crate::interner::Internable>::Interned>
= $crate::interner::intern::<
<$ty as $crate::interner::Internable>::Interned
>($expr as &$ty);
}
VALUE.with(|v| v.clone())
}};
($ty:ty : $expr:expr) => {{
thread_local! {
static VALUE: $crate::interner::Tok<<$ty as $crate::interner::Internable>::Interned>
= $crate::interner::intern::<
<$ty as $crate::interner::Internable>::Interned
>($expr as &$ty);
}
VALUE.with(|v| v.clone())
}};
}
pub fn sweep_master(retained: api::Retained) {
let mut g = interner();
assert!(g.master.is_none(), "Not master");
g.interners.strings.sweep_master(retained.strings.into_iter().collect());
g.interners.vecs.sweep_master(retained.vecs.into_iter().collect());
let mut g = interner();
assert!(g.master.is_none(), "Not master");
g.interners.strings.sweep_master(retained.strings.into_iter().collect());
g.interners.vecs.sweep_master(retained.vecs.into_iter().collect());
}
#[cfg(test)]
mod test {
use std::num::NonZero;
use std::num::NonZero;
use orchid_api_traits::{enc_vec, Decode};
use orchid_api_traits::{Decode, enc_vec};
use super::*;
use crate::api;
use super::*;
use crate::api;
#[test]
fn test_i() {
let _: Tok<String> = intern!(str: "foo");
let _: Tok<Vec<Tok<String>>> = intern!([Tok<String>]: &[
intern!(str: "bar"),
intern!(str: "baz")
]);
}
#[test]
fn test_i() {
let _: Tok<String> = intern!(str: "foo");
let _: Tok<Vec<Tok<String>>> = intern!([Tok<String>]: &[
intern!(str: "bar"),
intern!(str: "baz")
]);
}
#[test]
fn test_coding() {
let coded = api::TStr(NonZero::new(3u64).unwrap());
let mut enc = &enc_vec(&coded)[..];
api::TStr::decode(&mut enc);
assert_eq!(enc, [], "Did not consume all of {enc:?}")
}
#[test]
fn test_coding() {
let coded = api::TStr(NonZero::new(3u64).unwrap());
let mut enc = &enc_vec(&coded)[..];
api::TStr::decode(&mut enc);
assert_eq!(enc, [], "Did not consume all of {enc:?}")
}
}

View File

@@ -8,38 +8,38 @@ use never::Never;
/// Combine two hashmaps via an infallible value merger. See also
/// [try_join_maps]
pub fn join_maps<K: Eq + Hash, V>(
left: HashMap<K, V>,
right: HashMap<K, V>,
mut merge: impl FnMut(&K, V, V) -> V,
left: HashMap<K, V>,
right: HashMap<K, V>,
mut merge: impl FnMut(&K, V, V) -> V,
) -> HashMap<K, V> {
let (val, ev) = try_join_maps::<K, V, Never>(left, right, |k, l, r| Ok(merge(k, l, r)));
if let Some(e) = ev.first() {
match *e {}
}
val
let (val, ev) = try_join_maps::<K, V, Never>(left, right, |k, l, r| Ok(merge(k, l, r)));
if let Some(e) = ev.first() {
match *e {}
}
val
}
/// Combine two hashmaps via a fallible value merger. See also [join_maps]
pub fn try_join_maps<K: Eq + Hash, V, E>(
left: HashMap<K, V>,
mut right: HashMap<K, V>,
mut merge: impl FnMut(&K, V, V) -> Result<V, E>,
left: HashMap<K, V>,
mut right: HashMap<K, V>,
mut merge: impl FnMut(&K, V, V) -> Result<V, E>,
) -> (HashMap<K, V>, Vec<E>) {
let mut mixed = HashMap::with_capacity(left.len() + right.len());
let mut errors = Vec::new();
for (key, lval) in left {
let val = match right.remove(&key) {
None => lval,
Some(rval) => match merge(&key, lval, rval) {
Ok(v) => v,
Err(e) => {
errors.push(e);
continue;
},
},
};
mixed.insert(key, val);
}
mixed.extend(right);
(mixed, errors)
let mut mixed = HashMap::with_capacity(left.len() + right.len());
let mut errors = Vec::new();
for (key, lval) in left {
let val = match right.remove(&key) {
None => lval,
Some(rval) => match merge(&key, lval, rval) {
Ok(v) => v,
Err(e) => {
errors.push(e);
continue;
},
},
};
mixed.insert(key, val);
}
mixed.extend(right);
(mixed, errors)
}

View File

@@ -1,18 +1,20 @@
use orchid_api as api;
pub mod box_cow;
pub mod boxed_iter;
pub mod char_filter;
pub mod clone;
pub mod combine;
pub mod event;
pub mod msg;
pub mod box_cow;
pub mod char_filter;
pub mod error;
pub mod event;
pub mod id_store;
pub mod interner;
pub mod join;
pub mod location;
pub mod logging;
pub mod macros;
mod match_mapping;
pub mod msg;
pub mod name;
pub mod number;
pub mod parse;
@@ -22,5 +24,3 @@ pub mod sequence;
pub mod side;
pub mod tokens;
pub mod tree;
pub mod macros;
mod match_mapping;

View File

@@ -1,148 +1,142 @@
//! Structures that show where code or semantic elements came from
use crate::match_mapping;
use std::fmt;
use std::hash::Hash;
use std::ops::Range;
use trait_set::trait_set;
use crate::interner::{intern, Tok};
use crate::interner::{Tok, intern};
use crate::name::Sym;
use crate::{api, intern, sym};
use crate::{api, intern, match_mapping, sym};
trait_set! {
pub trait GetSrc = FnMut(&Sym) -> Tok<String>;
pub trait GetSrc = FnMut(&Sym) -> Tok<String>;
}
#[derive(Debug, Clone)]
pub enum Pos {
None,
SlotTarget,
/// Used in functions to denote the generated code that carries on the
/// location of the call. Not allowed in the const tree.
Inherit,
Gen(CodeGenInfo),
/// Range and file
SourceRange(SourceRange),
/// Range only, file implied. Most notably used by parsers
Range(Range<u32>),
None,
SlotTarget,
/// Used in functions to denote the generated code that carries on the
/// location of the call. Not allowed in the const tree.
Inherit,
Gen(CodeGenInfo),
/// Range and file
SourceRange(SourceRange),
/// Range only, file implied. Most notably used by parsers
Range(Range<u32>),
}
impl Pos {
pub fn pretty_print(&self, get_src: &mut impl GetSrc) -> String {
match self {
Self::Gen(g) => g.to_string(),
Self::SourceRange(sr) => sr.pretty_print(&get_src(&sr.path)),
// Can't pretty print partial and meta-location
other => format!("{other:?}"),
}
}
pub fn from_api(api: &api::Location) -> Self {
match_mapping!(api, api::Location => Pos {
None, Inherit, SlotTarget,
Range(r.clone()),
Gen(cgi => CodeGenInfo::from_api(cgi)),
SourceRange(sr => SourceRange::from_api(sr))
})
}
pub fn to_api(&self) -> api::Location {
match_mapping!(self, Pos => api::Location {
None, Inherit, SlotTarget,
Range(r.clone()),
Gen(cgi.to_api()),
SourceRange(sr.to_api()),
})
}
pub fn pretty_print(&self, get_src: &mut impl GetSrc) -> String {
match self {
Self::Gen(g) => g.to_string(),
Self::SourceRange(sr) => sr.pretty_print(&get_src(&sr.path)),
// Can't pretty print partial and meta-location
other => format!("{other:?}"),
}
}
pub fn from_api(api: &api::Location) -> Self {
match_mapping!(api, api::Location => Pos {
None, Inherit, SlotTarget,
Range(r.clone()),
Gen(cgi => CodeGenInfo::from_api(cgi)),
SourceRange(sr => SourceRange::from_api(sr))
})
}
pub fn to_api(&self) -> api::Location {
match_mapping!(self, Pos => api::Location {
None, Inherit, SlotTarget,
Range(r.clone()),
Gen(cgi.to_api()),
SourceRange(sr.to_api()),
})
}
}
/// Exact source code location. Includes where the code was loaded from, what
/// the original source code was, and a byte range.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SourceRange {
pub(crate) path: Sym,
pub(crate) range: Range<u32>,
pub(crate) path: Sym,
pub(crate) range: Range<u32>,
}
impl SourceRange {
pub fn new(range: &Range<u32>, path: &Sym) -> Self {
Self { range: range.clone(), path: path.clone() }
}
/// Create a dud [SourceRange] for testing. Its value is unspecified and
/// volatile.
pub fn mock() -> Self { Self { range: 0..1, path: sym!(test) } }
/// Path the source text was loaded from
pub fn path(&self) -> Sym { self.path.clone() }
/// Byte range
pub fn range(&self) -> Range<u32> { self.range.clone() }
/// 0-based index of first byte
pub fn start(&self) -> u32 { self.range.start }
/// 0-based index of last byte + 1
pub fn end(&self) -> u32 { self.range.end }
/// Syntactic location
pub fn pos(&self) -> Pos { Pos::SourceRange(self.clone()) }
/// Transform the numeric byte range
pub fn map_range(&self, map: impl FnOnce(Range<u32>) -> Range<u32>) -> Self {
Self { range: map(self.range()), path: self.path() }
}
pub fn pretty_print(&self, src: &str) -> String {
let (sl, sc) = pos2lc(src, self.range.start);
let (el, ec) = pos2lc(src, self.range.end);
match (el == sl, ec <= sc + 1) {
(true, true) => format!("{sl}:{sc}"),
(true, false) => format!("{sl}:{sc}..{ec}"),
(false, _) => format!("{sl}:{sc}..{el}:{ec}"),
}
}
pub fn zw(path: Sym, pos: u32) -> Self {
Self { path, range: pos..pos }
}
fn from_api(api: &api::SourceRange) -> Self {
Self { path: Sym::from_api(api.path), range: api.range.clone() }
}
fn to_api(&self) -> api::SourceRange {
api::SourceRange { path: self.path.to_api(), range: self.range.clone() }
}
pub fn new(range: &Range<u32>, path: &Sym) -> Self {
Self { range: range.clone(), path: path.clone() }
}
/// Create a dud [SourceRange] for testing. Its value is unspecified and
/// volatile.
pub fn mock() -> Self { Self { range: 0..1, path: sym!(test) } }
/// Path the source text was loaded from
pub fn path(&self) -> Sym { self.path.clone() }
/// Byte range
pub fn range(&self) -> Range<u32> { self.range.clone() }
/// 0-based index of first byte
pub fn start(&self) -> u32 { self.range.start }
/// 0-based index of last byte + 1
pub fn end(&self) -> u32 { self.range.end }
/// Syntactic location
pub fn pos(&self) -> Pos { Pos::SourceRange(self.clone()) }
/// Transform the numeric byte range
pub fn map_range(&self, map: impl FnOnce(Range<u32>) -> Range<u32>) -> Self {
Self { range: map(self.range()), path: self.path() }
}
pub fn pretty_print(&self, src: &str) -> String {
let (sl, sc) = pos2lc(src, self.range.start);
let (el, ec) = pos2lc(src, self.range.end);
match (el == sl, ec <= sc + 1) {
(true, true) => format!("{sl}:{sc}"),
(true, false) => format!("{sl}:{sc}..{ec}"),
(false, _) => format!("{sl}:{sc}..{el}:{ec}"),
}
}
pub fn zw(path: Sym, pos: u32) -> Self { Self { path, range: pos..pos } }
fn from_api(api: &api::SourceRange) -> Self {
Self { path: Sym::from_api(api.path), range: api.range.clone() }
}
fn to_api(&self) -> api::SourceRange {
api::SourceRange { path: self.path.to_api(), range: self.range.clone() }
}
}
/// Information about a code generator attached to the generated code
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct CodeGenInfo {
/// formatted like a Rust namespace
pub generator: Sym,
/// Unformatted user message with relevant circumstances and parameters
pub details: Tok<String>,
/// formatted like a Rust namespace
pub generator: Sym,
/// Unformatted user message with relevant circumstances and parameters
pub details: Tok<String>,
}
impl CodeGenInfo {
/// A codegen marker with no user message and parameters
pub fn no_details(generator: Sym) -> Self { Self { generator, details: intern!(str: "") } }
/// A codegen marker with a user message or parameters
pub fn details(generator: Sym, details: impl AsRef<str>) -> Self {
Self { generator, details: intern(details.as_ref()) }
}
/// Syntactic location
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
fn from_api(api: &api::CodeGenInfo) -> Self {
Self {
generator: Sym::from_api(api.generator),
details: Tok::from_api(api.details),
}
}
fn to_api(&self) -> api::CodeGenInfo {
api::CodeGenInfo { generator: self.generator.to_api(), details: self.details.to_api() }
}
/// A codegen marker with no user message and parameters
pub fn no_details(generator: Sym) -> Self { Self { generator, details: intern!(str: "") } }
/// A codegen marker with a user message or parameters
pub fn details(generator: Sym, details: impl AsRef<str>) -> Self {
Self { generator, details: intern(details.as_ref()) }
}
/// Syntactic location
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
fn from_api(api: &api::CodeGenInfo) -> Self {
Self { generator: Sym::from_api(api.generator), details: Tok::from_api(api.details) }
}
fn to_api(&self) -> api::CodeGenInfo {
api::CodeGenInfo { generator: self.generator.to_api(), details: self.details.to_api() }
}
}
impl fmt::Debug for CodeGenInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CodeGenInfo({self})") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CodeGenInfo({self})") }
}
impl fmt::Display for CodeGenInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "generated by {}", self.generator)?;
if !self.details.is_empty() { write!(f, ", details: {}", self.details) } else { write!(f, ".") }
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "generated by {}", self.generator)?;
if !self.details.is_empty() { write!(f, ", details: {}", self.details) } else { write!(f, ".") }
}
}
#[must_use]
fn pos2lc(s: &str, i: u32) -> (u32, u32) {
s.chars()
.take(i.try_into().unwrap())
.fold((1, 1), |(line, col), char| if char == '\n' { (line + 1, 1) } else { (line, col + 1) })
s.chars()
.take(i.try_into().unwrap())
.fold((1, 1), |(line, col), char| if char == '\n' { (line + 1, 1) } else { (line, col + 1) })
}

View File

@@ -1,6 +1,6 @@
use std::fmt::Arguments;
use std::fs::File;
use std::io::{stderr, Write};
use std::io::{Write, stderr};
pub use api::LogStrategy;
use itertools::Itertools;
@@ -10,21 +10,21 @@ use crate::api;
#[derive(Clone)]
pub struct Logger(api::LogStrategy);
impl Logger {
pub fn new(strat: api::LogStrategy) -> Self { Self(strat) }
pub fn log(&self, msg: impl AsRef<str>) { writeln!(self, "{}", msg.as_ref()) }
pub fn strat(&self) -> api::LogStrategy { self.0.clone() }
pub fn log_buf(&self, event: impl AsRef<str>, buf: &[u8]) {
if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) {
writeln!(self, "{}: [{}]", event.as_ref(), buf.iter().map(|b| format!("{b:02x}")).join(" "))
}
}
pub fn write_fmt(&self, fmt: Arguments) {
match &self.0 {
api::LogStrategy::StdErr => stderr().write_fmt(fmt).expect("Could not write to stderr!"),
api::LogStrategy::File(f) => {
let mut file = File::open(f).expect("Could not open logfile");
file.write_fmt(fmt).expect("Could not write to logfile");
},
}
}
pub fn new(strat: api::LogStrategy) -> Self { Self(strat) }
pub fn log(&self, msg: impl AsRef<str>) { writeln!(self, "{}", msg.as_ref()) }
pub fn strat(&self) -> api::LogStrategy { self.0.clone() }
pub fn log_buf(&self, event: impl AsRef<str>, buf: &[u8]) {
if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) {
writeln!(self, "{}: [{}]", event.as_ref(), buf.iter().map(|b| format!("{b:02x}")).join(" "))
}
}
pub fn write_fmt(&self, fmt: Arguments) {
match &self.0 {
api::LogStrategy::StdErr => stderr().write_fmt(fmt).expect("Could not write to stderr!"),
api::LogStrategy::File(f) => {
let mut file = File::open(f).expect("Could not open logfile");
file.write_fmt(fmt).expect("Could not write to logfile");
},
}
}
}

View File

@@ -13,84 +13,84 @@ use crate::{api, match_mapping};
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MacroSlot<'a>(api::MacroTreeId, PhantomData<&'a ()>);
impl MacroSlot<'_> {
pub fn id(self) -> api::MacroTreeId { self.0 }
pub fn id(self) -> api::MacroTreeId { self.0 }
}
trait_set! {
pub trait MacroAtomToApi<A> = FnMut(&A) -> api::MacroToken;
pub trait MacroAtomFromApi<'a, A> = FnMut(&api::Atom) -> MTok<'a, A>;
pub trait MacroAtomToApi<A> = FnMut(&A) -> api::MacroToken;
pub trait MacroAtomFromApi<'a, A> = FnMut(&api::Atom) -> MTok<'a, A>;
}
#[derive(Clone, Debug)]
pub struct MTree<'a, A> {
pub pos: Pos,
pub tok: Arc<MTok<'a, A>>,
pub pos: Pos,
pub tok: Arc<MTok<'a, A>>,
}
impl<'a, A> MTree<'a, A> {
pub(crate) fn from_api(api: &api::MacroTree, do_atom: &mut impl MacroAtomFromApi<'a, A>) -> Self {
Self { pos: Pos::from_api(&api.location), tok: Arc::new(MTok::from_api(&api.token, do_atom)) }
}
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) fn from_api(api: &api::MacroTree, do_atom: &mut impl MacroAtomFromApi<'a, A>) -> Self {
Self { pos: Pos::from_api(&api.location), tok: Arc::new(MTok::from_api(&api.token, do_atom)) }
}
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) }
}
}
#[derive(Clone, Debug)]
pub enum MTok<'a, A> {
S(Paren, Vec<MTree<'a, A>>),
Name(Sym),
Slot(MacroSlot<'a>),
Lambda(Vec<MTree<'a, A>>, Vec<MTree<'a, A>>),
Ph(Ph),
Atom(A),
/// Used in extensions to directly return input
Ref(Arc<MTok<'a, Never>>),
/// Used in the matcher to skip previous macro output which can only go in
/// vectorial placeholders
Done(Arc<MTok<'a, A>>),
S(Paren, Vec<MTree<'a, A>>),
Name(Sym),
Slot(MacroSlot<'a>),
Lambda(Vec<MTree<'a, A>>, Vec<MTree<'a, A>>),
Ph(Ph),
Atom(A),
/// Used in extensions to directly return input
Ref(Arc<MTok<'a, Never>>),
/// Used in the matcher to skip previous macro output which can only go in
/// vectorial placeholders
Done(Arc<MTok<'a, A>>),
}
impl<'a, A> MTok<'a, A> {
pub(crate) fn from_api(
api: &api::MacroToken,
do_atom: &mut impl MacroAtomFromApi<'a, A>,
) -> Self {
match_mapping!(&api, api::MacroToken => MTok::<'a, A> {
Lambda(x => mtreev_from_api(x, do_atom), b => mtreev_from_api(b, do_atom)),
Name(t => Sym::from_api(*t)),
Slot(tk => MacroSlot(*tk, PhantomData)),
S(p.clone(), b => mtreev_from_api(b, do_atom)),
Ph(ph => Ph::from_api(ph)),
} {
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 {} }
match_mapping!(&self, MTok => api::MacroToken {
Lambda(x => mtreev_to_api(x, do_atom), b => mtreev_to_api(b, do_atom)),
Name(t.tok().to_api()),
Ph(ph.to_api()),
S(p.clone(), b => mtreev_to_api(b, do_atom)),
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),
})
}
pub fn at(self, pos: Pos) -> MTree<'a, A> { MTree { pos, tok: Arc::new(self) } }
pub(crate) fn from_api(
api: &api::MacroToken,
do_atom: &mut impl MacroAtomFromApi<'a, A>,
) -> Self {
match_mapping!(&api, api::MacroToken => MTok::<'a, A> {
Lambda(x => mtreev_from_api(x, do_atom), b => mtreev_from_api(b, do_atom)),
Name(t => Sym::from_api(*t)),
Slot(tk => MacroSlot(*tk, PhantomData)),
S(p.clone(), b => mtreev_from_api(b, do_atom)),
Ph(ph => Ph::from_api(ph)),
} {
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 {} }
match_mapping!(&self, MTok => api::MacroToken {
Lambda(x => mtreev_to_api(x, do_atom), b => mtreev_to_api(b, do_atom)),
Name(t.tok().to_api()),
Ph(ph.to_api()),
S(p.clone(), b => mtreev_to_api(b, do_atom)),
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),
})
}
pub fn at(self, pos: Pos) -> MTree<'a, A> { MTree { pos, tok: Arc::new(self) } }
}
pub fn mtreev_from_api<'a, 'b, A>(
api: impl IntoIterator<Item = &'b api::MacroTree>,
do_atom: &mut impl MacroAtomFromApi<'a, A>,
api: impl IntoIterator<Item = &'b api::MacroTree>,
do_atom: &mut impl MacroAtomFromApi<'a, A>,
) -> Vec<MTree<'a, A>> {
api.into_iter().map(|api| MTree::from_api(api, do_atom)).collect_vec()
api.into_iter().map(|api| MTree::from_api(api, do_atom)).collect_vec()
}
pub fn mtreev_to_api<'a: 'b, 'b, A: 'b>(
v: impl IntoIterator<Item = &'b MTree<'a, A>>,
do_atom: &mut impl MacroAtomToApi<A>,
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()
v.into_iter().map(|t| t.to_api(do_atom)).collect_vec()
}

View File

@@ -1,7 +1,7 @@
/// A shorthand for mapping over enums with identical structure. Used for converting between
/// owned enums and the corresponding API enums that only differ in the type of their
/// fields.
///
/// A shorthand for mapping over enums with identical structure. Used for
/// converting between owned enums and the corresponding API enums that only
/// differ in the type of their fields.
///
/// The basic form is
/// ```ignore
/// match_mapping!(self, ThisType => OtherType {
@@ -78,7 +78,7 @@ macro_rules! match_mapping {
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident () $value:expr , $($tail:tt)*) => {
match_mapping!(@PAT_MUNCH $ctx ($($names)* $name) $($tail)*)
};
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident . $($tail:tt)*) => {
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident . $($tail:tt)*) => {
match_mapping!(@PAT_DOT_MUNCH $ctx ($($names)* $name) $($tail)*)
};
(@PAT_DOT_MUNCH $ctx:tt $names:tt , $($tail:tt)*) => {
@@ -122,4 +122,4 @@ macro_rules! match_mapping {
(@VAL_MUNCH ({} ($($prefix:tt)*)) ($( ( $name:ident $($value:tt)* ) )*) ) => {
$($prefix)* { $( $name : $($value)* ),* }
};
}
}

View File

@@ -3,14 +3,14 @@ use std::io;
use orchid_api_traits::{Decode, Encode};
pub fn send_msg(write: &mut impl io::Write, msg: &[u8]) -> io::Result<()> {
u32::try_from(msg.len()).unwrap().encode(write);
write.write_all(msg)?;
write.flush()
u32::try_from(msg.len()).unwrap().encode(write);
write.write_all(msg)?;
write.flush()
}
pub fn recv_msg(read: &mut impl io::Read) -> io::Result<Vec<u8>> {
let len = u32::decode(read);
let mut msg = vec![0u8; len as usize];
read.read_exact(&mut msg)?;
Ok(msg)
let len = u32::decode(read);
let mut msg = vec![0u8; len as usize];
read.read_exact(&mut msg)?;
Ok(msg)
}

View File

@@ -12,11 +12,11 @@ use itertools::Itertools;
use trait_set::trait_set;
use crate::api;
use crate::interner::{intern, InternMarker, Tok};
use crate::interner::{InternMarker, Tok, intern};
trait_set! {
/// Traits that all name iterators should implement
pub trait NameIter = Iterator<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
/// Traits that all name iterators should implement
pub trait NameIter = Iterator<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
}
/// A borrowed name fragment which can be empty. See [VPath] for the owned
@@ -25,129 +25,129 @@ trait_set! {
#[repr(transparent)]
pub struct PathSlice([Tok<String>]);
impl PathSlice {
/// Create a new [PathSlice]
pub fn new(slice: &[Tok<String>]) -> &PathSlice {
// SAFETY: This is ok because PathSlice is #[repr(transparent)]
unsafe { &*(slice as *const [Tok<String>] as *const PathSlice) }
}
/// Convert to an owned name fragment
pub fn to_vpath(&self) -> VPath { VPath(self.0.to_vec()) }
/// Iterate over the tokens
pub fn iter(&self) -> impl NameIter + '_ { self.into_iter() }
/// Iterate over the segments
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
Box::new(self.0.iter().map(|s| s.as_str()))
}
/// Find the longest shared prefix of this name and another sequence
pub fn coprefix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
}
/// Find the longest shared suffix of this name and another sequence
pub fn cosuffix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
}
/// Remove another
pub fn strip_prefix<'a>(&'a self, other: &PathSlice) -> Option<&'a PathSlice> {
let shared = self.coprefix(other).len();
(shared == other.len()).then_some(PathSlice::new(&self[shared..]))
}
/// Number of path segments
pub fn len(&self) -> u16 { self.0.len().try_into().expect("Too long name!") }
pub fn get<I: NameIndex>(&self, index: I) -> Option<&I::Output> { index.get(self) }
/// Whether there are any path segments. In other words, whether this is a
/// valid name
pub fn is_empty(&self) -> bool { self.len() == 0 }
/// Obtain a reference to the held slice. With all indexing traits shadowed,
/// this is better done explicitly
pub fn as_slice(&self) -> &[Tok<String>] { self }
/// Global empty path slice
pub fn empty() -> &'static Self { PathSlice::new(&[]) }
/// Create a new [PathSlice]
pub fn new(slice: &[Tok<String>]) -> &PathSlice {
// SAFETY: This is ok because PathSlice is #[repr(transparent)]
unsafe { &*(slice as *const [Tok<String>] as *const PathSlice) }
}
/// Convert to an owned name fragment
pub fn to_vpath(&self) -> VPath { VPath(self.0.to_vec()) }
/// Iterate over the tokens
pub fn iter(&self) -> impl NameIter + '_ { self.into_iter() }
/// Iterate over the segments
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
Box::new(self.0.iter().map(|s| s.as_str()))
}
/// Find the longest shared prefix of this name and another sequence
pub fn coprefix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
}
/// Find the longest shared suffix of this name and another sequence
pub fn cosuffix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count() as u16]
}
/// Remove another
pub fn strip_prefix<'a>(&'a self, other: &PathSlice) -> Option<&'a PathSlice> {
let shared = self.coprefix(other).len();
(shared == other.len()).then_some(PathSlice::new(&self[shared..]))
}
/// Number of path segments
pub fn len(&self) -> u16 { self.0.len().try_into().expect("Too long name!") }
pub fn get<I: NameIndex>(&self, index: I) -> Option<&I::Output> { index.get(self) }
/// Whether there are any path segments. In other words, whether this is a
/// valid name
pub fn is_empty(&self) -> bool { self.len() == 0 }
/// Obtain a reference to the held slice. With all indexing traits shadowed,
/// this is better done explicitly
pub fn as_slice(&self) -> &[Tok<String>] { self }
/// Global empty path slice
pub fn empty() -> &'static Self { PathSlice::new(&[]) }
}
impl fmt::Debug for PathSlice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
}
impl fmt::Display for PathSlice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
}
impl Borrow<[Tok<String>]> for PathSlice {
fn borrow(&self) -> &[Tok<String>] { &self.0 }
fn borrow(&self) -> &[Tok<String>] { &self.0 }
}
impl<'a> IntoIterator for &'a PathSlice {
type IntoIter = Cloned<slice::Iter<'a, Tok<String>>>;
type Item = Tok<String>;
fn into_iter(self) -> Self::IntoIter { self.0.iter().cloned() }
type IntoIter = Cloned<slice::Iter<'a, Tok<String>>>;
type Item = Tok<String>;
fn into_iter(self) -> Self::IntoIter { self.0.iter().cloned() }
}
pub trait NameIndex {
type Output: ?Sized;
fn get(self, name: &PathSlice) -> Option<&Self::Output>;
type Output: ?Sized;
fn get(self, name: &PathSlice) -> Option<&Self::Output>;
}
impl<T: NameIndex> Index<T> for PathSlice {
type Output = T::Output;
fn index(&self, index: T) -> &Self::Output { index.get(self).expect("Index out of bounds") }
type Output = T::Output;
fn index(&self, index: T) -> &Self::Output { index.get(self).expect("Index out of bounds") }
}
mod idx_impls {
use std::ops;
use std::ops;
use super::{conv_range, NameIndex, PathSlice};
use crate::interner::Tok;
use super::{NameIndex, PathSlice, conv_range};
use crate::interner::Tok;
impl NameIndex for u16 {
type Output = Tok<String>;
fn get(self, name: &PathSlice) -> Option<&Self::Output> { name.0.get(self as usize) }
}
impl NameIndex for u16 {
type Output = Tok<String>;
fn get(self, name: &PathSlice) -> Option<&Self::Output> { name.0.get(self as usize) }
}
impl NameIndex for ops::RangeFull {
type Output = PathSlice;
fn get(self, name: &PathSlice) -> Option<&Self::Output> { Some(name) }
}
impl NameIndex for ops::RangeFull {
type Output = PathSlice;
fn get(self, name: &PathSlice) -> Option<&Self::Output> { Some(name) }
}
macro_rules! impl_range_index_for_pathslice {
($range:ident) => {
impl ops::Index<ops::$range<u16>> for PathSlice {
type Output = Self;
fn index(&self, index: ops::$range<u16>) -> &Self::Output {
Self::new(&self.0[conv_range::<u16, usize>(index)])
}
}
};
}
macro_rules! impl_range_index_for_pathslice {
($range:ident) => {
impl ops::Index<ops::$range<u16>> for PathSlice {
type Output = Self;
fn index(&self, index: ops::$range<u16>) -> &Self::Output {
Self::new(&self.0[conv_range::<u16, usize>(index)])
}
}
};
}
impl_range_index_for_pathslice!(RangeFrom);
impl_range_index_for_pathslice!(RangeTo);
impl_range_index_for_pathslice!(Range);
impl_range_index_for_pathslice!(RangeInclusive);
impl_range_index_for_pathslice!(RangeToInclusive);
impl_range_index_for_pathslice!(RangeFrom);
impl_range_index_for_pathslice!(RangeTo);
impl_range_index_for_pathslice!(Range);
impl_range_index_for_pathslice!(RangeInclusive);
impl_range_index_for_pathslice!(RangeToInclusive);
}
impl Deref for PathSlice {
type Target = [Tok<String>];
type Target = [Tok<String>];
fn deref(&self) -> &Self::Target { &self.0 }
fn deref(&self) -> &Self::Target { &self.0 }
}
impl Borrow<PathSlice> for [Tok<String>] {
fn borrow(&self) -> &PathSlice { PathSlice::new(self) }
fn borrow(&self) -> &PathSlice { PathSlice::new(self) }
}
impl<const N: usize> Borrow<PathSlice> for [Tok<String>; N] {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
}
impl Borrow<PathSlice> for Vec<Tok<String>> {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
}
pub fn conv_bound<T: Into<U> + Clone, U>(bound: Bound<&T>) -> Bound<U> {
match bound {
Bound::Included(i) => Bound::Included(i.clone().into()),
Bound::Excluded(i) => Bound::Excluded(i.clone().into()),
Bound::Unbounded => Bound::Unbounded,
}
match bound {
Bound::Included(i) => Bound::Included(i.clone().into()),
Bound::Excluded(i) => Bound::Excluded(i.clone().into()),
Bound::Unbounded => Bound::Unbounded,
}
}
pub fn conv_range<'a, T: Into<U> + Clone + 'a, U: 'a>(
range: impl RangeBounds<T>,
range: impl RangeBounds<T>,
) -> (Bound<U>, Bound<U>) {
(conv_bound(range.start_bound()), conv_bound(range.end_bound()))
(conv_bound(range.start_bound()), conv_bound(range.end_bound()))
}
/// A token path which may be empty. [VName] is the non-empty,
@@ -155,90 +155,90 @@ pub fn conv_range<'a, T: Into<U> + Clone + 'a, U: 'a>(
#[derive(Clone, Default, Hash, PartialEq, Eq)]
pub struct VPath(pub Vec<Tok<String>>);
impl VPath {
/// Collect segments into a vector
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> 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 {
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 {
Self(self.0.into_iter().chain(items).collect())
}
/// Partition the string by `::` namespace separators
pub fn parse(s: &str) -> Self {
Self(if s.is_empty() { vec![] } else { s.split("::").map(intern).collect() })
}
/// Walk over the segments
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
Box::new(self.0.iter().map(|s| s.as_str()))
}
/// 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_prefix(self, name: Tok<String>) -> 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_suffix(self, name: Tok<String>) -> VName {
VName([name].into_iter().chain(self).collect())
}
/// Collect segments into a vector
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> 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 {
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 {
Self(self.0.into_iter().chain(items).collect())
}
/// Partition the string by `::` namespace separators
pub fn parse(s: &str) -> Self {
Self(if s.is_empty() { vec![] } else { s.split("::").map(intern).collect() })
}
/// Walk over the segments
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
Box::new(self.0.iter().map(|s| s.as_str()))
}
/// 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_prefix(self, name: Tok<String>) -> 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_suffix(self, name: Tok<String>) -> VName {
VName([name].into_iter().chain(self).collect())
}
/// Convert a fs path to a vpath
pub fn from_path(path: &Path) -> Option<(Self, bool)> {
let to_vpath =
|p: &Path| p.iter().map(|c| c.to_str().map(intern)).collect::<Option<_>>().map(VPath);
match path.extension().map(|s| s.to_str()) {
Some(Some("orc")) => Some((to_vpath(&path.with_extension(""))?, true)),
None => Some((to_vpath(path)?, false)),
Some(_) => None,
}
}
/// Convert a fs path to a vpath
pub fn from_path(path: &Path) -> Option<(Self, bool)> {
let to_vpath =
|p: &Path| p.iter().map(|c| c.to_str().map(intern)).collect::<Option<_>>().map(VPath);
match path.extension().map(|s| s.to_str()) {
Some(Some("orc")) => Some((to_vpath(&path.with_extension(""))?, true)),
None => Some((to_vpath(path)?, false)),
Some(_) => None,
}
}
}
impl fmt::Debug for VPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
}
impl fmt::Display for VPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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())
}
fn from_iter<T: IntoIterator<Item = Tok<String>>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
impl IntoIterator for VPath {
type Item = Tok<String>;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
type Item = Tok<String>;
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.borrow() }
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
}
impl Borrow<PathSlice> for VPath {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
}
impl Deref for VPath {
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
}
impl<T> Index<T> for VPath
where PathSlice: Index<T>
{
type Output = <PathSlice as Index<T>>::Output;
type Output = <PathSlice as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &Borrow::<PathSlice>::borrow(self)[index] }
fn index(&self, index: T) -> &Self::Output { &Borrow::<PathSlice>::borrow(self)[index] }
}
/// A mutable representation of a namespaced identifier of at least one segment.
@@ -250,71 +250,71 @@ where PathSlice: Index<T>
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct VName(Vec<Tok<String>>);
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> {
let data: Vec<_> = items.into_iter().collect();
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
}
pub fn deintern(items: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
Self::new(items.into_iter().map(Tok::from_api))
}
/// Unwrap the enclosed vector
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
/// Get a reference to the enclosed vector
pub fn vec(&self) -> &Vec<Tok<String>> { &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 }
/// Intern the name and return a [Sym]
pub fn to_sym(&self) -> Sym { Sym(intern(&self.0[..])) }
/// 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
#[must_use = "This is a pure function"]
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> 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 {
Self(self.0.into_iter().chain(items).collect())
}
/// Read a `::` separated namespaced name
pub fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s)) }
pub fn literal(s: &'static str) -> Self { Self::parse(s).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() }
/// 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> {
let data: Vec<_> = items.into_iter().collect();
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
}
pub fn deintern(items: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
Self::new(items.into_iter().map(Tok::from_api))
}
/// Unwrap the enclosed vector
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
/// Get a reference to the enclosed vector
pub fn vec(&self) -> &Vec<Tok<String>> { &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 }
/// Intern the name and return a [Sym]
pub fn to_sym(&self) -> Sym { Sym(intern(&self.0[..])) }
/// 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
#[must_use = "This is a pure function"]
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> 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 {
Self(self.0.into_iter().chain(items).collect())
}
/// Read a `::` separated namespaced name
pub fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s)) }
pub fn literal(s: &'static str) -> Self { Self::parse(s).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() }
}
impl fmt::Debug for VName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
}
impl fmt::Display for VName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
}
impl IntoIterator for VName {
type Item = Tok<String>;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
type Item = Tok<String>;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
impl<T> Index<T> for VName
where PathSlice: Index<T>
{
type Output = <PathSlice as Index<T>>::Output;
type Output = <PathSlice as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
}
impl Borrow<[Tok<String>]> for VName {
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
}
impl Borrow<PathSlice> for VName {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
}
impl Deref for VName {
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
}
/// Error produced when a non-empty name [VName] or [Sym] is constructed with an
@@ -322,10 +322,10 @@ impl Deref for VName {
#[derive(Debug, Copy, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EmptyNameError;
impl TryFrom<&[Tok<String>]> for VName {
type Error = EmptyNameError;
fn try_from(value: &[Tok<String>]) -> Result<Self, Self::Error> {
Self::new(value.iter().cloned())
}
type Error = EmptyNameError;
fn try_from(value: &[Tok<String>]) -> Result<Self, Self::Error> {
Self::new(value.iter().cloned())
}
}
/// An interned representation of a namespaced identifier.
@@ -336,94 +336,94 @@ impl TryFrom<&[Tok<String>]> for VName {
#[derive(Clone, Hash, PartialEq, Eq)]
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 fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
let items = v.into_iter().collect_vec();
Self::from_tok(intern(&items[..]))
}
/// Read a `::` separated namespaced name.
pub fn parse(s: &str) -> Result<Self, EmptyNameError> {
Ok(Sym(intern(&VName::parse(s)?.into_vec()[..])))
}
/// 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> {
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() }
/// Get a number unique to this name suitable for arbitrary ordering.
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 fn from_api(marker: api::TStrv) -> Sym {
Self::from_tok(Tok::from_api(marker)).expect("Empty sequence found for serialized Sym")
}
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
/// represent this invariant
pub fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
let items = v.into_iter().collect_vec();
Self::from_tok(intern(&items[..]))
}
/// Read a `::` separated namespaced name.
pub fn parse(s: &str) -> Result<Self, EmptyNameError> {
Ok(Sym(intern(&VName::parse(s)?.into_vec()[..])))
}
/// 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> {
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() }
/// Get a number unique to this name suitable for arbitrary ordering.
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 fn from_api(marker: api::TStrv) -> Sym {
Self::from_tok(Tok::from_api(marker)).expect("Empty sequence found for serialized Sym")
}
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
}
impl fmt::Debug for Sym {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Sym({self})") }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Sym({self})") }
}
impl fmt::Display for Sym {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
}
impl<T> Index<T> for Sym
where PathSlice: Index<T>
{
type Output = <PathSlice as Index<T>>::Output;
type Output = <PathSlice as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
}
impl Borrow<[Tok<String>]> for Sym {
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
}
impl Borrow<PathSlice> for Sym {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
}
impl Deref for Sym {
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
}
/// An abstraction over tokenized vs non-tokenized names so that they can be
/// 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<PathSlice>
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<PathSlice>
{
/// Convert into held slice
fn as_slice(&self) -> &[Tok<String>] { Borrow::<PathSlice>::borrow(self) }
/// Get iterator over tokens
fn iter(&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())
}
/// Fully resolve the name for printing
#[must_use]
fn to_strv(&self) -> Vec<String> { self.iter().map(|s| s.to_string()).collect() }
/// Format the name as an approximate filename
fn as_src_path(&self) -> String { format!("{}.orc", self.iter().join("/")) }
/// Return the number of segments in the name
fn len(&self) -> NonZeroUsize {
NonZeroUsize::try_from(self.iter().count()).expect("NameLike never empty")
}
/// Like slice's `split_first` except we know that it always returns Some
fn split_first(&self) -> (Tok<String>, &PathSlice) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), PathSlice::new(torso))
}
/// Like slice's `split_last` except we know that it always returns Some
fn split_last(&self) -> (Tok<String>, &PathSlice) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), PathSlice::new(torso))
}
/// Get the first element
fn first(&self) -> Tok<String> { self.split_first().0 }
/// Get the last element
fn last(&self) -> Tok<String> { self.split_last().0 }
/// Convert into held slice
fn as_slice(&self) -> &[Tok<String>] { Borrow::<PathSlice>::borrow(self) }
/// Get iterator over tokens
fn iter(&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())
}
/// Fully resolve the name for printing
#[must_use]
fn to_strv(&self) -> Vec<String> { self.iter().map(|s| s.to_string()).collect() }
/// Format the name as an approximate filename
fn as_src_path(&self) -> String { format!("{}.orc", self.iter().join("/")) }
/// Return the number of segments in the name
fn len(&self) -> NonZeroUsize {
NonZeroUsize::try_from(self.iter().count()).expect("NameLike never empty")
}
/// Like slice's `split_first` except we know that it always returns Some
fn split_first(&self) -> (Tok<String>, &PathSlice) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), PathSlice::new(torso))
}
/// Like slice's `split_last` except we know that it always returns Some
fn split_last(&self) -> (Tok<String>, &PathSlice) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), PathSlice::new(torso))
}
/// Get the first element
fn first(&self) -> Tok<String> { self.split_first().0 }
/// Get the last element
fn last(&self) -> Tok<String> { self.split_last().0 }
}
impl NameLike for Sym {}
@@ -492,35 +492,35 @@ macro_rules! path_slice {
#[cfg(test)]
mod test {
use std::borrow::Borrow;
use std::borrow::Borrow;
use super::{PathSlice, Sym, VName};
use crate::interner::{intern, Tok};
use crate::name::VPath;
use super::{PathSlice, Sym, VName};
use crate::interner::{Tok, intern};
use crate::name::VPath;
#[test]
fn recur() {
let myname = vname!(foo::bar);
let _borrowed_slice: &[Tok<String>] = myname.borrow();
let _borrowed_pathslice: &PathSlice = myname.borrow();
let _deref_pathslice: &PathSlice = &myname;
let _as_slice_out: &[Tok<String>] = myname.as_slice();
}
#[test]
fn recur() {
let myname = vname!(foo::bar);
let _borrowed_slice: &[Tok<String>] = myname.borrow();
let _borrowed_pathslice: &PathSlice = myname.borrow();
let _deref_pathslice: &PathSlice = &myname;
let _as_slice_out: &[Tok<String>] = myname.as_slice();
}
#[test]
fn literals() {
assert_eq!(
sym!(foo::bar::baz),
Sym::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
);
assert_eq!(
vname!(foo::bar::baz),
VName::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
);
assert_eq!(vpath!(foo::bar::baz), VPath::new([intern("foo"), intern("bar"), intern("baz")]));
assert_eq!(
path_slice!(foo::bar::baz),
PathSlice::new(&[intern("foo"), intern("bar"), intern("baz")])
);
}
#[test]
fn literals() {
assert_eq!(
sym!(foo::bar::baz),
Sym::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
);
assert_eq!(
vname!(foo::bar::baz),
VName::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
);
assert_eq!(vpath!(foo::bar::baz), VPath::new([intern("foo"), intern("bar"), intern("baz")]));
assert_eq!(
path_slice!(foo::bar::baz),
PathSlice::new(&[intern("foo"), intern("bar"), intern("baz")])
);
}
}

View File

@@ -1,131 +1,131 @@
use std::num::IntErrorKind;
use std::ops::Range;
use num_traits::ToPrimitive;
use ordered_float::NotNan;
use rust_decimal::Decimal;
use num_traits::ToPrimitive;
use crate::error::{mk_err, OrcErr};
use crate::error::{OrcErr, mk_err};
use crate::intern;
use crate::location::Pos;
/// A number, either floating point or unsigned int, parsed by Orchid.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Numeric {
/// A nonnegative integer
Uint(u64),
/// A binary float other than NaN
Float(NotNan<f64>),
/// A decimal number
Decimal(Decimal),
/// A nonnegative integer
Uint(u64),
/// A binary float other than NaN
Float(NotNan<f64>),
/// A decimal number
Decimal(Decimal),
}
impl Numeric {
pub fn decimal(num: i64, scale: u32) -> Self { Self::Decimal(Decimal::new(num, scale)) }
pub fn float(value: f64) -> Self { Self::Float(NotNan::new(value).unwrap()) }
pub fn to_f64(self) -> NotNan<f64> {
match self {
Self::Float(f) => f,
Self::Decimal(d) => {
let f = d.to_f64().expect("This is apparently always possible");
NotNan::new(f).expect("decimal was nan")
},
Self::Uint(i) => NotNan::new(i as f64).expect("int cannot be NaN"),
}
}
pub fn decimal(num: i64, scale: u32) -> Self { Self::Decimal(Decimal::new(num, scale)) }
pub fn float(value: f64) -> Self { Self::Float(NotNan::new(value).unwrap()) }
pub fn to_f64(self) -> NotNan<f64> {
match self {
Self::Float(f) => f,
Self::Decimal(d) => {
let f = d.to_f64().expect("This is apparently always possible");
NotNan::new(f).expect("decimal was nan")
},
Self::Uint(i) => NotNan::new(i as f64).expect("int cannot be NaN"),
}
}
}
/// Rasons why [parse_num] might fail. See [NumError].
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NumErrorKind {
/// The literal describes [f64::NAN]
NaN,
/// Some integer appearing in the literal overflows [usize]
Overflow,
/// A character that isn't a digit in the given base was found
InvalidDigit,
/// The literal describes [f64::NAN]
NaN,
/// Some integer appearing in the literal overflows [usize]
Overflow,
/// A character that isn't a digit in the given base was found
InvalidDigit,
}
impl NumErrorKind {
fn from_int(kind: &IntErrorKind) -> Self {
match kind {
IntErrorKind::InvalidDigit => Self::InvalidDigit,
IntErrorKind::NegOverflow | IntErrorKind::PosOverflow => Self::Overflow,
_ => panic!("Impossible error condition"),
}
}
fn from_int(kind: &IntErrorKind) -> Self {
match kind {
IntErrorKind::InvalidDigit => Self::InvalidDigit,
IntErrorKind::NegOverflow | IntErrorKind::PosOverflow => Self::Overflow,
_ => panic!("Impossible error condition"),
}
}
}
/// Error produced by [parse_num]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NumError {
/// Location
pub range: Range<usize>,
/// Reason
pub kind: NumErrorKind,
/// Location
pub range: Range<usize>,
/// Reason
pub kind: NumErrorKind,
}
pub fn num_to_err(NumError { kind, range }: NumError, offset: u32) -> OrcErr {
mk_err(
intern!(str: "Failed to parse number"),
match kind {
NumErrorKind::NaN => "NaN emerged during parsing",
NumErrorKind::InvalidDigit => "non-digit character encountered",
NumErrorKind::Overflow => "The number being described is too large or too accurate",
},
[Pos::Range(offset + range.start as u32..offset + range.end as u32).into()],
)
mk_err(
intern!(str: "Failed to parse number"),
match kind {
NumErrorKind::NaN => "NaN emerged during parsing",
NumErrorKind::InvalidDigit => "non-digit character encountered",
NumErrorKind::Overflow => "The number being described is too large or too accurate",
},
[Pos::Range(offset + range.start as u32..offset + range.end as u32).into()],
)
}
/// Parse a numbre literal out of text
pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
let overflow_err = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow };
let (radix, noprefix, pos) = (string.strip_prefix("0x").map(|s| (16u8, s, 2)))
.or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2)))
.or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2)))
.unwrap_or((10u8, string, 0));
// identity
let (base, exponent) = match noprefix.split_once('p') {
Some((b, e)) => {
let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1));
(b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32)
},
None => (noprefix, 0),
};
match base.split_once('.') {
None => {
let base_usize = int_parse(base, radix, pos)?;
if let Ok(pos_exp) = u32::try_from(exponent) {
if let Some(radical) = u64::from(radix).checked_pow(pos_exp) {
let number = base_usize.checked_mul(radical).ok_or(overflow_err)?;
return Ok(Numeric::Uint(number));
}
}
let f = (base_usize as f64) * (radix as f64).powi(exponent);
let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN };
Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?))
},
Some((whole, part)) => {
let whole_n = int_parse(whole, radix, pos)?;
let part_n = int_parse(part, radix, pos + whole.len() + 1)?;
let scale = part.chars().filter(|c| *c != '_').count() as u32;
if radix == 10 {
let mut scaled_unit = Decimal::ONE;
(scaled_unit.set_scale(scale))
.map_err(|_| NumError { range: 0..string.len(), kind: NumErrorKind::Overflow })?;
Ok(Numeric::Decimal(Decimal::from(whole_n) + scaled_unit * Decimal::from(part_n)))
} else {
let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32));
let f = real_val * (radix as f64).powi(exponent);
Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN")))
}
},
}
let overflow_err = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow };
let (radix, noprefix, pos) = (string.strip_prefix("0x").map(|s| (16u8, s, 2)))
.or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2)))
.or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2)))
.unwrap_or((10u8, string, 0));
// identity
let (base, exponent) = match noprefix.split_once('p') {
Some((b, e)) => {
let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1));
(b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32)
},
None => (noprefix, 0),
};
match base.split_once('.') {
None => {
let base_usize = int_parse(base, radix, pos)?;
if let Ok(pos_exp) = u32::try_from(exponent) {
if let Some(radical) = u64::from(radix).checked_pow(pos_exp) {
let number = base_usize.checked_mul(radical).ok_or(overflow_err)?;
return Ok(Numeric::Uint(number));
}
}
let f = (base_usize as f64) * (radix as f64).powi(exponent);
let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN };
Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?))
},
Some((whole, part)) => {
let whole_n = int_parse(whole, radix, pos)?;
let part_n = int_parse(part, radix, pos + whole.len() + 1)?;
let scale = part.chars().filter(|c| *c != '_').count() as u32;
if radix == 10 {
let mut scaled_unit = Decimal::ONE;
(scaled_unit.set_scale(scale))
.map_err(|_| NumError { range: 0..string.len(), kind: NumErrorKind::Overflow })?;
Ok(Numeric::Decimal(Decimal::from(whole_n) + scaled_unit * Decimal::from(part_n)))
} else {
let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32));
let f = real_val * (radix as f64).powi(exponent);
Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN")))
}
},
}
}
fn int_parse(s: &str, radix: u8, start: usize) -> Result<u64, NumError> {
let s = s.chars().filter(|c| *c != '_').collect::<String>();
let range = start..(start + s.len());
u64::from_str_radix(&s, radix as u32)
.map_err(|e| NumError { range, kind: NumErrorKind::from_int(e.kind()) })
let s = s.chars().filter(|c| *c != '_').collect::<String>();
let range = start..(start + s.len());
u64::from_str_radix(&s, radix as u32)
.map_err(|e| NumError { range, kind: NumErrorKind::from_int(e.kind()) })
}
/// Filter for characters that can appear in numbers
@@ -136,42 +136,42 @@ pub fn numstart(c: char) -> bool { c.is_ascii_digit() }
/// Print a number as a base-16 floating point literal
#[must_use]
pub fn print_nat16(num: NotNan<f64>) -> String {
if *num == 0.0 {
return "0x0".to_string();
} else if num.is_infinite() {
return match num.is_sign_positive() {
true => "Infinity".to_string(),
false => "-Infinity".to_string(),
};
} else if num.is_nan() {
return "NaN".to_string();
}
let exp = num.log(16.0).floor();
let man = *num / 16_f64.powf(exp);
format!("0x{man}p{exp:.0}")
if *num == 0.0 {
return "0x0".to_string();
} else if num.is_infinite() {
return match num.is_sign_positive() {
true => "Infinity".to_string(),
false => "-Infinity".to_string(),
};
} else if num.is_nan() {
return "NaN".to_string();
}
let exp = num.log(16.0).floor();
let man = *num / 16_f64.powf(exp);
format!("0x{man}p{exp:.0}")
}
#[cfg(test)]
mod test {
use super::{parse_num, Numeric};
use super::{Numeric, parse_num};
#[test]
fn just_ints() {
let test = |s, n| assert_eq!(parse_num(s), Ok(Numeric::Uint(n)));
test("12345", 12345);
test("0xcafebabe", 0xcafebabe);
test("0o751", 0o751);
test("0b111000111", 0b111000111);
}
#[test]
fn just_ints() {
let test = |s, n| assert_eq!(parse_num(s), Ok(Numeric::Uint(n)));
test("12345", 12345);
test("0xcafebabe", 0xcafebabe);
test("0o751", 0o751);
test("0b111000111", 0b111000111);
}
#[test]
fn decimals() {
let test = |s, n| assert_eq!(parse_num(s), Ok(n));
test("3.1417", Numeric::decimal(31417, 4));
test("0xf.cafe", Numeric::float(0xf as f64 + 0xcafe as f64 / 0x10000 as f64));
test("34p3", Numeric::Uint(34000));
test("0x2p3", Numeric::Uint(0x2 * 0x1000));
test("1.5p3", Numeric::decimal(1500, 0));
test("0x2.5p3", Numeric::float((0x25 * 0x100) as f64));
}
#[test]
fn decimals() {
let test = |s, n| assert_eq!(parse_num(s), Ok(n));
test("3.1417", Numeric::decimal(31417, 4));
test("0xf.cafe", Numeric::float(0xf as f64 + 0xcafe as f64 / 0x10000 as f64));
test("34p3", Numeric::Uint(34000));
test("0x2p3", Numeric::Uint(0x2 * 0x1000));
test("1.5p3", Numeric::decimal(1500, 0));
test("0x2.5p3", Numeric::float((0x25 * 0x100) as f64));
}
}

View File

@@ -3,8 +3,8 @@ use std::ops::{Deref, Range};
use itertools::Itertools;
use crate::error::{mk_err, mk_errv, OrcRes, Reporter};
use crate::interner::{intern, Tok};
use crate::error::{OrcRes, Reporter, mk_err, mk_errv};
use crate::interner::{Tok, intern};
use crate::location::Pos;
use crate::name::VPath;
use crate::tree::{AtomRepr, ExtraTok, Paren, TokTree, Token};
@@ -17,297 +17,299 @@ pub fn unrep_space(c: char) -> bool { c.is_whitespace() && !"\r\n".contains(c) }
#[derive(Debug)]
pub struct Snippet<'a, 'b, A: AtomRepr, X: ExtraTok> {
prev: &'a TokTree<'b, A, X>,
cur: &'a [TokTree<'b, A, X>],
prev: &'a TokTree<'b, A, X>,
cur: &'a [TokTree<'b, A, X>],
}
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 split_at(self, pos: u32) -> (Self, Self) {
let fst = Self { prev: self.prev, cur: &self.cur[..pos as usize] };
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..] };
(fst, snd)
}
pub fn find_idx(self, mut f: impl FnMut(&Token<'b, A, X>) -> bool) -> Option<u32> {
self.cur.iter().position(|t| f(&t.tok)).map(|t| t as u32)
}
pub fn get(self, idx: u32) -> Option<&'a TokTree<'b, A, X>> { self.cur.get(idx as usize) }
pub fn len(self) -> u32 { self.cur.len() as u32 }
pub fn prev(self) -> &'a TokTree<'b, A, X> { self.prev }
pub fn pos(self) -> Range<u32> {
(self.cur.first().map(|f| f.range.start..self.cur.last().unwrap().range.end))
.unwrap_or(self.prev.range.clone())
}
pub fn pop_front(self) -> Option<(&'a TokTree<'b, A, X>, Self)> {
self.cur.first().map(|r| (r, self.split_at(1).1))
}
pub fn pop_back(self) -> Option<(Self, &'a TokTree<'b, A, X>)> {
self.cur.last().map(|r| (self.split_at(self.len() - 1).0, r))
}
pub fn split_once(self, f: impl FnMut(&Token<'b, A, X>) -> bool) -> Option<(Self, Self)> {
let idx = self.find_idx(f)?;
Some((self.split_at(idx).0, self.split_at(idx + 1).1))
}
pub fn split(
mut self,
mut f: impl FnMut(&Token<'b, A, X>) -> bool,
) -> impl Iterator<Item = Self> {
iter::from_fn(move || {
self.is_empty().then_some(())?;
let (ret, next) = self.split_once(&mut f).unwrap_or(self.split_at(self.len()));
self = next;
Some(ret)
})
}
pub fn is_empty(self) -> bool { self.len() == 0 }
pub fn skip_fluff(self) -> Self {
let non_fluff_start = self.find_idx(|t| !matches!(t, Token::NS | Token::Comment(_)));
self.split_at(non_fluff_start.unwrap_or(self.len())).1
}
pub fn new(prev: &'a TokTree<'b, A, X>, cur: &'a [TokTree<'b, A, X>]) -> Self {
Self { prev, cur }
}
pub fn split_at(self, pos: u32) -> (Self, Self) {
let fst = Self { prev: self.prev, cur: &self.cur[..pos as usize] };
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..] };
(fst, snd)
}
pub fn find_idx(self, mut f: impl FnMut(&Token<'b, A, X>) -> bool) -> Option<u32> {
self.cur.iter().position(|t| f(&t.tok)).map(|t| t as u32)
}
pub fn get(self, idx: u32) -> Option<&'a TokTree<'b, A, X>> { self.cur.get(idx as usize) }
pub fn len(self) -> u32 { self.cur.len() as u32 }
pub fn prev(self) -> &'a TokTree<'b, A, X> { self.prev }
pub fn pos(self) -> Range<u32> {
(self.cur.first().map(|f| f.range.start..self.cur.last().unwrap().range.end))
.unwrap_or(self.prev.range.clone())
}
pub fn pop_front(self) -> Option<(&'a TokTree<'b, A, X>, Self)> {
self.cur.first().map(|r| (r, self.split_at(1).1))
}
pub fn pop_back(self) -> Option<(Self, &'a TokTree<'b, A, X>)> {
self.cur.last().map(|r| (self.split_at(self.len() - 1).0, r))
}
pub fn split_once(self, f: impl FnMut(&Token<'b, A, X>) -> bool) -> Option<(Self, Self)> {
let idx = self.find_idx(f)?;
Some((self.split_at(idx).0, self.split_at(idx + 1).1))
}
pub fn split(
mut self,
mut f: impl FnMut(&Token<'b, A, X>) -> bool,
) -> impl Iterator<Item = Self> {
iter::from_fn(move || {
self.is_empty().then_some(())?;
let (ret, next) = self.split_once(&mut f).unwrap_or(self.split_at(self.len()));
self = next;
Some(ret)
})
}
pub fn is_empty(self) -> bool { self.len() == 0 }
pub fn skip_fluff(self) -> Self {
let non_fluff_start = self.find_idx(|t| !matches!(t, Token::NS | Token::Comment(_)));
self.split_at(non_fluff_start.unwrap_or(self.len())).1
}
}
impl<A: AtomRepr, X: ExtraTok> Copy for Snippet<'_, '_, A, X> {}
impl<A: AtomRepr, X: ExtraTok> Clone for Snippet<'_, '_, A, X> {
fn clone(&self) -> Self { *self }
fn clone(&self) -> Self { *self }
}
impl<'b, A: AtomRepr, X: ExtraTok> Deref for Snippet<'_, 'b, A, X> {
type Target = [TokTree<'b, A, X>];
fn deref(&self) -> &Self::Target { self.cur }
type Target = [TokTree<'b, A, X>];
fn deref(&self) -> &Self::Target { self.cur }
}
/// Remove tokens that aren't meaningful in expression context, such as comments
/// or line breaks
pub fn strip_fluff<'a, A: AtomRepr, X: ExtraTok>(
tt: &TokTree<'a, A, X>,
tt: &TokTree<'a, A, X>,
) -> Option<TokTree<'a, A, X>> {
let tok = match &tt.tok {
Token::BR => return None,
Token::Comment(_) => return None,
Token::LambdaHead(arg) => Token::LambdaHead(arg.iter().filter_map(strip_fluff).collect()),
Token::S(p, b) => Token::S(*p, b.iter().filter_map(strip_fluff).collect()),
t => t.clone(),
};
Some(TokTree { tok, range: tt.range.clone() })
let tok = match &tt.tok {
Token::BR => return None,
Token::Comment(_) => return None,
Token::LambdaHead(arg) => Token::LambdaHead(arg.iter().filter_map(strip_fluff).collect()),
Token::S(p, b) => Token::S(*p, b.iter().filter_map(strip_fluff).collect()),
t => t.clone(),
};
Some(TokTree { tok, range: tt.range.clone() })
}
#[derive(Clone, Debug)]
pub struct Comment {
pub text: Tok<String>,
pub pos: Pos,
pub text: Tok<String>,
pub pos: Pos,
}
impl Comment {
pub fn to_api(&self) -> api::Comment {
api::Comment { location: self.pos.to_api(), text: self.text.to_api() }
}
pub fn from_api(api: &api::Comment) -> Self {
Self { pos: Pos::from_api(&api.location), text: Tok::from_api(api.text) }
}
pub fn to_api(&self) -> api::Comment {
api::Comment { location: self.pos.to_api(), text: self.text.to_api() }
}
pub fn from_api(api: &api::Comment) -> Self {
Self { pos: Pos::from_api(&api.location), text: Tok::from_api(api.text) }
}
}
pub fn line_items<'a, 'b, A: AtomRepr, X: ExtraTok>(
snip: Snippet<'a, 'b, A, X>,
snip: Snippet<'a, 'b, A, X>,
) -> Vec<Parsed<'a, 'b, Vec<Comment>, A, X>> {
let mut items = Vec::new();
let mut comments = Vec::new();
for mut line in snip.split(|t| matches!(t, Token::BR)) {
match &line.cur {
[TokTree { tok: Token::S(Paren::Round, tokens), .. }] => line.cur = tokens,
[] => continue,
_ => (),
}
match line.find_idx(|t| !matches!(t, Token::Comment(_))) {
None => comments.extend(line.cur),
Some(i) => {
let (cmts, tail) = line.split_at(i);
let comments = Vec::from_iter(comments.drain(..).chain(cmts.cur).map(|t| match &t.tok {
Token::Comment(c) => Comment { text: intern(&**c), pos: Pos::Range(t.range.clone()) },
_ => unreachable!("All are comments checked above"),
}));
items.push(Parsed { output: comments, tail });
},
}
}
items
let mut items = Vec::new();
let mut comments = Vec::new();
for mut line in snip.split(|t| matches!(t, Token::BR)) {
match &line.cur {
[TokTree { tok: Token::S(Paren::Round, tokens), .. }] => line.cur = tokens,
[] => continue,
_ => (),
}
match line.find_idx(|t| !matches!(t, Token::Comment(_))) {
None => comments.extend(line.cur),
Some(i) => {
let (cmts, tail) = line.split_at(i);
let comments = Vec::from_iter(comments.drain(..).chain(cmts.cur).map(|t| match &t.tok {
Token::Comment(c) => Comment { text: intern(&**c), pos: Pos::Range(t.range.clone()) },
_ => unreachable!("All are comments checked above"),
}));
items.push(Parsed { output: comments, tail });
},
}
}
items
}
pub fn try_pop_no_fluff<'a, 'b, A: AtomRepr, X: ExtraTok>(
snip: Snippet<'a, 'b, A, X>,
snip: Snippet<'a, 'b, A, X>,
) -> ParseRes<'a, 'b, &'a TokTree<'b, A, X>, A, X> {
snip.skip_fluff().pop_front().map(|(output, tail)| Parsed { output, tail }).ok_or_else(|| {
mk_errv(
intern!(str: "Unexpected end"),
"Pattern ends abruptly",
[Pos::Range(snip.pos()).into()],
)
})
snip.skip_fluff().pop_front().map(|(output, tail)| Parsed { output, tail }).ok_or_else(|| {
mk_errv(
intern!(str: "Unexpected end"),
"Pattern ends abruptly",
[Pos::Range(snip.pos()).into()],
)
})
}
pub 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"),
"Code found after the end of the line",
[Pos::Range(surplus.range.clone()).into()],
)),
None => Ok(()),
}
match snip.skip_fluff().get(0) {
Some(surplus) => Err(mk_errv(
intern!(str: "Extra code after end of line"),
"Code found after the end of the line",
[Pos::Range(surplus.range.clone()).into()],
)),
None => Ok(()),
}
}
pub fn expect_tok<'a, 'b, A: AtomRepr, X: ExtraTok>(
snip: Snippet<'a, 'b, A, X>,
tok: Tok<String>,
snip: Snippet<'a, 'b, A, X>,
tok: Tok<String>,
) -> ParseRes<'a, 'b, (), A, X> {
let Parsed { output: head, tail } = try_pop_no_fluff(snip)?;
match &head.tok {
Token::Name(n) if *n == tok => Ok(Parsed { output: (), tail }),
t => Err(mk_errv(
intern!(str: "Expected specific keyword"),
format!("Expected {tok} but found {t}"),
[Pos::Range(head.range.clone()).into()],
)),
}
let Parsed { output: head, tail } = try_pop_no_fluff(snip)?;
match &head.tok {
Token::Name(n) if *n == tok => Ok(Parsed { output: (), tail }),
t => Err(mk_errv(
intern!(str: "Expected specific keyword"),
format!("Expected {tok} but found {t}"),
[Pos::Range(head.range.clone()).into()],
)),
}
}
pub struct Parsed<'a, 'b, T, A: AtomRepr, X: ExtraTok> {
pub output: T,
pub tail: Snippet<'a, 'b, A, X>,
pub output: T,
pub tail: Snippet<'a, 'b, A, X>,
}
pub type ParseRes<'a, 'b, T, A, X> = OrcRes<Parsed<'a, 'b, T, A, X>>;
pub fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
ctx: &impl Reporter,
tail: Snippet<'a, 'b, A, X>,
ctx: &impl Reporter,
tail: Snippet<'a, 'b, A, X>,
) -> ParseRes<'a, 'b, Vec<(Import, Pos)>, A, X> {
let ret = rec(ctx, tail);
#[allow(clippy::type_complexity)] // it's an internal function
pub fn rec<'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: ",");
let globstar = intern!(str: "*");
let (name, tail) = tail.skip_fluff().pop_front().ok_or_else(|| {
mk_err(intern!(str: "Expected name"), "Expected a name, a list of names, or a globstar.", [
Pos::Range(tail.pos()).into(),
])
})?;
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"), "Only names can precede ::", [
Pos::Range(name.range.clone()).into(),
])),
};
match (rec(ctx, tail), n) {
(Err(ev), n) => Err(ev.extended(n.err())),
(Ok(Parsed { tail, .. }), Err(e)) => {
ctx.report(e);
Ok(Parsed { output: vec![], tail })
},
(Ok(Parsed { tail, output }), Ok(pre)) => Ok(Parsed {
output: output.into_iter().update(|i| i.0.push(pre.clone())).collect_vec(),
tail,
}),
}
} else {
let output = match &name.tok {
Token::Name(ntok) => {
let nopt = match ntok {
n if *n == globstar => None,
n if n.starts_with(op_char) =>
return Err(mk_errv(
intern!(str: "Unescaped operator in multiname"),
"Operators in multinames should be enclosed in []",
[Pos::Range(name.range.clone()).into()],
)),
n => Some(n.clone()),
};
vec![(vec![], nopt, Pos::Range(name.range.clone()))]
},
Token::S(Paren::Square, b) => {
let mut ok = Vec::new();
b.iter().for_each(|tt| match &tt.tok {
Token::Name(n) if n.starts_with(op_char) =>
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"),
"In multinames, [] functions as a literal name list reserved for operators",
[Pos::Range(name.range.clone()).into()],
)),
});
ok
},
Token::S(Paren::Round, b) => {
let mut ok = Vec::new();
let body = Snippet::new(name, b);
for csent in body.split(|n| matches!(n, Token::Name(n) if *n == comma)) {
match rec(ctx, csent) {
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"),
"Unexpected token. Likely missing a :: or , or wanted [] instead of ()",
[Pos::Range(t.range.clone()).into()],
)),
},
}
}
ok
},
t =>
return Err(mk_errv(
intern!(str: "Unrecognized name end"),
format!("Names cannot end with {t} tokens"),
[Pos::Range(name.range.clone()).into()],
)),
};
Ok(Parsed { output, tail })
}
}
ret.map(|Parsed { output, tail }| {
let output = (output.into_iter())
.map(|(p, name, pos)| (Import { path: VPath::new(p.into_iter().rev()), name }, pos))
.collect_vec();
Parsed { output, tail }
})
let ret = rec(ctx, tail);
#[allow(clippy::type_complexity)] // it's an internal function
pub fn rec<'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: ",");
let globstar = intern!(str: "*");
let (name, tail) = tail.skip_fluff().pop_front().ok_or_else(|| {
mk_err(intern!(str: "Expected name"), "Expected a name, a list of names, or a globstar.", [
Pos::Range(tail.pos()).into(),
])
})?;
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"), "Only names can precede ::", [
Pos::Range(name.range.clone()).into(),
])),
};
match (rec(ctx, tail), n) {
(Err(ev), n) => Err(ev.extended(n.err())),
(Ok(Parsed { tail, .. }), Err(e)) => {
ctx.report(e);
Ok(Parsed { output: vec![], tail })
},
(Ok(Parsed { tail, output }), Ok(pre)) => Ok(Parsed {
output: output.into_iter().update(|i| i.0.push(pre.clone())).collect_vec(),
tail,
}),
}
} else {
let output = match &name.tok {
Token::Name(ntok) => {
let nopt = match ntok {
n if *n == globstar => None,
n if n.starts_with(op_char) => {
return Err(mk_errv(
intern!(str: "Unescaped operator in multiname"),
"Operators in multinames should be enclosed in []",
[Pos::Range(name.range.clone()).into()],
));
},
n => Some(n.clone()),
};
vec![(vec![], nopt, Pos::Range(name.range.clone()))]
},
Token::S(Paren::Square, b) => {
let mut ok = Vec::new();
b.iter().for_each(|tt| match &tt.tok {
Token::Name(n) if n.starts_with(op_char) =>
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"),
"In multinames, [] functions as a literal name list reserved for operators",
[Pos::Range(name.range.clone()).into()],
)),
});
ok
},
Token::S(Paren::Round, b) => {
let mut ok = Vec::new();
let body = Snippet::new(name, b);
for csent in body.split(|n| matches!(n, Token::Name(n) if *n == comma)) {
match rec(ctx, csent) {
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"),
"Unexpected token. Likely missing a :: or , or wanted [] instead of ()",
[Pos::Range(t.range.clone()).into()],
)),
},
}
}
ok
},
t => {
return Err(mk_errv(
intern!(str: "Unrecognized name end"),
format!("Names cannot end with {t} tokens"),
[Pos::Range(name.range.clone()).into()],
));
},
};
Ok(Parsed { output, tail })
}
}
ret.map(|Parsed { output, tail }| {
let output = (output.into_iter())
.map(|(p, name, pos)| (Import { path: VPath::new(p.into_iter().rev()), name }, pos))
.collect_vec();
Parsed { output, tail }
})
}
/// A compound name, possibly ending with a globstar
#[derive(Debug, Clone)]
pub struct Import {
pub path: VPath,
pub name: Option<Tok<String>>,
pub path: VPath,
pub name: Option<Tok<String>>,
}
impl Import {
// pub fn from_api(i: api::CompName) -> Self {
// Self { path: VPath::new(i.path.into_iter().map(deintern)), name: i.name.map(deintern) }
// }
// pub fn to_api(&self) -> api::CompName {
// api::CompName {
// path: self.path.iter().map(|t| t.marker()).collect(),
// name: self.name.as_ref().map(|t| t.marker()),
// }
// }
// pub fn from_api(i: api::CompName) -> Self {
// Self { path: VPath::new(i.path.into_iter().map(deintern)), name:
// i.name.map(deintern) } }
// pub fn to_api(&self) -> api::CompName {
// api::CompName {
// path: self.path.iter().map(|t| t.marker()).collect(),
// name: self.name.as_ref().map(|t| t.marker()),
// }
// }
}
#[cfg(test)]
mod test {
use never::Never;
use never::Never;
use super::Snippet;
use super::Snippet;
fn _covary_snip_a<'a, 'b>(
x: Snippet<'static, 'b, Never, Never>,
) -> Snippet<'a, 'b, Never, Never> {
x
}
fn _covary_snip_b<'a, 'b>(
x: Snippet<'a, 'static, Never, Never>,
) -> Snippet<'a, 'b, Never, Never> {
x
}
fn _covary_snip_a<'a, 'b>(
x: Snippet<'static, 'b, Never, Never>,
) -> Snippet<'a, 'b, Never, Never> {
x
}
fn _covary_snip_b<'a, 'b>(
x: Snippet<'a, 'static, Never, Never>,
) -> Snippet<'a, 'b, Never, Never> {
x
}
}

View File

@@ -7,7 +7,7 @@ use std::iter;
/// Create a new vector consisting of the provided vector with the
/// element appended. See [pushed_ref] to use it with a slice
pub fn pushed<I: IntoIterator, C: FromIterator<I::Item>>(vec: I, t: I::Item) -> C {
vec.into_iter().chain(iter::once(t)).collect()
vec.into_iter().chain(iter::once(t)).collect()
}
/// Pure version of [Vec::push]
@@ -15,21 +15,21 @@ pub fn pushed<I: IntoIterator, C: FromIterator<I::Item>>(vec: I, t: I::Item) ->
/// Create a new vector consisting of the provided slice with the
/// element appended. See [pushed] for the owned version
pub fn pushed_ref<'a, T: Clone + 'a, C: FromIterator<T>>(
vec: impl IntoIterator<Item = &'a T>,
t: T,
vec: impl IntoIterator<Item = &'a T>,
t: T,
) -> C {
vec.into_iter().cloned().chain(iter::once(t)).collect()
vec.into_iter().cloned().chain(iter::once(t)).collect()
}
/// Push an element on the adhoc stack, pass it to the callback, then pop the
/// element out again.
pub fn with_pushed<T, U>(
vec: &mut Vec<T>,
item: T,
cb: impl for<'a> FnOnce(&'a mut Vec<T>) -> U,
vec: &mut Vec<T>,
item: T,
cb: impl for<'a> FnOnce(&'a mut Vec<T>) -> U,
) -> (T, U) {
vec.push(item);
let out = cb(vec);
let item = vec.pop().expect("top element stolen by callback");
(item, out)
vec.push(item);
let out = cb(vec);
let item = vec.pop().expect("top element stolen by callback");
(item, out)
}

View File

@@ -3,84 +3,84 @@ use std::cell::RefCell;
use std::marker::PhantomData;
use std::ops::{BitAnd, Deref};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{sync_channel, SyncSender};
use std::sync::mpsc::{SyncSender, sync_channel};
use std::sync::{Arc, Mutex};
use std::{mem, thread};
use derive_destructure::destructure;
use dyn_clone::{clone_box, DynClone};
use dyn_clone::{DynClone, clone_box};
use hashbrown::HashMap;
use orchid_api_traits::{Channel, Coding, Decode, Encode, MsgSet, Request};
use trait_set::trait_set;
pub struct Receipt;
impl Receipt {
pub fn off_thread(name: String, cb: impl FnOnce() -> Self + Send + 'static) -> Self {
thread::Builder::new().name(name).spawn(cb).unwrap();
Self
}
pub fn off_thread(name: String, cb: impl FnOnce() -> Self + Send + 'static) -> Self {
thread::Builder::new().name(name).spawn(cb).unwrap();
Self
}
}
trait_set! {
pub trait SendFn<T: MsgSet> = for<'a> FnMut(&'a [u8], ReqNot<T>) + DynClone + Send + 'static;
pub trait ReqFn<T: MsgSet> =
FnMut(RequestHandle<T>, <T::In as Channel>::Req) -> Receipt + DynClone + Send + Sync + 'static;
pub trait NotifFn<T: MsgSet> =
for<'a> FnMut(<T::In as Channel>::Notif, ReqNot<T>) + DynClone + Send + Sync + 'static;
pub trait SendFn<T: MsgSet> = for<'a> FnMut(&'a [u8], ReqNot<T>) + DynClone + Send + 'static;
pub trait ReqFn<T: MsgSet> =
FnMut(RequestHandle<T>, <T::In as Channel>::Req) -> Receipt + DynClone + Send + Sync + 'static;
pub trait NotifFn<T: MsgSet> =
for<'a> FnMut(<T::In as Channel>::Notif, ReqNot<T>) + DynClone + Send + Sync + 'static;
}
fn get_id(message: &[u8]) -> (u64, &[u8]) {
(u64::from_be_bytes(message[..8].to_vec().try_into().unwrap()), &message[8..])
(u64::from_be_bytes(message[..8].to_vec().try_into().unwrap()), &message[8..])
}
pub trait ReqHandlish {
fn defer_drop(&self, val: impl Any + 'static);
fn defer_drop(&self, val: impl Any + 'static);
}
#[derive(destructure)]
pub struct RequestHandle<MS: MsgSet> {
defer_drop: RefCell<Vec<Box<dyn Any>>>,
fulfilled: AtomicBool,
id: u64,
parent: ReqNot<MS>,
defer_drop: RefCell<Vec<Box<dyn Any>>>,
fulfilled: AtomicBool,
id: u64,
parent: ReqNot<MS>,
}
impl<MS: MsgSet + 'static> RequestHandle<MS> {
fn new(parent: ReqNot<MS>, id: u64) -> Self {
Self { defer_drop: RefCell::default(), fulfilled: false.into(), parent, id }
}
pub fn reqnot(&self) -> ReqNot<MS> { self.parent.clone() }
pub fn handle<U: Request>(&self, _: &U, rep: &U::Response) -> Receipt { self.respond(rep) }
pub fn will_handle_as<U: Request>(&self, _: &U) -> ReqTypToken<U> { ReqTypToken(PhantomData) }
pub fn handle_as<U: Request>(&self, _: ReqTypToken<U>, rep: &U::Response) -> Receipt {
self.respond(rep)
}
pub fn respond(&self, response: &impl Encode) -> Receipt {
assert!(!self.fulfilled.swap(true, Ordering::Relaxed), "Already responded to {}", self.id);
let mut buf = (!self.id).to_be_bytes().to_vec();
response.encode(&mut buf);
let mut send = clone_box(&*self.reqnot().0.lock().unwrap().send);
(send)(&buf, self.parent.clone());
Receipt
}
fn new(parent: ReqNot<MS>, id: u64) -> Self {
Self { defer_drop: RefCell::default(), fulfilled: false.into(), parent, id }
}
pub fn reqnot(&self) -> ReqNot<MS> { self.parent.clone() }
pub fn handle<U: Request>(&self, _: &U, rep: &U::Response) -> Receipt { self.respond(rep) }
pub fn will_handle_as<U: Request>(&self, _: &U) -> ReqTypToken<U> { ReqTypToken(PhantomData) }
pub fn handle_as<U: Request>(&self, _: ReqTypToken<U>, rep: &U::Response) -> Receipt {
self.respond(rep)
}
pub fn respond(&self, response: &impl Encode) -> Receipt {
assert!(!self.fulfilled.swap(true, Ordering::Relaxed), "Already responded to {}", self.id);
let mut buf = (!self.id).to_be_bytes().to_vec();
response.encode(&mut buf);
let mut send = clone_box(&*self.reqnot().0.lock().unwrap().send);
(send)(&buf, self.parent.clone());
Receipt
}
}
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(&self, val: impl Any) { self.defer_drop.borrow_mut().push(Box::new(val)) }
}
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)
}
fn drop(&mut self) {
let done = self.fulfilled.load(Ordering::Relaxed);
debug_assert!(done, "Request {} dropped without response", self.id)
}
}
pub struct ReqTypToken<T>(PhantomData<T>);
pub struct ReqNotData<T: MsgSet> {
id: u64,
send: Box<dyn SendFn<T>>,
notif: Box<dyn NotifFn<T>>,
req: Box<dyn ReqFn<T>>,
responses: HashMap<u64, SyncSender<Vec<u8>>>,
id: u64,
send: Box<dyn SendFn<T>>,
notif: Box<dyn NotifFn<T>>,
req: Box<dyn ReqFn<T>>,
responses: HashMap<u64, SyncSender<Vec<u8>>>,
}
/// Wraps a raw message buffer to save on copying.
@@ -88,180 +88,180 @@ pub struct ReqNotData<T: MsgSet> {
#[derive(Debug, Clone)]
pub struct RawReply(Vec<u8>);
impl Deref for RawReply {
type Target = [u8];
fn deref(&self) -> &Self::Target { get_id(&self.0[..]).1 }
type Target = [u8];
fn deref(&self) -> &Self::Target { get_id(&self.0[..]).1 }
}
pub struct ReqNot<T: MsgSet>(Arc<Mutex<ReqNotData<T>>>);
impl<T: MsgSet> ReqNot<T> {
pub fn new(send: impl SendFn<T>, notif: impl NotifFn<T>, req: impl ReqFn<T>) -> Self {
Self(Arc::new(Mutex::new(ReqNotData {
id: 1,
send: Box::new(send),
notif: Box::new(notif),
req: Box::new(req),
responses: HashMap::new(),
})))
}
pub fn new(send: impl SendFn<T>, notif: impl NotifFn<T>, req: impl ReqFn<T>) -> Self {
Self(Arc::new(Mutex::new(ReqNotData {
id: 1,
send: Box::new(send),
notif: Box::new(notif),
req: Box::new(req),
responses: HashMap::new(),
})))
}
/// Can be called from a polling thread or dispatched in any other way
pub fn receive(&self, message: &[u8]) {
let mut g = self.0.lock().unwrap();
let (id, payload) = get_id(message);
if id == 0 {
let mut notif = clone_box(&*g.notif);
mem::drop(g);
notif(<T::In as Channel>::Notif::decode(&mut &payload[..]), self.clone())
} else if 0 < id.bitand(1 << 63) {
let sender = g.responses.remove(&!id).expect("Received response for invalid message");
sender.send(message.to_vec()).unwrap();
} else {
let message = <T::In as Channel>::Req::decode(&mut &payload[..]);
let mut req = clone_box(&*g.req);
mem::drop(g);
let rn = self.clone();
thread::Builder::new()
.name(format!("request {id}"))
.spawn(move || req(RequestHandle::new(rn, id), message))
.unwrap();
}
}
/// Can be called from a polling thread or dispatched in any other way
pub fn receive(&self, message: &[u8]) {
let mut g = self.0.lock().unwrap();
let (id, payload) = get_id(message);
if id == 0 {
let mut notif = clone_box(&*g.notif);
mem::drop(g);
notif(<T::In as Channel>::Notif::decode(&mut &payload[..]), self.clone())
} else if 0 < id.bitand(1 << 63) {
let sender = g.responses.remove(&!id).expect("Received response for invalid message");
sender.send(message.to_vec()).unwrap();
} else {
let message = <T::In as Channel>::Req::decode(&mut &payload[..]);
let mut req = clone_box(&*g.req);
mem::drop(g);
let rn = self.clone();
thread::Builder::new()
.name(format!("request {id}"))
.spawn(move || req(RequestHandle::new(rn, id), message))
.unwrap();
}
}
pub fn notify<N: Coding + Into<<T::Out as Channel>::Notif>>(&self, notif: N) {
let mut send = clone_box(&*self.0.lock().unwrap().send);
let mut buf = vec![0; 8];
let msg: <T::Out as Channel>::Notif = notif.into();
msg.encode(&mut buf);
send(&buf, self.clone())
}
pub fn notify<N: Coding + Into<<T::Out as Channel>::Notif>>(&self, notif: N) {
let mut send = clone_box(&*self.0.lock().unwrap().send);
let mut buf = vec![0; 8];
let msg: <T::Out as Channel>::Notif = notif.into();
msg.encode(&mut buf);
send(&buf, self.clone())
}
}
pub trait DynRequester: Send + Sync {
type Transfer;
/// Encode and send a request, then receive the response buffer.
fn raw_request(&self, data: Self::Transfer) -> RawReply;
type Transfer;
/// Encode and send a request, then receive the response buffer.
fn raw_request(&self, data: Self::Transfer) -> RawReply;
}
pub struct MappedRequester<'a, T>(Box<dyn Fn(T) -> RawReply + Send + Sync + 'a>);
impl<'a, T> MappedRequester<'a, T> {
fn new<U: DynRequester + 'a>(req: U) -> Self
where T: Into<U::Transfer> {
MappedRequester(Box::new(move |t| req.raw_request(t.into())))
}
fn new<U: DynRequester + 'a>(req: U) -> Self
where T: Into<U::Transfer> {
MappedRequester(Box::new(move |t| req.raw_request(t.into())))
}
}
impl<T> DynRequester for MappedRequester<'_, T> {
type Transfer = T;
fn raw_request(&self, data: Self::Transfer) -> RawReply { self.0(data) }
type Transfer = T;
fn raw_request(&self, data: Self::Transfer) -> RawReply { self.0(data) }
}
impl<T: MsgSet> DynRequester for ReqNot<T> {
type Transfer = <T::Out as Channel>::Req;
fn raw_request(&self, req: Self::Transfer) -> RawReply {
let mut g = self.0.lock().unwrap();
let id = g.id;
g.id += 1;
let mut buf = id.to_be_bytes().to_vec();
req.encode(&mut buf);
let (send, recv) = sync_channel(1);
g.responses.insert(id, send);
let mut send = clone_box(&*g.send);
mem::drop(g);
send(&buf, self.clone());
RawReply(recv.recv().unwrap())
}
type Transfer = <T::Out as Channel>::Req;
fn raw_request(&self, req: Self::Transfer) -> RawReply {
let mut g = self.0.lock().unwrap();
let id = g.id;
g.id += 1;
let mut buf = id.to_be_bytes().to_vec();
req.encode(&mut buf);
let (send, recv) = sync_channel(1);
g.responses.insert(id, send);
let mut send = clone_box(&*g.send);
mem::drop(g);
send(&buf, self.clone());
RawReply(recv.recv().unwrap())
}
}
pub trait Requester: DynRequester {
#[must_use = "These types are subject to change with protocol versions. \
#[must_use = "These types are subject to change with protocol versions. \
If you don't want to use the return value, At a minimum, force the type."]
fn request<R: Request + Into<Self::Transfer>>(&self, data: R) -> R::Response;
fn map<'a, U: Into<Self::Transfer>>(self) -> MappedRequester<'a, U>
where Self: Sized + 'a {
MappedRequester::new(self)
}
fn request<R: Request + Into<Self::Transfer>>(&self, data: R) -> R::Response;
fn map<'a, U: Into<Self::Transfer>>(self) -> MappedRequester<'a, U>
where Self: Sized + 'a {
MappedRequester::new(self)
}
}
impl<This: DynRequester + ?Sized> Requester for This {
fn request<R: Request + Into<Self::Transfer>>(&self, data: R) -> R::Response {
R::Response::decode(&mut &self.raw_request(data.into())[..])
}
fn request<R: Request + Into<Self::Transfer>>(&self, data: R) -> R::Response {
R::Response::decode(&mut &self.raw_request(data.into())[..])
}
}
impl<T: MsgSet> Clone for ReqNot<T> {
fn clone(&self) -> Self { Self(self.0.clone()) }
fn clone(&self) -> Self { Self(self.0.clone()) }
}
#[cfg(test)]
mod test {
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex};
use orchid_api_derive::Coding;
use orchid_api_traits::{Channel, Request};
use orchid_api_derive::Coding;
use orchid_api_traits::{Channel, Request};
use super::{MsgSet, ReqNot};
use crate::clone;
use crate::reqnot::Requester as _;
use super::{MsgSet, ReqNot};
use crate::clone;
use crate::reqnot::Requester as _;
#[derive(Clone, Debug, Coding, PartialEq)]
pub struct TestReq(u8);
impl Request for TestReq {
type Response = u8;
}
#[derive(Clone, Debug, Coding, PartialEq)]
pub struct TestReq(u8);
impl Request for TestReq {
type Response = u8;
}
pub struct TestChan;
impl Channel for TestChan {
type Notif = u8;
type Req = TestReq;
}
pub struct TestChan;
impl Channel for TestChan {
type Notif = u8;
type Req = TestReq;
}
pub struct TestMsgSet;
impl MsgSet for TestMsgSet {
type In = TestChan;
type Out = TestChan;
}
pub struct TestMsgSet;
impl MsgSet for TestMsgSet {
type In = TestChan;
type Out = TestChan;
}
#[test]
fn notification() {
let received = Arc::new(Mutex::new(None));
let receiver = ReqNot::<TestMsgSet>::new(
|_, _| panic!("Should not send anything"),
clone!(received; move |notif, _| *received.lock().unwrap() = Some(notif)),
|_, _| panic!("Not receiving a request"),
);
let sender = ReqNot::<TestMsgSet>::new(
clone!(receiver; move |d, _| receiver.receive(d)),
|_, _| panic!("Should not receive notif"),
|_, _| panic!("Should not receive request"),
);
sender.notify(3);
assert_eq!(*received.lock().unwrap(), Some(3));
sender.notify(4);
assert_eq!(*received.lock().unwrap(), Some(4));
}
#[test]
fn notification() {
let received = Arc::new(Mutex::new(None));
let receiver = ReqNot::<TestMsgSet>::new(
|_, _| panic!("Should not send anything"),
clone!(received; move |notif, _| *received.lock().unwrap() = Some(notif)),
|_, _| panic!("Not receiving a request"),
);
let sender = ReqNot::<TestMsgSet>::new(
clone!(receiver; move |d, _| receiver.receive(d)),
|_, _| panic!("Should not receive notif"),
|_, _| panic!("Should not receive request"),
);
sender.notify(3);
assert_eq!(*received.lock().unwrap(), Some(3));
sender.notify(4);
assert_eq!(*received.lock().unwrap(), Some(4));
}
#[test]
fn request() {
let receiver = Arc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
let sender = Arc::new(ReqNot::<TestMsgSet>::new(
{
let receiver = receiver.clone();
move |d, _| receiver.lock().unwrap().as_ref().unwrap().receive(d)
},
|_, _| panic!("Should not receive notif"),
|_, _| panic!("Should not receive request"),
));
*receiver.lock().unwrap() = Some(ReqNot::new(
{
let sender = sender.clone();
move |d, _| sender.receive(d)
},
|_, _| panic!("Not receiving notifs"),
|hand, req| {
assert_eq!(req, TestReq(5));
hand.respond(&6u8)
},
));
let response = sender.request(TestReq(5));
assert_eq!(response, 6);
}
#[test]
fn request() {
let receiver = Arc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
let sender = Arc::new(ReqNot::<TestMsgSet>::new(
{
let receiver = receiver.clone();
move |d, _| receiver.lock().unwrap().as_ref().unwrap().receive(d)
},
|_, _| panic!("Should not receive notif"),
|_, _| panic!("Should not receive request"),
));
*receiver.lock().unwrap() = Some(ReqNot::new(
{
let sender = sender.clone();
move |d, _| sender.receive(d)
},
|_, _| panic!("Not receiving notifs"),
|hand, req| {
assert_eq!(req, TestReq(5));
hand.respond(&6u8)
},
));
let response = sender.request(TestReq(5));
assert_eq!(response, 6);
}
}

View File

@@ -8,20 +8,20 @@ use trait_set::trait_set;
use super::boxed_iter::BoxedIter;
trait_set! {
trait Payload<'a, T> = Fn() -> BoxedIter<'a, T> + 'a;
trait Payload<'a, T> = Fn() -> BoxedIter<'a, T> + 'a;
}
/// Dynamic iterator building callback. Given how many trait objects this
/// involves, it may actually be slower than C#.
pub struct Sequence<'a, T: 'a>(Rc<dyn Payload<'a, T>>);
impl<'a, T: 'a> Sequence<'a, T> {
/// Construct from a concrete function returning a concrete iterator
pub fn new<I: IntoIterator<Item = T> + 'a>(f: impl Fn() -> I + 'a) -> Self {
Self(Rc::new(move || Box::new(f().into_iter())))
}
/// Get an iterator from the function
pub fn iter(&self) -> BoxedIter<'_, T> { (self.0)() }
/// Construct from a concrete function returning a concrete iterator
pub fn new<I: IntoIterator<Item = T> + 'a>(f: impl Fn() -> I + 'a) -> Self {
Self(Rc::new(move || Box::new(f().into_iter())))
}
/// Get an iterator from the function
pub fn iter(&self) -> BoxedIter<'_, T> { (self.0)() }
}
impl<'a, T: 'a> Clone for Sequence<'a, T> {
fn clone(&self) -> Self { Self(self.0.clone()) }
fn clone(&self) -> Self { Self(self.0.clone()) }
}

View File

@@ -10,88 +10,88 @@ use crate::boxed_iter::BoxedIter;
/// are technically usable for this purpose, they're very easy to confuse
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Side {
/// Left, low, or high-to-low in the case of sequences
Left,
/// Right, high, or low-to-high in the case of sequences
Right,
/// Left, low, or high-to-low in the case of sequences
Left,
/// Right, high, or low-to-high in the case of sequences
Right,
}
impl fmt::Display for Side {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Left => write!(f, "Left"),
Self::Right => write!(f, "Right"),
}
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Left => write!(f, "Left"),
Self::Right => write!(f, "Right"),
}
}
}
impl Side {
/// Get the side that is not the current one
pub fn opposite(&self) -> Self {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left,
}
}
/// Shorthand for opposite
pub fn inv(&self) -> Self { self.opposite() }
/// take N elements from this end of a slice
pub fn slice<'a, T>(&self, size: usize, slice: &'a [T]) -> &'a [T] {
match self {
Side::Left => &slice[..size],
Side::Right => &slice[slice.len() - size..],
}
}
/// ignore N elements from this end of a slice
pub fn crop<'a, T>(&self, margin: usize, slice: &'a [T]) -> &'a [T] {
self.opposite().slice(slice.len() - margin, slice)
}
/// ignore N elements from this end and M elements from the other end
/// of a slice
pub fn crop_both<'a, T>(&self, margin: usize, opposite: usize, slice: &'a [T]) -> &'a [T] {
self.crop(margin, self.opposite().crop(opposite, slice))
}
/// Pick this side from a pair of things
pub fn pick<T>(&self, pair: (T, T)) -> T {
match self {
Side::Left => pair.0,
Side::Right => pair.1,
}
}
/// Make a pair with the first element on this side
pub fn pair<T>(&self, this: T, opposite: T) -> (T, T) {
match self {
Side::Left => (this, opposite),
Side::Right => (opposite, this),
}
}
/// Walk a double ended iterator (assumed to be left-to-right) in this
/// direction
pub fn walk<'a, I: DoubleEndedIterator + 'a>(&self, iter: I) -> BoxedIter<'a, I::Item> {
match self {
Side::Right => Box::new(iter) as BoxedIter<I::Item>,
Side::Left => Box::new(iter.rev()),
}
}
/// Get the side that is not the current one
pub fn opposite(&self) -> Self {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left,
}
}
/// Shorthand for opposite
pub fn inv(&self) -> Self { self.opposite() }
/// take N elements from this end of a slice
pub fn slice<'a, T>(&self, size: usize, slice: &'a [T]) -> &'a [T] {
match self {
Side::Left => &slice[..size],
Side::Right => &slice[slice.len() - size..],
}
}
/// ignore N elements from this end of a slice
pub fn crop<'a, T>(&self, margin: usize, slice: &'a [T]) -> &'a [T] {
self.opposite().slice(slice.len() - margin, slice)
}
/// ignore N elements from this end and M elements from the other end
/// of a slice
pub fn crop_both<'a, T>(&self, margin: usize, opposite: usize, slice: &'a [T]) -> &'a [T] {
self.crop(margin, self.opposite().crop(opposite, slice))
}
/// Pick this side from a pair of things
pub fn pick<T>(&self, pair: (T, T)) -> T {
match self {
Side::Left => pair.0,
Side::Right => pair.1,
}
}
/// Make a pair with the first element on this side
pub fn pair<T>(&self, this: T, opposite: T) -> (T, T) {
match self {
Side::Left => (this, opposite),
Side::Right => (opposite, this),
}
}
/// Walk a double ended iterator (assumed to be left-to-right) in this
/// direction
pub fn walk<'a, I: DoubleEndedIterator + 'a>(&self, iter: I) -> BoxedIter<'a, I::Item> {
match self {
Side::Right => Box::new(iter) as BoxedIter<I::Item>,
Side::Left => Box::new(iter.rev()),
}
}
}
impl Not for Side {
type Output = Side;
type Output = Side;
fn not(self) -> Self::Output { self.opposite() }
fn not(self) -> Self::Output { self.opposite() }
}
#[cfg(test)]
mod test {
use itertools::Itertools;
use itertools::Itertools;
use super::*;
use super::*;
/// I apparently have a tendency to mix these up so it's best if
/// the sides are explicitly stated
#[test]
fn test_walk() {
assert_eq!(Side::Right.walk(0..4).collect_vec(), vec![0, 1, 2, 3], "can walk a range");
assert_eq!(Side::Left.walk(0..4).collect_vec(), vec![3, 2, 1, 0], "can walk a range backwards")
}
/// I apparently have a tendency to mix these up so it's best if
/// the sides are explicitly stated
#[test]
fn test_walk() {
assert_eq!(Side::Right.walk(0..4).collect_vec(), vec![0, 1, 2, 3], "can walk a range");
assert_eq!(Side::Left.walk(0..4).collect_vec(), vec![3, 2, 1, 0], "can walk a range backwards")
}
}

View File

@@ -3,4 +3,4 @@ pub use api::Paren;
use crate::api;
pub const PARENS: &[(char, char, Paren)] =
&[('(', ')', Paren::Round), ('[', ']', Paren::Square), ('{', '}', Paren::Curly)];
&[('(', ')', Paren::Round), ('[', ']', Paren::Square), ('{', '}', Paren::Curly)];

View File

@@ -6,320 +6,319 @@ use std::marker::PhantomData;
use std::ops::Range;
use std::sync::Arc;
pub use api::PhKind;
use itertools::Itertools;
use never::Never;
use ordered_float::NotNan;
use trait_set::trait_set;
use crate::{api, match_mapping};
use crate::error::OrcErrv;
use crate::interner::Tok;
use crate::location::Pos;
use crate::name::PathSlice;
use crate::parse::Snippet;
use crate::tokens::PARENS;
pub use api::PhKind as PhKind;
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 RecurCB<'a, A: AtomRepr, X: ExtraTok> = Fn(TokTree<'a, A, X>) -> TokTree<'a, A, X>;
pub trait ExtraTok = Display + Clone + fmt::Debug;
}
pub fn recur<'a, A: AtomRepr, X: ExtraTok>(
tt: TokTree<'a, A, X>,
f: &impl Fn(TokTree<'a, A, X>, &dyn RecurCB<'a, A, X>) -> TokTree<'a, A, X>,
tt: TokTree<'a, A, X>,
f: &impl Fn(TokTree<'a, A, X>, &dyn RecurCB<'a, A, X>) -> TokTree<'a, A, X>,
) -> TokTree<'a, A, X> {
f(tt, &|TokTree { range, tok }| {
let tok = match tok {
tok @ (Token::Atom(_) | Token::BR | Token::Bottom(_) | Token::Comment(_) | Token::NS) => tok,
tok @ (Token::Name(_) | Token::Slot(_) | Token::X(_) | Token::Ph(_) | Token::Macro(_)) => tok,
Token::LambdaHead(arg) =>
Token::LambdaHead(arg.into_iter().map(|tt| recur(tt, f)).collect_vec()),
Token::S(p, b) => Token::S(p, b.into_iter().map(|tt| recur(tt, f)).collect_vec()),
};
TokTree { range, tok }
})
f(tt, &|TokTree { range, tok }| {
let tok = match tok {
tok @ (Token::Atom(_) | Token::BR | Token::Bottom(_) | Token::Comment(_) | Token::NS) => tok,
tok @ (Token::Name(_) | Token::Slot(_) | Token::X(_) | Token::Ph(_) | Token::Macro(_)) => tok,
Token::LambdaHead(arg) =>
Token::LambdaHead(arg.into_iter().map(|tt| recur(tt, f)).collect_vec()),
Token::S(p, b) => Token::S(p, b.into_iter().map(|tt| recur(tt, f)).collect_vec()),
};
TokTree { range, tok }
})
}
pub trait AtomRepr: fmt::Display + Clone + fmt::Debug {
type Ctx: ?Sized;
fn from_api(api: &api::Atom, pos: Pos, ctx: &mut Self::Ctx) -> Self;
fn to_api(&self) -> orchid_api::Atom;
type Ctx: ?Sized;
fn from_api(api: &api::Atom, pos: Pos, ctx: &mut Self::Ctx) -> Self;
fn to_api(&self) -> orchid_api::Atom;
}
impl AtomRepr for Never {
type Ctx = Never;
fn from_api(_: &api::Atom, _: Pos, _: &mut Self::Ctx) -> Self { panic!() }
fn to_api(&self) -> orchid_api::Atom { match *self {} }
type Ctx = Never;
fn from_api(_: &api::Atom, _: Pos, _: &mut Self::Ctx) -> Self { panic!() }
fn to_api(&self) -> orchid_api::Atom { match *self {} }
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct TokHandle<'a>(api::TreeTicket, PhantomData<&'a ()>);
impl TokHandle<'static> {
pub fn new(tt: api::TreeTicket) -> Self { TokHandle(tt, PhantomData) }
pub fn new(tt: api::TreeTicket) -> Self { TokHandle(tt, PhantomData) }
}
impl TokHandle<'_> {
pub fn ticket(self) -> api::TreeTicket { self.0 }
pub fn ticket(self) -> api::TreeTicket { self.0 }
}
impl Display for TokHandle<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Handle({})", self.0.0) }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Handle({})", self.0.0) }
}
#[derive(Clone, Debug)]
pub struct TokTree<'a, A: AtomRepr, X: ExtraTok> {
pub tok: Token<'a, A, X>,
pub range: Range<u32>,
pub tok: Token<'a, A, X>,
pub range: Range<u32>,
}
impl<'a, A: AtomRepr, X: ExtraTok> TokTree<'a, A, X> {
pub fn from_api(tt: &api::TokenTree, ctx: &mut A::Ctx) -> Self {
let tok = match_mapping!(&tt.token, api::Token => Token::<'a, A, X> {
BR, NS,
Atom(a => A::from_api(a, Pos::Range(tt.range.clone()), ctx)),
Bottom(e => OrcErrv::from_api(e)),
LambdaHead(arg => ttv_from_api(arg, ctx)),
Name(n => Tok::from_api(*n)),
S(*par, b => ttv_from_api(b, ctx)),
Comment(c.clone()),
Slot(id => TokHandle::new(*id)),
Ph(ph => Ph::from_api(ph)),
Macro(*prio)
});
Self { range: tt.range.clone(), tok }
}
pub fn from_api(tt: &api::TokenTree, ctx: &mut A::Ctx) -> Self {
let tok = match_mapping!(&tt.token, api::Token => Token::<'a, A, X> {
BR, NS,
Atom(a => A::from_api(a, Pos::Range(tt.range.clone()), ctx)),
Bottom(e => OrcErrv::from_api(e)),
LambdaHead(arg => ttv_from_api(arg, ctx)),
Name(n => Tok::from_api(*n)),
S(*par, b => ttv_from_api(b, ctx)),
Comment(c.clone()),
Slot(id => TokHandle::new(*id)),
Ph(ph => Ph::from_api(ph)),
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 {
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)),
Name(n.to_api()),
Slot(tt.ticket()),
S(*p, b => ttv_to_api(b, do_extra)),
Ph(ph.to_api()),
Macro(*prio),
} {
Token::X(x) => return do_extra(x, self.range.clone())
});
api::TokenTree { range: self.range.clone(), token }
}
pub fn to_api(
&self,
do_extra: &mut impl FnMut(&X, Range<u32>) -> api::TokenTree,
) -> 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)),
Name(n.to_api()),
Slot(tt.ticket()),
S(*p, b => ttv_to_api(b, do_extra)),
Ph(ph.to_api()),
Macro(*prio),
} {
Token::X(x) => return do_extra(x, self.range.clone())
});
api::TokenTree { range: self.range.clone(), token }
}
pub fn into_api(
self,
do_extra: &mut impl FnMut(X, Range<u32>) -> api::TokenTree,
) -> api::TokenTree {
let token = match self.tok {
Token::Atom(a) => api::Token::Atom(a.to_api()),
Token::BR => api::Token::BR,
Token::NS => api::Token::NS,
Token::Bottom(e) => api::Token::Bottom(e.to_api()),
Token::Comment(c) => api::Token::Comment(c.clone()),
Token::LambdaHead(arg) => api::Token::LambdaHead(ttv_into_api(arg, do_extra)),
Token::Name(n) => api::Token::Name(n.to_api()),
Token::Slot(tt) => api::Token::Slot(tt.ticket()),
Token::S(p, b) => api::Token::S(p, ttv_into_api(b, do_extra)),
Token::Ph(Ph { kind, name }) =>
api::Token::Ph(api::Placeholder { name: name.to_api(), kind }),
Token::X(x) => return do_extra(x, self.range.clone()),
Token::Macro(prio) => api::Token::Macro(prio),
};
api::TokenTree { range: self.range.clone(), token }
}
pub fn into_api(
self,
do_extra: &mut impl FnMut(X, Range<u32>) -> api::TokenTree,
) -> api::TokenTree {
let token = match self.tok {
Token::Atom(a) => api::Token::Atom(a.to_api()),
Token::BR => api::Token::BR,
Token::NS => api::Token::NS,
Token::Bottom(e) => api::Token::Bottom(e.to_api()),
Token::Comment(c) => api::Token::Comment(c.clone()),
Token::LambdaHead(arg) => api::Token::LambdaHead(ttv_into_api(arg, do_extra)),
Token::Name(n) => api::Token::Name(n.to_api()),
Token::Slot(tt) => api::Token::Slot(tt.ticket()),
Token::S(p, b) => api::Token::S(p, ttv_into_api(b, do_extra)),
Token::Ph(Ph { kind, name }) =>
api::Token::Ph(api::Placeholder { name: name.to_api(), kind }),
Token::X(x) => return do_extra(x, self.range.clone()),
Token::Macro(prio) => api::Token::Macro(prio),
};
api::TokenTree { range: self.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>> {
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 lambda(arg: Vec<Self>, mut body: Vec<Self>) -> Self {
let arg_range = ttv_range(&arg);
let s_range = arg_range.start..body.last().expect("Lambda with empty body!").range.end;
body.insert(0, Token::LambdaHead(arg).at(arg_range));
Token::S(Paren::Round, body).at(s_range)
}
pub fn is_kw(&self, tk: Tok<String>) -> bool { self.tok.is_kw(tk) }
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 lambda(arg: Vec<Self>, mut body: Vec<Self>) -> Self {
let arg_range = ttv_range(&arg);
let s_range = arg_range.start..body.last().expect("Lambda with empty body!").range.end;
body.insert(0, Token::LambdaHead(arg).at(arg_range));
Token::S(Paren::Round, body).at(s_range)
}
}
impl<A: AtomRepr, X: ExtraTok> Display for TokTree<'_, A, X> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.tok) }
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.tok) }
}
pub fn ttv_from_api<A: AtomRepr, X: ExtraTok>(
tokv: impl IntoIterator<Item: Borrow<api::TokenTree>>,
ctx: &mut A::Ctx,
tokv: impl IntoIterator<Item: Borrow<api::TokenTree>>,
ctx: &mut A::Ctx,
) -> Vec<TokTree<'static, A, X>> {
tokv.into_iter().map(|t| TokTree::<A, X>::from_api(t.borrow(), ctx)).collect()
tokv.into_iter().map(|t| TokTree::<A, X>::from_api(t.borrow(), ctx)).collect()
}
pub 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,
tokv: impl IntoIterator<Item: Borrow<TokTree<'a, A, X>>>,
do_extra: &mut impl FnMut(&X, Range<u32>) -> api::TokenTree,
) -> Vec<api::TokenTree> {
tokv.into_iter().map(|tok| Borrow::<TokTree<A, X>>::borrow(&tok).to_api(do_extra)).collect_vec()
tokv.into_iter().map(|tok| Borrow::<TokTree<A, X>>::borrow(&tok).to_api(do_extra)).collect_vec()
}
pub fn ttv_into_api<'a, A: AtomRepr, X: ExtraTok>(
tokv: impl IntoIterator<Item = TokTree<'a, A, X>>,
do_extra: &mut impl FnMut(X, Range<u32>) -> api::TokenTree,
tokv: impl IntoIterator<Item = TokTree<'a, A, X>>,
do_extra: &mut impl FnMut(X, Range<u32>) -> api::TokenTree,
) -> Vec<api::TokenTree> {
tokv.into_iter().map(|t| t.into_api(do_extra)).collect_vec()
tokv.into_iter().map(|t| t.into_api(do_extra)).collect_vec()
}
/// This takes a position and not a range because it assigns the range to
/// multiple leaf tokens, which is only valid if it's a zero-width range
pub fn vname_tv<'a: 'b, 'b, A: AtomRepr + 'a, X: ExtraTok + 'a>(
name: &'b PathSlice,
pos: u32,
name: &'b PathSlice,
pos: u32,
) -> impl Iterator<Item = TokTree<'a, A, X>> + 'b {
let (head, tail) = name.split_first().expect("Empty vname");
iter::once(Token::Name(head.clone()))
.chain(tail.iter().flat_map(|t| [Token::NS, Token::Name(t.clone())]))
.map(move |t| t.at(pos..pos))
let (head, tail) = name.split_first().expect("Empty vname");
iter::once(Token::Name(head.clone()))
.chain(tail.iter().flat_map(|t| [Token::NS, Token::Name(t.clone())]))
.map(move |t| t.at(pos..pos))
}
pub fn wrap_tokv<'a, A: AtomRepr, X: ExtraTok>(
items: impl IntoIterator<Item = TokTree<'a, A, X>>
items: impl IntoIterator<Item = TokTree<'a, A, X>>,
) -> TokTree<'a, A, X> {
let items_v = items.into_iter().collect_vec();
match items_v.len() {
0 => panic!("A tokv with no elements is illegal"),
1 => items_v.into_iter().next().unwrap(),
_ => {
let range = items_v.first().unwrap().range.start..items_v.last().unwrap().range.end;
Token::S(api::Paren::Round, items_v).at(range)
},
}
let items_v = items.into_iter().collect_vec();
match items_v.len() {
0 => panic!("A tokv with no elements is illegal"),
1 => items_v.into_iter().next().unwrap(),
_ => {
let range = items_v.first().unwrap().range.start..items_v.last().unwrap().range.end;
Token::S(api::Paren::Round, items_v).at(range)
},
}
}
pub use api::Paren;
#[derive(Clone, Debug)]
pub enum Token<'a, A: AtomRepr, X: ExtraTok> {
Comment(Arc<String>),
LambdaHead(Vec<TokTree<'a, A, X>>),
Name(Tok<String>),
NS,
BR,
S(Paren, Vec<TokTree<'a, A, X>>),
Atom(A),
Bottom(OrcErrv),
Slot(TokHandle<'a>),
X(X),
Ph(Ph),
Macro(Option<NotNan<f64>>),
Comment(Arc<String>),
LambdaHead(Vec<TokTree<'a, A, X>>),
Name(Tok<String>),
NS,
BR,
S(Paren, Vec<TokTree<'a, A, X>>),
Atom(A),
Bottom(OrcErrv),
Slot(TokHandle<'a>),
X(X),
Ph(Ph),
Macro(Option<NotNan<f64>>),
}
impl<'a, A: AtomRepr, X: ExtraTok> Token<'a, A, X> {
pub fn at(self, range: Range<u32>) -> TokTree<'a, A, X> { TokTree { range, tok: self } }
pub fn is_kw(&self, tk: Tok<String>) -> bool {
matches!(self, Token::Name(n) if *n == tk)
}
pub fn as_s(&self, par: Paren) -> Option<&[TokTree<'a, A, X>]> {
match self {
Self::S(p, b) if *p == par => Some(b),
_ => None,
}
}
pub fn at(self, range: Range<u32>) -> TokTree<'a, A, X> { TokTree { range, tok: self } }
pub fn is_kw(&self, tk: Tok<String>) -> bool { matches!(self, Token::Name(n) if *n == tk) }
pub fn as_s(&self, par: Paren) -> Option<&[TokTree<'a, A, X>]> {
match self {
Self::S(p, b) if *p == par => Some(b),
_ => None,
}
}
}
impl<A: AtomRepr, X: ExtraTok> Display for Token<'_, A, X> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
thread_local! {
static PAREN_LEVEL: RefCell<usize> = 0.into();
}
fn get_indent() -> usize { PAREN_LEVEL.with_borrow(|t| *t) }
fn with_indent<T>(f: impl FnOnce() -> T) -> T {
PAREN_LEVEL.with_borrow_mut(|t| *t += 1);
let r = f();
PAREN_LEVEL.with_borrow_mut(|t| *t -= 1);
r
}
match self {
Self::Atom(a) => f.write_str(&indent(&format!("{a} "), get_indent(), false)),
Self::BR => write!(f, "\n{}", " ".repeat(get_indent())),
Self::Bottom(err) if err.len() == 1 => write!(f, "Bottom({}) ", err.one().unwrap()),
Self::Bottom(err) => {
write!(f, "Botttom(\n{}) ", indent(&err.to_string(), get_indent() + 1, true))
},
Self::Comment(c) => write!(f, "--[{c}]-- "),
Self::LambdaHead(arg) => with_indent(|| write!(f, "\\ {} . ", ttv_fmt(arg))),
Self::NS => f.write_str(":: "),
Self::Name(n) => write!(f, "{n} "),
Self::Slot(th) => write!(f, "{th} "),
Self::Ph(Ph { kind, name }) => match &kind {
PhKind::Scalar => write!(f, "${name}"),
PhKind::Vector { at_least_one, priority } => {
if *at_least_one { write!(f, ".")? }
write!(f, "..${name}")?;
if 0 < *priority { write!(f, "{priority}") } else { Ok(()) }
}
}
Self::S(p, b) => {
let (lp, rp, _) = PARENS.iter().find(|(_, _, par)| par == p).unwrap();
write!(f, "{lp} ")?;
with_indent(|| f.write_str(&ttv_fmt(b)))?;
write!(f, "{rp} ")
},
Self::X(x) => write!(f, "{x} "),
Self::Macro(None) => write!(f, "macro "),
Self::Macro(Some(prio)) => write!(f, "macro({prio})"),
}
}
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
thread_local! {
static PAREN_LEVEL: RefCell<usize> = 0.into();
}
fn get_indent() -> usize { PAREN_LEVEL.with_borrow(|t| *t) }
fn with_indent<T>(f: impl FnOnce() -> T) -> T {
PAREN_LEVEL.with_borrow_mut(|t| *t += 1);
let r = f();
PAREN_LEVEL.with_borrow_mut(|t| *t -= 1);
r
}
match self {
Self::Atom(a) => f.write_str(&indent(&format!("{a} "), get_indent(), false)),
Self::BR => write!(f, "\n{}", " ".repeat(get_indent())),
Self::Bottom(err) if err.len() == 1 => write!(f, "Bottom({}) ", err.one().unwrap()),
Self::Bottom(err) => {
write!(f, "Botttom(\n{}) ", indent(&err.to_string(), get_indent() + 1, true))
},
Self::Comment(c) => write!(f, "--[{c}]-- "),
Self::LambdaHead(arg) => with_indent(|| write!(f, "\\ {} . ", ttv_fmt(arg))),
Self::NS => f.write_str(":: "),
Self::Name(n) => write!(f, "{n} "),
Self::Slot(th) => write!(f, "{th} "),
Self::Ph(Ph { kind, name }) => match &kind {
PhKind::Scalar => write!(f, "${name}"),
PhKind::Vector { at_least_one, priority } => {
if *at_least_one {
write!(f, ".")?
}
write!(f, "..${name}")?;
if 0 < *priority { write!(f, "{priority}") } else { Ok(()) }
},
},
Self::S(p, b) => {
let (lp, rp, _) = PARENS.iter().find(|(_, _, par)| par == p).unwrap();
write!(f, "{lp} ")?;
with_indent(|| f.write_str(&ttv_fmt(b)))?;
write!(f, "{rp} ")
},
Self::X(x) => write!(f, "{x} "),
Self::Macro(None) => write!(f, "macro "),
Self::Macro(Some(prio)) => write!(f, "macro({prio})"),
}
}
}
pub fn ttv_range(ttv: &[TokTree<'_, impl AtomRepr, impl ExtraTok>]) -> Range<u32> {
assert!(!ttv.is_empty(), "Empty slice has no range");
ttv.first().unwrap().range.start..ttv.last().unwrap().range.end
assert!(!ttv.is_empty(), "Empty slice has no range");
ttv.first().unwrap().range.start..ttv.last().unwrap().range.end
}
pub fn ttv_fmt<'a: 'b, 'b>(
ttv: impl IntoIterator<Item = &'b TokTree<'a, impl AtomRepr + 'b, impl ExtraTok + 'b>>,
ttv: impl IntoIterator<Item = &'b TokTree<'a, impl AtomRepr + 'b, impl ExtraTok + 'b>>,
) -> String {
ttv.into_iter().join("")
ttv.into_iter().join("")
}
pub fn indent(s: &str, lvl: usize, first: bool) -> String {
if first {
s.replace("\n", &("\n".to_string() + &" ".repeat(lvl)))
} else if let Some((fst, rest)) = s.split_once('\n') {
fst.to_string() + "\n" + &indent(rest, lvl, true)
} else {
s.to_string()
}
if first {
s.replace("\n", &("\n".to_string() + &" ".repeat(lvl)))
} else if let Some((fst, rest)) = s.split_once('\n') {
fst.to_string() + "\n" + &indent(rest, lvl, true)
} else {
s.to_string()
}
}
#[derive(Clone, Debug)]
pub struct Ph {
pub name: Tok<String>,
pub kind: PhKind,
pub name: Tok<String>,
pub kind: PhKind,
}
impl Ph {
pub fn from_api(api: &api::Placeholder) -> Self {
Self { name: Tok::from_api(api.name), kind: api.kind }
}
pub fn to_api(&self) -> api::Placeholder {
api::Placeholder { name: self.name.to_api(), kind: self.kind }
}
pub fn from_api(api: &api::Placeholder) -> Self {
Self { name: Tok::from_api(api.name), kind: api.kind }
}
pub fn to_api(&self) -> api::Placeholder {
api::Placeholder { name: self.name.to_api(), kind: self.kind }
}
}
#[cfg(test)]
mod test {
use super::*;
use super::*;
#[test]
fn test_covariance() {
fn _f<'a>(x: Token<'static, Never, Never>) -> Token<'a, Never, Never> { x }
}
#[test]
fn test_covariance() {
fn _f<'a>(x: Token<'static, Never, Never>) -> Token<'a, Never, Never> { x }
}
#[test]
fn fail_covariance() {
// this fails to compile
// fn _f<'a, 'b>(x: &'a mut &'static ()) -> &'a mut &'b () { x }
// this passes because it's covariant
fn _f<'a, 'b>(x: &'a fn() -> &'static ()) -> &'a fn() -> &'b () { x }
}
#[test]
fn fail_covariance() {
// this fails to compile
// fn _f<'a, 'b>(x: &'a mut &'static ()) -> &'a mut &'b () { x }
// this passes because it's covariant
fn _f<'a, 'b>(x: &'a fn() -> &'static ()) -> &'a fn() -> &'b () { x }
}
}