mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
More syntax changes
This commit is contained in:
parent
9895e0c0ae
commit
352ab5ed34
4 changed files with 81 additions and 49 deletions
49
cli/test.roc
49
cli/test.roc
|
@ -1,17 +1,21 @@
|
||||||
succeed = (val) -> Success val
|
succeed = (val) ->
|
||||||
|
Success val
|
||||||
|
|
||||||
|
|
||||||
fail = (val) -> Failure val
|
fail = (val) ->
|
||||||
|
Failure val
|
||||||
|
|
||||||
|
|
||||||
echo = (str) -> Echo str, succeed, fail
|
echo = (str) ->
|
||||||
|
Echo str, succeed, fail
|
||||||
|
|
||||||
|
|
||||||
read = Read succeed, fail
|
readInput =
|
||||||
|
Read succeed, fail
|
||||||
|
|
||||||
|
|
||||||
map = (convert, task) ->
|
map = (convert, task) ->
|
||||||
await task, (output) ->
|
after task, (output) ->
|
||||||
succeed (convert output)
|
succeed (convert output)
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,45 +24,46 @@ mapErr = (convert, task) ->
|
||||||
fail (convert err)
|
fail (convert err)
|
||||||
|
|
||||||
|
|
||||||
await = (task, cont) ->
|
after = (task, cont) ->
|
||||||
match task
|
case task
|
||||||
when Success val then cont val
|
when Success val then cont val
|
||||||
when Failure val then Failure val
|
when Failure val then Failure val
|
||||||
|
|
||||||
when Echo str, prevCont, onFailure then
|
when Echo str, prevCont, onFailure then
|
||||||
Echo str,
|
Echo str,
|
||||||
(({}) -> await (prevCont {}), cont)
|
({} -> after (prevCont {}), cont),
|
||||||
((ioErr) -> await (onFailure ioErr), cont)
|
(ioErr -> after (onFailure ioErr), cont)
|
||||||
|
|
||||||
when Read prevCont, onFailure then
|
when Read prevCont, onFailure then
|
||||||
Read
|
Read
|
||||||
((str) -> await (prevCont str), cont)
|
(str -> after (prevCont str), cont),
|
||||||
((ioErr) -> await (onFailure ioErr), cont)
|
(ioErr -> after (onFailure ioErr), cont)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fallback = (task, onFailure) ->
|
fallback = (task, onFailure) ->
|
||||||
match task
|
case task
|
||||||
when Success val then Success val
|
when Success val then Success val
|
||||||
when Failure val then onFailure val
|
when Failure val then onFailure val
|
||||||
|
|
||||||
when Echo str, cont, prevOnFailure then
|
when Echo str, cont, prevOnFailure then
|
||||||
Echo str
|
Echo str
|
||||||
(({}) -> fallback (cont {}), onFailure)
|
({} -> fallback (cont {}), onFailure),
|
||||||
((ioErr) -> fallback (prevOnFailure ioErr), onFailure)
|
(ioErr -> fallback (prevOnFailure ioErr), onFailure)
|
||||||
|
|
||||||
when Read cont, prevOnFailure then
|
when Read cont, prevOnFailure then
|
||||||
Read
|
Read
|
||||||
((str) -> fallback (cont str), onFailure)
|
(str -> fallback (cont str), onFailure),
|
||||||
((ioErr) -> fallback (prevOnFailure ioErr), onFailure)
|
(ioErr -> fallback (prevOnFailure ioErr), onFailure)
|
||||||
|
|
||||||
|
|
||||||
demo =
|
demo =
|
||||||
await (echo "Enter first name"), ({}) ->
|
after (echo "Enter first name"), ({}) ->
|
||||||
await read, (firstName) ->
|
after readInput, (firstName) ->
|
||||||
await (echo "Enter last name"), ({}) ->
|
after (echo "Enter last name"), ({}) ->
|
||||||
await read, (lastName) ->
|
after readInput, (lastName) ->
|
||||||
echo "Your name is: \(firstName) \(lastName)"
|
fullName = "\(firstName) \(lastName)"
|
||||||
|
|
||||||
|
echo "Your name is: \(fullName)"
|
||||||
|
|
||||||
|
|
||||||
demo
|
demo
|
||||||
|
|
24
src/eval.rs
24
src/eval.rs
|
@ -31,7 +31,7 @@ fn problem(prob: Problem) -> Evaluated {
|
||||||
pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
|
pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
|
||||||
match expr {
|
match expr {
|
||||||
// Primitives need no further evaluation
|
// Primitives need no further evaluation
|
||||||
Error(_) | Int(_) | Str(_) | Frac(_, _) | Char(_) | Bool(_) | Closure(_, _) => Evaluated(expr),
|
Error(_) | Int(_) | Str(_) | Frac(_, _) | Char(_) | Bool(_) | Closure(_, _) | Expr::EmptyRecord => Evaluated(expr),
|
||||||
|
|
||||||
// Resolve variable names
|
// Resolve variable names
|
||||||
Var(name) => match vars.get(&name) {
|
Var(name) => match vars.get(&name) {
|
||||||
|
@ -72,6 +72,14 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
|
||||||
scoped_eval(*in_expr, vars)
|
scoped_eval(*in_expr, vars)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Let(Pattern::EmptyRecord, definition, in_expr) => {
|
||||||
|
// Faithfully eval this, but discard its result.
|
||||||
|
scoped_eval(*definition, &vars);
|
||||||
|
|
||||||
|
// Actually use this part.
|
||||||
|
scoped_eval(*in_expr, vars)
|
||||||
|
},
|
||||||
|
|
||||||
Func(name, args) => {
|
Func(name, args) => {
|
||||||
let func_expr = match vars.get(&name) {
|
let func_expr = match vars.get(&name) {
|
||||||
Some(resolved) => {
|
Some(resolved) => {
|
||||||
|
@ -93,8 +101,8 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
|
||||||
eval_apply(scoped_eval(*func_expr, vars), args, vars)
|
eval_apply(scoped_eval(*func_expr, vars), args, vars)
|
||||||
},
|
},
|
||||||
|
|
||||||
Match(condition, branches) => {
|
Case(condition, branches) => {
|
||||||
eval_match(scoped_eval(*condition, vars), branches, vars)
|
eval_case(scoped_eval(*condition, vars), branches, vars)
|
||||||
},
|
},
|
||||||
|
|
||||||
Operator(left_arg, op, right_arg) => {
|
Operator(left_arg, op, right_arg) => {
|
||||||
|
@ -225,7 +233,7 @@ fn eval_operator(Evaluated(left_expr): &Evaluated, op: Operator, Evaluated(right
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn eval_match (condition: Evaluated, branches: SmallVec<[(Pattern, Box<Expr>); 4]>, vars: &Scope) -> Evaluated {
|
fn eval_case (condition: Evaluated, branches: SmallVec<[(Pattern, Box<Expr>); 4]>, vars: &Scope) -> Evaluated {
|
||||||
let Evaluated(ref evaluated_expr) = condition;
|
let Evaluated(ref evaluated_expr) = condition;
|
||||||
|
|
||||||
for (pattern, definition) in branches {
|
for (pattern, definition) in branches {
|
||||||
|
@ -254,6 +262,14 @@ fn pattern_match(evaluated: Evaluated, pattern: Pattern, vars: &mut Scope) -> Re
|
||||||
// Underscore matches anything, and records no new vars.
|
// Underscore matches anything, and records no new vars.
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
Pattern::EmptyRecord => {
|
||||||
|
match evaluated {
|
||||||
|
Evaluated(Expr::EmptyRecord) => Ok(()),
|
||||||
|
Evaluated(expr) => Err(TypeMismatch(
|
||||||
|
format!("Wanted a `{}`, but was given `{}`.", "{}", expr)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
Variant(pattern_variant_name, opt_pattern_contents) => {
|
Variant(pattern_variant_name, opt_pattern_contents) => {
|
||||||
match evaluated {
|
match evaluated {
|
||||||
Evaluated(ApplyVariant(applied_variant_name, opt_applied_contents)) => {
|
Evaluated(ApplyVariant(applied_variant_name, opt_applied_contents)) => {
|
||||||
|
|
|
@ -23,9 +23,12 @@ pub enum Expr {
|
||||||
// Sum Types
|
// Sum Types
|
||||||
ApplyVariant(String, Option<Vec<Expr>>),
|
ApplyVariant(String, Option<Vec<Expr>>),
|
||||||
|
|
||||||
|
// Product Types
|
||||||
|
EmptyRecord,
|
||||||
|
|
||||||
// Conditionals
|
// Conditionals
|
||||||
If(Box<Expr>, Box<Expr>, Box<Expr>),
|
If(Box<Expr>, Box<Expr>, Box<Expr>),
|
||||||
Match(Box<Expr>, SmallVec<[(Pattern, Box<Expr>); 4]>),
|
Case(Box<Expr>, SmallVec<[(Pattern, Box<Expr>); 4]>),
|
||||||
|
|
||||||
// Error
|
// Error
|
||||||
Error(Problem),
|
Error(Problem),
|
||||||
|
@ -104,6 +107,7 @@ pub enum Problem {
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
Variant(String, Option<Vec<Pattern>>),
|
Variant(String, Option<Vec<Pattern>>),
|
||||||
|
EmptyRecord,
|
||||||
Underscore
|
Underscore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
src/parse.rs
19
src/parse.rs
|
@ -123,7 +123,9 @@ parser! {
|
||||||
let min_indent = *min_indent_ref;
|
let min_indent = *min_indent_ref;
|
||||||
|
|
||||||
choice((
|
choice((
|
||||||
|
closure(min_indent),
|
||||||
parenthetical_expr(min_indent),
|
parenthetical_expr(min_indent),
|
||||||
|
string("{}").with(value(Expr::EmptyRecord)),
|
||||||
string("True").with(value(Expr::Bool(true))),
|
string("True").with(value(Expr::Bool(true))),
|
||||||
string("False").with(value(Expr::Bool(false))),
|
string("False").with(value(Expr::Bool(false))),
|
||||||
string_literal(),
|
string_literal(),
|
||||||
|
@ -131,7 +133,6 @@ parser! {
|
||||||
char_literal(),
|
char_literal(),
|
||||||
if_expr(min_indent),
|
if_expr(min_indent),
|
||||||
match_expr(min_indent),
|
match_expr(min_indent),
|
||||||
closure(min_indent),
|
|
||||||
let_expr(min_indent),
|
let_expr(min_indent),
|
||||||
apply_variant(min_indent),
|
apply_variant(min_indent),
|
||||||
func_or_var(min_indent),
|
func_or_var(min_indent),
|
||||||
|
@ -204,7 +205,7 @@ pub fn match_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("match").skip(indented_whitespaces1(min_indent))
|
string("case").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))
|
||||||
.and(
|
.and(
|
||||||
many::<SmallVec<_>, _>(
|
many::<SmallVec<_>, _>(
|
||||||
|
@ -219,7 +220,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
||||||
// TODO handle this more gracefully
|
// TODO handle this more gracefully
|
||||||
panic!("encountered match-expression with no branches!")
|
panic!("encountered match-expression with no branches!")
|
||||||
} else {
|
} else {
|
||||||
Expr::Match(Box::new(conditional), branches)
|
Expr::Case(Box::new(conditional), branches)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -336,12 +337,17 @@ 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>
|
||||||
{
|
{
|
||||||
// TODO patterns must be separated by commas!
|
// TODO patterns must be separated by commas!
|
||||||
between(char('|'), char('|'),
|
attempt(
|
||||||
|
between(char('('), char(')'),
|
||||||
sep_by1(
|
sep_by1(
|
||||||
pattern(min_indent),
|
pattern(min_indent),
|
||||||
char(',').skip(indented_whitespaces(min_indent))
|
char(',').skip(indented_whitespaces(min_indent))
|
||||||
))
|
))
|
||||||
.and(whitespace1().with(expr_body(min_indent)))
|
.skip(indented_whitespaces1(min_indent))
|
||||||
|
.skip(string("->"))
|
||||||
|
.skip(indented_whitespaces1(min_indent))
|
||||||
|
)
|
||||||
|
.and(expr_body(min_indent))
|
||||||
.map(|(patterns, closure_body)| {
|
.map(|(patterns, closure_body)| {
|
||||||
Expr::Closure(patterns, Box::new(closure_body))
|
Expr::Closure(patterns, Box::new(closure_body))
|
||||||
})
|
})
|
||||||
|
@ -356,6 +362,7 @@ parser! {
|
||||||
|
|
||||||
choice((
|
choice((
|
||||||
char('_').map(|_| Pattern::Underscore),
|
char('_').map(|_| Pattern::Underscore),
|
||||||
|
string("{}").map(|_| Pattern::EmptyRecord),
|
||||||
ident().map(|name| Pattern::Identifier(name)),
|
ident().map(|name| Pattern::Identifier(name)),
|
||||||
match_variant(min_indent)
|
match_variant(min_indent)
|
||||||
))
|
))
|
||||||
|
@ -420,7 +427,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
||||||
"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(),
|
"else" => unexpected_any("Reserved keyword `else`").left(),
|
||||||
"match" => unexpected_any("Reserved keyword `match`").left(),
|
"case" => unexpected_any("Reserved keyword `case`").left(),
|
||||||
"when" => unexpected_any("Reserved keyword `when`").left(),
|
"when" => unexpected_any("Reserved keyword `when`").left(),
|
||||||
_ => value(ident_str).right()
|
_ => value(ident_str).right()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue