cl-parser: Dedicated parsing logic for patterns!
This commit is contained in:
parent
e6156343c3
commit
3e2063835b
@ -586,6 +586,7 @@ pub struct MatchArm(pub Pattern, pub Expr);
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Pattern {
|
||||
Name(Sym),
|
||||
Path(Path),
|
||||
Literal(Literal),
|
||||
Rest(Option<Box<Pattern>>),
|
||||
Ref(Mutability, Box<Pattern>),
|
||||
|
@ -468,6 +468,7 @@ impl Display for Pattern {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Pattern::Name(sym) => sym.fmt(f),
|
||||
Pattern::Path(path) => path.fmt(f),
|
||||
Pattern::Literal(literal) => literal.fmt(f),
|
||||
Pattern::Rest(Some(name)) => write!(f, "..{name}"),
|
||||
Pattern::Rest(None) => "..".fmt(f),
|
||||
|
@ -338,6 +338,7 @@ impl WeightOf for Pattern {
|
||||
fn weight_of(&self) -> usize {
|
||||
match self {
|
||||
Pattern::Name(s) => size_of_val(s),
|
||||
Pattern::Path(p) => p.weight_of(),
|
||||
Pattern::Literal(literal) => literal.weight_of(),
|
||||
Pattern::Rest(Some(pattern)) => pattern.weight_of(),
|
||||
Pattern::Rest(None) => 0,
|
||||
|
@ -253,6 +253,7 @@ pub trait Fold {
|
||||
fn fold_pattern(&mut self, p: Pattern) -> Pattern {
|
||||
match p {
|
||||
Pattern::Name(sym) => Pattern::Name(self.fold_sym(sym)),
|
||||
Pattern::Path(path) => Pattern::Path(self.fold_path(path)),
|
||||
Pattern::Literal(literal) => Pattern::Literal(self.fold_literal(literal)),
|
||||
Pattern::Rest(Some(name)) => Pattern::Rest(Some(self.fold_pattern(*name).into())),
|
||||
Pattern::Rest(None) => Pattern::Rest(None),
|
||||
|
@ -793,6 +793,7 @@ impl Walk for Pattern {
|
||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
||||
match self {
|
||||
Pattern::Name(sym) => sym.visit_in(v),
|
||||
Pattern::Path(path) => path.visit_in(v),
|
||||
Pattern::Literal(literal) => literal.visit_in(v),
|
||||
Pattern::Rest(pattern) => pattern.visit_in(v),
|
||||
Pattern::Ref(mutability, pattern) => {
|
||||
|
@ -14,8 +14,9 @@ use std::collections::{HashMap, VecDeque};
|
||||
pub fn variables(pat: &Pattern) -> Vec<&Sym> {
|
||||
fn patvars<'p>(set: &mut Vec<&'p Sym>, pat: &'p Pattern) {
|
||||
match pat {
|
||||
Pattern::Name(name) if &**name == "_" => {}
|
||||
Pattern::Name(name) if name.to_ref() == "_" => {}
|
||||
Pattern::Name(name) => set.push(name),
|
||||
Pattern::Path(_) => {}
|
||||
Pattern::Literal(_) => {}
|
||||
Pattern::Rest(Some(pattern)) => patvars(set, pattern),
|
||||
Pattern::Rest(None) => {}
|
||||
|
@ -1093,10 +1093,94 @@ impl Parse<'_> for Return {
|
||||
}
|
||||
}
|
||||
|
||||
fn pathpattern(p: &mut Parser<'_>) -> PResult<Pattern> {
|
||||
const P: Parsing = Parsing::Pattern;
|
||||
let name = Path::parse(p)?;
|
||||
|
||||
let struct_members = |p: &mut Parser| {
|
||||
let name = p.parse()?;
|
||||
let pat = if p.match_type(TokenKind::Colon, P).is_ok() {
|
||||
Some(p.parse()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok((name, pat))
|
||||
};
|
||||
|
||||
Ok(match p.peek_kind(Parsing::Pattern)? {
|
||||
TokenKind::LCurly => Pattern::Struct(
|
||||
name,
|
||||
delim(
|
||||
sep(struct_members, TokenKind::Comma, TokenKind::RCurly, P),
|
||||
CURLIES,
|
||||
P,
|
||||
)(p)?,
|
||||
),
|
||||
TokenKind::LParen => Pattern::TupleStruct(
|
||||
name,
|
||||
delim(
|
||||
sep(Parse::parse, TokenKind::Comma, TokenKind::RParen, P),
|
||||
PARENS,
|
||||
P,
|
||||
)(p)?,
|
||||
),
|
||||
_ => name
|
||||
.as_sym()
|
||||
.map(Pattern::Name)
|
||||
.unwrap_or(Pattern::Path(name)),
|
||||
})
|
||||
}
|
||||
|
||||
impl Parse<'_> for Pattern {
|
||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||
let value = prec::expr(p, prec::Precedence::Pattern.level())?;
|
||||
Pattern::try_from(value).map_err(|e| p.error(InvalidPattern(e.into()), Parsing::Pattern))
|
||||
const P: Parsing = Parsing::Pattern;
|
||||
Ok(match p.peek_kind(P)? {
|
||||
// Name, Path, Struct, TupleStruct
|
||||
TokenKind::Identifier => pathpattern(p)?,
|
||||
// Literal
|
||||
TokenKind::Literal => Pattern::Literal(p.parse()?),
|
||||
// Rest
|
||||
TokenKind::DotDot => {
|
||||
p.consume_peeked();
|
||||
if matches!(
|
||||
p.peek_kind(P),
|
||||
Ok(TokenKind::Identifier | TokenKind::Literal)
|
||||
) {
|
||||
Pattern::Rest(Some(p.parse()?))
|
||||
} else {
|
||||
Pattern::Rest(None)
|
||||
}
|
||||
}
|
||||
// Ref
|
||||
TokenKind::Amp => {
|
||||
p.consume_peeked();
|
||||
Pattern::Ref(p.parse()?, p.parse()?)
|
||||
}
|
||||
// Ref(Ref)
|
||||
TokenKind::AmpAmp => {
|
||||
p.consume_peeked();
|
||||
Pattern::Ref(
|
||||
Mutability::Not,
|
||||
Box::new(Pattern::Ref(p.parse()?, p.parse()?)),
|
||||
)
|
||||
}
|
||||
// Tuple
|
||||
TokenKind::LParen => Pattern::Tuple(delim(
|
||||
sep(Parse::parse, TokenKind::Comma, TokenKind::RParen, P),
|
||||
PARENS,
|
||||
P,
|
||||
)(p)?),
|
||||
// Array
|
||||
TokenKind::LBrack => Pattern::Array(delim(
|
||||
sep(Parse::parse, TokenKind::Comma, TokenKind::RBrack, P),
|
||||
BRACKETS,
|
||||
P,
|
||||
)(p)?),
|
||||
_ => {
|
||||
let bad_expr = p.parse()?;
|
||||
Err(p.error(ErrorKind::InvalidPattern(bad_expr), P))?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,6 @@ fn structor_body(p: &mut Parser, to: Path) -> PResult<Structor> {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Precedence {
|
||||
Assign,
|
||||
Pattern, // A pattern can contain a structor
|
||||
Structor, // A structor is never a valid conditional
|
||||
Condition, // Anything that syntactically needs a block following it
|
||||
Logic,
|
||||
|
@ -508,6 +508,7 @@ pub mod clangify {
|
||||
// TODO: Pattern match desugaring!!!
|
||||
match self {
|
||||
Pattern::Name(name) => y.p(name),
|
||||
Pattern::Path(path) => y.p(path),
|
||||
Pattern::Literal(literal) => y.p(literal),
|
||||
Pattern::Rest(name) => y.p("..").p(name),
|
||||
Pattern::Ref(mutability, pattern) => y.p("&").p(mutability).p(pattern),
|
||||
|
@ -428,6 +428,7 @@ pub mod yamlify {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
match self {
|
||||
Pattern::Name(name) => y.value(name),
|
||||
Pattern::Path(path) => y.value(path),
|
||||
Pattern::Literal(literal) => y.value(literal),
|
||||
Pattern::Rest(name) => y.pair("Rest", name),
|
||||
Pattern::Ref(mutability, pattern) => y.yaml(mutability).pair("Pat", pattern),
|
||||
|
@ -519,6 +519,11 @@ impl<'a> Inference<'a> for Pattern {
|
||||
e.at = node;
|
||||
Ok(node)
|
||||
}
|
||||
Pattern::Path(path) => {
|
||||
// Evaluating a path pattern puts type constraints on the scrutinee
|
||||
path.evaluate(e.table, e.at)
|
||||
.map_err(|_| InferenceError::NotFound(path.clone()))
|
||||
}
|
||||
Pattern::Literal(literal) => literal.infer(e),
|
||||
Pattern::Rest(Some(pat)) => pat.infer(e), // <-- glaring soundness holes
|
||||
Pattern::Rest(_) => todo!("Fix glaring soundness holes in pattern"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user