Merge pull request #1155 from rtfeldman/outdent-parse-crash

Outdent parse crash
This commit is contained in:
Richard Feldman 2021-04-05 21:38:23 -04:00 committed by GitHub
commit e4da63cc48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 207 additions and 66 deletions

View file

@ -1,7 +1,7 @@
use crate::ast::CommentOrNewline;
use crate::ast::Spaceable;
use crate::parser::{
self, and, BadInputError, Col, Parser,
self, and, backtrackable, BadInputError, Col, Parser,
Progress::{self, *},
Row, State,
};
@ -31,38 +31,75 @@ where
space0_e(min_indent, space_problem, indent_after_problem),
),
),
move |arena: &'a Bump,
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)
}
},
spaces_around_help,
)
}
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>(
parser: P,
min_indent: u16,

View file

@ -1273,7 +1273,7 @@ macro_rules! collection_trailing_sep_e {
and!(
$crate::parser::trailing_sep_by0(
$delimiter,
$crate::blankspace::space0_around_ee(
$crate::blankspace::space0_before_optional_after(
$elem,
$min_indent,
$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_rules! and {
($p1:expr, $p2:expr) => {

View file

@ -147,7 +147,7 @@ fn loc_type_in_parens<'a>(
TInParens::IndentOpen,
TInParens::IndentEnd,
),
word1(b')', TInParens::End)
word1(b')', TInParens::IndentEnd)
)
}

View file

@ -1750,7 +1750,7 @@ fn to_precord_report<'a>(
}
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)) => {
let surroundings =
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) => {
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)) => {
let surroundings =
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) => {
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)) => {
let surroundings =
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) => {
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)) => {
let surroundings =
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) => {
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)) => {
let surroundings =
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.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.concat(vec![
alloc.reflow("I was expecting to see a closing square "),
alloc.reflow("bracket before this, so try adding a "),
alloc.parser_suggestion("]"),
alloc.reflow("I was expecting to see a parenthesis "),
alloc.reflow("before this, so try adding a "),
alloc.parser_suggestion(")"),
alloc.reflow(" and see if that helps?"),
]),
note_for_tag_union_type_indent(alloc),

View file

@ -4533,8 +4533,10 @@ mod test_reporting {
1 f : ( I64
^
I was expecting to see a closing parenthesis before this, so try
adding a ) and see if that helps?
I was expecting to see a parenthesis before this, so try adding a )
and see if that helps?
Note: I may be confused by indentation
"#
),
)
@ -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!
"#
),
)
}
}