mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Relax indentation parsing inside parens, lists, and records
This commit is contained in:
parent
1b4f5bbb52
commit
96c5dcb651
7 changed files with 146 additions and 29 deletions
|
@ -51,7 +51,11 @@ pub fn test_parse_expr<'a>(
|
|||
state: State<'a>,
|
||||
) -> Result<Loc<Expr<'a>>, EExpr<'a>> {
|
||||
let parser = skip_second(
|
||||
space0_before_optional_after(loc_expr_block(true), EExpr::IndentStart, EExpr::IndentEnd),
|
||||
space0_before_optional_after(
|
||||
loc_expr_block(true, false),
|
||||
EExpr::IndentStart,
|
||||
EExpr::IndentEnd,
|
||||
),
|
||||
expr_end(),
|
||||
);
|
||||
|
||||
|
@ -78,7 +82,7 @@ pub struct ExprParseOptions {
|
|||
|
||||
pub fn expr_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
loc_expr(true)
|
||||
loc_expr(true, false)
|
||||
.parse(arena, state, min_indent)
|
||||
.map(|(a, b, c)| (a, b.value, c))
|
||||
}
|
||||
|
@ -88,11 +92,7 @@ fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EInParens<'a>
|
|||
then(
|
||||
loc(collection_trailing_sep_e(
|
||||
byte(b'(', EInParens::Open),
|
||||
specialize_err_ref(
|
||||
EInParens::Expr,
|
||||
// space0_before_e(
|
||||
loc_expr_block(false),
|
||||
),
|
||||
specialize_err_ref(EInParens::Expr, loc_expr_block(false, true)),
|
||||
byte(b',', EInParens::End),
|
||||
byte(b')', EInParens::End),
|
||||
Expr::SpaceBefore,
|
||||
|
@ -383,21 +383,27 @@ fn unary_not<'a>() -> impl Parser<'a, (), EExpr<'a>> {
|
|||
}
|
||||
|
||||
/// Entry point for parsing an expression.
|
||||
fn expr_start<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
fn expr_start<'a>(
|
||||
options: ExprParseOptions,
|
||||
allow_any_indent: bool,
|
||||
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
one_of![
|
||||
loc(specialize_err(EExpr::If, if_expr_help(options))),
|
||||
loc(specialize_err(EExpr::When, when::when_expr_help(options))),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(expr_operator_chain(options)),
|
||||
loc(expr_operator_chain(options, allow_any_indent)),
|
||||
fail_expr_start_e()
|
||||
]
|
||||
.trace("expr_start")
|
||||
}
|
||||
|
||||
/// Parse a chain of expressions separated by operators. Also handles function application.
|
||||
fn expr_operator_chain<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
fn expr_operator_chain<'a>(
|
||||
options: ExprParseOptions,
|
||||
allow_any_indent: bool,
|
||||
) -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
(move |arena, state: State<'a>, min_indent: u32| {
|
||||
parse_expr_operator_chain(arena, state, min_indent, options)
|
||||
parse_expr_operator_chain(arena, state, min_indent, options, allow_any_indent)
|
||||
})
|
||||
.trace("expr_operator_chain")
|
||||
}
|
||||
|
@ -407,6 +413,7 @@ fn parse_expr_operator_chain<'a>(
|
|||
state: State<'a>,
|
||||
min_indent: u32,
|
||||
options: ExprParseOptions,
|
||||
allow_any_indent: bool,
|
||||
) -> Result<(Progress, Expr<'a>, State<'a>), (Progress, EExpr<'a>)> {
|
||||
let line_indent = state.line_indent();
|
||||
|
||||
|
@ -432,7 +439,7 @@ fn parse_expr_operator_chain<'a>(
|
|||
|
||||
let mut state = state;
|
||||
|
||||
let call_min_indent = line_indent + 1;
|
||||
let call_min_indent = if allow_any_indent { 0 } else { line_indent + 1 };
|
||||
|
||||
loop {
|
||||
let allow_negate = state.pos() > end;
|
||||
|
@ -1675,7 +1682,7 @@ fn parse_stmt_backpassing<'a>(
|
|||
match expr_to_pattern_help(arena, &call.value) {
|
||||
Ok(good) => {
|
||||
let (_, mut ann_type, state) =
|
||||
expr_start(options).parse(arena, state, call_min_indent)?;
|
||||
expr_start(options, false).parse(arena, state, call_min_indent)?;
|
||||
|
||||
// put the spaces from after the operator in front of the call
|
||||
if !spaces_after_operator.is_empty() {
|
||||
|
@ -1753,7 +1760,7 @@ fn parse_stmt_multi_backpassing<'a>(
|
|||
match two_bytes(b'<', b'-', EExpr::BackpassArrow).parse(arena, state.clone(), min_indent) {
|
||||
Err((_, fail)) => Err((MadeProgress, fail)),
|
||||
Ok((_, _, state)) => {
|
||||
let parse_body = space0_before_e(expr_start(options), EExpr::IndentEnd);
|
||||
let parse_body = space0_before_e(expr_start(options, false), EExpr::IndentEnd);
|
||||
|
||||
let (_, loc_body, state) = parse_body.parse(arena, state, line_indent + 1)?;
|
||||
|
||||
|
@ -1790,6 +1797,7 @@ fn parse_stmt_assignment<'a>(
|
|||
|a, _| a.clone(),
|
||||
spaces_after_operator,
|
||||
!spaces_after_operator.value.is_empty(),
|
||||
false,
|
||||
)?;
|
||||
|
||||
let alias =
|
||||
|
@ -2065,6 +2073,7 @@ fn parse_ability_def<'a>(
|
|||
|
||||
pub fn loc_expr_block<'a>(
|
||||
accept_multi_backpassing: bool,
|
||||
allow_any_indent: bool,
|
||||
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
space0_after_e(
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
|
@ -2085,6 +2094,7 @@ pub fn loc_expr_block<'a>(
|
|||
|a, _| a.clone(),
|
||||
loc_first_space,
|
||||
true,
|
||||
allow_any_indent,
|
||||
)
|
||||
},
|
||||
EExpr::IndentEnd,
|
||||
|
@ -2092,12 +2102,18 @@ pub fn loc_expr_block<'a>(
|
|||
.trace("loc_expr_block")
|
||||
}
|
||||
|
||||
pub fn loc_expr<'a>(accept_multi_backpassing: bool) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
pub fn loc_expr<'a>(
|
||||
accept_multi_backpassing: bool,
|
||||
allow_any_indent: bool,
|
||||
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
space0_before_e(
|
||||
expr_start(ExprParseOptions {
|
||||
accept_multi_backpassing,
|
||||
check_for_arrow: true,
|
||||
}),
|
||||
expr_start(
|
||||
ExprParseOptions {
|
||||
accept_multi_backpassing,
|
||||
check_for_arrow: true,
|
||||
},
|
||||
allow_any_indent,
|
||||
),
|
||||
EExpr::IndentEnd,
|
||||
)
|
||||
}
|
||||
|
@ -2383,7 +2399,7 @@ mod when {
|
|||
indented_seq_skip_first(
|
||||
parser::keyword(keyword::WHEN, EWhen::When),
|
||||
space0_around_e_no_after_indent_check(
|
||||
specialize_err_ref(EWhen::Condition, expr_start(options)),
|
||||
specialize_err_ref(EWhen::Condition, expr_start(options, true)),
|
||||
EWhen::IndentCondition,
|
||||
)
|
||||
),
|
||||
|
@ -2494,7 +2510,7 @@ mod when {
|
|||
space0_around_ee(
|
||||
specialize_err_ref(
|
||||
EWhen::IfGuard,
|
||||
increment_min_indent(expr_start(options))
|
||||
increment_min_indent(expr_start(options, true))
|
||||
),
|
||||
EWhen::IndentIfGuard,
|
||||
EWhen::IndentArrow,
|
||||
|
@ -2620,7 +2636,7 @@ fn if_branch<'a>() -> impl Parser<'a, ((Loc<Expr<'a>>, u32), Loc<Expr<'a>>), EIf
|
|||
and(
|
||||
and(
|
||||
space0_around_ee(
|
||||
specialize_err_ref(EIf::Condition, loc_expr(true)),
|
||||
specialize_err_ref(EIf::Condition, loc_expr(true, false)),
|
||||
EIf::IndentCondition,
|
||||
EIf::IndentThenToken,
|
||||
)
|
||||
|
@ -2796,6 +2812,7 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
|
|||
EIf::ElseBranch,
|
||||
loc_first_space,
|
||||
allow_defs,
|
||||
false,
|
||||
)?;
|
||||
|
||||
let expr = Expr::If {
|
||||
|
@ -2868,6 +2885,7 @@ where
|
|||
wrap_error,
|
||||
loc_first_space,
|
||||
allow_defs,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2884,6 +2902,7 @@ fn parse_block_inner<'a, E>(
|
|||
wrap_error: fn(&'a EExpr<'a>, Position) -> E,
|
||||
first_space: Loc<&'a [CommentOrNewline<'a>]>,
|
||||
allow_defs: bool,
|
||||
allow_any_indent: bool,
|
||||
) -> ParseResult<'a, Loc<Expr<'a>>, E>
|
||||
where
|
||||
E: 'a + SpaceProblem,
|
||||
|
@ -2922,7 +2941,8 @@ where
|
|||
Ok((MadeProgress, loc_expr, state))
|
||||
} else {
|
||||
let (p2, loc_expr, state) =
|
||||
specialize_err_ref(wrap_error, expr_start(options)).parse(arena, state, min_indent)?;
|
||||
specialize_err_ref(wrap_error, expr_start(options, allow_any_indent))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let loc_expr = if first_space.value.is_empty() {
|
||||
loc_expr
|
||||
|
@ -3547,7 +3567,7 @@ fn list_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EList<'a>> {
|
|||
map_with_arena(
|
||||
collection_trailing_sep_e(
|
||||
byte(b'[', EList::Open),
|
||||
specialize_err_ref(EList::Expr, loc_expr(false)),
|
||||
specialize_err_ref(EList::Expr, loc_expr(false, true)),
|
||||
byte(b',', EList::End),
|
||||
byte(b']', EList::End),
|
||||
Expr::SpaceBefore,
|
||||
|
@ -3640,7 +3660,7 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
|||
and(byte(b':', ERecord::Colon), record_field_expr()),
|
||||
and(
|
||||
byte(b'?', ERecord::QuestionMark),
|
||||
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false, true))),
|
||||
),
|
||||
)),
|
||||
),
|
||||
|
@ -3657,7 +3677,7 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
|||
spaces(),
|
||||
skip_first(
|
||||
byte(b':', ERecord::Colon),
|
||||
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false, false))),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -3698,7 +3718,10 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
|||
|
||||
fn record_field_expr<'a>() -> impl Parser<'a, Loc<Expr<'a>>, ERecord<'a>> {
|
||||
map_with_arena(
|
||||
and(spaces(), specialize_err_ref(ERecord::Expr, loc_expr(false))),
|
||||
and(
|
||||
spaces(),
|
||||
specialize_err_ref(ERecord::Expr, loc_expr(false, false)),
|
||||
),
|
||||
|arena: &'a bumpalo::Bump, (spaces, loc_expr)| {
|
||||
if spaces.is_empty() {
|
||||
loc_expr
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue