New macro system and stdlib additions

This commit is contained in:
2025-11-21 14:25:03 +01:00
parent b77653f841
commit 603efef28e
230 changed files with 3033 additions and 16640 deletions

View File

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

View File

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

View File

@@ -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])
);
})

View File

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