mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
fiddling with the when
parser
This commit is contained in:
parent
dd8bdcb806
commit
2a0c5c669b
@ -28,7 +28,7 @@ mod test_fmt {
|
||||
|
||||
assert_eq!(buf, expected)
|
||||
}
|
||||
Err(error) => panic!("Unexpected parse failure when parsing this for formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", input, error)
|
||||
Err(error) => panic!("Unexpected parse failure when parsing this for formatting:\n\n{}\n\nParse error was:\n\n{:?}\n\n", input, error)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ where
|
||||
E: 'a,
|
||||
{
|
||||
move |_, state: State<'a>| {
|
||||
if state.column > min_indent {
|
||||
if state.column >= min_indent {
|
||||
Ok((NoProgress, (), state))
|
||||
} else {
|
||||
Err((NoProgress, indent_problem(state.line, state.column), state))
|
||||
|
@ -16,16 +16,33 @@ use roc_region::all::{Located, Position, Region};
|
||||
|
||||
use crate::parser::Progress::{self, *};
|
||||
|
||||
fn expr_end<'a>() -> impl Parser<'a, (), EExpr<'a>> {
|
||||
|_arena, state: State<'a>| {
|
||||
if state.has_reached_end() {
|
||||
Ok((NoProgress, (), state))
|
||||
} else {
|
||||
Err((
|
||||
NoProgress,
|
||||
EExpr::BadExprEnd(state.line, state.column),
|
||||
state,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_parse_expr<'a>(
|
||||
min_indent: u16,
|
||||
arena: &'a bumpalo::Bump,
|
||||
state: State<'a>,
|
||||
) -> Result<Located<Expr<'a>>, EExpr<'a>> {
|
||||
let parser = space0_before_e(
|
||||
let parser = skip_second!(
|
||||
space0_before_e(
|
||||
move |a, s| parse_loc_expr(min_indent, a, s),
|
||||
min_indent,
|
||||
EExpr::Space,
|
||||
EExpr::IndentStart,
|
||||
),
|
||||
expr_end()
|
||||
);
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
@ -1593,15 +1610,13 @@ mod when {
|
||||
// 1. Parse the first branch and get its indentation level. (It must be >= min_indent.)
|
||||
// 2. Parse the other branches. Their indentation levels must be == the first branch's.
|
||||
|
||||
let (_, (loc_first_patterns, loc_first_guard), state) =
|
||||
branch_alternatives(min_indent).parse(arena, state)?;
|
||||
let loc_first_pattern = loc_first_patterns.first().unwrap();
|
||||
let original_indent = loc_first_pattern.region.start_col;
|
||||
let indented_more = original_indent + 1;
|
||||
let (_, ((pattern_indent_level, loc_first_patterns), loc_first_guard), state) =
|
||||
branch_alternatives(min_indent, None).parse(arena, state)?;
|
||||
let original_indent = pattern_indent_level;
|
||||
|
||||
// Parse the first "->" and the expression after it.
|
||||
let (_, loc_first_expr, mut state) =
|
||||
branch_result(indented_more).parse(arena, state)?;
|
||||
branch_result(original_indent + 1).parse(arena, state)?;
|
||||
|
||||
// Record this as the first branch, then optionally parse additional branches.
|
||||
branches.push(arena.alloc(WhenBranch {
|
||||
@ -1613,19 +1628,21 @@ mod when {
|
||||
let branch_parser = map!(
|
||||
and!(
|
||||
then(
|
||||
branch_alternatives(min_indent),
|
||||
move |_arena, state, _, (loc_patterns, loc_guard)| {
|
||||
match alternatives_indented_correctly(&loc_patterns, original_indent) {
|
||||
Ok(()) => Ok((MadeProgress, (loc_patterns, loc_guard), state)),
|
||||
Err(indent) => Err((
|
||||
branch_alternatives(min_indent, Some(pattern_indent_level)),
|
||||
move |_arena, state, _, ((indent_col, loc_patterns), loc_guard)| {
|
||||
if pattern_indent_level == indent_col {
|
||||
Ok((MadeProgress, (loc_patterns, loc_guard), state))
|
||||
} else {
|
||||
let indent = pattern_indent_level - indent_col;
|
||||
Err((
|
||||
MadeProgress,
|
||||
When::PatternAlignment(indent, state.line, state.column),
|
||||
state,
|
||||
)),
|
||||
))
|
||||
}
|
||||
},
|
||||
),
|
||||
branch_result(indented_more)
|
||||
branch_result(original_indent + 1)
|
||||
),
|
||||
|((patterns, guard), expr)| {
|
||||
let patterns: Vec<'a, _> = patterns;
|
||||
@ -1662,9 +1679,43 @@ mod when {
|
||||
/// Parsing alternative patterns in when branches.
|
||||
fn branch_alternatives<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, (Vec<'a, Located<Pattern<'a>>>, Option<Located<Expr<'a>>>), When<'a>> {
|
||||
pattern_indent_level: Option<u16>,
|
||||
) -> impl Parser<
|
||||
'a,
|
||||
(
|
||||
(Col, Vec<'a, Located<Pattern<'a>>>),
|
||||
Option<Located<Expr<'a>>>,
|
||||
),
|
||||
When<'a>,
|
||||
> {
|
||||
and!(
|
||||
sep_by1(word1(b'|', When::Bar), |arena, state| {
|
||||
branch_alternatives_help(min_indent, pattern_indent_level),
|
||||
one_of![
|
||||
map!(
|
||||
skip_first!(
|
||||
parser::keyword_e(keyword::IF, When::IfToken),
|
||||
// TODO we should require space before the expression but not after
|
||||
space0_around_ee(
|
||||
specialize_ref(When::IfGuard, move |arena, state| {
|
||||
parse_loc_expr(min_indent + 1, arena, state)
|
||||
}),
|
||||
min_indent,
|
||||
When::Space,
|
||||
When::IndentIfGuard,
|
||||
When::IndentArrow,
|
||||
)
|
||||
),
|
||||
Some
|
||||
),
|
||||
|_, s| Ok((NoProgress, None, s))
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
fn branch_single_alternative<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Located<Pattern<'a>>, When<'a>> {
|
||||
move |arena, state| {
|
||||
let (_, spaces, state) =
|
||||
backtrackable(space0_e(min_indent, When::Space, When::IndentPattern))
|
||||
.parse(arena, state)?;
|
||||
@ -1688,45 +1739,76 @@ mod when {
|
||||
},
|
||||
state,
|
||||
))
|
||||
}),
|
||||
one_of![
|
||||
map!(
|
||||
skip_first!(
|
||||
parser::keyword_e(keyword::IF, When::IfToken),
|
||||
// TODO we should require space before the expression but not after
|
||||
space0_around_ee(
|
||||
specialize_ref(When::IfGuard, move |arena, state| {
|
||||
parse_loc_expr(min_indent, arena, state)
|
||||
}),
|
||||
min_indent,
|
||||
When::Space,
|
||||
When::IndentIfGuard,
|
||||
When::IndentArrow,
|
||||
)
|
||||
),
|
||||
Some
|
||||
),
|
||||
|_, s| Ok((NoProgress, None, s))
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if alternatives of a when branch are indented correctly.
|
||||
fn alternatives_indented_correctly<'a>(
|
||||
loc_patterns: &'a Vec<'a, Located<Pattern<'a>>>,
|
||||
original_indent: u16,
|
||||
) -> Result<(), u16> {
|
||||
let (first, rest) = loc_patterns.split_first().unwrap();
|
||||
let first_indented_correctly = first.region.start_col == original_indent;
|
||||
if first_indented_correctly {
|
||||
for when_pattern in rest.iter() {
|
||||
if when_pattern.region.start_col < original_indent {
|
||||
return Err(original_indent - when_pattern.region.start_col);
|
||||
fn branch_alternatives_help<'a>(
|
||||
min_indent: u16,
|
||||
pattern_indent_level: Option<u16>,
|
||||
) -> impl Parser<'a, (Col, Vec<'a, Located<Pattern<'a>>>), When<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let initial = state;
|
||||
|
||||
// put no restrictions on the indent after the spaces; we'll check it manually
|
||||
match space0_e(0, When::Space, When::IndentPattern).parse(arena, state) {
|
||||
Err((MadeProgress, fail, _)) => Err((NoProgress, fail, initial)),
|
||||
Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)),
|
||||
Ok((_, spaces, state)) => {
|
||||
match pattern_indent_level {
|
||||
Some(wanted) if state.column > wanted => {
|
||||
// this branch is indented too much
|
||||
Err((
|
||||
MadeProgress,
|
||||
When::IndentPattern(state.line, state.column),
|
||||
state,
|
||||
))
|
||||
}
|
||||
Some(wanted) if state.column < wanted => {
|
||||
let indent = wanted - state.column;
|
||||
Err((
|
||||
NoProgress,
|
||||
When::PatternAlignment(indent, state.line, state.column),
|
||||
initial,
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
let pattern_indent =
|
||||
min_indent.max(pattern_indent_level.unwrap_or(min_indent));
|
||||
// the region is not reliable for the indent col in the case of
|
||||
// parentheses around patterns
|
||||
let pattern_indent_col = state.column;
|
||||
|
||||
let parser = sep_by1(
|
||||
word1(b'|', When::Bar),
|
||||
branch_single_alternative(pattern_indent + 1),
|
||||
);
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
Err((MadeProgress, fail, state)) => {
|
||||
Err((MadeProgress, fail, state))
|
||||
}
|
||||
Err((NoProgress, fail, _)) => {
|
||||
// roll back space parsing if the pattern made no progress
|
||||
Err((NoProgress, fail, initial))
|
||||
}
|
||||
|
||||
Ok((_, mut loc_patterns, state)) => {
|
||||
// tag spaces onto the first parsed pattern
|
||||
if !spaces.is_empty() {
|
||||
if let Some(first) = loc_patterns.get_mut(0) {
|
||||
*first = arena
|
||||
.alloc(first.value)
|
||||
.with_spaces_before(spaces, first.region);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((MadeProgress, (pattern_indent_col, loc_patterns), state))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(original_indent - first.region.start_col)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,6 +379,7 @@ pub type Col = u16;
|
||||
pub enum EExpr<'a> {
|
||||
Start(Row, Col),
|
||||
End(Row, Col),
|
||||
BadExprEnd(Row, Col),
|
||||
Space(BadInputError, Row, Col),
|
||||
|
||||
Dot(Row, Col),
|
||||
@ -926,8 +927,8 @@ where
|
||||
state = next_state;
|
||||
buf.push(next_output);
|
||||
}
|
||||
Err((element_progress, fail, state)) => {
|
||||
return Err((element_progress, fail, state));
|
||||
Err((_, fail, state)) => {
|
||||
return Err((MadeProgress, fail, state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,8 +62,8 @@ pub fn loc_pattern_help<'a>(
|
||||
EPattern::Record,
|
||||
crate::pattern::record_pattern_help(min_indent)
|
||||
)),
|
||||
loc!(number_pattern_help()),
|
||||
loc!(string_pattern_help()),
|
||||
loc!(number_pattern_help())
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2550,6 +2550,201 @@ mod test_parse {
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_negative_numbers() {
|
||||
let arena = Bump::new();
|
||||
let newlines = &[Newline];
|
||||
let pattern1 = Pattern::SpaceBefore(arena.alloc(NumLiteral("1")), newlines);
|
||||
let loc_pattern1 = Located::new(1, 1, 1, 2, pattern1);
|
||||
let expr1 = Num("2");
|
||||
let loc_expr1 = Located::new(1, 1, 6, 7, expr1);
|
||||
let branch1 = &*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern1]),
|
||||
value: loc_expr1,
|
||||
guard: None,
|
||||
});
|
||||
let newlines = &[Newline];
|
||||
let pattern2 = Pattern::SpaceBefore(arena.alloc(NumLiteral("-3")), newlines);
|
||||
let loc_pattern2 = Located::new(2, 2, 1, 3, pattern2);
|
||||
let expr2 = Num("4");
|
||||
let loc_expr2 = Located::new(2, 2, 7, 8, expr2);
|
||||
let branch2 = &*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern2]),
|
||||
value: loc_expr2,
|
||||
guard: None,
|
||||
});
|
||||
let branches = &[branch1, branch2];
|
||||
let var = Var {
|
||||
module_name: "",
|
||||
ident: "x",
|
||||
};
|
||||
let loc_cond = Located::new(0, 0, 5, 6, var);
|
||||
let expected = Expr::When(arena.alloc(loc_cond), branches);
|
||||
let actual = parse_expr_with(
|
||||
&arena,
|
||||
indoc!(
|
||||
r#"
|
||||
when x is
|
||||
1 -> 2
|
||||
-3 -> 4
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_function_application() {
|
||||
let arena = Bump::new();
|
||||
let newlines = &[Newline];
|
||||
let pattern1 = Pattern::SpaceBefore(arena.alloc(NumLiteral("1")), newlines);
|
||||
let loc_pattern1 = Located::new(1, 1, 4, 5, pattern1);
|
||||
let num_2 = Num("2");
|
||||
let num_neg = Located::new(
|
||||
1,
|
||||
1,
|
||||
9,
|
||||
16,
|
||||
Expr::Var {
|
||||
module_name: "Num",
|
||||
ident: "neg",
|
||||
},
|
||||
);
|
||||
let expr0 = Located::new(2, 2, 5, 6, Expr::SpaceBefore(&num_2, &[Newline]));
|
||||
let expr1 = Expr::Apply(
|
||||
&num_neg,
|
||||
&*arena.alloc([&*arena.alloc(expr0)]),
|
||||
CalledVia::Space,
|
||||
);
|
||||
let loc_expr1 = Located::new(1, 2, 9, 6, expr1);
|
||||
let branch1 = &*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern1]),
|
||||
value: loc_expr1,
|
||||
guard: None,
|
||||
});
|
||||
let newlines = &[Newline];
|
||||
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore("")), newlines);
|
||||
let loc_pattern2 = Located::new(3, 3, 4, 5, pattern2);
|
||||
let expr2 = Num("4");
|
||||
let loc_expr2 = Located::new(3, 3, 9, 10, expr2);
|
||||
let branch2 = &*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern2]),
|
||||
value: loc_expr2,
|
||||
guard: None,
|
||||
});
|
||||
let branches = &[branch1, branch2];
|
||||
let var = Var {
|
||||
module_name: "",
|
||||
ident: "x",
|
||||
};
|
||||
let loc_cond = Located::new(0, 0, 5, 6, var);
|
||||
let expected = Expr::When(arena.alloc(loc_cond), branches);
|
||||
let actual = parse_expr_with(
|
||||
&arena,
|
||||
indoc!(
|
||||
r#"
|
||||
when x is
|
||||
1 -> Num.neg
|
||||
2
|
||||
_ -> 4
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_if_guard() {
|
||||
let arena = Bump::new();
|
||||
|
||||
let branch1 = {
|
||||
let newlines = &[Newline];
|
||||
let pattern1 = Pattern::SpaceBefore(arena.alloc(Underscore("")), newlines);
|
||||
let loc_pattern1 = Located::new(1, 1, 4, 5, pattern1);
|
||||
let num_1 = Num("1");
|
||||
let expr1 = Located::new(
|
||||
2,
|
||||
2,
|
||||
8,
|
||||
9,
|
||||
Expr::SpaceBefore(arena.alloc(num_1), &[Newline]),
|
||||
);
|
||||
let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1);
|
||||
&*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern1]),
|
||||
value: loc_expr1,
|
||||
guard: None,
|
||||
})
|
||||
};
|
||||
|
||||
let branch2 = {
|
||||
let pattern1 = Pattern::SpaceBefore(arena.alloc(Underscore("")), &[Newline, Newline]);
|
||||
let loc_pattern1 = Located::new(4, 4, 4, 5, pattern1);
|
||||
let num_1 = Num("2");
|
||||
let expr1 = Located::new(
|
||||
5,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
Expr::SpaceBefore(arena.alloc(num_1), &[Newline]),
|
||||
);
|
||||
let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1);
|
||||
&*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern1]),
|
||||
value: loc_expr1,
|
||||
guard: None,
|
||||
})
|
||||
};
|
||||
|
||||
let branch3 = {
|
||||
let pattern1 =
|
||||
Pattern::SpaceBefore(arena.alloc(Pattern::GlobalTag("Ok")), &[Newline, Newline]);
|
||||
let loc_pattern1 = Located::new(7, 7, 4, 6, pattern1);
|
||||
let num_1 = Num("3");
|
||||
let expr1 = Located::new(
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
9,
|
||||
Expr::SpaceBefore(arena.alloc(num_1), &[Newline]),
|
||||
);
|
||||
let loc_expr1 = expr1; // Located::new(1, 2, 9, 6, expr1);
|
||||
&*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern1]),
|
||||
value: loc_expr1,
|
||||
guard: None,
|
||||
})
|
||||
};
|
||||
|
||||
let branches = &[branch1, branch2, branch3];
|
||||
let var = Var {
|
||||
module_name: "",
|
||||
ident: "x",
|
||||
};
|
||||
let loc_cond = Located::new(0, 0, 5, 6, var);
|
||||
let expected = Expr::When(arena.alloc(loc_cond), branches);
|
||||
let actual = parse_expr_with(
|
||||
&arena,
|
||||
indoc!(
|
||||
r#"
|
||||
when x is
|
||||
_ ->
|
||||
1
|
||||
|
||||
_ ->
|
||||
2
|
||||
|
||||
Ok ->
|
||||
3
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_records() {
|
||||
let arena = Bump::new();
|
||||
@ -2620,9 +2815,9 @@ mod test_parse {
|
||||
let pattern2_alt =
|
||||
Pattern::SpaceBefore(arena.alloc(StrLiteral(PlainLine("bar"))), newlines);
|
||||
let loc_pattern2 = Located::new(2, 2, 1, 6, pattern2);
|
||||
let loc_pattern2_alt = Located::new(3, 3, 1, 6, pattern2_alt);
|
||||
let loc_pattern2_alt = Located::new(3, 3, 2, 7, pattern2_alt);
|
||||
let expr2 = Num("2");
|
||||
let loc_expr2 = Located::new(3, 3, 10, 11, expr2);
|
||||
let loc_expr2 = Located::new(3, 3, 11, 12, expr2);
|
||||
let branch2 = &*arena.alloc(WhenBranch {
|
||||
patterns: arena.alloc([loc_pattern2, loc_pattern2_alt]),
|
||||
value: loc_expr2,
|
||||
|
@ -458,6 +458,27 @@ fn to_expr_report<'a>(
|
||||
*col,
|
||||
),
|
||||
|
||||
EExpr::BadExprEnd(row, col) => {
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
||||
let region = Region::from_row_col(*row, *col);
|
||||
|
||||
let doc = alloc.stack(vec![
|
||||
alloc.reflow(r"I got stuck here:"),
|
||||
alloc.region_with_subregion(surroundings, region),
|
||||
alloc.concat(vec![
|
||||
alloc.reflow("Whatever I am running into is confusing me al lot! "),
|
||||
alloc.reflow("Normally I can give fairly specific hints, "),
|
||||
alloc.reflow("but something is really tripping me up this time."),
|
||||
]),
|
||||
]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "SYNTAX PROBLEM".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
EExpr::Colon(row, col) => {
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
||||
let region = Region::from_row_col(*row, *col);
|
||||
@ -982,7 +1003,7 @@ fn to_list_report<'a>(
|
||||
),
|
||||
|
||||
List::Open(row, col) | List::End(row, col) => {
|
||||
match dbg!(what_is_next(alloc.src_lines, row, col)) {
|
||||
match what_is_next(alloc.src_lines, row, col) {
|
||||
Next::Other(Some(',')) => {
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||
let region = Region::from_row_col(row, col);
|
||||
@ -1388,6 +1409,36 @@ fn to_unfinished_when_report<'a>(
|
||||
start_col: Col,
|
||||
message: RocDocBuilder<'a>,
|
||||
) -> Report<'a> {
|
||||
match what_is_next(alloc.src_lines, row, col) {
|
||||
Next::Token("->") => {
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||
let region = Region::from_rows_cols(row, col, row, col + 2);
|
||||
|
||||
let doc = alloc.stack(vec![
|
||||
alloc.concat(vec![
|
||||
alloc.reflow(r"I am parsing a "),
|
||||
alloc.keyword("when"),
|
||||
alloc.reflow(r" expression right now, but this arrow is confusing me:"),
|
||||
]),
|
||||
alloc.region_with_subregion(surroundings, region),
|
||||
alloc.concat(vec![
|
||||
alloc.reflow(r"It makes sense to see arrows around here, "),
|
||||
alloc.reflow(r"so I suspect it is something earlier."),
|
||||
alloc.reflow(
|
||||
r"Maybe this pattern is indented a bit farther from the previous patterns?",
|
||||
),
|
||||
]),
|
||||
note_for_when_error(alloc),
|
||||
]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "UNEXPECTED ARROW".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||
let region = Region::from_row_col(row, col);
|
||||
|
||||
@ -1408,6 +1459,8 @@ fn to_unfinished_when_report<'a>(
|
||||
title: "UNFINISHED WHEN".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn note_for_when_error<'a>(alloc: &'a RocDocAllocator<'a>) -> RocDocBuilder<'a> {
|
||||
alloc.stack(vec![
|
||||
|
@ -4964,7 +4964,6 @@ mod test_reporting {
|
||||
|
||||
#[test]
|
||||
fn empty_or_pattern() {
|
||||
// this should get better with time
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
@ -4978,29 +4977,16 @@ mod test_reporting {
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── MISSING EXPRESSION ──────────────────────────────────────────────────────────
|
||||
── UNFINISHED PATTERN ──────────────────────────────────────────────────────────
|
||||
|
||||
I am partway through parsing a definition, but I got stuck here:
|
||||
I just started parsing a pattern, but I got stuck here:
|
||||
|
||||
1│ when Just 4 is
|
||||
2│ Just 4 | ->
|
||||
^
|
||||
|
||||
I was expecting to see an expression like 42 or "hello".
|
||||
Note: I may be confused by indentation
|
||||
"#
|
||||
),
|
||||
// indoc!(
|
||||
// r#"
|
||||
// ── UNFINISHED PATTERN ──────────────────────────────────────────────────────────
|
||||
//
|
||||
// I just started parsing a pattern, but I got stuck here:
|
||||
//
|
||||
// 2│ Just 4 | ->
|
||||
// ^
|
||||
//
|
||||
// Note: I may be confused by indentation
|
||||
// "#
|
||||
// ),
|
||||
)
|
||||
}
|
||||
|
||||
@ -5127,6 +5113,57 @@ mod test_reporting {
|
||||
#[test]
|
||||
fn when_outdented_branch() {
|
||||
// this should get better with time
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
when 4 is
|
||||
5 -> 2
|
||||
2 -> 2
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||
|
||||
I got stuck here:
|
||||
|
||||
1│ when 4 is
|
||||
2│ 5 -> 2
|
||||
^
|
||||
|
||||
Whatever I am running into is confusing me al lot! Normally I can give
|
||||
fairly specific hints, but something is really tripping me up this
|
||||
time.
|
||||
"#
|
||||
),
|
||||
// TODO this formerly gave
|
||||
//
|
||||
// ── UNFINISHED WHEN ─────────────────────────────────────────────────────────────
|
||||
//
|
||||
// I was partway through parsing a `when` expression, but I got stuck here:
|
||||
//
|
||||
// 3│ _ -> 2
|
||||
// ^
|
||||
//
|
||||
// I suspect this is a pattern that is not indented enough? (by 2 spaces)
|
||||
//
|
||||
// but that requires parsing the next pattern blindly, irrespective of indentation. Can
|
||||
// we find an efficient solution that doesn't require parsing an extra pattern for
|
||||
// every `when`, i.e. we want a good error message for the test case above, but for
|
||||
// a valid `when`, we don't want to do extra work, e.g. here
|
||||
//
|
||||
// x
|
||||
// when x is
|
||||
// n -> n
|
||||
//
|
||||
// 4
|
||||
//
|
||||
// We don't want to parse the `4` and say it's an outdented pattern!
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_over_indented_underscore() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
@ -5144,7 +5181,47 @@ mod test_reporting {
|
||||
3│ _ -> 2
|
||||
^
|
||||
|
||||
I suspect this is a pattern that is not indented enough? (by 2 spaces)
|
||||
I was expecting to see a pattern next
|
||||
|
||||
Note: Here is an example of a valid `when` expression for reference.
|
||||
|
||||
when List.first plants is
|
||||
Ok n ->
|
||||
n
|
||||
|
||||
Err _ ->
|
||||
200
|
||||
|
||||
Notice the indentation. All patterns are aligned, and each branch is
|
||||
indented a bit more than the corresponding pattern. That is important!
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_over_indented_int() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
when 4 is
|
||||
5 -> Num.neg
|
||||
2 -> 2
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── UNEXPECTED ARROW ────────────────────────────────────────────────────────────
|
||||
|
||||
I am parsing a `when` expression right now, but this arrow is confusing
|
||||
me:
|
||||
|
||||
3│ 2 -> 2
|
||||
^^
|
||||
|
||||
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
|
||||
patterns?
|
||||
|
||||
Note: Here is an example of a valid `when` expression for reference.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use roc_docs::{documentation_to_template_data, files_to_documentations, ModuleEntry};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_docs {
|
||||
|
Loading…
Reference in New Issue
Block a user