mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Add match keyword
This commit is contained in:
parent
7cb0facacd
commit
878513b1ea
3 changed files with 43 additions and 6 deletions
10
src/eval.rs
10
src/eval.rs
|
@ -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(
|
eval_operator(
|
||||||
&scoped_eval(*left_arg, vars),
|
&scoped_eval(*left_arg, vars),
|
||||||
&op,
|
&op,
|
||||||
&scoped_eval(*right_arg, vars)
|
&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) => {
|
If(condition, if_true, if_false) => {
|
||||||
match scoped_eval(*condition, vars) {
|
match scoped_eval(*condition, vars) {
|
||||||
|
|
|
@ -22,8 +22,11 @@ pub enum Expr {
|
||||||
// Sum Types
|
// Sum Types
|
||||||
ApplyVariant(String, Option<Vec<Expr>>),
|
ApplyVariant(String, Option<Vec<Expr>>),
|
||||||
|
|
||||||
|
// Conditionals
|
||||||
If(Box<Expr>, Box<Expr>, Box<Expr>),
|
If(Box<Expr>, Box<Expr>, Box<Expr>),
|
||||||
|
Match(Box<Expr>, Vec<(Pattern, Box<Expr>)>),
|
||||||
|
|
||||||
|
// Error
|
||||||
Error(Problem),
|
Error(Problem),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
src/parse.rs
34
src/parse.rs
|
@ -129,6 +129,7 @@ parser! {
|
||||||
number_literal(),
|
number_literal(),
|
||||||
char_literal(),
|
char_literal(),
|
||||||
if_expr(min_indent),
|
if_expr(min_indent),
|
||||||
|
match_expr(min_indent),
|
||||||
closure(min_indent),
|
closure(min_indent),
|
||||||
let_expr(min_indent),
|
let_expr(min_indent),
|
||||||
apply_variant(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>,
|
where I: Stream<Item = char, Position = IndentablePosition>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>
|
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))
|
.with(expr_body(min_indent)).skip(indented_whitespaces1(min_indent))
|
||||||
.skip(string("then")).skip(indented_whitespaces1(min_indent))
|
.skip(string("then")).skip(indented_whitespaces1(min_indent))
|
||||||
.and(expr_body(min_indent)).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>
|
pub fn parenthetical_expr<I>(min_indent: i32) -> impl Parser<Input = I, Output = Expr>
|
||||||
where I: Stream<Item = char, Position = IndentablePosition>,
|
where I: Stream<Item = char, Position = IndentablePosition>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>
|
I::Error: ParseError<I::Item, I::Range, I::Position>
|
||||||
|
@ -229,7 +254,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
||||||
sep_by1(
|
sep_by1(
|
||||||
attempt(
|
attempt(
|
||||||
// Keywords like "then" and "else" are not function application!
|
// 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
|
// Don't parse operators because they have a higher
|
||||||
// precedence than function application. If we see one,
|
// precedence than function application. If we see one,
|
||||||
// we're done!
|
// we're done!
|
||||||
|
@ -404,6 +429,9 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
||||||
match ident_str.as_str() {
|
match ident_str.as_str() {
|
||||||
"if" => unexpected_any("Reserved keyword `if`").left(),
|
"if" => unexpected_any("Reserved keyword `if`").left(),
|
||||||
"then" => unexpected_any("Reserved keyword `then`").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()
|
_ => value(ident_str).right()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -561,7 +589,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
||||||
char(' ').skip(
|
char(' ').skip(
|
||||||
// Don't mistake keywords like `then` and `else` for
|
// Don't mistake keywords like `then` and `else` for
|
||||||
// space-separated digits!
|
// space-separated digits!
|
||||||
not_followed_by(choice((string("then"), string("else"))))
|
not_followed_by(choice((string("then"), string("else"), string("when"))))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue