mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Parse parenthetical defs
This commit is contained in:
parent
8c9041685c
commit
d7a7ba790d
2 changed files with 72 additions and 24 deletions
|
@ -31,10 +31,10 @@ use parse::blankspace::{
|
||||||
use parse::ident::{ident, Ident, MaybeQualified};
|
use parse::ident::{ident, Ident, MaybeQualified};
|
||||||
use parse::number_literal::number_literal;
|
use parse::number_literal::number_literal;
|
||||||
use parse::parser::{
|
use parse::parser::{
|
||||||
and, attempt, between, char, either, loc, map, map_with_arena, not_followed_by, one_of2,
|
and, attempt, between, char, either, loc, map, map_with_arena, not_followed_by, one_of10,
|
||||||
one_of4, one_of5, one_of8, one_of9, one_or_more, optional, sep_by0, skip_first, skip_second,
|
one_of2, one_of4, one_of5, one_or_more, optional, sep_by0, skip_first, skip_second, string,
|
||||||
string, then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult,
|
then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult, Parser,
|
||||||
Parser, State,
|
State,
|
||||||
};
|
};
|
||||||
use parse::string_literal::string_literal;
|
use parse::string_literal::string_literal;
|
||||||
use region::Located;
|
use region::Located;
|
||||||
|
@ -69,8 +69,9 @@ fn loc_parse_expr_body_without_operators<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
) -> ParseResult<'a, Located<Expr<'a>>> {
|
) -> ParseResult<'a, Located<Expr<'a>>> {
|
||||||
one_of9(
|
one_of10(
|
||||||
loc_parenthetical_expr(min_indent),
|
loc_parenthetical_expr(min_indent),
|
||||||
|
loc_parenthetical_def(min_indent),
|
||||||
loc(string_literal()),
|
loc(string_literal()),
|
||||||
loc(number_literal()),
|
loc(number_literal()),
|
||||||
loc(closure(min_indent)),
|
loc(closure(min_indent)),
|
||||||
|
@ -139,40 +140,25 @@ pub fn loc_parenthetical_expr<'a>(min_indent: u16) -> impl Parser<'a, Located<Ex
|
||||||
// There may optionally be function args after the ')'
|
// There may optionally be function args after the ')'
|
||||||
// e.g. ((foo bar) baz)
|
// e.g. ((foo bar) baz)
|
||||||
loc_function_args(min_indent),
|
loc_function_args(min_indent),
|
||||||
// If there aren't any args, there may be a '=' or ':' after it.
|
// There may be a '.' for field access after it, e.g. `(foo).bar`,
|
||||||
//
|
|
||||||
// (It's a syntax error to write e.g. `foo bar =` - so if there
|
|
||||||
// were any args, there is definitely no need to parse '=' or ':'!)
|
|
||||||
//
|
|
||||||
// Also, there may be a '.' for field access (e.g. `(foo).bar`),
|
|
||||||
// but we only want to look for that if there weren't any args,
|
// but we only want to look for that if there weren't any args,
|
||||||
// as if there were any args they'd have consumed it anyway
|
// as if there were any args they'd have consumed it anyway
|
||||||
// e.g. in `((foo bar) baz.blah)` the `.blah` will be consumed by the `baz` parser
|
// e.g. in `((foo bar) baz.blah)` the `.blah` will be consumed by the `baz` parser
|
||||||
either(
|
|
||||||
one_or_more(skip_first(char('.'), unqualified_ident())),
|
one_or_more(skip_first(char('.'), unqualified_ident())),
|
||||||
and(space0(min_indent), either(equals_for_def(), char(':'))),
|
|
||||||
),
|
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
|arena, loc_expr_with_extras| {
|
|arena, loc_expr_with_extras| {
|
||||||
// We parse the parenthetical expression *and* the arguments after it
|
// We parse the parenthetical expression *and* the arguments after it
|
||||||
// in one region, so that (for example) the region for Apply includes its args.
|
// in one region, so that (for example) the region for Apply includes its args.
|
||||||
let (loc_expr, opt_extras) = loc_expr_with_extras.value;
|
let (loc_expr, opt_extras) = loc_expr_with_extras.value;
|
||||||
|
|
||||||
match opt_extras {
|
match opt_extras {
|
||||||
Some(Either::First(loc_args)) => Located {
|
Some(Either::First(loc_args)) => Located {
|
||||||
region: loc_expr_with_extras.region,
|
region: loc_expr_with_extras.region,
|
||||||
value: Expr::Apply(arena.alloc((loc_expr, loc_args))),
|
value: Expr::Apply(arena.alloc((loc_expr, loc_args))),
|
||||||
},
|
},
|
||||||
// '=' after optional spaces
|
|
||||||
Some(Either::Second(Either::Second((_space_list, Either::First(()))))) => {
|
|
||||||
panic!("TODO handle def, making sure not to drop comments!");
|
|
||||||
}
|
|
||||||
// ':' after optional spaces
|
|
||||||
Some(Either::Second(Either::Second((_space_list, Either::Second(()))))) => {
|
|
||||||
panic!("TODO handle annotation, making sure not to drop comments!");
|
|
||||||
}
|
|
||||||
// '.' and a record field immediately after ')', no optional spaces
|
// '.' and a record field immediately after ')', no optional spaces
|
||||||
Some(Either::Second(Either::First(fields))) => Located {
|
Some(Either::Second(fields)) => Located {
|
||||||
region: loc_expr_with_extras.region,
|
region: loc_expr_with_extras.region,
|
||||||
value: Expr::Field(arena.alloc(loc_expr), fields),
|
value: Expr::Field(arena.alloc(loc_expr), fields),
|
||||||
},
|
},
|
||||||
|
@ -182,6 +168,41 @@ pub fn loc_parenthetical_expr<'a>(min_indent: u16) -> impl Parser<'a, Located<Ex
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A def beginning with a parenthetical pattern, for example:
|
||||||
|
///
|
||||||
|
/// (UserId userId) = ...
|
||||||
|
///
|
||||||
|
/// Note: Parenthetical patterns are a shorthand convenience, and may not have type annotations.
|
||||||
|
/// It would be too weird to parse; imagine `(UserId userId) : ...` above `(UserId userId) = ...`
|
||||||
|
pub fn loc_parenthetical_def<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>> {
|
||||||
|
move |arena, state| {
|
||||||
|
let (loc_tuple, state) = loc(and(
|
||||||
|
space0_after(
|
||||||
|
between(
|
||||||
|
char('('),
|
||||||
|
space0_around(loc(pattern(min_indent)), min_indent),
|
||||||
|
char(')'),
|
||||||
|
),
|
||||||
|
min_indent,
|
||||||
|
),
|
||||||
|
equals_with_indent(),
|
||||||
|
))
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
let region = loc_tuple.region;
|
||||||
|
let (loc_first_pattern, equals_sign_indent) = loc_tuple.value;
|
||||||
|
let (value, state) = parse_def_expr(
|
||||||
|
min_indent,
|
||||||
|
equals_sign_indent,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
loc_first_pattern,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok((Located { value, region }, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The '=' used in a def can't be followed by another '=' (or else it's actually
|
/// The '=' used in a def can't be followed by another '=' (or else it's actually
|
||||||
/// an "==") and also it can't be followed by '>' (or else it's actually an "=>")
|
/// an "==") and also it can't be followed by '>' (or else it's actually an "=>")
|
||||||
fn equals_for_def<'a>() -> impl Parser<'a, ()> {
|
fn equals_for_def<'a>() -> impl Parser<'a, ()> {
|
||||||
|
|
|
@ -901,6 +901,33 @@ where
|
||||||
one_of2(p1, one_of8(p2, p3, p4, p5, p6, p7, p8, p9))
|
one_of2(p1, one_of8(p2, p3, p4, p5, p6, p7, p8, p9))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn one_of10<'a, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, A>(
|
||||||
|
p1: P1,
|
||||||
|
p2: P2,
|
||||||
|
p3: P3,
|
||||||
|
p4: P4,
|
||||||
|
p5: P5,
|
||||||
|
p6: P6,
|
||||||
|
p7: P7,
|
||||||
|
p8: P8,
|
||||||
|
p9: P9,
|
||||||
|
p10: P10,
|
||||||
|
) -> impl Parser<'a, A>
|
||||||
|
where
|
||||||
|
P1: Parser<'a, A>,
|
||||||
|
P2: Parser<'a, A>,
|
||||||
|
P3: Parser<'a, A>,
|
||||||
|
P4: Parser<'a, A>,
|
||||||
|
P5: Parser<'a, A>,
|
||||||
|
P6: Parser<'a, A>,
|
||||||
|
P7: Parser<'a, A>,
|
||||||
|
P8: Parser<'a, A>,
|
||||||
|
P9: Parser<'a, A>,
|
||||||
|
P10: Parser<'a, A>,
|
||||||
|
{
|
||||||
|
one_of2(p1, one_of9(p2, p3, p4, p5, p6, p7, p8, p9, p10))
|
||||||
|
}
|
||||||
|
|
||||||
// DEBUG COMBINATORS
|
// DEBUG COMBINATORS
|
||||||
//
|
//
|
||||||
// These use dyn for runtime dynamic dispatch. It prevents combinatoric
|
// These use dyn for runtime dynamic dispatch. It prevents combinatoric
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue