mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
checkpoint
This commit is contained in:
parent
abd56c16b9
commit
0016ef1e95
2 changed files with 220 additions and 26 deletions
|
@ -32,8 +32,15 @@ pub fn expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
||||||
fn loc_expr_in_parens<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>, SyntaxError<'a>> {
|
fn loc_expr_in_parens<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>, SyntaxError<'a>> {
|
||||||
specialize(
|
specialize(
|
||||||
|e, r, c| SyntaxError::Expr(EExpr::InParens(e, r, c)),
|
|e, r, c| SyntaxError::Expr(EExpr::InParens(e, r, c)),
|
||||||
move |arena, state| {
|
loc_expr_in_parens_help(min_indent),
|
||||||
let (_, loc_expr, state) = loc_expr_in_parens_help(min_indent).parse(arena, state)?;
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loc_expr_in_parens_help<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
) -> impl Parser<'a, Located<Expr<'a>>, EInParens<'a>> {
|
||||||
|
debug!(move |arena, state| {
|
||||||
|
let (_, loc_expr, state) = loc_expr_in_parens_help_help(min_indent).parse(arena, state)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
MadeProgress,
|
MadeProgress,
|
||||||
|
@ -43,11 +50,10 @@ fn loc_expr_in_parens<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>,
|
||||||
},
|
},
|
||||||
state,
|
state,
|
||||||
))
|
))
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loc_expr_in_parens_help<'a>(
|
fn loc_expr_in_parens_help_help<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
) -> impl Parser<'a, Located<Expr<'a>>, EInParens<'a>> {
|
) -> impl Parser<'a, Located<Expr<'a>>, EInParens<'a>> {
|
||||||
between!(
|
between!(
|
||||||
|
@ -66,20 +72,25 @@ fn loc_expr_in_parens_help<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loc_expr_in_parens_etc<'a, P>(
|
fn loc_expr_in_parens_etc<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
args_parser: P,
|
) -> impl Parser<'a, Located<Expr<'a>>, SyntaxError<'a>> {
|
||||||
) -> impl Parser<'a, Located<Expr<'a>>, SyntaxError<'a>>
|
specialize(
|
||||||
where
|
|e, _, _| SyntaxError::Expr(e),
|
||||||
P: Parser<'a, Vec<'a, Located<Expr<'a>>>, SyntaxError<'a>> + Copy,
|
loc_expr_in_parens_etc_help(min_indent),
|
||||||
{
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loc_expr_in_parens_etc_help<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
) -> impl Parser<'a, Located<Expr<'a>>, EExpr<'a>> {
|
||||||
then(
|
then(
|
||||||
loc!(and!(
|
loc!(and!(
|
||||||
loc_expr_in_parens(min_indent),
|
specialize(EExpr::InParens, loc_expr_in_parens_help(min_indent)),
|
||||||
optional(either!(
|
optional(either!(
|
||||||
// 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)
|
||||||
args_parser,
|
loc_function_args_help(min_indent),
|
||||||
// If there aren't any args, there may be a '=' or ':' after it.
|
// If there aren't any args, there may be a '=' or ':' after it.
|
||||||
//
|
//
|
||||||
// (It's a syntax error to write e.g. `foo bar =` - so if there
|
// (It's a syntax error to write e.g. `foo bar =` - so if there
|
||||||
|
@ -90,12 +101,48 @@ where
|
||||||
// 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!(
|
either!(
|
||||||
one_or_more!(skip_first!(ascii_char(b'.'), lowercase_ident())),
|
record_field_access_chain(),
|
||||||
and!(space0(min_indent), equals_with_indent())
|
and!(
|
||||||
|
space0_e(min_indent, EExpr::Space, EExpr::IndentEquals),
|
||||||
|
equals_with_indent_help()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
)),
|
)),
|
||||||
move |arena, state, _progress, parsed| helper(arena, state, parsed, min_indent),
|
move |arena, state, _progress, parsed| helper_help(arena, state, parsed, min_indent),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, &'a str>, EExpr<'a>> {
|
||||||
|
|arena, state| match record_field_access().parse(arena, state) {
|
||||||
|
Ok((_, initial, state)) => {
|
||||||
|
let mut accesses = Vec::with_capacity_in(1, arena);
|
||||||
|
|
||||||
|
accesses.push(initial);
|
||||||
|
|
||||||
|
let mut loop_state = state;
|
||||||
|
loop {
|
||||||
|
match record_field_access().parse(arena, loop_state) {
|
||||||
|
Ok((_, next, state)) => {
|
||||||
|
accesses.push(next);
|
||||||
|
loop_state = state;
|
||||||
|
}
|
||||||
|
Err((MadeProgress, fail, state)) => return Err((MadeProgress, fail, state)),
|
||||||
|
Err((NoProgress, _, state)) => return Ok((MadeProgress, accesses, state)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
|
||||||
|
Err((NoProgress, _, state)) => {
|
||||||
|
Err((NoProgress, EExpr::Access(state.line, state.column), state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_field_access<'a>() -> impl Parser<'a, &'a str, EExpr<'a>> {
|
||||||
|
specialize(
|
||||||
|
|_, r, c| EExpr::Access(r, c),
|
||||||
|
skip_first!(ascii_char(b'.'), lowercase_ident()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +224,45 @@ fn helper<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn helper_help<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
loc_expr_with_extras: Extras<'a>,
|
||||||
|
min_indent: u16,
|
||||||
|
) -> ParseResult<'a, Located<Expr<'a>>, EExpr<'a>> {
|
||||||
|
// We parse the parenthetical expression *and* the arguments after it
|
||||||
|
// in one region, so that (for example) the region for Apply includes its args.
|
||||||
|
let (loc_expr, opt_extras) = loc_expr_with_extras.value;
|
||||||
|
|
||||||
|
match opt_extras {
|
||||||
|
Some(Either::First(loc_args)) => Ok((
|
||||||
|
MadeProgress,
|
||||||
|
expr_in_parens_then_arguments(arena, loc_expr, loc_args, loc_expr_with_extras.region),
|
||||||
|
state,
|
||||||
|
)),
|
||||||
|
Some(Either::Second(Either::Second((spaces_before_equals, equals_indent)))) => {
|
||||||
|
// '=' after optional spaces
|
||||||
|
expr_in_parens_then_equals_help(
|
||||||
|
min_indent,
|
||||||
|
loc_expr,
|
||||||
|
spaces_before_equals,
|
||||||
|
equals_indent,
|
||||||
|
loc_expr_with_extras.region.start_col,
|
||||||
|
)
|
||||||
|
.parse(arena, state)
|
||||||
|
}
|
||||||
|
Some(Either::Second(Either::First(fields))) => {
|
||||||
|
// '.' and a record field immediately after ')', no optional spaces
|
||||||
|
Ok((
|
||||||
|
MadeProgress,
|
||||||
|
expr_in_parens_then_access(arena, loc_expr, fields),
|
||||||
|
state,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
None => Ok((MadeProgress, loc_expr, state)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn expr_in_parens_then_equals<'a>(
|
fn expr_in_parens_then_equals<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
loc_expr: Located<Expr<'a>>,
|
loc_expr: Located<Expr<'a>>,
|
||||||
|
@ -226,6 +312,63 @@ fn expr_in_parens_then_equals<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expr_in_parens_then_equals_help<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
loc_expr: Located<Expr<'a>>,
|
||||||
|
spaces_before_equals: &'a [CommentOrNewline],
|
||||||
|
equals_indent: u16,
|
||||||
|
def_start_col: u16,
|
||||||
|
) -> impl Parser<'a, Located<Expr<'a>>, EExpr<'a>> {
|
||||||
|
move |arena, state: State<'a>| {
|
||||||
|
let region = loc_expr.region;
|
||||||
|
|
||||||
|
// Re-parse the Expr as a Pattern.
|
||||||
|
let pattern = match expr_to_pattern(arena, &loc_expr.value) {
|
||||||
|
Ok(valid) => valid,
|
||||||
|
Err(fail) => {
|
||||||
|
return Err((
|
||||||
|
MadeProgress,
|
||||||
|
EExpr::Syntax(arena.alloc(fail), state.line, state.column),
|
||||||
|
state,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure we don't discard the spaces - might be comments in there!
|
||||||
|
let value = if spaces_before_equals.is_empty() {
|
||||||
|
pattern
|
||||||
|
} else {
|
||||||
|
Pattern::SpaceAfter(arena.alloc(pattern), spaces_before_equals)
|
||||||
|
};
|
||||||
|
|
||||||
|
let loc_first_pattern = Located { region, value };
|
||||||
|
|
||||||
|
// Continue parsing the expression as a Def.
|
||||||
|
let (_, spaces_after_equals, state) =
|
||||||
|
space0_e(min_indent, EExpr::Space, EExpr::IndentDefBody).parse(arena, state)?;
|
||||||
|
|
||||||
|
// Use loc_expr_with_extras because we want to include the opening '(' char.
|
||||||
|
let (_, parsed_expr, state) = parse_def_expr_help(
|
||||||
|
min_indent,
|
||||||
|
def_start_col,
|
||||||
|
equals_indent,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
loc_first_pattern,
|
||||||
|
spaces_after_equals,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
MadeProgress,
|
||||||
|
Located {
|
||||||
|
value: parsed_expr,
|
||||||
|
region,
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn expr_in_parens_then_arguments<'a>(
|
fn expr_in_parens_then_arguments<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
loc_expr: Located<Expr<'a>>,
|
loc_expr: Located<Expr<'a>>,
|
||||||
|
@ -274,7 +417,8 @@ fn loc_parse_expr_body_without_operators<'a>(
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
) -> ParseResult<'a, Located<Expr<'a>>, SyntaxError<'a>> {
|
) -> ParseResult<'a, Located<Expr<'a>>, SyntaxError<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
loc_parenthetical_expr!(min_indent, loc_function_args(min_indent)),
|
// loc_parenthetical_expr!(min_indent, loc_function_args(min_indent)),
|
||||||
|
loc_expr_in_parens_etc(min_indent),
|
||||||
loc!(string_literal()),
|
loc!(string_literal()),
|
||||||
loc!(number_literal()),
|
loc!(number_literal()),
|
||||||
loc!(closure(min_indent)),
|
loc!(closure(min_indent)),
|
||||||
|
@ -849,6 +993,35 @@ fn parse_defs<'a>(
|
||||||
zero_or_more!(allocated(parse_def))
|
zero_or_more!(allocated(parse_def))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_def_expr_help<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
def_start_col: u16,
|
||||||
|
equals_sign_indent: u16,
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
loc_first_pattern: Located<Pattern<'a>>,
|
||||||
|
spaces_after_equals: &'a [CommentOrNewline<'a>],
|
||||||
|
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||||
|
let result = parse_def_expr(
|
||||||
|
min_indent,
|
||||||
|
def_start_col,
|
||||||
|
equals_sign_indent,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
loc_first_pattern,
|
||||||
|
spaces_after_equals,
|
||||||
|
);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(good) => Ok(good),
|
||||||
|
Err((progress, fail, state)) => {
|
||||||
|
let row = state.line;
|
||||||
|
let col = state.column;
|
||||||
|
Err((progress, EExpr::Def(arena.alloc(fail), row, col), state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_def_expr<'a>(
|
fn parse_def_expr<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
def_start_col: u16,
|
def_start_col: u16,
|
||||||
|
@ -1461,10 +1634,10 @@ pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
||||||
debug!(specialize(
|
specialize(
|
||||||
|e, r, c| SyntaxError::Expr(EExpr::If(e, r, c)),
|
|e, r, c| SyntaxError::Expr(EExpr::If(e, r, c)),
|
||||||
if_expr_help(min_indent),
|
if_expr_help(min_indent),
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is a helper function for parsing function args.
|
/// This is a helper function for parsing function args.
|
||||||
|
@ -1546,6 +1719,12 @@ fn unary_negate_function_arg<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn loc_function_args_help<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
) -> impl Parser<'a, Vec<'a, Located<Expr<'a>>>, EExpr<'a>> {
|
||||||
|
specialize_ref(EExpr::Syntax, loc_function_args(min_indent))
|
||||||
|
}
|
||||||
|
|
||||||
fn loc_function_args<'a>(
|
fn loc_function_args<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
) -> impl Parser<'a, Vec<'a, Located<Expr<'a>>>, SyntaxError<'a>> {
|
) -> impl Parser<'a, Vec<'a, Located<Expr<'a>>>, SyntaxError<'a>> {
|
||||||
|
@ -1729,6 +1908,14 @@ pub fn ident_without_apply<'a>() -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like equals_for_def(), except it produces the indent_col of the state rather than ()
|
||||||
|
pub fn equals_with_indent_help<'a>() -> impl Parser<'a, u16, EExpr<'a>> {
|
||||||
|
move |arena, state: State<'a>| match word1(b'=', EExpr::Equals).parse(arena, state) {
|
||||||
|
Ok((_, _, state)) => Ok((MadeProgress, state.indent_col, state)),
|
||||||
|
Err(bad) => Err(bad),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Like equals_for_def(), except it produces the indent_col of the state rather than ()
|
/// Like equals_for_def(), except it produces the indent_col of the state rather than ()
|
||||||
pub fn equals_with_indent<'a>() -> impl Parser<'a, u16, SyntaxError<'a>> {
|
pub fn equals_with_indent<'a>() -> impl Parser<'a, u16, SyntaxError<'a>> {
|
||||||
move |arena, state: State<'a>| {
|
move |arena, state: State<'a>| {
|
||||||
|
|
|
@ -379,6 +379,13 @@ pub enum EExpr<'a> {
|
||||||
Dot(Row, Col),
|
Dot(Row, Col),
|
||||||
Access(Row, Col),
|
Access(Row, Col),
|
||||||
|
|
||||||
|
Def(&'a SyntaxError<'a>, Row, Col),
|
||||||
|
IndentDefBody(Row, Col),
|
||||||
|
IndentEquals(Row, Col),
|
||||||
|
Equals(Row, Col),
|
||||||
|
|
||||||
|
Syntax(&'a SyntaxError<'a>, Row, Col),
|
||||||
|
|
||||||
When(When<'a>, Row, Col),
|
When(When<'a>, Row, Col),
|
||||||
If(If<'a>, Row, Col),
|
If(If<'a>, Row, Col),
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue