mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
more flexible statement parsing
This commit is contained in:
parent
68c00a1493
commit
b13adf6898
2 changed files with 94 additions and 23 deletions
|
@ -197,12 +197,17 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_indent<'a, E>(indent_problem: fn(Position) -> E) -> impl Parser<'a, (), E>
|
pub fn check_indent<'a, E>(
|
||||||
|
indent_problem: fn(Position) -> E,
|
||||||
|
inside_suffixed_statement: bool,
|
||||||
|
) -> impl Parser<'a, (), E>
|
||||||
where
|
where
|
||||||
E: 'a,
|
E: 'a,
|
||||||
{
|
{
|
||||||
|
let extra_spaces = if inside_suffixed_statement { 4 } else { 0 };
|
||||||
|
|
||||||
move |_, state: State<'a>, min_indent: u32| {
|
move |_, state: State<'a>, min_indent: u32| {
|
||||||
if state.column() >= min_indent {
|
if state.column() >= (min_indent + extra_spaces) {
|
||||||
Ok((NoProgress, (), state))
|
Ok((NoProgress, (), state))
|
||||||
} else {
|
} else {
|
||||||
Err((NoProgress, indent_problem(state.pos())))
|
Err((NoProgress, indent_problem(state.pos())))
|
||||||
|
|
|
@ -67,6 +67,20 @@ pub struct ExprParseOptions {
|
||||||
///
|
///
|
||||||
/// > Just foo if foo == 2 -> ...
|
/// > Just foo if foo == 2 -> ...
|
||||||
pub check_for_arrow: bool,
|
pub check_for_arrow: bool,
|
||||||
|
|
||||||
|
/// Check for a suffixed expression, if we find one then
|
||||||
|
/// subsequent parsing for this expression should have an increased
|
||||||
|
/// indent, this is so we can distinguish between the end of the
|
||||||
|
/// statement and the next expression.
|
||||||
|
pub suffixed_found: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprParseOptions {
|
||||||
|
pub fn set_suffixed_found(&self) -> Self {
|
||||||
|
let mut new = *self;
|
||||||
|
new.suffixed_found = true;
|
||||||
|
new
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
pub fn expr_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||||
|
@ -327,13 +341,13 @@ fn expr_operator_chain<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a
|
||||||
let initial_state = state.clone();
|
let initial_state = state.clone();
|
||||||
let end = state.pos();
|
let end = state.pos();
|
||||||
|
|
||||||
let new_indent = if is_loc_expr_suffixed(&expr) {
|
let new_options = if is_loc_expr_suffixed(&expr) {
|
||||||
min_indent + 1
|
options.set_suffixed_found()
|
||||||
} else {
|
} else {
|
||||||
min_indent
|
options
|
||||||
};
|
};
|
||||||
|
|
||||||
match space0_e(EExpr::IndentEnd).parse(arena, state.clone(), new_indent) {
|
match space0_e(EExpr::IndentEnd).parse(arena, state.clone(), min_indent) {
|
||||||
Err((_, _)) => Ok((MadeProgress, expr.value, state)),
|
Err((_, _)) => Ok((MadeProgress, expr.value, state)),
|
||||||
Ok((_, spaces_before_op, state)) => {
|
Ok((_, spaces_before_op, state)) => {
|
||||||
let expr_state = ExprState {
|
let expr_state = ExprState {
|
||||||
|
@ -344,7 +358,14 @@ fn expr_operator_chain<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a
|
||||||
end,
|
end,
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_expr_end(new_indent, options, expr_state, arena, state, initial_state)
|
parse_expr_end(
|
||||||
|
min_indent,
|
||||||
|
new_options,
|
||||||
|
expr_state,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
initial_state,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1082,7 +1103,7 @@ fn parse_defs_end<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
defs.replace_with_value_def(
|
defs.replace_with_value_def(
|
||||||
defs.tags.len().saturating_sub(1),
|
defs.tags.len() - 1,
|
||||||
value_def,
|
value_def,
|
||||||
region,
|
region,
|
||||||
);
|
);
|
||||||
|
@ -1104,7 +1125,7 @@ fn parse_defs_end<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
defs.replace_with_value_def(
|
defs.replace_with_value_def(
|
||||||
defs.tags.len().saturating_sub(1),
|
defs.tags.len() - 1,
|
||||||
value_def,
|
value_def,
|
||||||
region,
|
region,
|
||||||
);
|
);
|
||||||
|
@ -1733,21 +1754,51 @@ fn parse_expr_operator<'a>(
|
||||||
expr_state.end = new_end;
|
expr_state.end = new_end;
|
||||||
expr_state.spaces_after = spaces;
|
expr_state.spaces_after = spaces;
|
||||||
|
|
||||||
// For suffixed expressions we restrict multi-line statements to be indented
|
let new_options = if is_loc_expr_suffixed(&new_expr) {
|
||||||
// so that we can parse a statement like,
|
options.set_suffixed_found()
|
||||||
// ```
|
|
||||||
// "hello"
|
|
||||||
// |> sayHi!
|
|
||||||
// ```
|
|
||||||
// if we don't do this then we do not know where the statement ends
|
|
||||||
// and the next expressions starts
|
|
||||||
let new_indent = if is_loc_expr_suffixed(&new_expr) {
|
|
||||||
min_indent + 1
|
|
||||||
} else {
|
} else {
|
||||||
min_indent
|
options
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_expr_end(new_indent, options, expr_state, arena, state, initial_state)
|
match parse_expr_end(
|
||||||
|
min_indent,
|
||||||
|
new_options,
|
||||||
|
expr_state,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
initial_state,
|
||||||
|
) {
|
||||||
|
Ok((progress, expr, state)) => {
|
||||||
|
if let Expr::BinOps(..) = expr {
|
||||||
|
let def_region = expr.get_region_spanning_binops();
|
||||||
|
let mut new_expr = Loc::at(def_region, expr);
|
||||||
|
|
||||||
|
if is_loc_expr_suffixed(&new_expr) {
|
||||||
|
// We have parsed a statement such as `"hello" |> line!`
|
||||||
|
// put the spaces from after the operator in front of the call
|
||||||
|
if !spaces_after_operator.is_empty() {
|
||||||
|
new_expr = arena.alloc(expr).with_spaces_before(
|
||||||
|
spaces_after_operator,
|
||||||
|
def_region,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let value_def = ValueDef::Stmt(arena.alloc(new_expr));
|
||||||
|
|
||||||
|
let mut defs = Defs::default();
|
||||||
|
defs.push_value_def(value_def, def_region, &[], &[]);
|
||||||
|
|
||||||
|
return parse_defs_expr(
|
||||||
|
options, min_indent, defs, arena, state,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// else return the parsed expression
|
||||||
|
Ok((progress, expr, state))
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1767,7 +1818,7 @@ fn parse_expr_end<'a>(
|
||||||
initial_state: State<'a>,
|
initial_state: State<'a>,
|
||||||
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||||
let parser = skip_first!(
|
let parser = skip_first!(
|
||||||
crate::blankspace::check_indent(EExpr::IndentEnd),
|
crate::blankspace::check_indent(EExpr::IndentEnd, options.suffixed_found),
|
||||||
loc_term_or_underscore(options)
|
loc_term_or_underscore(options)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1829,6 +1880,12 @@ fn parse_expr_end<'a>(
|
||||||
Ok((_, mut arg, state)) => {
|
Ok((_, mut arg, state)) => {
|
||||||
let new_end = state.pos();
|
let new_end = state.pos();
|
||||||
|
|
||||||
|
let new_options = if is_loc_expr_suffixed(&arg) {
|
||||||
|
options.set_suffixed_found()
|
||||||
|
} else {
|
||||||
|
options
|
||||||
|
};
|
||||||
|
|
||||||
// now that we have `function arg1 ... <spaces> argn`, attach the spaces to the `argn`
|
// now that we have `function arg1 ... <spaces> argn`, attach the spaces to the `argn`
|
||||||
if !expr_state.spaces_after.is_empty() {
|
if !expr_state.spaces_after.is_empty() {
|
||||||
arg = arena
|
arg = arena
|
||||||
|
@ -1853,7 +1910,14 @@ fn parse_expr_end<'a>(
|
||||||
expr_state.end = new_end;
|
expr_state.end = new_end;
|
||||||
expr_state.spaces_after = new_spaces;
|
expr_state.spaces_after = new_spaces;
|
||||||
|
|
||||||
parse_expr_end(min_indent, options, expr_state, arena, state, initial_state)
|
parse_expr_end(
|
||||||
|
min_indent,
|
||||||
|
new_options,
|
||||||
|
expr_state,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
initial_state,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1969,6 +2033,7 @@ pub fn loc_expr<'a>(accept_multi_backpassing: bool) -> impl Parser<'a, Loc<Expr<
|
||||||
expr_start(ExprParseOptions {
|
expr_start(ExprParseOptions {
|
||||||
accept_multi_backpassing,
|
accept_multi_backpassing,
|
||||||
check_for_arrow: true,
|
check_for_arrow: true,
|
||||||
|
suffixed_found: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2175,6 +2240,7 @@ pub fn toplevel_defs<'a>() -> impl Parser<'a, Defs<'a>, EExpr<'a>> {
|
||||||
let options = ExprParseOptions {
|
let options = ExprParseOptions {
|
||||||
accept_multi_backpassing: true,
|
accept_multi_backpassing: true,
|
||||||
check_for_arrow: true,
|
check_for_arrow: true,
|
||||||
|
suffixed_found: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output = Defs::default();
|
let mut output = Defs::default();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue