forked from Orchid/orchid
New macro system and stdlib additions
This commit is contained in:
@@ -7,7 +7,7 @@ use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
use futures::future::join_all;
|
||||
use itertools::Itertools;
|
||||
use itertools::{Itertools, chain};
|
||||
use never::Never;
|
||||
use regex::Regex;
|
||||
|
||||
@@ -47,12 +47,14 @@ impl FmtUnit {
|
||||
}
|
||||
}
|
||||
pub fn sequence(
|
||||
head: &str,
|
||||
delim: &str,
|
||||
tail: &str,
|
||||
seq_bnd: Option<bool>,
|
||||
seq: impl IntoIterator<Item = FmtUnit>,
|
||||
) -> Self {
|
||||
let items = seq.into_iter().collect_vec();
|
||||
FmtUnit::new(Variants::sequence(items.len(), delim, seq_bnd), items)
|
||||
Variants::default().sequence(items.len(), head, delim, tail, seq_bnd).units_own(items)
|
||||
}
|
||||
}
|
||||
impl<T> From<T> for FmtUnit
|
||||
@@ -110,8 +112,29 @@ pub struct Variant {
|
||||
|
||||
#[test]
|
||||
fn variants_parse_test() {
|
||||
let vars = Variants::default().bounded("({0})");
|
||||
println!("final: {vars:?}")
|
||||
let vars = Rc::new(Variants::default().bounded("({{{0}}})"));
|
||||
let expected_vars = Rc::new(Variants(vec![Variant {
|
||||
bounded: true,
|
||||
elements: vec![
|
||||
FmtElement::String(Rc::new("({".to_string())),
|
||||
FmtElement::Sub { bounded: Some(false), slot: 0 },
|
||||
FmtElement::String(Rc::new("})".to_string())),
|
||||
],
|
||||
}]));
|
||||
assert_eq!(vars.as_ref(), expected_vars.as_ref());
|
||||
let unit = vars.units(["1".into()]);
|
||||
assert_eq!(unit, FmtUnit {
|
||||
subs: vec![FmtUnit {
|
||||
subs: vec![],
|
||||
variants: Rc::new(Variants(vec![Variant {
|
||||
bounded: true,
|
||||
elements: vec![FmtElement::String(Rc::new("1".to_string()))]
|
||||
}]))
|
||||
}],
|
||||
variants: expected_vars
|
||||
});
|
||||
let str = take_first(&unit, true);
|
||||
assert_eq!(str, "({1})");
|
||||
}
|
||||
|
||||
/// Represents a collection of formatting strings for the same set of parameters
|
||||
@@ -208,12 +231,27 @@ impl Variants {
|
||||
self.add(false, s);
|
||||
self
|
||||
}
|
||||
pub fn sequence(len: usize, delim: &str, seq_bnd: Option<bool>) -> Rc<Self> {
|
||||
let seq = Itertools::intersperse(
|
||||
FmtElement::sequence(len, seq_bnd).into_iter(),
|
||||
FmtElement::str(delim),
|
||||
pub fn sequence(
|
||||
mut self,
|
||||
len: usize,
|
||||
head: &str,
|
||||
delim: &str,
|
||||
tail: &str,
|
||||
seq_bnd: Option<bool>,
|
||||
) -> Self {
|
||||
let seq = chain!(
|
||||
[FmtElement::str(head)],
|
||||
Itertools::intersperse(
|
||||
FmtElement::sequence(len, seq_bnd).into_iter(),
|
||||
FmtElement::str(delim),
|
||||
),
|
||||
[FmtElement::str(tail)],
|
||||
);
|
||||
Rc::new(Variants(vec![Variant { bounded: true, elements: seq.collect_vec() }]))
|
||||
self.0.push(Variant { bounded: true, elements: seq.collect_vec() });
|
||||
self
|
||||
}
|
||||
pub fn units_own(self, subs: impl IntoIterator<Item = FmtUnit>) -> FmtUnit {
|
||||
FmtUnit::new(Rc::new(self), subs)
|
||||
}
|
||||
pub fn units(self: &Rc<Self>, subs: impl IntoIterator<Item = FmtUnit>) -> FmtUnit {
|
||||
FmtUnit::new(self.clone(), subs)
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Range;
|
||||
use std::ops::{Add, AddAssign, Range};
|
||||
|
||||
use futures::future::join_all;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::error::ErrPos;
|
||||
@@ -25,6 +26,7 @@ pub enum Pos {
|
||||
Gen(CodeGenInfo),
|
||||
/// Range and file
|
||||
SrcRange(SrcRange),
|
||||
Multi(Vec<Pos>),
|
||||
}
|
||||
impl Pos {
|
||||
pub fn pretty_print(&self, get_src: &mut impl GetSrc) -> String {
|
||||
@@ -39,6 +41,7 @@ impl Pos {
|
||||
match_mapping!(api, api::Location => Pos {
|
||||
None, Inherit, SlotTarget,
|
||||
Gen(cgi => CodeGenInfo::from_api(cgi, i).await),
|
||||
Multi(v => join_all(v.iter().map(|l| Pos::from_api(l, i))).await)
|
||||
} {
|
||||
api::Location::SourceRange(sr) => Self::SrcRange(SrcRange::from_api(sr, i).await)
|
||||
})
|
||||
@@ -47,6 +50,7 @@ impl Pos {
|
||||
match_mapping!(self, Pos => api::Location {
|
||||
None, Inherit, SlotTarget,
|
||||
Gen(cgi.to_api()),
|
||||
Multi(v => v.iter().map(|pos| pos.to_api()).collect()),
|
||||
} {
|
||||
Self::SrcRange(sr) => api::Location::SourceRange(sr.to_api()),
|
||||
})
|
||||
@@ -60,9 +64,36 @@ impl fmt::Display for Pos {
|
||||
Pos::None => f.write_str("N/A"),
|
||||
Pos::Gen(g) => write!(f, "{g}"),
|
||||
Pos::SrcRange(sr) => write!(f, "{sr}"),
|
||||
Pos::Multi(posv) => {
|
||||
write!(f, "{}", posv[0])?;
|
||||
for pos in posv {
|
||||
write!(f, "+{}", pos)?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Add for Pos {
|
||||
type Output = Pos;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
match (self, rhs) {
|
||||
(Pos::Multi(l), Pos::Multi(r)) => Pos::Multi(l.into_iter().chain(r).collect()),
|
||||
(Pos::None, any) => any,
|
||||
(any, Pos::None) => any,
|
||||
(Pos::Multi(v), single) => Pos::Multi(v.into_iter().chain([single]).collect()),
|
||||
(single, Pos::Multi(v)) => Pos::Multi([single].into_iter().chain(v).collect()),
|
||||
(l, r) => Pos::Multi(vec![l, r]),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AddAssign for Pos {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
let mut tmp = Pos::None;
|
||||
std::mem::swap(&mut tmp, self);
|
||||
*self = tmp + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
/// Exact source code location. Includes where the code was loaded from, what
|
||||
/// the original source code was, and a byte range.
|
||||
@@ -77,7 +108,7 @@ impl SrcRange {
|
||||
}
|
||||
/// Create a dud [SourceRange] for testing. Its value is unspecified and
|
||||
/// volatile.
|
||||
pub async fn mock(i: &Interner) -> Self { Self { range: 0..1, path: sym!(test; i).await } }
|
||||
pub async fn mock(i: &Interner) -> Self { Self { range: 0..1, path: sym!(test; i) } }
|
||||
/// Path the source text was loaded from
|
||||
pub fn path(&self) -> Sym { self.path.clone() }
|
||||
/// Byte range
|
||||
|
||||
@@ -311,7 +311,7 @@ impl NameLike for VName {}
|
||||
/// cloning the token.
|
||||
#[macro_export]
|
||||
macro_rules! sym {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => {
|
||||
$crate::name::Sym::from_tok(
|
||||
$i.i(&[
|
||||
$i.i(stringify!($seg1)).await
|
||||
@@ -319,9 +319,7 @@ macro_rules! sym {
|
||||
])
|
||||
.await
|
||||
).unwrap()
|
||||
}
|
||||
};
|
||||
(@NAME $seg:tt) => {}
|
||||
}
|
||||
|
||||
/// Create a [VName] literal.
|
||||
@@ -329,12 +327,12 @@ macro_rules! sym {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vname {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => {
|
||||
$crate::name::VName::new([
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )*
|
||||
]).unwrap()
|
||||
} };
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a [VPath] literal.
|
||||
@@ -342,12 +340,12 @@ macro_rules! vname {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vpath {
|
||||
($seg1:tt $( :: $seg:tt)+ ; $i:expr) => { async {
|
||||
($seg1:tt $( :: $seg:tt)+ ; $i:expr) => {
|
||||
$crate::name::VPath(vec![
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )+
|
||||
])
|
||||
} };
|
||||
};
|
||||
() => {
|
||||
$crate::name::VPath(vec![])
|
||||
}
|
||||
@@ -367,7 +365,7 @@ mod test {
|
||||
fn recur() {
|
||||
spin_on(async {
|
||||
let i = Interner::new_master();
|
||||
let myname = vname!(foo::bar; i).await;
|
||||
let myname = vname!(foo::bar; i);
|
||||
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||
let _deref_pathslice: &[Tok<String>] = &myname;
|
||||
let _as_slice_out: &[Tok<String>] = myname.as_slice();
|
||||
@@ -379,15 +377,15 @@ mod test {
|
||||
spin_on(async {
|
||||
let i = Interner::new_master();
|
||||
assert_eq!(
|
||||
sym!(foo::bar::baz; i).await,
|
||||
sym!(foo::bar::baz; i),
|
||||
Sym::new([i.i("foo").await, i.i("bar").await, i.i("baz").await], &i).await.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vname!(foo::bar::baz; i).await,
|
||||
vname!(foo::bar::baz; i),
|
||||
VName::new([i.i("foo").await, i.i("bar").await, i.i("baz").await]).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vpath!(foo::bar::baz; i).await,
|
||||
vpath!(foo::bar::baz; i),
|
||||
VPath::new([i.i("foo").await, i.i("bar").await, i.i("baz").await])
|
||||
);
|
||||
})
|
||||
|
||||
@@ -307,7 +307,7 @@ pub async fn ttv_fmt<'a: 'b, 'b>(
|
||||
ttv: impl IntoIterator<Item = &'b TokTree<impl ExprRepr + 'a, impl ExtraTok + 'a>>,
|
||||
c: &(impl FmtCtx + ?Sized),
|
||||
) -> FmtUnit {
|
||||
FmtUnit::sequence(" ", None, join_all(ttv.into_iter().map(|t| t.print(c))).await)
|
||||
FmtUnit::sequence("", " ", "", None, join_all(ttv.into_iter().map(|t| t.print(c))).await)
|
||||
}
|
||||
|
||||
pub fn indent(s: &str) -> String { s.replace("\n", "\n ") }
|
||||
|
||||
Reference in New Issue
Block a user