mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-01 05:24:15 +00:00
Make ListStart branch less brittle; Add ListEnd branch
This commit is contained in:
parent
69c36af43e
commit
c28d6b9411
2 changed files with 120 additions and 69 deletions
|
|
@ -6432,6 +6432,82 @@ All branches in an `if` must have the same type!
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exposes_start() {
|
||||
report_header_problem_as(
|
||||
indoc!(
|
||||
r"
|
||||
module foobar []
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── WEIRD EXPOSES in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
I am partway through parsing a header, but I got stuck here:
|
||||
|
||||
1│ module foobar []
|
||||
^
|
||||
|
||||
I was expecting an `exposes` list like
|
||||
|
||||
[Animal, default, tame]
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exposes_missing_comma() {
|
||||
report_header_problem_as(
|
||||
indoc!(
|
||||
r"
|
||||
module [value func]
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── WEIRD EXPOSES in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
I am partway through parsing an `exposes` list, but I got stuck here:
|
||||
|
||||
1│ module [value func]
|
||||
^
|
||||
|
||||
I was expecting a type name, value name or function name next, like
|
||||
|
||||
[Animal, default, tame]
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exposes_end() {
|
||||
report_header_problem_as(
|
||||
indoc!(
|
||||
r"
|
||||
module [value
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── WEIRD EXPOSES in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
I am partway through parsing an `exposes` list, but I got stuck here:
|
||||
|
||||
1│ module [value
|
||||
2│
|
||||
^
|
||||
|
||||
I was expecting a type name, value name or function name next, like
|
||||
|
||||
[Animal, default, tame]
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_app_name() {
|
||||
report_header_problem_as(
|
||||
|
|
@ -6458,39 +6534,6 @@ All branches in an `if` must have the same type!
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unneeded_module_name() {
|
||||
report_header_problem_as(
|
||||
indoc!(
|
||||
r"
|
||||
module foobar []
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── WEIRD MODULE NAME in /code/proj/Main.roc ────────────────────────────────────
|
||||
|
||||
I am partway through parsing a header, but I got stuck here:
|
||||
|
||||
1│ module foobar []
|
||||
^
|
||||
|
||||
I am expecting a list of exports like
|
||||
|
||||
module [func, value]
|
||||
|
||||
or module params like
|
||||
|
||||
module { echo } -> [func, value]
|
||||
|
||||
If you're trying to specify a module name, recall that unlike
|
||||
application names, module names are not specified in the header.
|
||||
Instead, they are derived from the name of the module's filename.
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
test_report!(
|
||||
apply_unary_negative,
|
||||
indoc!(
|
||||
|
|
|
|||
|
|
@ -4049,20 +4049,24 @@ fn to_exposes_report<'a>(
|
|||
let severity = Severity::RuntimeError;
|
||||
|
||||
match *parse_problem {
|
||||
EExposes::ListEnd(pos) | // TODO: give this its own error message
|
||||
EExposes::Identifier(pos) => {
|
||||
// TODO: It would be nice to give ListEnd it's own error message.
|
||||
// However with how parsing error are currently reported, ListEnd and
|
||||
// Identifier are tightly coupled and Identifier is basically never
|
||||
// "thrown". Splitting these up to make more specific error messages
|
||||
// would require tweaking how parsing works.
|
||||
EExposes::ListEnd(pos) | EExposes::Identifier(pos) => {
|
||||
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 an `exposes` list, but I got stuck here:"),
|
||||
alloc.concat([
|
||||
alloc.reflow("I am partway through parsing an "),
|
||||
alloc.keyword("exposes"),
|
||||
alloc.reflow(" list, but I got stuck here:"),
|
||||
]),
|
||||
alloc.region_with_subregion(lines.convert_region(surroundings), region, severity),
|
||||
alloc.concat([alloc.reflow(
|
||||
"I was expecting a type name, value name or function name next, like",
|
||||
)]),
|
||||
alloc
|
||||
.parser_suggestion("[Animal, default, tame]")
|
||||
.indent(4),
|
||||
alloc.reflow("I was expecting a type name, value name or function name next, like"),
|
||||
alloc.parser_suggestion("[Animal, default, tame]").indent(4),
|
||||
]);
|
||||
|
||||
Report {
|
||||
|
|
@ -4085,9 +4089,7 @@ fn to_exposes_report<'a>(
|
|||
alloc.keyword("exposes"),
|
||||
alloc.reflow(" keyword next, like"),
|
||||
]),
|
||||
alloc
|
||||
.parser_suggestion("[Animal, default, tame]")
|
||||
.indent(4),
|
||||
alloc.parser_suggestion("[Animal, default, tame]").indent(4),
|
||||
]);
|
||||
|
||||
Report {
|
||||
|
|
@ -4100,7 +4102,20 @@ fn to_exposes_report<'a>(
|
|||
|
||||
EExposes::Space(error, pos) => to_space_report(alloc, lines, filename, &error, pos),
|
||||
|
||||
EExposes::ListStart(pos@Position { offset: 7 }) => {
|
||||
// TODO: Depending on the type of header we're parsing, it would be
|
||||
// great to add more context to this error message. For example, if
|
||||
// we're parsing a `module` then saying something like:
|
||||
//
|
||||
// I was expecting an exposes list like
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// or module params like
|
||||
// ...
|
||||
//
|
||||
// would be great. But currently we don't capture the type of header in
|
||||
// the parse problem data type, so this isn't possible
|
||||
EExposes::ListStart(pos) => {
|
||||
let surroundings = Region::new(start, pos);
|
||||
let region = LineColumnRegion::from_pos(lines.convert_pos(pos));
|
||||
|
||||
|
|
@ -4108,40 +4123,33 @@ fn to_exposes_report<'a>(
|
|||
alloc.reflow(r"I am partway through parsing a header, but I got stuck here:"),
|
||||
alloc.region_with_subregion(lines.convert_region(surroundings), region, severity),
|
||||
alloc.concat([
|
||||
alloc.reflow("I am expecting a list of exports like"),
|
||||
]),
|
||||
alloc
|
||||
.parser_suggestion("module [func, value]")
|
||||
.indent(4),
|
||||
alloc.concat([
|
||||
alloc.reflow("or module params like"),
|
||||
]),
|
||||
alloc
|
||||
.parser_suggestion("module { echo } -> [func, value]")
|
||||
.indent(4),
|
||||
alloc.concat([
|
||||
alloc.reflow("If you're trying to specify a module name, recall that unlike "),
|
||||
alloc.reflow("application names, module names are not specified in the header. "),
|
||||
alloc.reflow("Instead, they are derived from the name of the module's filename."),
|
||||
alloc.reflow("I was expecting an "),
|
||||
alloc.keyword("exposes"),
|
||||
alloc.reflow(" list like"),
|
||||
]),
|
||||
alloc.parser_suggestion("[Animal, default, tame]").indent(4),
|
||||
]);
|
||||
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "WEIRD MODULE NAME".to_string(),
|
||||
title: "WEIRD EXPOSES".to_string(),
|
||||
severity,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// If you're adding or changing syntax, please handle the case with a
|
||||
// good error message above instead of adding more unhandled cases below.
|
||||
EExposes::Open(pos) |
|
||||
EExposes::IndentExposes(pos) |
|
||||
EExposes::IndentListStart(pos) |
|
||||
EExposes::ListStart(pos) =>
|
||||
to_unhandled_parse_error_report(alloc, lines, filename, format!("{:?}", parse_problem), pos, start)
|
||||
EExposes::Open(pos) | EExposes::IndentExposes(pos) | EExposes::IndentListStart(pos) => {
|
||||
to_unhandled_parse_error_report(
|
||||
alloc,
|
||||
lines,
|
||||
filename,
|
||||
format!("{:?}", parse_problem),
|
||||
pos,
|
||||
start,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue