parser/pat: allow ranges in function type annotations

This commit is contained in:
2025-12-05 09:24:57 -05:00
parent 12cf529186
commit 1887c9c014

View File

@@ -18,26 +18,36 @@ pub enum Prec {
Tuple, Tuple,
/// Type annotation: `Pat : Pat` /// Type annotation: `Pat : Pat`
Typed, Typed,
/// Range pattern: `Pat .. Pat`, `Pat ..= Pat`
Range,
/// Function pattern: `Pat -> Pat` /// Function pattern: `Pat -> Pat`
Fn, Fn,
/// Range pattern: `Pat .. Pat`, `Pat ..= Pat`
Range,
/// The highest precedence /// The highest precedence
Max, Max,
} }
macro_rules! intify {
($enum:ident($value:path) = $min:ident, $max: ident, $($variant:ident),*$(,)?) => {
#[expect(non_upper_case_globals)] {
const $min: u32 = $enum::$min as _;
const $max: u32 = $enum::$max as _;
$(const $variant: u32 = $enum::$variant as _;)*
match $value {
..=$min => $enum::$min,
$($variant => $enum::$variant,)*
$max.. => $enum::$max,
}
}};
}
impl Prec { impl Prec {
const fn from_int(value: u32) -> Self {
intify! {Prec(value) = Min, Max, Alt, Tuple, Typed, Fn, Range}
}
/// Returns the level of precedence higher than this one /// Returns the level of precedence higher than this one
const fn next(self) -> Self { const fn next(self) -> Self {
match self { Self::from_int(self as u32 + 1)
Self::Min => Self::Alt,
Self::Alt => Self::Tuple,
Self::Tuple => Self::Typed,
Self::Typed => Self::Range,
Self::Range => Self::Fn,
Self::Fn => Self::Max,
Self::Max => Self::Max,
}
} }
} }
@@ -45,12 +55,12 @@ impl Prec {
/// and its [precedence level](Prec) /// and its [precedence level](Prec)
fn from_infix(token: &Token) -> Option<(PatOp, Prec)> { fn from_infix(token: &Token) -> Option<(PatOp, Prec)> {
Some(match token.kind { Some(match token.kind {
TKind::DotDot => (PatOp::RangeEx, Prec::Range),
TKind::DotDotEq => (PatOp::RangeIn, Prec::Range),
TKind::Colon => (PatOp::Typed, Prec::Typed),
TKind::Comma => (PatOp::Tuple, Prec::Tuple),
TKind::Arrow => (PatOp::Fn, Prec::Fn), TKind::Arrow => (PatOp::Fn, Prec::Fn),
TKind::Bar => (PatOp::Alt, Prec::Alt), TKind::Bar => (PatOp::Alt, Prec::Alt),
TKind::Colon => (PatOp::Typed, Prec::Typed),
TKind::Comma => (PatOp::Tuple, Prec::Tuple),
TKind::DotDot => (PatOp::RangeEx, Prec::Range),
TKind::DotDotEq => (PatOp::RangeIn, Prec::Range),
_ => None?, _ => None?,
}) })
} }
@@ -135,7 +145,7 @@ impl<'t> Parse<'t> for Pat {
{ {
let kind = tok.kind; let kind = tok.kind;
head = match op { head = match op {
PatOp::Typed => Pat::Op(PatOp::Typed, vec![head, p.consume().parse(Prec::Max)?]), PatOp::Typed => Pat::Op(PatOp::Typed, vec![head, p.consume().parse(prec.next())?]),
PatOp::Fn => Pat::Op(PatOp::Fn, vec![head, p.consume().parse(Prec::Fn.next())?]), PatOp::Fn => Pat::Op(PatOp::Fn, vec![head, p.consume().parse(Prec::Fn.next())?]),
op @ (PatOp::RangeEx | PatOp::RangeIn) => Pat::Op( op @ (PatOp::RangeEx | PatOp::RangeIn) => Pat::Op(
op, op,