Use commas between function arguments

This commit is contained in:
Richard Feldman 2019-12-18 21:45:00 -05:00
parent a0bf4d829d
commit d0fa8bf857
10 changed files with 123 additions and 61 deletions

View file

@ -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)

View file

@ -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

View file

@ -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("->");

View file

@ -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

View file

@ -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>,

View file

@ -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

View file

@ -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

View file

@ -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)",

View file

@ -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
"#

View file

@ -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))",