mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
improve message for outdented then
This commit is contained in:
parent
3907680536
commit
6eab8abe9e
7 changed files with 270 additions and 57 deletions
|
@ -60,11 +60,12 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn space0_around_e<'a, P, S, E>(
|
pub fn space0_around_ee<'a, P, S, E>(
|
||||||
parser: P,
|
parser: P,
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
space_problem: fn(BadInputError, Row, Col) -> E,
|
space_problem: fn(BadInputError, Row, Col) -> E,
|
||||||
indent_problem: fn(Row, Col) -> E,
|
indent_before_problem: fn(Row, Col) -> E,
|
||||||
|
indent_after_problem: fn(Row, Col) -> E,
|
||||||
) -> impl Parser<'a, Located<S>, E>
|
) -> impl Parser<'a, Located<S>, E>
|
||||||
where
|
where
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
|
@ -75,8 +76,11 @@ where
|
||||||
{
|
{
|
||||||
parser::map_with_arena(
|
parser::map_with_arena(
|
||||||
and(
|
and(
|
||||||
space0_e(min_indent, space_problem, indent_problem),
|
space0_e(min_indent, space_problem, indent_before_problem),
|
||||||
and(parser, space0_e(min_indent, space_problem, indent_problem)),
|
and(
|
||||||
|
parser,
|
||||||
|
space0_e(min_indent, space_problem, indent_after_problem),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
move |arena: &'a Bump,
|
move |arena: &'a Bump,
|
||||||
tuples: (
|
tuples: (
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::ast::{
|
||||||
AssignedField, Attempting, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation,
|
AssignedField, Attempting, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{
|
use crate::blankspace::{
|
||||||
line_comment, space0, space0_after, space0_after_e, space0_around, space0_around_e,
|
line_comment, space0, space0_after, space0_after_e, space0_around, space0_around_ee,
|
||||||
space0_before, space0_before_e, space0_e, space1, space1_before, spaces_exactly,
|
space0_before, space0_before_e, space0_e, space1, space1_before, spaces_exactly,
|
||||||
};
|
};
|
||||||
use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
|
use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
|
||||||
|
@ -1029,14 +1029,15 @@ mod when {
|
||||||
and!(
|
and!(
|
||||||
when_with_indent(),
|
when_with_indent(),
|
||||||
skip_second!(
|
skip_second!(
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
loc!(specialize_ref(
|
loc!(specialize_ref(
|
||||||
When::Syntax,
|
When::Syntax,
|
||||||
move |arena, state| parse_expr(min_indent, arena, state)
|
move |arena, state| parse_expr(min_indent, arena, state)
|
||||||
)),
|
)),
|
||||||
min_indent,
|
min_indent,
|
||||||
When::Space,
|
When::Space,
|
||||||
When::IndentCondition
|
When::IndentCondition,
|
||||||
|
When::IndentIs,
|
||||||
),
|
),
|
||||||
parser::keyword_e(keyword::IS, When::Is)
|
parser::keyword_e(keyword::IS, When::Is)
|
||||||
)
|
)
|
||||||
|
@ -1182,13 +1183,14 @@ mod when {
|
||||||
skip_first!(
|
skip_first!(
|
||||||
parser::keyword_e(keyword::IF, When::IfToken),
|
parser::keyword_e(keyword::IF, When::IfToken),
|
||||||
// TODO we should require space before the expression but not after
|
// TODO we should require space before the expression but not after
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
loc!(specialize_ref(When::IfGuard, move |arena, state| {
|
loc!(specialize_ref(When::IfGuard, move |arena, state| {
|
||||||
parse_expr(min_indent, arena, state)
|
parse_expr(min_indent, arena, state)
|
||||||
})),
|
})),
|
||||||
min_indent,
|
min_indent,
|
||||||
When::Space,
|
When::Space,
|
||||||
When::IndentIfGuard,
|
When::IndentIfGuard,
|
||||||
|
When::IndentArrow,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Some
|
Some
|
||||||
|
@ -1234,6 +1236,49 @@ mod when {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn if_branch<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
) -> impl Parser<'a, (Located<Expr<'a>>, Located<Expr<'a>>), If<'a>> {
|
||||||
|
move |arena, state| {
|
||||||
|
// NOTE: only parse spaces before the expression
|
||||||
|
let (_, cond, state) = space0_around_ee(
|
||||||
|
specialize_ref(
|
||||||
|
If::Syntax,
|
||||||
|
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||||
|
),
|
||||||
|
min_indent,
|
||||||
|
If::Space,
|
||||||
|
If::IndentCondition,
|
||||||
|
If::IndentThenToken,
|
||||||
|
)
|
||||||
|
.parse(arena, state)
|
||||||
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
|
|
||||||
|
let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then)
|
||||||
|
.parse(arena, state)
|
||||||
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
|
|
||||||
|
let (_, then_branch, state) = space0_around_ee(
|
||||||
|
specialize_ref(
|
||||||
|
If::Syntax,
|
||||||
|
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||||
|
),
|
||||||
|
min_indent,
|
||||||
|
If::Space,
|
||||||
|
If::IndentThenBranch,
|
||||||
|
If::IndentElseToken,
|
||||||
|
)
|
||||||
|
.parse(arena, state)
|
||||||
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
|
|
||||||
|
let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else)
|
||||||
|
.parse(arena, state)
|
||||||
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
|
|
||||||
|
Ok((MadeProgress, (cond, then_branch), state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
|
pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
|
||||||
move |arena: &'a Bump, state| {
|
move |arena: &'a Bump, state| {
|
||||||
let (_, _, state) = parser::keyword_e(keyword::IF, If::If).parse(arena, state)?;
|
let (_, _, state) = parser::keyword_e(keyword::IF, If::If).parse(arena, state)?;
|
||||||
|
@ -1243,38 +1288,7 @@ pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
|
||||||
let mut loop_state = state;
|
let mut loop_state = state;
|
||||||
|
|
||||||
let state_final_else = loop {
|
let state_final_else = loop {
|
||||||
let state = loop_state;
|
let (_, (cond, then_branch), state) = if_branch(min_indent).parse(arena, loop_state)?;
|
||||||
let (_, cond, state) = space0_around_e(
|
|
||||||
specialize_ref(
|
|
||||||
If::Syntax,
|
|
||||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
|
||||||
),
|
|
||||||
min_indent,
|
|
||||||
If::Space,
|
|
||||||
If::IndentCondition,
|
|
||||||
)
|
|
||||||
.parse(arena, state)
|
|
||||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
|
||||||
|
|
||||||
let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then)
|
|
||||||
.parse(arena, state)
|
|
||||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
|
||||||
|
|
||||||
let (_, then_branch, state) = space0_around_e(
|
|
||||||
specialize_ref(
|
|
||||||
If::Syntax,
|
|
||||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
|
||||||
),
|
|
||||||
min_indent,
|
|
||||||
If::Space,
|
|
||||||
If::IndentThen,
|
|
||||||
)
|
|
||||||
.parse(arena, state)
|
|
||||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
|
||||||
|
|
||||||
let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else)
|
|
||||||
.parse(arena, state)
|
|
||||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
|
||||||
|
|
||||||
branches.push((cond, then_branch));
|
branches.push((cond, then_branch));
|
||||||
|
|
||||||
|
@ -1301,7 +1315,7 @@ pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
|
||||||
),
|
),
|
||||||
min_indent,
|
min_indent,
|
||||||
If::Space,
|
If::Space,
|
||||||
If::IndentElse,
|
If::IndentElseBranch,
|
||||||
)
|
)
|
||||||
.parse(arena, state_final_else)
|
.parse(arena, state_final_else)
|
||||||
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
|
||||||
|
|
|
@ -423,10 +423,10 @@ pub enum If<'a> {
|
||||||
|
|
||||||
IndentCondition(Row, Col),
|
IndentCondition(Row, Col),
|
||||||
IndentIf(Row, Col),
|
IndentIf(Row, Col),
|
||||||
IndentThen(Row, Col),
|
IndentThenToken(Row, Col),
|
||||||
IndentElse(Row, Col),
|
IndentElseToken(Row, Col),
|
||||||
|
IndentThenBranch(Row, Col),
|
||||||
PatternAlignment(u16, Row, Col),
|
IndentElseBranch(Row, Col),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -1452,10 +1452,11 @@ macro_rules! collection_trailing_sep_e {
|
||||||
and!(
|
and!(
|
||||||
$crate::parser::trailing_sep_by0(
|
$crate::parser::trailing_sep_by0(
|
||||||
$delimiter,
|
$delimiter,
|
||||||
$crate::blankspace::space0_around_e(
|
$crate::blankspace::space0_around_ee(
|
||||||
$elem,
|
$elem,
|
||||||
$min_indent,
|
$min_indent,
|
||||||
$space_problem,
|
$space_problem,
|
||||||
|
$indent_problem,
|
||||||
$indent_problem
|
$indent_problem
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ast::Pattern;
|
use crate::ast::Pattern;
|
||||||
use crate::blankspace::{space0_around_e, space0_before_e, space0_e};
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::ident::{ident, lowercase_ident, Ident};
|
use crate::ident::{ident, lowercase_ident, Ident};
|
||||||
use crate::number_literal::number_literal;
|
use crate::number_literal::number_literal;
|
||||||
use crate::parser::Progress::{self, *};
|
use crate::parser::Progress::{self, *};
|
||||||
|
@ -133,11 +133,12 @@ fn loc_pattern_in_parens_help<'a>(
|
||||||
) -> impl Parser<'a, Located<Pattern<'a>>, PInParens<'a>> {
|
) -> impl Parser<'a, Located<Pattern<'a>>, PInParens<'a>> {
|
||||||
between!(
|
between!(
|
||||||
word1(b'(', PInParens::Open),
|
word1(b'(', PInParens::Open),
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
move |arena, state| specialize_ref(PInParens::Syntax, loc_pattern(min_indent))
|
move |arena, state| specialize_ref(PInParens::Syntax, loc_pattern(min_indent))
|
||||||
.parse(arena, state),
|
.parse(arena, state),
|
||||||
min_indent,
|
min_indent,
|
||||||
PInParens::Space,
|
PInParens::Space,
|
||||||
|
PInParens::IndentOpen,
|
||||||
PInParens::IndentEnd,
|
PInParens::IndentEnd,
|
||||||
),
|
),
|
||||||
word1(b')', PInParens::End)
|
word1(b')', PInParens::End)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ast::{AssignedField, Tag, TypeAnnotation};
|
use crate::ast::{AssignedField, Tag, TypeAnnotation};
|
||||||
use crate::blankspace::{space0_around_e, space0_before_e, space0_e};
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::ident::join_module_parts;
|
use crate::ident::join_module_parts;
|
||||||
use crate::keyword;
|
use crate::keyword;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
|
@ -146,11 +146,12 @@ fn loc_type_in_parens<'a>(
|
||||||
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, TInParens<'a>> {
|
) -> impl Parser<'a, Located<TypeAnnotation<'a>>, TInParens<'a>> {
|
||||||
between!(
|
between!(
|
||||||
word1(b'(', TInParens::Open),
|
word1(b'(', TInParens::Open),
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
move |arena, state| specialize_ref(TInParens::Type, expression(min_indent))
|
move |arena, state| specialize_ref(TInParens::Type, expression(min_indent))
|
||||||
.parse(arena, state),
|
.parse(arena, state),
|
||||||
min_indent,
|
min_indent,
|
||||||
TInParens::Space,
|
TInParens::Space,
|
||||||
|
TInParens::IndentOpen,
|
||||||
TInParens::IndentEnd,
|
TInParens::IndentEnd,
|
||||||
),
|
),
|
||||||
word1(b')', TInParens::End)
|
word1(b')', TInParens::End)
|
||||||
|
@ -436,11 +437,12 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
|
||||||
let (p2, rest, state) = zero_or_more!(skip_first!(
|
let (p2, rest, state) = zero_or_more!(skip_first!(
|
||||||
word1(b',', Type::TFunctionArgument),
|
word1(b',', Type::TFunctionArgument),
|
||||||
one_of![
|
one_of![
|
||||||
space0_around_e(
|
space0_around_ee(
|
||||||
term(min_indent),
|
term(min_indent),
|
||||||
min_indent,
|
min_indent,
|
||||||
Type::TSpace,
|
Type::TSpace,
|
||||||
Type::TIndentStart
|
Type::TIndentStart,
|
||||||
|
Type::TIndentEnd
|
||||||
),
|
),
|
||||||
|_, state: State<'a>| Err((
|
|_, state: State<'a>| Err((
|
||||||
NoProgress,
|
NoProgress,
|
||||||
|
|
|
@ -158,7 +158,9 @@ enum Context {
|
||||||
enum Node {
|
enum Node {
|
||||||
WhenCondition,
|
WhenCondition,
|
||||||
WhenBranch,
|
WhenBranch,
|
||||||
// WhenIfGuard,
|
IfCondition,
|
||||||
|
IfThenBranch,
|
||||||
|
IfElseBranch,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_expr_report<'a>(
|
fn to_expr_report<'a>(
|
||||||
|
@ -173,10 +175,130 @@ fn to_expr_report<'a>(
|
||||||
|
|
||||||
match parse_problem {
|
match parse_problem {
|
||||||
EExpr::When(when, row, col) => to_when_report(alloc, filename, context, &when, *row, *col),
|
EExpr::When(when, row, col) => to_when_report(alloc, filename, context, &when, *row, *col),
|
||||||
|
EExpr::If(when, row, col) => to_if_report(alloc, filename, context, &when, *row, *col),
|
||||||
_ => todo!("unhandled parse error: {:?}", parse_problem),
|
_ => todo!("unhandled parse error: {:?}", parse_problem),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_if_report<'a>(
|
||||||
|
alloc: &'a RocDocAllocator<'a>,
|
||||||
|
filename: PathBuf,
|
||||||
|
context: Context,
|
||||||
|
parse_problem: &roc_parse::parser::If<'a>,
|
||||||
|
start_row: Row,
|
||||||
|
start_col: Col,
|
||||||
|
) -> Report<'a> {
|
||||||
|
use roc_parse::parser::If;
|
||||||
|
|
||||||
|
match *parse_problem {
|
||||||
|
If::Syntax(syntax, row, col) => to_syntax_report(alloc, filename, syntax, row, col),
|
||||||
|
If::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
|
||||||
|
|
||||||
|
If::Condition(expr, row, col) => to_expr_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
Context::InNode(Node::IfCondition, start_row, start_col, Box::new(context)),
|
||||||
|
expr,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
),
|
||||||
|
|
||||||
|
If::ThenBranch(expr, row, col) => to_expr_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
Context::InNode(Node::IfThenBranch, start_row, start_col, Box::new(context)),
|
||||||
|
expr,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
),
|
||||||
|
|
||||||
|
If::ElseBranch(expr, row, col) => to_expr_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
Context::InNode(Node::IfElseBranch, start_row, start_col, Box::new(context)),
|
||||||
|
expr,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
),
|
||||||
|
|
||||||
|
If::If(_row, _col) => unreachable!("another branch would be taken"),
|
||||||
|
If::IndentIf(_row, _col) => unreachable!("another branch would be taken"),
|
||||||
|
|
||||||
|
If::Then(row, col) | If::IndentThenBranch(row, col) | If::IndentThenToken(row, col) => {
|
||||||
|
to_unfinished_if_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
start_row,
|
||||||
|
start_col,
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I was expecting to see the "),
|
||||||
|
alloc.keyword("then"),
|
||||||
|
alloc.reflow(r" keyword next."),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
If::Else(row, col) | If::IndentElseBranch(row, col) | If::IndentElseToken(row, col) => {
|
||||||
|
to_unfinished_if_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
start_row,
|
||||||
|
start_col,
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I was expecting to see the "),
|
||||||
|
alloc.keyword("else"),
|
||||||
|
alloc.reflow(r" keyword next."),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
If::IndentCondition(row, col) => to_unfinished_if_report(
|
||||||
|
alloc,
|
||||||
|
filename,
|
||||||
|
row,
|
||||||
|
col,
|
||||||
|
start_row,
|
||||||
|
start_col,
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I was expecting to see a expression next")
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_unfinished_if_report<'a>(
|
||||||
|
alloc: &'a RocDocAllocator<'a>,
|
||||||
|
filename: PathBuf,
|
||||||
|
row: Row,
|
||||||
|
col: Col,
|
||||||
|
start_row: Row,
|
||||||
|
start_col: Col,
|
||||||
|
message: RocDocBuilder<'a>,
|
||||||
|
) -> Report<'a> {
|
||||||
|
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.concat(vec![
|
||||||
|
alloc.reflow(r"I was partway through parsing an "),
|
||||||
|
alloc.keyword("if"),
|
||||||
|
alloc.reflow(r" expression, but I got stuck here:"),
|
||||||
|
]),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
message,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNFINISHED IF".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_when_report<'a>(
|
fn to_when_report<'a>(
|
||||||
alloc: &'a RocDocAllocator<'a>,
|
alloc: &'a RocDocAllocator<'a>,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
|
@ -792,6 +914,23 @@ fn to_type_report<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type::TIndentEnd(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 am partway through parsing a type, but I got stuck here:"),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
alloc.note("I may be confused by indentation"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNFINISHED TYPE".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type::TAsIndentStart(row, col) => {
|
Type::TAsIndentStart(row, col) => {
|
||||||
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
||||||
let region = Region::from_row_col(*row, *col);
|
let region = Region::from_row_col(*row, *col);
|
||||||
|
|
|
@ -4637,7 +4637,7 @@ mod test_reporting {
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED TYPE ─────────────────────────────────────────────────────────────
|
── UNFINISHED TYPE ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I just started parsing a type, but I got stuck here:
|
I am partway through parsing a type, but I got stuck here:
|
||||||
|
|
||||||
1│ f : I64, I64
|
1│ f : I64, I64
|
||||||
^
|
^
|
||||||
|
@ -4950,4 +4950,56 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_outdented_then() {
|
||||||
|
// TODO I think we can do better here
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x =
|
||||||
|
if 5 == 5
|
||||||
|
then 2 else 3
|
||||||
|
|
||||||
|
x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I was partway through parsing an `if` expression, but I got stuck here:
|
||||||
|
|
||||||
|
2│ if 5 == 5
|
||||||
|
^
|
||||||
|
|
||||||
|
I was expecting to see the `then` keyword next.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_missing_else() {
|
||||||
|
// this should get better with time
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
if 5 == 5 then 2
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I was partway through parsing an `if` expression, but I got stuck here:
|
||||||
|
|
||||||
|
1│ if 5 == 5 then 2
|
||||||
|
^
|
||||||
|
|
||||||
|
I was expecting to see the `else` keyword next.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue