mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Use commas between function arguments
This commit is contained in:
parent
a0bf4d829d
commit
d0fa8bf857
10 changed files with 123 additions and 61 deletions
|
@ -28,5 +28,5 @@ eq : val, val -> Bool
|
|||
##
|
||||
## This is the same as the #=/= operator.
|
||||
notEq : val, val -> Bool
|
||||
notEq = \left right ->
|
||||
notEq = \left, right ->
|
||||
not (equal left right)
|
||||
|
|
|
@ -109,7 +109,7 @@ round = \num ->
|
|||
## >>> Float.pi
|
||||
## >>> |> Float.div 2.0
|
||||
#div : Float, Float -> Result Float DivByZero
|
||||
div = \numerator denominator ->
|
||||
div = \numerator, denominator ->
|
||||
case numerator when
|
||||
0.0 -> 0.0 # TODO return Result!
|
||||
_ -> denominator
|
||||
|
|
|
@ -102,12 +102,24 @@ pub fn fmt_expr<'a>(
|
|||
indent
|
||||
};
|
||||
|
||||
for loc_pattern in loc_patterns.iter() {
|
||||
fmt_pattern(buf, &loc_pattern.value, indent, true);
|
||||
let mut any_args_printed = false;
|
||||
|
||||
if !arguments_are_multiline {
|
||||
buf.push(' ');
|
||||
for loc_pattern in loc_patterns.iter() {
|
||||
if any_args_printed {
|
||||
buf.push(',');
|
||||
|
||||
if !arguments_are_multiline {
|
||||
buf.push(' ');
|
||||
}
|
||||
} else {
|
||||
any_args_printed = true;
|
||||
}
|
||||
|
||||
fmt_pattern(buf, &loc_pattern.value, indent, true);
|
||||
}
|
||||
|
||||
if !arguments_are_multiline {
|
||||
buf.push(' ');
|
||||
}
|
||||
|
||||
buf.push_str("->");
|
||||
|
|
|
@ -13,14 +13,13 @@ pub mod type_annotation;
|
|||
use crate::operator::{BinOp, CalledVia, UnaryOp};
|
||||
use crate::parse::ast::{AssignedField, Attempting, Def, Expr, MaybeQualified, Pattern, Spaceable};
|
||||
use crate::parse::blankspace::{
|
||||
space0, space0_after, space0_around, space0_before, space1, space1_after, space1_around,
|
||||
space1_before,
|
||||
space0, space0_after, space0_around, space0_before, space1, space1_around, space1_before,
|
||||
};
|
||||
use crate::parse::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
|
||||
use crate::parse::number_literal::number_literal;
|
||||
use crate::parse::parser::{
|
||||
allocated, char, not, not_followed_by, optional, string, then, unexpected, unexpected_eof,
|
||||
Either, Fail, FailReason, ParseResult, Parser, State,
|
||||
allocated, char, not, not_followed_by, optional, sep_by1, string, then, unexpected,
|
||||
unexpected_eof, Either, Fail, FailReason, ParseResult, Parser, State,
|
||||
};
|
||||
use crate::region::{Located, Region};
|
||||
use bumpalo::collections::Vec;
|
||||
|
@ -409,7 +408,6 @@ fn equals_for_def<'a>() -> impl Parser<'a, ()> {
|
|||
|
||||
/// A definition, consisting of one of these:
|
||||
///
|
||||
/// * A custom type definition using (`:=`)
|
||||
/// * A type alias using `:`
|
||||
/// * A pattern followed by '=' and then an expression
|
||||
/// * A type annotation
|
||||
|
@ -653,13 +651,11 @@ fn closure<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
// Parse the params
|
||||
attempt!(
|
||||
Attempting::ClosureParams,
|
||||
// Note: because this is parse1_after, you *must* have
|
||||
// a space before the "->" in a closure declaration.
|
||||
//
|
||||
// We could make this significantly more complicated in
|
||||
// order to support e.g. (\x-> 5) with no space before
|
||||
// the "->" but that does not seem worthwhile.
|
||||
one_or_more!(space1_after(loc_closure_param(min_indent), min_indent))
|
||||
// Params are comma-separated
|
||||
sep_by1(
|
||||
char(','),
|
||||
space0_around(loc_closure_param(min_indent), min_indent)
|
||||
)
|
||||
),
|
||||
skip_first!(
|
||||
// Parse the -> which separates params from body
|
||||
|
|
|
@ -462,6 +462,60 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse one or more values separated by a delimiter (e.g. a comma) whose
|
||||
/// values are discarded
|
||||
pub fn sep_by1<'a, P, D, Val>(delimiter: D, parser: P) -> impl Parser<'a, Vec<'a, Val>>
|
||||
where
|
||||
D: Parser<'a, ()>,
|
||||
P: Parser<'a, Val>,
|
||||
{
|
||||
move |arena, state: State<'a>| {
|
||||
let original_attempting = state.attempting;
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
Ok((first_output, next_state)) => {
|
||||
let mut state = next_state;
|
||||
let mut buf = Vec::with_capacity_in(1, arena);
|
||||
|
||||
buf.push(first_output);
|
||||
|
||||
loop {
|
||||
match delimiter.parse(arena, state) {
|
||||
Ok(((), next_state)) => {
|
||||
// If the delimiter passed, check the element parser.
|
||||
match parser.parse(arena, next_state) {
|
||||
Ok((next_output, next_state)) => {
|
||||
state = next_state;
|
||||
buf.push(next_output);
|
||||
}
|
||||
Err((fail, state)) => {
|
||||
// If the delimiter parsed, but the following
|
||||
// element did not, that's a fatal error.
|
||||
return Err((
|
||||
Fail {
|
||||
attempting: original_attempting,
|
||||
..fail
|
||||
},
|
||||
state,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err((_, old_state)) => return Ok((buf, old_state)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err((fail, new_state)) => Err((
|
||||
Fail {
|
||||
attempting: original_attempting,
|
||||
..fail
|
||||
},
|
||||
new_state,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn satisfies<'a, P, A, F>(parser: P, predicate: F) -> impl Parser<'a, A>
|
||||
where
|
||||
P: Parser<'a, A>,
|
||||
|
|
|
@ -205,7 +205,7 @@ mod test_canonicalize {
|
|||
// This function will get passed in as a pointer.
|
||||
let src = indoc!(
|
||||
r#"
|
||||
apply = \f x -> f x
|
||||
apply = \f, x -> f x
|
||||
|
||||
identity = \a -> a
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ mod test_format {
|
|||
fn func_def() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
f = \x y ->
|
||||
f = \x, y ->
|
||||
x
|
||||
|
||||
f 4
|
||||
|
@ -147,7 +147,7 @@ mod test_format {
|
|||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
f = \x y ->
|
||||
f = \x, y ->
|
||||
y = 4
|
||||
z = 8
|
||||
x
|
||||
|
@ -156,7 +156,7 @@ mod test_format {
|
|||
),
|
||||
indoc!(
|
||||
r#"
|
||||
f = \x y ->
|
||||
f = \x, y ->
|
||||
y = 4
|
||||
z = 8
|
||||
|
||||
|
@ -169,7 +169,7 @@ mod test_format {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
f = \x y ->
|
||||
f = \x, y ->
|
||||
a = 3
|
||||
b = 6
|
||||
|
||||
|
@ -289,7 +289,7 @@ mod test_format {
|
|||
fn multi_arg_closure() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
\a b c -> a b c
|
||||
\a, b, c -> a b c
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
@ -467,7 +467,7 @@ mod test_format {
|
|||
// fn record_field_destructuring() {
|
||||
// expr_formats_same(indoc!(
|
||||
// r#"
|
||||
// case foo of
|
||||
// case foo when
|
||||
// { x: 5 } -> 42
|
||||
// "#
|
||||
// ));
|
||||
|
@ -519,7 +519,7 @@ mod test_format {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
identity = \a
|
||||
identity = \a,
|
||||
b
|
||||
-> a
|
||||
|
||||
|
@ -529,8 +529,8 @@ mod test_format {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
identity = \a
|
||||
b
|
||||
identity = \a,
|
||||
b,
|
||||
# it's c!!
|
||||
c
|
||||
-> a
|
||||
|
|
|
@ -305,7 +305,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\_ _ -> 42
|
||||
\_, _ -> 42
|
||||
"#
|
||||
),
|
||||
"*, * -> Int",
|
||||
|
@ -317,7 +317,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\_ _ _ -> "test!"
|
||||
\_, _, _ -> "test!"
|
||||
"#
|
||||
),
|
||||
"*, *, * -> Str",
|
||||
|
@ -373,7 +373,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
func = \_ _ -> 42
|
||||
func = \_, _ -> 42
|
||||
|
||||
func
|
||||
"#
|
||||
|
@ -387,7 +387,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
f = \_ _ _ -> "test!"
|
||||
f = \_, _, _ -> "test!"
|
||||
|
||||
f
|
||||
"#
|
||||
|
@ -401,7 +401,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
a = \_ _ _ -> "test!"
|
||||
a = \_, _, _ -> "test!"
|
||||
|
||||
b = a
|
||||
|
||||
|
@ -545,7 +545,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
always = \a b -> a
|
||||
always = \a, b -> a
|
||||
|
||||
1 |> always "foo"
|
||||
"#
|
||||
|
@ -610,7 +610,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
apply = \f x -> f x
|
||||
apply = \f, x -> f x
|
||||
identity = \a -> a
|
||||
|
||||
apply identity 5
|
||||
|
@ -625,7 +625,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\f x -> f x
|
||||
\f, x -> f x
|
||||
"#
|
||||
),
|
||||
"(a -> b), a -> b",
|
||||
|
@ -654,7 +654,7 @@ mod test_infer {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\f -> (\a b -> f b a),
|
||||
\f -> (\a, b -> f b a),
|
||||
"#
|
||||
),
|
||||
"(a, b -> c) -> (b, a -> c)",
|
||||
|
|
|
@ -989,13 +989,13 @@ mod test_parse {
|
|||
fn two_arg_closure() {
|
||||
let arena = Bump::new();
|
||||
let arg1 = Located::new(0, 0, 1, 2, Identifier("a"));
|
||||
let arg2 = Located::new(0, 0, 3, 4, Identifier("b"));
|
||||
let arg2 = Located::new(0, 0, 4, 5, Identifier("b"));
|
||||
let patterns = bumpalo::vec![in &arena; arg1, arg2];
|
||||
let expected = Closure(
|
||||
arena.alloc(patterns),
|
||||
arena.alloc(Located::new(0, 0, 8, 10, Int("42"))),
|
||||
arena.alloc(Located::new(0, 0, 9, 11, Int("42"))),
|
||||
);
|
||||
let actual = parse_with(&arena, "\\a b -> 42");
|
||||
let actual = parse_with(&arena, "\\a, b -> 42");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
@ -1004,14 +1004,14 @@ mod test_parse {
|
|||
fn three_arg_closure() {
|
||||
let arena = Bump::new();
|
||||
let arg1 = Located::new(0, 0, 1, 2, Identifier("a"));
|
||||
let arg2 = Located::new(0, 0, 3, 4, Identifier("b"));
|
||||
let arg3 = Located::new(0, 0, 5, 6, Identifier("c"));
|
||||
let arg2 = Located::new(0, 0, 4, 5, Identifier("b"));
|
||||
let arg3 = Located::new(0, 0, 7, 8, Identifier("c"));
|
||||
let patterns = bumpalo::vec![in &arena; arg1, arg2, arg3];
|
||||
let expected = Closure(
|
||||
arena.alloc(patterns),
|
||||
arena.alloc(Located::new(0, 0, 10, 12, Int("42"))),
|
||||
arena.alloc(Located::new(0, 0, 12, 14, Int("42"))),
|
||||
);
|
||||
let actual = parse_with(&arena, "\\a b c -> 42");
|
||||
let actual = parse_with(&arena, "\\a, b, c -> 42");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
@ -1020,13 +1020,13 @@ mod test_parse {
|
|||
fn closure_with_underscores() {
|
||||
let arena = Bump::new();
|
||||
let underscore1 = Located::new(0, 0, 1, 2, Underscore);
|
||||
let underscore2 = Located::new(0, 0, 3, 4, Underscore);
|
||||
let underscore2 = Located::new(0, 0, 4, 5, Underscore);
|
||||
let patterns = bumpalo::vec![in &arena; underscore1, underscore2];
|
||||
let expected = Closure(
|
||||
arena.alloc(patterns),
|
||||
arena.alloc(Located::new(0, 0, 8, 10, Int("42"))),
|
||||
arena.alloc(Located::new(0, 0, 9, 11, Int("42"))),
|
||||
);
|
||||
let actual = parse_with(&arena, "\\_ _ -> 42");
|
||||
let actual = parse_with(&arena, "\\_, _ -> 42");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
@ -1259,21 +1259,21 @@ mod test_parse {
|
|||
|
||||
let args = bumpalo::vec![in &arena;
|
||||
Located::new(1,1,7,8, Identifier("x")),
|
||||
Located::new(1,1,9,10, Underscore)
|
||||
Located::new(1,1,10,11, Underscore)
|
||||
];
|
||||
let body = Located::new(1, 1, 14, 16, Int("42"));
|
||||
let body = Located::new(1, 1, 15, 17, Int("42"));
|
||||
|
||||
let closure = Expr::Closure(&args, &body);
|
||||
|
||||
let def = Def::Body(
|
||||
arena.alloc(Located::new(1, 1, 0, 3, Identifier("foo"))),
|
||||
arena.alloc(Located::new(1, 1, 6, 16, closure)),
|
||||
arena.alloc(Located::new(1, 1, 6, 17, closure)),
|
||||
);
|
||||
let loc_def = &*arena.alloc(Located::new(
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
16,
|
||||
17,
|
||||
Def::SpaceBefore(arena.alloc(def), newline.into_bump_slice()),
|
||||
));
|
||||
|
||||
|
@ -1287,7 +1287,7 @@ mod test_parse {
|
|||
indoc!(
|
||||
r#"
|
||||
foo : Int, Float -> Bool
|
||||
foo = \x _ -> 42
|
||||
foo = \x, _ -> 42
|
||||
|
||||
42
|
||||
"#
|
||||
|
|
|
@ -322,7 +322,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\_ _ -> 42
|
||||
\_, _ -> 42
|
||||
"#
|
||||
),
|
||||
"Attr.Attr * (*, * -> Attr.Attr * Int)",
|
||||
|
@ -334,7 +334,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\_ _ _ -> "test!"
|
||||
\_, _, _ -> "test!"
|
||||
"#
|
||||
),
|
||||
"Attr.Attr * (*, *, * -> Attr.Attr * Str)",
|
||||
|
@ -390,7 +390,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
func = \_ _ -> 42
|
||||
func = \_, _ -> 42
|
||||
|
||||
func
|
||||
"#
|
||||
|
@ -404,7 +404,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
f = \_ _ _ -> "test!"
|
||||
f = \_, _, _ -> "test!"
|
||||
|
||||
f
|
||||
"#
|
||||
|
@ -418,7 +418,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
a = \_ _ _ -> "test!"
|
||||
a = \_, _, _ -> "test!"
|
||||
|
||||
b = a
|
||||
|
||||
|
@ -575,7 +575,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
always = \a b -> a
|
||||
always = \a, b -> a
|
||||
|
||||
1 |> always "foo"
|
||||
"#
|
||||
|
@ -640,7 +640,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
apply = \f x -> f x
|
||||
apply = \f, x -> f x
|
||||
identity = \a -> a
|
||||
|
||||
apply identity 5
|
||||
|
@ -655,7 +655,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\f x -> f x
|
||||
\f, x -> f x
|
||||
"#
|
||||
),
|
||||
"Attr.Attr * (Attr.Attr * (a -> b), a -> b)",
|
||||
|
@ -684,7 +684,7 @@ mod test_infer_uniq {
|
|||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
\f -> (\a b -> f b a),
|
||||
\f -> (\a, b -> f b a),
|
||||
"#
|
||||
),
|
||||
"Attr.Attr * (Attr.Attr * (a, b -> c) -> Attr.Attr * (b, a -> c))",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue