mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31: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) ->
|
||||
await task, (output) ->
|
||||
after task, (output) ->
|
||||
succeed (convert output)
|
||||
|
||||
|
||||
|
@ -20,45 +24,46 @@ mapErr = (convert, task) ->
|
|||
fail (convert err)
|
||||
|
||||
|
||||
await = (task, cont) ->
|
||||
match task
|
||||
after = (task, cont) ->
|
||||
case task
|
||||
when Success val then cont val
|
||||
when Failure val then Failure val
|
||||
|
||||
when Echo str, prevCont, onFailure then
|
||||
Echo str,
|
||||
(({}) -> await (prevCont {}), cont)
|
||||
((ioErr) -> await (onFailure ioErr), cont)
|
||||
({} -> after (prevCont {}), cont),
|
||||
(ioErr -> after (onFailure ioErr), cont)
|
||||
|
||||
when Read prevCont, onFailure then
|
||||
Read
|
||||
((str) -> await (prevCont str), cont)
|
||||
((ioErr) -> await (onFailure ioErr), cont)
|
||||
|
||||
(str -> after (prevCont str), cont),
|
||||
(ioErr -> after (onFailure ioErr), cont)
|
||||
|
||||
|
||||
fallback = (task, onFailure) ->
|
||||
match task
|
||||
case task
|
||||
when Success val then Success val
|
||||
when Failure val then onFailure val
|
||||
|
||||
when Echo str, cont, prevOnFailure then
|
||||
Echo str
|
||||
(({}) -> fallback (cont {}), onFailure)
|
||||
((ioErr) -> fallback (prevOnFailure ioErr), onFailure)
|
||||
({} -> fallback (cont {}), onFailure),
|
||||
(ioErr -> fallback (prevOnFailure ioErr), onFailure)
|
||||
|
||||
when Read cont, prevOnFailure then
|
||||
Read
|
||||
((str) -> fallback (cont str), onFailure)
|
||||
((ioErr) -> fallback (prevOnFailure ioErr), onFailure)
|
||||
(str -> fallback (cont str), onFailure),
|
||||
(ioErr -> fallback (prevOnFailure ioErr), onFailure)
|
||||
|
||||
|
||||
demo =
|
||||
await (echo "Enter first name"), ({}) ->
|
||||
await read, (firstName) ->
|
||||
await (echo "Enter last name"), ({}) ->
|
||||
await read, (lastName) ->
|
||||
echo "Your name is: \(firstName) \(lastName)"
|
||||
after (echo "Enter first name"), ({}) ->
|
||||
after readInput, (firstName) ->
|
||||
after (echo "Enter last name"), ({}) ->
|
||||
after readInput, (lastName) ->
|
||||
fullName = "\(firstName) \(lastName)"
|
||||
|
||||
echo "Your name is: \(fullName)"
|
||||
|
||||
|
||||
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 {
|
||||
match expr {
|
||||
// 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
|
||||
Var(name) => match vars.get(&name) {
|
||||
|
@ -72,6 +72,14 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
|
|||
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) => {
|
||||
let func_expr = match vars.get(&name) {
|
||||
Some(resolved) => {
|
||||
|
@ -93,8 +101,8 @@ pub fn scoped_eval(expr: Expr, vars: &Scope) -> Evaluated {
|
|||
eval_apply(scoped_eval(*func_expr, vars), args, vars)
|
||||
},
|
||||
|
||||
Match(condition, branches) => {
|
||||
eval_match(scoped_eval(*condition, vars), branches, vars)
|
||||
Case(condition, branches) => {
|
||||
eval_case(scoped_eval(*condition, vars), branches, vars)
|
||||
},
|
||||
|
||||
Operator(left_arg, op, right_arg) => {
|
||||
|
@ -225,7 +233,7 @@ fn eval_operator(Evaluated(left_expr): &Evaluated, op: Operator, Evaluated(right
|
|||
}
|
||||
|
||||
#[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;
|
||||
|
||||
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.
|
||||
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) => {
|
||||
match evaluated {
|
||||
Evaluated(ApplyVariant(applied_variant_name, opt_applied_contents)) => {
|
||||
|
|
|
@ -23,9 +23,12 @@ pub enum Expr {
|
|||
// Sum Types
|
||||
ApplyVariant(String, Option<Vec<Expr>>),
|
||||
|
||||
// Product Types
|
||||
EmptyRecord,
|
||||
|
||||
// Conditionals
|
||||
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(Problem),
|
||||
|
@ -104,6 +107,7 @@ pub enum Problem {
|
|||
pub enum Pattern {
|
||||
Identifier(String),
|
||||
Variant(String, Option<Vec<Pattern>>),
|
||||
EmptyRecord,
|
||||
Underscore
|
||||
}
|
||||
|
||||
|
|
19
src/parse.rs
19
src/parse.rs
|
@ -123,7 +123,9 @@ parser! {
|
|||
let min_indent = *min_indent_ref;
|
||||
|
||||
choice((
|
||||
closure(min_indent),
|
||||
parenthetical_expr(min_indent),
|
||||
string("{}").with(value(Expr::EmptyRecord)),
|
||||
string("True").with(value(Expr::Bool(true))),
|
||||
string("False").with(value(Expr::Bool(false))),
|
||||
string_literal(),
|
||||
|
@ -131,7 +133,6 @@ parser! {
|
|||
char_literal(),
|
||||
if_expr(min_indent),
|
||||
match_expr(min_indent),
|
||||
closure(min_indent),
|
||||
let_expr(min_indent),
|
||||
apply_variant(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>,
|
||||
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))
|
||||
.and(
|
||||
many::<SmallVec<_>, _>(
|
||||
|
@ -219,7 +220,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
|||
// TODO handle this more gracefully
|
||||
panic!("encountered match-expression with no branches!")
|
||||
} 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>
|
||||
{
|
||||
// TODO patterns must be separated by commas!
|
||||
between(char('|'), char('|'),
|
||||
attempt(
|
||||
between(char('('), char(')'),
|
||||
sep_by1(
|
||||
pattern(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)| {
|
||||
Expr::Closure(patterns, Box::new(closure_body))
|
||||
})
|
||||
|
@ -356,6 +362,7 @@ parser! {
|
|||
|
||||
choice((
|
||||
char('_').map(|_| Pattern::Underscore),
|
||||
string("{}").map(|_| Pattern::EmptyRecord),
|
||||
ident().map(|name| Pattern::Identifier(name)),
|
||||
match_variant(min_indent)
|
||||
))
|
||||
|
@ -420,7 +427,7 @@ where I: Stream<Item = char, Position = IndentablePosition>,
|
|||
"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(),
|
||||
"case" => unexpected_any("Reserved keyword `case`").left(),
|
||||
"when" => unexpected_any("Reserved keyword `when`").left(),
|
||||
_ => value(ident_str).right()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue