mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-31 02:13:45 +00:00
Add parsing error reporting for list patterns
This commit is contained in:
parent
9bb523ce97
commit
89867a4dc5
4 changed files with 247 additions and 10 deletions
|
@ -566,8 +566,6 @@ pub enum PList<'a> {
|
|||
Space(BadInputError, Position),
|
||||
|
||||
IndentOpen(Position),
|
||||
IndentColon(Position),
|
||||
IndentOptional(Position),
|
||||
IndentEnd(Position),
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
|||
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, optional, specialize, specialize_ref, then, word1, word2, EPattern, PInParens,
|
||||
PList, PRecord, ParseResult, Parser,
|
||||
backtrackable, optional, specialize, specialize_ref, then, word1, word2, word3, EPattern,
|
||||
PInParens, PList, PRecord, ParseResult, Parser,
|
||||
};
|
||||
use crate::state::State;
|
||||
use bumpalo::collections::string::String;
|
||||
|
@ -59,10 +59,10 @@ pub fn loc_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>
|
|||
EPattern::Record,
|
||||
crate::pattern::record_pattern_help(min_indent)
|
||||
)),
|
||||
loc!(specialize(EPattern::List, list_pattern_help(min_indent))),
|
||||
loc!(number_pattern_help()),
|
||||
loc!(string_pattern_help()),
|
||||
loc!(single_quote_pattern_help()),
|
||||
loc!(specialize(EPattern::List, list_pattern_help(min_indent))),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -227,13 +227,23 @@ fn list_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Pattern<'a>, PList<
|
|||
|
||||
fn list_element_pattern<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||
one_of!(
|
||||
three_list_rest_pattern_error(),
|
||||
list_rest_pattern(),
|
||||
specialize_ref(PList::Pattern, loc_pattern_help(min_indent)),
|
||||
)
|
||||
}
|
||||
|
||||
fn three_list_rest_pattern_error<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||
then(
|
||||
loc!(word3(b'.', b'.', b'.', PList::Rest)),
|
||||
|_arena, state, _progress, word| {
|
||||
Err((MadeProgress, PList::Rest(word.region.start()), state))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn list_rest_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||
map!(loc!(word2(b'.', b'.', PList::Rest)), |loc_word: Loc<_>| {
|
||||
map!(loc!(word2(b'.', b'.', PList::Open)), |loc_word: Loc<_>| {
|
||||
loc_word.map(|_| Pattern::ListRest)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use roc_parse::parser::{ENumber, FileError, SyntaxError};
|
||||
use roc_parse::parser::{ENumber, FileError, PList, SyntaxError};
|
||||
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Position, Region};
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -23,6 +23,10 @@ fn note_for_record_pattern_indent<'a>(alloc: &'a RocDocAllocator<'a>) -> RocDocB
|
|||
alloc.note("I may be confused by indentation")
|
||||
}
|
||||
|
||||
fn note_for_list_pattern_indent<'a>(alloc: &'a RocDocAllocator<'a>) -> RocDocBuilder<'a> {
|
||||
alloc.note("I may be confused by indentation")
|
||||
}
|
||||
|
||||
fn note_for_tag_union_type_indent<'a>(alloc: &'a RocDocAllocator<'a>) -> RocDocBuilder<'a> {
|
||||
alloc.note("I may be confused by indentation")
|
||||
}
|
||||
|
@ -46,6 +50,15 @@ fn record_patterns_look_like<'a>(alloc: &'a RocDocAllocator<'a>) -> RocDocBuilde
|
|||
])
|
||||
}
|
||||
|
||||
fn list_patterns_look_like<'a>(alloc: &'a RocDocAllocator<'a>) -> RocDocBuilder<'a> {
|
||||
alloc.concat([
|
||||
alloc.reflow(r"Record pattern look like "),
|
||||
alloc.parser_suggestion("[1, 2, ..]"),
|
||||
alloc.reflow(" or "),
|
||||
alloc.parser_suggestion("[first, .., last]"),
|
||||
])
|
||||
}
|
||||
|
||||
fn to_syntax_report<'a>(
|
||||
alloc: &'a RocDocAllocator<'a>,
|
||||
lines: &LineInfo,
|
||||
|
@ -1595,6 +1608,7 @@ fn to_pattern_report<'a>(
|
|||
}
|
||||
}
|
||||
EPattern::Record(record, pos) => to_precord_report(alloc, lines, filename, record, *pos),
|
||||
EPattern::List(list, pos) => to_plist_report(alloc, lines, filename, list, *pos),
|
||||
EPattern::PInParens(inparens, pos) => {
|
||||
to_pattern_in_parens_report(alloc, lines, filename, inparens, *pos)
|
||||
}
|
||||
|
@ -1855,6 +1869,155 @@ fn to_precord_report<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn to_plist_report<'a>(
|
||||
alloc: &'a RocDocAllocator<'a>,
|
||||
lines: &LineInfo,
|
||||
filename: PathBuf,
|
||||
parse_problem: &PList<'a>,
|
||||
start: Position,
|
||||
) -> Report<'a> {
|
||||
match *parse_problem {
|
||||
PList::Open(pos) => {
|
||||
let surroundings = Region::new(start, pos);
|
||||
let region = LineColumnRegion::from_pos(lines.convert_pos(pos));
|
||||
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow(r"I just started parsing a list pattern, but I got stuck here:"),
|
||||
alloc.region_with_subregion(lines.convert_region(surroundings), region),
|
||||
list_patterns_look_like(alloc),
|
||||
]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "UNFINISHED LIST PATTERN".to_string(),
|
||||
severity: Severity::RuntimeError,
|
||||
}
|
||||
}
|
||||
|
||||
PList::End(pos) => {
|
||||
let surroundings = Region::new(start, pos);
|
||||
let region = LineColumnRegion::from_pos(lines.convert_pos(pos));
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow("I am partway through parsing a list pattern, but I got stuck here:"),
|
||||
alloc.region_with_subregion(lines.convert_region(surroundings), region),
|
||||
alloc.concat([
|
||||
alloc.reflow(
|
||||
r"I was expecting to see a closing square brace before this, so try adding a ",
|
||||
),
|
||||
alloc.parser_suggestion("]"),
|
||||
alloc.reflow(" and see if that helps?"),
|
||||
])]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "UNFINISHED LIST PATTERN".to_string(),
|
||||
severity: Severity::RuntimeError,
|
||||
}
|
||||
}
|
||||
|
||||
PList::Rest(pos) => {
|
||||
let surroundings = Region::new(start, pos);
|
||||
let region = LineColumnRegion::from_pos(lines.convert_pos(pos));
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow("It looks like you may trying to write a list rest pattern, but it's not the form I expect:"),
|
||||
alloc.region_with_subregion(lines.convert_region(surroundings), region),
|
||||
alloc.concat([
|
||||
alloc.reflow(
|
||||
r"List rest patterns, which match zero or more elements in a list, are denoted with ",
|
||||
),
|
||||
alloc.parser_suggestion(".."),
|
||||
alloc.reflow(" - is that what you meant?"),
|
||||
])]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "INCORRECT REST PATTERN".to_string(),
|
||||
severity: Severity::RuntimeError,
|
||||
}
|
||||
}
|
||||
|
||||
PList::Pattern(pattern, pos) => to_pattern_report(alloc, lines, filename, pattern, pos),
|
||||
|
||||
PList::IndentOpen(pos) => {
|
||||
let surroundings = Region::new(start, pos);
|
||||
let region = LineColumnRegion::from_pos(lines.convert_pos(pos));
|
||||
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow(r"I just started parsing a list pattern, but I got stuck here:"),
|
||||
alloc.region_with_subregion(lines.convert_region(surroundings), region),
|
||||
record_patterns_look_like(alloc),
|
||||
note_for_list_pattern_indent(alloc),
|
||||
]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "UNFINISHED LIST PATTERN".to_string(),
|
||||
severity: Severity::RuntimeError,
|
||||
}
|
||||
}
|
||||
|
||||
PList::IndentEnd(pos) => {
|
||||
match next_line_starts_with_close_square_bracket(
|
||||
alloc.src_lines,
|
||||
lines.convert_pos(pos),
|
||||
) {
|
||||
Some(curly_pos) => {
|
||||
let surroundings = LineColumnRegion::new(lines.convert_pos(start), curly_pos);
|
||||
let region = LineColumnRegion::from_pos(curly_pos);
|
||||
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow(
|
||||
"I am partway through parsing a list pattern, but I got stuck here:",
|
||||
),
|
||||
alloc.region_with_subregion(surroundings, region),
|
||||
alloc.concat([
|
||||
alloc.reflow("I need this square brace to be indented more. Try adding more spaces before it!"),
|
||||
]),
|
||||
]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "NEED MORE INDENTATION".to_string(),
|
||||
severity: Severity::RuntimeError,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let surroundings = Region::new(start, pos);
|
||||
let region = LineColumnRegion::from_pos(lines.convert_pos(pos));
|
||||
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow(
|
||||
r"I am partway through parsing a list pattern, but I got stuck here:",
|
||||
),
|
||||
alloc.region_with_subregion(lines.convert_region(surroundings), region),
|
||||
alloc.concat([
|
||||
alloc.reflow("I was expecting to see a closing square "),
|
||||
alloc.reflow("brace before this, so try adding a "),
|
||||
alloc.parser_suggestion("]"),
|
||||
alloc.reflow(" and see if that helps?"),
|
||||
]),
|
||||
note_for_list_pattern_indent(alloc),
|
||||
]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "UNFINISHED LIST PATTERN".to_string(),
|
||||
severity: Severity::RuntimeError,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PList::Space(error, pos) => to_space_report(alloc, lines, filename, &error, pos),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_pattern_in_parens_report<'a>(
|
||||
alloc: &'a RocDocAllocator<'a>,
|
||||
lines: &LineInfo,
|
||||
|
@ -1941,9 +2104,9 @@ fn to_pattern_in_parens_report<'a>(
|
|||
|
||||
PInParens::IndentEnd(pos) => {
|
||||
match next_line_starts_with_close_parenthesis(alloc.src_lines, lines.convert_pos(pos)) {
|
||||
Some(curly_pos) => {
|
||||
let surroundings = LineColumnRegion::new(lines.convert_pos(start), curly_pos);
|
||||
let region = LineColumnRegion::from_pos(curly_pos);
|
||||
Some(close_pos) => {
|
||||
let surroundings = LineColumnRegion::new(lines.convert_pos(start), close_pos);
|
||||
let region = LineColumnRegion::from_pos(close_pos);
|
||||
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow(
|
||||
|
|
|
@ -11665,4 +11665,70 @@ All branches in an `if` must have the same type!
|
|||
clause of `x`.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
list_pattern_not_terminated,
|
||||
indoc!(
|
||||
r#"
|
||||
when [] is
|
||||
[1, 2, -> ""
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── UNFINISHED LIST PATTERN ────────── tmp/list_pattern_not_terminated/Test.roc ─
|
||||
|
||||
I am partway through parsing a list pattern, but I got stuck here:
|
||||
|
||||
5│ [1, 2, -> ""
|
||||
^
|
||||
|
||||
I was expecting to see a closing square brace before this, so try
|
||||
adding a ] and see if that helps?
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
list_pattern_weird_indent,
|
||||
indoc!(
|
||||
r#"
|
||||
when [] is
|
||||
[1, 2,
|
||||
3] -> ""
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── UNFINISHED LIST PATTERN ──────────── tmp/list_pattern_weird_indent/Test.roc ─
|
||||
|
||||
I am partway through parsing a list pattern, but I got stuck here:
|
||||
|
||||
5│ [1, 2,
|
||||
6│ 3] -> ""
|
||||
^
|
||||
|
||||
I was expecting to see a closing square brace before this, so try
|
||||
adding a ] and see if that helps?
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
list_pattern_weird_rest_pattern,
|
||||
indoc!(
|
||||
r#"
|
||||
when [] is
|
||||
[...] -> ""
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── INCORRECT REST PATTERN ─────── tmp/list_pattern_weird_rest_pattern/Test.roc ─
|
||||
|
||||
It looks like you may trying to write a list rest pattern, but it's
|
||||
not the form I expect:
|
||||
|
||||
5│ [...] -> ""
|
||||
^
|
||||
|
||||
List rest patterns, which match zero or more elements in a list, are
|
||||
denoted with .. - is that what you meant?
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue