mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Merge pull request #1155 from rtfeldman/outdent-parse-crash
Outdent parse crash
This commit is contained in:
commit
e4da63cc48
5 changed files with 207 additions and 66 deletions
|
@ -1,7 +1,7 @@
|
||||||
use crate::ast::CommentOrNewline;
|
use crate::ast::CommentOrNewline;
|
||||||
use crate::ast::Spaceable;
|
use crate::ast::Spaceable;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
self, and, BadInputError, Col, Parser,
|
self, and, backtrackable, BadInputError, Col, Parser,
|
||||||
Progress::{self, *},
|
Progress::{self, *},
|
||||||
Row, State,
|
Row, State,
|
||||||
};
|
};
|
||||||
|
@ -31,38 +31,75 @@ where
|
||||||
space0_e(min_indent, space_problem, indent_after_problem),
|
space0_e(min_indent, space_problem, indent_after_problem),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
move |arena: &'a Bump,
|
spaces_around_help,
|
||||||
tuples: (
|
|
||||||
&'a [CommentOrNewline<'a>],
|
|
||||||
(Located<S>, &'a [CommentOrNewline<'a>]),
|
|
||||||
)| {
|
|
||||||
let (spaces_before, (loc_val, spaces_after)) = tuples;
|
|
||||||
|
|
||||||
if spaces_before.is_empty() {
|
|
||||||
if spaces_after.is_empty() {
|
|
||||||
loc_val
|
|
||||||
} else {
|
|
||||||
arena
|
|
||||||
.alloc(loc_val.value)
|
|
||||||
.with_spaces_after(spaces_after, loc_val.region)
|
|
||||||
}
|
|
||||||
} else if spaces_after.is_empty() {
|
|
||||||
arena
|
|
||||||
.alloc(loc_val.value)
|
|
||||||
.with_spaces_before(spaces_before, loc_val.region)
|
|
||||||
} else {
|
|
||||||
let wrapped_expr = arena
|
|
||||||
.alloc(loc_val.value)
|
|
||||||
.with_spaces_after(spaces_after, loc_val.region);
|
|
||||||
|
|
||||||
arena
|
|
||||||
.alloc(wrapped_expr.value)
|
|
||||||
.with_spaces_before(spaces_before, wrapped_expr.region)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn space0_before_optional_after<'a, P, S, E>(
|
||||||
|
parser: P,
|
||||||
|
min_indent: u16,
|
||||||
|
space_problem: fn(BadInputError, Row, Col) -> E,
|
||||||
|
indent_before_problem: fn(Row, Col) -> E,
|
||||||
|
indent_after_problem: fn(Row, Col) -> E,
|
||||||
|
) -> impl Parser<'a, Located<S>, E>
|
||||||
|
where
|
||||||
|
S: Spaceable<'a>,
|
||||||
|
S: 'a,
|
||||||
|
P: Parser<'a, Located<S>, E>,
|
||||||
|
P: 'a,
|
||||||
|
E: 'a,
|
||||||
|
{
|
||||||
|
parser::map_with_arena(
|
||||||
|
and(
|
||||||
|
space0_e(min_indent, space_problem, indent_before_problem),
|
||||||
|
and(
|
||||||
|
parser,
|
||||||
|
one_of![
|
||||||
|
backtrackable(space0_e(min_indent, space_problem, indent_after_problem)),
|
||||||
|
succeed!(&[] as &[_]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
spaces_around_help,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spaces_around_help<'a, S>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
tuples: (
|
||||||
|
&'a [CommentOrNewline<'a>],
|
||||||
|
(Located<S>, &'a [CommentOrNewline<'a>]),
|
||||||
|
),
|
||||||
|
) -> Located<S>
|
||||||
|
where
|
||||||
|
S: Spaceable<'a>,
|
||||||
|
S: 'a,
|
||||||
|
{
|
||||||
|
let (spaces_before, (loc_val, spaces_after)) = tuples;
|
||||||
|
|
||||||
|
if spaces_before.is_empty() {
|
||||||
|
if spaces_after.is_empty() {
|
||||||
|
loc_val
|
||||||
|
} else {
|
||||||
|
arena
|
||||||
|
.alloc(loc_val.value)
|
||||||
|
.with_spaces_after(spaces_after, loc_val.region)
|
||||||
|
}
|
||||||
|
} else if spaces_after.is_empty() {
|
||||||
|
arena
|
||||||
|
.alloc(loc_val.value)
|
||||||
|
.with_spaces_before(spaces_before, loc_val.region)
|
||||||
|
} else {
|
||||||
|
let wrapped_expr = arena
|
||||||
|
.alloc(loc_val.value)
|
||||||
|
.with_spaces_after(spaces_after, loc_val.region);
|
||||||
|
|
||||||
|
arena
|
||||||
|
.alloc(wrapped_expr.value)
|
||||||
|
.with_spaces_before(spaces_before, wrapped_expr.region)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn space0_before_e<'a, P, S, E>(
|
pub fn space0_before_e<'a, P, S, E>(
|
||||||
parser: P,
|
parser: P,
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
|
|
|
@ -1273,7 +1273,7 @@ macro_rules! collection_trailing_sep_e {
|
||||||
and!(
|
and!(
|
||||||
$crate::parser::trailing_sep_by0(
|
$crate::parser::trailing_sep_by0(
|
||||||
$delimiter,
|
$delimiter,
|
||||||
$crate::blankspace::space0_around_ee(
|
$crate::blankspace::space0_before_optional_after(
|
||||||
$elem,
|
$elem,
|
||||||
$min_indent,
|
$min_indent,
|
||||||
$space_problem,
|
$space_problem,
|
||||||
|
@ -1299,6 +1299,15 @@ macro_rules! collection_trailing_sep_e {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! succeed {
|
||||||
|
($value:expr) => {
|
||||||
|
move |_arena: &'a bumpalo::Bump, state: $crate::parser::State<'a>| {
|
||||||
|
Ok((NoProgress, $value, state))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! and {
|
macro_rules! and {
|
||||||
($p1:expr, $p2:expr) => {
|
($p1:expr, $p2:expr) => {
|
||||||
|
|
|
@ -147,7 +147,7 @@ fn loc_type_in_parens<'a>(
|
||||||
TInParens::IndentOpen,
|
TInParens::IndentOpen,
|
||||||
TInParens::IndentEnd,
|
TInParens::IndentEnd,
|
||||||
),
|
),
|
||||||
word1(b')', TInParens::End)
|
word1(b')', TInParens::IndentEnd)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1750,7 +1750,7 @@ fn to_precord_report<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
PRecord::IndentEnd(row, col) => {
|
PRecord::IndentEnd(row, col) => {
|
||||||
match next_line_starts_with_close_curly(alloc.src_lines, row.saturating_sub(1)) {
|
match next_line_starts_with_close_curly(alloc.src_lines, row) {
|
||||||
Some((curly_row, curly_col)) => {
|
Some((curly_row, curly_col)) => {
|
||||||
let surroundings =
|
let surroundings =
|
||||||
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
||||||
|
@ -1895,7 +1895,7 @@ fn to_pattern_in_parens_report<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
PInParens::IndentEnd(row, col) => {
|
PInParens::IndentEnd(row, col) => {
|
||||||
match next_line_starts_with_close_parenthesis(alloc.src_lines, row.saturating_sub(1)) {
|
match next_line_starts_with_close_parenthesis(alloc.src_lines, row) {
|
||||||
Some((curly_row, curly_col)) => {
|
Some((curly_row, curly_col)) => {
|
||||||
let surroundings =
|
let surroundings =
|
||||||
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
||||||
|
@ -2257,7 +2257,7 @@ fn to_trecord_report<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
TRecord::IndentEnd(row, col) => {
|
TRecord::IndentEnd(row, col) => {
|
||||||
match next_line_starts_with_close_curly(alloc.src_lines, row.saturating_sub(1)) {
|
match next_line_starts_with_close_curly(alloc.src_lines, row) {
|
||||||
Some((curly_row, curly_col)) => {
|
Some((curly_row, curly_col)) => {
|
||||||
let surroundings =
|
let surroundings =
|
||||||
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
||||||
|
@ -2478,7 +2478,7 @@ fn to_ttag_union_report<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
TTagUnion::IndentEnd(row, col) => {
|
TTagUnion::IndentEnd(row, col) => {
|
||||||
match next_line_starts_with_close_square_bracket(alloc.src_lines, row - 1) {
|
match next_line_starts_with_close_square_bracket(alloc.src_lines, row) {
|
||||||
Some((curly_row, curly_col)) => {
|
Some((curly_row, curly_col)) => {
|
||||||
let surroundings =
|
let surroundings =
|
||||||
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
||||||
|
@ -2682,7 +2682,7 @@ fn to_tinparens_report<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
TInParens::IndentEnd(row, col) => {
|
TInParens::IndentEnd(row, col) => {
|
||||||
match next_line_starts_with_close_square_bracket(alloc.src_lines, row - 1) {
|
match next_line_starts_with_close_parenthesis(alloc.src_lines, row) {
|
||||||
Some((curly_row, curly_col)) => {
|
Some((curly_row, curly_col)) => {
|
||||||
let surroundings =
|
let surroundings =
|
||||||
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
Region::from_rows_cols(start_row, start_col, curly_row, curly_col);
|
||||||
|
@ -2694,7 +2694,7 @@ fn to_tinparens_report<'a>(
|
||||||
),
|
),
|
||||||
alloc.region_with_subregion(surroundings, region),
|
alloc.region_with_subregion(surroundings, region),
|
||||||
alloc.concat(vec![
|
alloc.concat(vec![
|
||||||
alloc.reflow("I need this square bracket to be indented more. Try adding more spaces before it!"),
|
alloc.reflow("I need this parenthesis to be indented more. Try adding more spaces before it!"),
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -2714,9 +2714,9 @@ fn to_tinparens_report<'a>(
|
||||||
),
|
),
|
||||||
alloc.region_with_subregion(surroundings, region),
|
alloc.region_with_subregion(surroundings, region),
|
||||||
alloc.concat(vec![
|
alloc.concat(vec![
|
||||||
alloc.reflow("I was expecting to see a closing square "),
|
alloc.reflow("I was expecting to see a parenthesis "),
|
||||||
alloc.reflow("bracket before this, so try adding a "),
|
alloc.reflow("before this, so try adding a "),
|
||||||
alloc.parser_suggestion("]"),
|
alloc.parser_suggestion(")"),
|
||||||
alloc.reflow(" and see if that helps?"),
|
alloc.reflow(" and see if that helps?"),
|
||||||
]),
|
]),
|
||||||
note_for_tag_union_type_indent(alloc),
|
note_for_tag_union_type_indent(alloc),
|
||||||
|
|
|
@ -4526,15 +4526,17 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED PARENTHESES ──────────────────────────────────────────────────────
|
── UNFINISHED PARENTHESES ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am partway through parsing a type in parentheses, but I got stuck
|
I am partway through parsing a type in parentheses, but I got stuck
|
||||||
here:
|
here:
|
||||||
|
|
||||||
1│ f : ( I64
|
1│ f : ( I64
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see a closing parenthesis before this, so try
|
I was expecting to see a parenthesis before this, so try adding a )
|
||||||
adding a ) and see if that helps?
|
and see if that helps?
|
||||||
|
|
||||||
|
Note: I may be confused by indentation
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -4979,12 +4981,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED PATTERN ──────────────────────────────────────────────────────────
|
── UNFINISHED PATTERN ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I just started parsing a pattern, but I got stuck here:
|
I just started parsing a pattern, but I got stuck here:
|
||||||
|
|
||||||
2│ Just 4 | ->
|
2│ Just 4 | ->
|
||||||
^
|
^
|
||||||
|
|
||||||
Note: I may be confused by indentation
|
Note: I may be confused by indentation
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5125,13 +5127,13 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I got stuck here:
|
I got stuck here:
|
||||||
|
|
||||||
1│ when 4 is
|
1│ when 4 is
|
||||||
2│ 5 -> 2
|
2│ 5 -> 2
|
||||||
^
|
^
|
||||||
|
|
||||||
Whatever I am running into is confusing me a lot! Normally I can give
|
Whatever I am running into is confusing me a lot! Normally I can give
|
||||||
fairly specific hints, but something is really tripping me up this
|
fairly specific hints, but something is really tripping me up this
|
||||||
time.
|
time.
|
||||||
|
@ -5176,13 +5178,13 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I got stuck here:
|
I got stuck here:
|
||||||
|
|
||||||
1│ when 4 is
|
1│ when 4 is
|
||||||
2│ 5 -> 2
|
2│ 5 -> 2
|
||||||
^
|
^
|
||||||
|
|
||||||
Whatever I am running into is confusing me a lot! Normally I can give
|
Whatever I am running into is confusing me a lot! Normally I can give
|
||||||
fairly specific hints, but something is really tripping me up this
|
fairly specific hints, but something is really tripping me up this
|
||||||
time.
|
time.
|
||||||
|
@ -5204,26 +5206,26 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNEXPECTED ARROW ────────────────────────────────────────────────────────────
|
── UNEXPECTED ARROW ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am parsing a `when` expression right now, but this arrow is confusing
|
I am parsing a `when` expression right now, but this arrow is confusing
|
||||||
me:
|
me:
|
||||||
|
|
||||||
3│ 2 -> 2
|
3│ 2 -> 2
|
||||||
^^
|
^^
|
||||||
|
|
||||||
It makes sense to see arrows around here, so I suspect it is something
|
It makes sense to see arrows around here, so I suspect it is something
|
||||||
earlier.Maybe this pattern is indented a bit farther from the previous
|
earlier.Maybe this pattern is indented a bit farther from the previous
|
||||||
patterns?
|
patterns?
|
||||||
|
|
||||||
Note: Here is an example of a valid `when` expression for reference.
|
Note: Here is an example of a valid `when` expression for reference.
|
||||||
|
|
||||||
when List.first plants is
|
when List.first plants is
|
||||||
Ok n ->
|
Ok n ->
|
||||||
n
|
n
|
||||||
|
|
||||||
Err _ ->
|
Err _ ->
|
||||||
200
|
200
|
||||||
|
|
||||||
Notice the indentation. All patterns are aligned, and each branch is
|
Notice the indentation. All patterns are aligned, and each branch is
|
||||||
indented a bit more than the corresponding pattern. That is important!
|
indented a bit more than the corresponding pattern. That is important!
|
||||||
"#
|
"#
|
||||||
|
@ -5876,14 +5878,14 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNKNOWN OPERATOR ────────────────────────────────────────────────────────────
|
── UNKNOWN OPERATOR ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
This looks like an operator, but it's not one I recognize!
|
This looks like an operator, but it's not one I recognize!
|
||||||
|
|
||||||
1│ main = 5 -> 3
|
1│ main = 5 -> 3
|
||||||
^^
|
^^
|
||||||
|
|
||||||
The arrow -> is only used to define cases in a `when`.
|
The arrow -> is only used to define cases in a `when`.
|
||||||
|
|
||||||
when color is
|
when color is
|
||||||
Red -> "stop!"
|
Red -> "stop!"
|
||||||
Green -> "go!"
|
Green -> "go!"
|
||||||
|
@ -6208,4 +6210,97 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn outdented_alias() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Box item : [
|
||||||
|
Box item,
|
||||||
|
Items item item
|
||||||
|
]
|
||||||
|
|
||||||
|
4
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── NEED MORE INDENTATION ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I am partway through parsing a tag union type, but I got stuck here:
|
||||||
|
|
||||||
|
1│ Box item : [
|
||||||
|
2│ Box item,
|
||||||
|
3│ Items item item
|
||||||
|
4│ ]
|
||||||
|
^
|
||||||
|
|
||||||
|
I need this square bracket to be indented more. Try adding more spaces
|
||||||
|
before it!
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn outdented_in_parens() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Box : (
|
||||||
|
Str
|
||||||
|
)
|
||||||
|
|
||||||
|
4
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── NEED MORE INDENTATION ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I am partway through parsing a type in parentheses, but I got stuck
|
||||||
|
here:
|
||||||
|
|
||||||
|
1│ Box : (
|
||||||
|
2│ Str
|
||||||
|
3│ )
|
||||||
|
^
|
||||||
|
|
||||||
|
I need this parenthesis to be indented more. Try adding more spaces
|
||||||
|
before it!
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn outdented_record() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Box : {
|
||||||
|
id: Str
|
||||||
|
}
|
||||||
|
|
||||||
|
4
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── NEED MORE INDENTATION ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I am partway through parsing a record type, but I got stuck here:
|
||||||
|
|
||||||
|
1│ Box : {
|
||||||
|
2│ id: Str
|
||||||
|
3│ }
|
||||||
|
^
|
||||||
|
|
||||||
|
I need this curly brace to be indented more. Try adding more spaces
|
||||||
|
before it!
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue