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)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Name(Sym),
|
Name(Sym),
|
||||||
|
Path(Path),
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Rest(Option<Box<Pattern>>),
|
Rest(Option<Box<Pattern>>),
|
||||||
Ref(Mutability, 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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Name(sym) => sym.fmt(f),
|
Pattern::Name(sym) => sym.fmt(f),
|
||||||
|
Pattern::Path(path) => path.fmt(f),
|
||||||
Pattern::Literal(literal) => literal.fmt(f),
|
Pattern::Literal(literal) => literal.fmt(f),
|
||||||
Pattern::Rest(Some(name)) => write!(f, "..{name}"),
|
Pattern::Rest(Some(name)) => write!(f, "..{name}"),
|
||||||
Pattern::Rest(None) => "..".fmt(f),
|
Pattern::Rest(None) => "..".fmt(f),
|
||||||
|
@ -338,6 +338,7 @@ impl WeightOf for Pattern {
|
|||||||
fn weight_of(&self) -> usize {
|
fn weight_of(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Name(s) => size_of_val(s),
|
Pattern::Name(s) => size_of_val(s),
|
||||||
|
Pattern::Path(p) => p.weight_of(),
|
||||||
Pattern::Literal(literal) => literal.weight_of(),
|
Pattern::Literal(literal) => literal.weight_of(),
|
||||||
Pattern::Rest(Some(pattern)) => pattern.weight_of(),
|
Pattern::Rest(Some(pattern)) => pattern.weight_of(),
|
||||||
Pattern::Rest(None) => 0,
|
Pattern::Rest(None) => 0,
|
||||||
|
@ -253,6 +253,7 @@ pub trait Fold {
|
|||||||
fn fold_pattern(&mut self, p: Pattern) -> Pattern {
|
fn fold_pattern(&mut self, p: Pattern) -> Pattern {
|
||||||
match p {
|
match p {
|
||||||
Pattern::Name(sym) => Pattern::Name(self.fold_sym(sym)),
|
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::Literal(literal) => Pattern::Literal(self.fold_literal(literal)),
|
||||||
Pattern::Rest(Some(name)) => Pattern::Rest(Some(self.fold_pattern(*name).into())),
|
Pattern::Rest(Some(name)) => Pattern::Rest(Some(self.fold_pattern(*name).into())),
|
||||||
Pattern::Rest(None) => Pattern::Rest(None),
|
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) {
|
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Name(sym) => sym.visit_in(v),
|
Pattern::Name(sym) => sym.visit_in(v),
|
||||||
|
Pattern::Path(path) => path.visit_in(v),
|
||||||
Pattern::Literal(literal) => literal.visit_in(v),
|
Pattern::Literal(literal) => literal.visit_in(v),
|
||||||
Pattern::Rest(pattern) => pattern.visit_in(v),
|
Pattern::Rest(pattern) => pattern.visit_in(v),
|
||||||
Pattern::Ref(mutability, pattern) => {
|
Pattern::Ref(mutability, pattern) => {
|
||||||
|
@ -14,8 +14,9 @@ use std::collections::{HashMap, VecDeque};
|
|||||||
pub fn variables(pat: &Pattern) -> Vec<&Sym> {
|
pub fn variables(pat: &Pattern) -> Vec<&Sym> {
|
||||||
fn patvars<'p>(set: &mut Vec<&'p Sym>, pat: &'p Pattern) {
|
fn patvars<'p>(set: &mut Vec<&'p Sym>, pat: &'p Pattern) {
|
||||||
match pat {
|
match pat {
|
||||||
Pattern::Name(name) if &**name == "_" => {}
|
Pattern::Name(name) if name.to_ref() == "_" => {}
|
||||||
Pattern::Name(name) => set.push(name),
|
Pattern::Name(name) => set.push(name),
|
||||||
|
Pattern::Path(_) => {}
|
||||||
Pattern::Literal(_) => {}
|
Pattern::Literal(_) => {}
|
||||||
Pattern::Rest(Some(pattern)) => patvars(set, pattern),
|
Pattern::Rest(Some(pattern)) => patvars(set, pattern),
|
||||||
Pattern::Rest(None) => {}
|
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 {
|
impl Parse<'_> for Pattern {
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
let value = prec::expr(p, prec::Precedence::Pattern.level())?;
|
const P: Parsing = Parsing::Pattern;
|
||||||
Pattern::try_from(value).map_err(|e| p.error(InvalidPattern(e.into()), 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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Precedence {
|
pub enum Precedence {
|
||||||
Assign,
|
Assign,
|
||||||
Pattern, // A pattern can contain a structor
|
|
||||||
Structor, // A structor is never a valid conditional
|
Structor, // A structor is never a valid conditional
|
||||||
Condition, // Anything that syntactically needs a block following it
|
Condition, // Anything that syntactically needs a block following it
|
||||||
Logic,
|
Logic,
|
||||||
|
@ -508,6 +508,7 @@ pub mod clangify {
|
|||||||
// TODO: Pattern match desugaring!!!
|
// TODO: Pattern match desugaring!!!
|
||||||
match self {
|
match self {
|
||||||
Pattern::Name(name) => y.p(name),
|
Pattern::Name(name) => y.p(name),
|
||||||
|
Pattern::Path(path) => y.p(path),
|
||||||
Pattern::Literal(literal) => y.p(literal),
|
Pattern::Literal(literal) => y.p(literal),
|
||||||
Pattern::Rest(name) => y.p("..").p(name),
|
Pattern::Rest(name) => y.p("..").p(name),
|
||||||
Pattern::Ref(mutability, pattern) => y.p("&").p(mutability).p(pattern),
|
Pattern::Ref(mutability, pattern) => y.p("&").p(mutability).p(pattern),
|
||||||
|
@ -428,6 +428,7 @@ pub mod yamlify {
|
|||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Name(name) => y.value(name),
|
Pattern::Name(name) => y.value(name),
|
||||||
|
Pattern::Path(path) => y.value(path),
|
||||||
Pattern::Literal(literal) => y.value(literal),
|
Pattern::Literal(literal) => y.value(literal),
|
||||||
Pattern::Rest(name) => y.pair("Rest", name),
|
Pattern::Rest(name) => y.pair("Rest", name),
|
||||||
Pattern::Ref(mutability, pattern) => y.yaml(mutability).pair("Pat", pattern),
|
Pattern::Ref(mutability, pattern) => y.yaml(mutability).pair("Pat", pattern),
|
||||||
|
@ -519,6 +519,11 @@ impl<'a> Inference<'a> for Pattern {
|
|||||||
e.at = node;
|
e.at = node;
|
||||||
Ok(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::Literal(literal) => literal.infer(e),
|
||||||
Pattern::Rest(Some(pat)) => pat.infer(e), // <-- glaring soundness holes
|
Pattern::Rest(Some(pat)) => pat.infer(e), // <-- glaring soundness holes
|
||||||
Pattern::Rest(_) => todo!("Fix glaring soundness holes in pattern"),
|
Pattern::Rest(_) => todo!("Fix glaring soundness holes in pattern"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user