First steps for the macro system

This commit is contained in:
2025-08-01 18:32:55 +02:00
parent f87185ef88
commit 051b5e666f
18 changed files with 356 additions and 166 deletions

View File

@@ -158,6 +158,40 @@ impl fmt::Display for OrcErrv {
pub type OrcRes<T> = Result<T, OrcErrv>;
pub fn join_ok<T, U>(left: OrcRes<T>, right: OrcRes<U>) -> OrcRes<(T, U)> {
match (left, right) {
(Ok(t), Ok(u)) => Ok((t, u)),
(Err(e), Ok(_)) | (Ok(_), Err(e)) => Err(e),
(Err(e1), Err(e2)) => Err(e1 + e2),
}
}
#[macro_export]
macro_rules! join_ok {
($($names:ident $(: $tys:ty)? = $vals:expr;)*) => {
let $crate::join_ok!(@NAMES $($names $(: $tys)? = $vals;)*)
:
$crate::join_ok!(@TYPES $($names $(: $tys)? = $vals;)*)
=
$crate::join_ok!(@VALUES $($names $(: $tys)? = $vals;)*)?;
};
(@NAMES $name:ident $(: $ty:ty)? = $val:expr ; $($names:ident $(: $tys:ty)? = $vals:expr;)*) => {
($name, $crate::join_ok!(@NAMES $($names $(: $tys)? = $vals;)*))
};
(@NAMES) => { _ };
(@TYPES $name:ident : $ty:ty = $val:expr ; $($names:ident $(: $tys:ty)? = $vals:expr;)*) => {
($ty, $crate::join_ok!(@TYPES $($names $(: $tys)? = $vals;)*))
};
(@TYPES $name:ident = $val:expr ; $($names:ident $(: $tys:ty)? = $vals:expr;)*) => {
(_, $crate::join_ok!(@TYPES $($names $(: $tys)? = $vals;)*))
};
(@TYPES) => { () };
(@VALUES $name:ident $(: $ty:ty)? = $val:expr ; $($names:ident $(: $tys:ty)? = $vals:expr;)*) => {
$crate::error::join_ok($val, $crate::join_ok!(@VALUES $($names $(: $tys)? = $vals;)*))
};
(@VALUES) => { Ok(()) };
}
pub fn mk_err(
description: Tok<String>,
message: impl AsRef<str>,

View File

@@ -108,6 +108,10 @@ impl SrcRange {
pub fn to_api(&self) -> api::SourceRange {
api::SourceRange { path: self.path.to_api(), range: self.range.clone() }
}
pub fn to(&self, rhs: &Self) -> Self {
assert_eq!(self.path, rhs.path, "Range continues across files");
Self { path: self.path(), range: self.start().min(rhs.start())..self.end().max(rhs.end()) }
}
}
impl From<SrcRange> for ErrPos {
fn from(val: SrcRange) -> Self { val.pos().into() }

View File

@@ -236,8 +236,8 @@ impl Sym {
Self::from_tok(Tok::from_api(marker, i).await).expect("Empty sequence found for serialized Sym")
}
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
pub async fn push(&self, tok: Tok<String>, i: &Interner) -> Sym {
Self::new(self.0.iter().cloned().chain([tok]), i).await.unwrap()
pub async fn suffix(&self, tokv: impl IntoIterator<Item = Tok<String>>, i: &Interner) -> Sym {
Self::new(self.0.iter().cloned().chain(tokv), i).await.unwrap()
}
}
impl fmt::Debug for Sym {

View File

@@ -11,14 +11,14 @@ use crate::error::{OrcErrv, OrcRes, Reporter, mk_err, mk_errv};
use crate::format::{FmtCtx, FmtUnit, Format, fmt};
use crate::interner::{Interner, Tok};
use crate::location::SrcRange;
use crate::name::{Sym, VName, VPath};
use crate::name::{NameLike, Sym, VName, VPath};
use crate::tree::{ExprRepr, ExtraTok, Paren, TokTree, Token, ttv_fmt, ttv_range};
pub trait ParseCtx {
#[must_use]
fn i(&self) -> &Interner;
#[must_use]
fn reporter(&self) -> &Reporter;
fn rep(&self) -> &Reporter;
}
pub struct ParseCtxImpl<'a> {
pub i: &'a Interner,
@@ -26,7 +26,7 @@ pub struct ParseCtxImpl<'a> {
}
impl ParseCtx for ParseCtxImpl<'_> {
fn i(&self) -> &Interner { self.i }
fn reporter(&self) -> &Reporter { self.r }
fn rep(&self) -> &Reporter { self.r }
}
pub fn name_start(c: char) -> bool { c.is_alphabetic() || c == '_' }
@@ -237,7 +237,7 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
match &tt.tok {
Token::NS(ns, body) => {
if !ns.starts_with(name_start) {
ctx.reporter().report(mk_err(
ctx.rep().report(mk_err(
ctx.i().i("Unexpected name prefix").await,
"Only names can precede ::",
[ttpos.into()],
@@ -257,7 +257,7 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
while let Some((output, tail)) = body.pop_front() {
match rec(output, ctx).boxed_local().await {
Ok(names) => o.extend(names),
Err(e) => ctx.reporter().report(e),
Err(e) => ctx.rep().report(e),
}
body = tail;
}
@@ -296,6 +296,10 @@ impl Import {
None => self.path.into_name().expect("Import cannot be empty"),
}
}
pub fn new(sr: SrcRange, path: VPath, name: Tok<String>) -> Self {
Import { path, name: Some(name), sr }
}
pub fn new_glob(sr: SrcRange, path: VPath) -> Self { Import { path, name: None, sr } }
}
impl Display for Import {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@@ -16,7 +16,7 @@ use crate::error::OrcErrv;
use crate::format::{FmtCtx, FmtUnit, Format, Variants};
use crate::interner::{Interner, Tok};
use crate::location::{Pos, SrcRange};
use crate::name::Sym;
use crate::name::{Sym, VName, VPath};
use crate::parse::Snippet;
use crate::{api, match_mapping, tl_cache};
@@ -149,6 +149,20 @@ impl<H: ExprRepr, X: ExtraTok> TokTree<H, X> {
pub fn as_name(&self) -> Option<Tok<String>> {
if let Token::Name(n) = &self.tok { Some(n.clone()) } else { None }
}
pub fn as_multiname(&self) -> Result<VName, &TokTree<H, X>> {
let mut segs = VPath::new([]);
let mut cur = self;
loop {
match &cur.tok {
Token::Name(last) => return Ok(segs.name_with_suffix(last.clone())),
Token::NS(seg, inner) => {
segs = segs.suffix([seg.clone()]);
cur = inner;
},
_ => return Err(cur),
}
}
}
pub fn as_s(&self, par: Paren) -> Option<Snippet<'_, H, X>> {
self.tok.as_s(par).map(|slc| Snippet::new(self, slc))
}