Add match keyword

This commit is contained in:
Richard Feldman 2019-05-28 18:19:04 -04:00
parent 7cb0facacd
commit 878513b1ea
3 changed files with 43 additions and 6 deletions

View file

@ -80,13 +80,19 @@ pub fn scoped_eval(expr: Expr, vars: &HashMap<String, Rc<Expr>>) -> Expr {
}
},
Operator(left_arg, op, right_arg) =>
Operator(left_arg, op, right_arg) => {
eval_operator(
&scoped_eval(*left_arg, vars),
&op,
&scoped_eval(*right_arg, vars)
)
,
},
Match(condition, branches) => {
match scoped_eval(*condition, vars) {
_ => { panic!("TODO implement eval for match-expressions"); }
}
},
If(condition, if_true, if_false) => {
match scoped_eval(*condition, vars) {

View file

@ -22,8 +22,11 @@ pub enum Expr {
// Sum Types
ApplyVariant(String, Option<Vec<Expr>>),
// Conditionals
If(Box<Expr>, Box<Expr>, Box<Expr>),
Match(Box<Expr>, Vec<(Pattern, Box<Expr>)>),
// Error
Error(Problem),
}

View file

@ -129,6 +129,7 @@ parser! {
number_literal(),
char_literal(),
if_expr(min_indent),
match_expr(min_indent),
closure(min_indent),
let_expr(min_indent),
apply_variant(min_indent),
@ -184,7 +185,7 @@ pub fn if_expr<I>(min_indent: i32) -> impl Parser<Input = I, Output = Expr>
where I: Stream<Item = char, Position = IndentablePosition>,
I::Error: ParseError<I::Item, I::Range, I::Position>
{
string("if").with(indented_whitespaces1(min_indent))
string("if").skip(indented_whitespaces1(min_indent))
.with(expr_body(min_indent)).skip(indented_whitespaces1(min_indent))
.skip(string("then")).skip(indented_whitespaces1(min_indent))
.and(expr_body(min_indent)).skip(indented_whitespaces1(min_indent))
@ -199,6 +200,30 @@ where I: Stream<Item = char, Position = IndentablePosition>,
)
}
pub fn match_expr<I>(min_indent: i32) -> impl Parser<Input = I, Output = Expr>
where I: Stream<Item = char, Position = IndentablePosition>,
I::Error: ParseError<I::Item, I::Range, I::Position>
{
string("match").skip(indented_whitespaces1(min_indent))
.with(expr_body(min_indent)).skip(indented_whitespaces1(min_indent))
.and(
many::<Vec<_>, _>(
string("when").skip(indented_whitespaces1(min_indent))
.with(pattern(min_indent)).skip(indented_whitespaces1(min_indent))
.skip(string("then")).skip(indented_whitespaces1(min_indent))
.and(expr_body(min_indent).map(|expr| Box::new(expr)))
)
)
.map(|(conditional, branches)|
if branches.is_empty() {
// TODO handle this more gracefully
panic!("encountered match-expression with no branches!")
} else {
Expr::Match(Box::new(conditional), branches)
}
)
}
pub fn parenthetical_expr<I>(min_indent: i32) -> impl Parser<Input = I, Output = Expr>
where I: Stream<Item = char, Position = IndentablePosition>,
I::Error: ParseError<I::Item, I::Range, I::Position>
@ -229,7 +254,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
sep_by1(
attempt(
// Keywords like "then" and "else" are not function application!
not_followed_by(choice((string("then"), string("else"))))
not_followed_by(choice((string("then"), string("else"), string("when"))))
// Don't parse operators because they have a higher
// precedence than function application. If we see one,
// we're done!
@ -404,6 +429,9 @@ where I: Stream<Item = char, Position = IndentablePosition>,
match ident_str.as_str() {
"if" => unexpected_any("Reserved keyword `if`").left(),
"then" => unexpected_any("Reserved keyword `then`").left(),
"else" => unexpected_any("Reserved keyword `else`").left(),
"match" => unexpected_any("Reserved keyword `match`").left(),
"when" => unexpected_any("Reserved keyword `when`").left(),
_ => value(ident_str).right()
}
} else {
@ -561,7 +589,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
char(' ').skip(
// Don't mistake keywords like `then` and `else` for
// space-separated digits!
not_followed_by(choice((string("then"), string("else"))))
not_followed_by(choice((string("then"), string("else"), string("when"))))
)
)
))