[fine] Starting on pattern matching, make patterns explicit
This commit is contained in:
parent
f00b9e22e7
commit
deed9d9a45
4 changed files with 178 additions and 50 deletions
|
|
@ -138,6 +138,7 @@ pub enum TreeKind {
|
|||
GroupingExpression,
|
||||
Identifier,
|
||||
IfStatement,
|
||||
IsExpression,
|
||||
LetStatement,
|
||||
ListConstructor,
|
||||
ListConstructorElement,
|
||||
|
|
@ -156,8 +157,12 @@ pub enum TreeKind {
|
|||
TypeParameterList,
|
||||
UnaryExpression,
|
||||
|
||||
IsExpression,
|
||||
Pattern,
|
||||
VariableBinding,
|
||||
|
||||
MatchExpression,
|
||||
MatchBody,
|
||||
MatchArm,
|
||||
}
|
||||
|
||||
pub struct Tree<'a> {
|
||||
|
|
@ -902,6 +907,7 @@ const EXPRESSION_FIRST: &[TokenKind] = &[
|
|||
TokenKind::Selff,
|
||||
TokenKind::LeftBracket,
|
||||
TokenKind::New,
|
||||
TokenKind::Match,
|
||||
];
|
||||
|
||||
fn expression(p: &mut CParser) {
|
||||
|
|
@ -979,20 +985,26 @@ fn is_expression(p: &mut CParser, left: MarkClosed, right_power: u8) -> MarkClos
|
|||
let m = p.start_before(left);
|
||||
p.advance(); // Consume the operator
|
||||
|
||||
// This is hard to do with just, like, no lookahead.
|
||||
pattern(p, right_power);
|
||||
|
||||
p.end(m, TreeKind::IsExpression)
|
||||
}
|
||||
|
||||
fn pattern(p: &mut CParser, right_power: u8) {
|
||||
let m = p.start();
|
||||
|
||||
// patterns are very simple.
|
||||
if p.peek() == TokenKind::Identifier && p.peek_next() == TokenKind::Colon {
|
||||
// This is a variable binding.
|
||||
variable_binding(p);
|
||||
} else {
|
||||
type_expr(p);
|
||||
}
|
||||
|
||||
// Additional predicates go into the right-hand-side.
|
||||
type_expr(p);
|
||||
|
||||
if p.eat(TokenKind::And) {
|
||||
expression_with_power(p, right_power);
|
||||
}
|
||||
|
||||
p.end(m, TreeKind::IsExpression)
|
||||
p.end(m, TreeKind::Pattern);
|
||||
}
|
||||
|
||||
fn variable_binding(p: &mut CParser) {
|
||||
|
|
@ -1000,7 +1012,6 @@ fn variable_binding(p: &mut CParser) {
|
|||
|
||||
p.expect_start(TokenKind::Identifier);
|
||||
p.expect_start(TokenKind::Colon);
|
||||
type_expr(p);
|
||||
|
||||
p.end(m, TreeKind::VariableBinding);
|
||||
}
|
||||
|
|
@ -1055,9 +1066,14 @@ fn prefix_expression(p: &mut CParser) -> Option<MarkClosed> {
|
|||
TokenKind::LeftBracket => list_constructor(p),
|
||||
|
||||
TokenKind::New => object_constructor(p),
|
||||
TokenKind::Match => match_expression(p),
|
||||
|
||||
_ => {
|
||||
assert!(!p.at_any(EXPRESSION_FIRST));
|
||||
assert!(
|
||||
!p.at_any(EXPRESSION_FIRST),
|
||||
"TokenKind::{:?} is in EXPRESSION_FIRST but not handled; is this a new kind of prefix?",
|
||||
p.peek()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
|
@ -1214,6 +1230,60 @@ fn field_value(p: &mut CParser) {
|
|||
p.end(m, TreeKind::FieldValue);
|
||||
}
|
||||
|
||||
fn match_expression(p: &mut CParser) -> MarkClosed {
|
||||
let m = p.start();
|
||||
|
||||
p.expect_start(TokenKind::Match);
|
||||
expression(p); // ?
|
||||
if p.at(TokenKind::LeftBrace) {
|
||||
match_body(p);
|
||||
} else {
|
||||
p.error("expected a '{' to start the alternatives after `match`");
|
||||
}
|
||||
|
||||
p.end(m, TreeKind::MatchExpression)
|
||||
}
|
||||
|
||||
fn match_body(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
p.expect_start(TokenKind::LeftBrace);
|
||||
while !p.at(TokenKind::RightBrace) && !p.eof() {
|
||||
if p.at(TokenKind::Identifier) {
|
||||
// TODO: type_expr_first ?
|
||||
match_arm(p);
|
||||
} else {
|
||||
if p.at_any(STATEMENT_RECOVERY) {
|
||||
break;
|
||||
}
|
||||
p.advance_with_error("expected a type expression to start a match arm");
|
||||
}
|
||||
}
|
||||
p.expect(
|
||||
TokenKind::RightBrace,
|
||||
"expected a '}' to end the alternatives in a match",
|
||||
);
|
||||
|
||||
p.end(m, TreeKind::MatchBody);
|
||||
}
|
||||
|
||||
fn match_arm(p: &mut CParser) {
|
||||
let m = p.start();
|
||||
|
||||
pattern(p, 0);
|
||||
|
||||
if p.eat(TokenKind::Arrow) {
|
||||
expression(p);
|
||||
} else {
|
||||
p.error("expected an arrow after the pattern in a match arm");
|
||||
}
|
||||
if !p.at(TokenKind::RightBrace) {
|
||||
p.expect(TokenKind::Comma, "expected a comma between match arms");
|
||||
}
|
||||
|
||||
p.end(m, TreeKind::MatchArm);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue