mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Merge pull request #1056 from rtfeldman/parse-operators
Parse operators
This commit is contained in:
commit
c2525d2407
5 changed files with 529 additions and 241 deletions
|
@ -313,27 +313,68 @@ fn expr_in_parens_then_access<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loc_parse_expr_body_without_operators_help<'a>(
|
fn in_parens_region_fix<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>, EExpr<'a>> {
|
||||||
|
// we get the region of the expression inside the parens, but current tests want us to
|
||||||
|
// include the parentheses in the region
|
||||||
|
map!(
|
||||||
|
loc!(loc_expr_in_parens_etc_help(min_indent)),
|
||||||
|
|loc_loc_expr: Located<Located<Expr<'a>>>| {
|
||||||
|
let value = loc_loc_expr.value.value;
|
||||||
|
let region = loc_loc_expr.region;
|
||||||
|
|
||||||
|
Located::at(region, value)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_loc_term<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
) -> ParseResult<'a, Located<Expr<'a>>, EExpr<'a>> {
|
) -> ParseResult<'a, Located<Expr<'a>>, EExpr<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
loc_expr_in_parens_etc_help(min_indent),
|
in_parens_region_fix(min_indent),
|
||||||
loc!(specialize(EExpr::Str, string_literal_help())),
|
loc!(specialize(EExpr::Str, string_literal_help())),
|
||||||
loc!(specialize(EExpr::Number, number_literal_help())),
|
loc!(specialize(EExpr::Number, number_literal_help())),
|
||||||
loc!(specialize(EExpr::Lambda, closure_help(min_indent))),
|
|
||||||
loc!(record_literal_help(min_indent)),
|
loc!(record_literal_help(min_indent)),
|
||||||
loc!(specialize(EExpr::List, list_literal_help(min_indent))),
|
loc!(specialize(EExpr::List, list_literal_help(min_indent))),
|
||||||
loc!(unary_op_help(min_indent)),
|
loc!(ident_etc_help(min_indent))
|
||||||
loc!(specialize(EExpr::When, when::expr_help(min_indent))),
|
|
||||||
loc!(specialize(EExpr::If, if_expr_help(min_indent))),
|
|
||||||
loc!(ident_etc_help(min_indent)),
|
|
||||||
fail_expr_start_e()
|
|
||||||
)
|
)
|
||||||
.parse(arena, state)
|
.parse(arena, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn loc_possibly_negative_or_negated_term<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
) -> impl Parser<'a, Located<Expr<'a>>, EExpr<'a>> {
|
||||||
|
one_of![
|
||||||
|
loc!(map_with_arena!(
|
||||||
|
// slight complication; a unary minus must be part of the number literal for overflow
|
||||||
|
// reasons
|
||||||
|
and!(loc!(unary_negate()), |a, s| parse_loc_term(
|
||||||
|
min_indent, a, s
|
||||||
|
)),
|
||||||
|
|arena: &'a Bump, (loc_op, loc_expr): (Located<_>, _)| {
|
||||||
|
Expr::UnaryOp(
|
||||||
|
arena.alloc(loc_expr),
|
||||||
|
Located::at(loc_op.region, UnaryOp::Negate),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
loc!(map_with_arena!(
|
||||||
|
and!(loc!(word1(b'!', EExpr::Start)), |a, s| parse_loc_term(
|
||||||
|
min_indent, a, s
|
||||||
|
)),
|
||||||
|
|arena: &'a Bump, (loc_op, loc_expr): (Located<_>, _)| {
|
||||||
|
Expr::UnaryOp(
|
||||||
|
arena.alloc(loc_expr),
|
||||||
|
Located::at(loc_op.region, UnaryOp::Not),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
|arena, state| parse_loc_term(min_indent, arena, state)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn fail_expr_start_e<'a, T>() -> impl Parser<'a, T, EExpr<'a>>
|
fn fail_expr_start_e<'a, T>() -> impl Parser<'a, T, EExpr<'a>>
|
||||||
where
|
where
|
||||||
T: 'a,
|
T: 'a,
|
||||||
|
@ -436,22 +477,23 @@ fn parse_expr_help<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||||
let expr_parser = crate::parser::map_with_arena(
|
let (_, loc_expr1, state) = one_of![
|
||||||
and!(
|
loc!(specialize(EExpr::If, if_expr_help(min_indent))),
|
||||||
// First parse the body without operators, then try to parse possible operators after.
|
loc!(specialize(EExpr::When, when::expr_help(min_indent))),
|
||||||
move |arena, state| loc_parse_expr_body_without_operators_help(
|
loc!(specialize(EExpr::Lambda, closure_help(min_indent))),
|
||||||
min_indent, arena, state
|
loc_possibly_negative_or_negated_term(min_indent),
|
||||||
),
|
// |arena, state| loc_term(min_indent, arena, state),
|
||||||
// Parse the operator, with optional spaces before it.
|
fail_expr_start_e()
|
||||||
//
|
]
|
||||||
// Since spaces can only wrap an Expr, not an BinOp, we have to first
|
.parse(arena, state)?;
|
||||||
// parse the spaces and then attach them retroactively to the expression
|
|
||||||
// preceding the operator (the one we parsed before considering operators).
|
let initial = state.clone();
|
||||||
optional(and!(
|
|
||||||
and!(
|
match space0_e(min_indent, EExpr::Space, EExpr::IndentEnd).parse(arena, state) {
|
||||||
space0_e(min_indent, EExpr::Space, EExpr::IndentEnd),
|
Err((_, _, state)) => Ok((MadeProgress, loc_expr1.value, state)),
|
||||||
loc!(binop_help())
|
Ok((_, spaces_before_op, state)) => {
|
||||||
),
|
let parser = and!(
|
||||||
|
loc!(operator()),
|
||||||
// The spaces *after* the operator can be attached directly to
|
// The spaces *after* the operator can be attached directly to
|
||||||
// the expression following the operator.
|
// the expression following the operator.
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
|
@ -460,27 +502,27 @@ fn parse_expr_help<'a>(
|
||||||
EExpr::Space,
|
EExpr::Space,
|
||||||
EExpr::IndentEnd,
|
EExpr::IndentEnd,
|
||||||
)
|
)
|
||||||
))
|
);
|
||||||
),
|
|
||||||
|arena, (loc_expr1, opt_operator)| match opt_operator {
|
|
||||||
Some(((spaces_before_op, loc_op), loc_expr2)) => {
|
|
||||||
let loc_expr1 = if spaces_before_op.is_empty() {
|
|
||||||
loc_expr1
|
|
||||||
} else {
|
|
||||||
// Attach the spaces retroactively to the expression preceding the operator.
|
|
||||||
arena
|
|
||||||
.alloc(loc_expr1.value)
|
|
||||||
.with_spaces_after(spaces_before_op, loc_expr1.region)
|
|
||||||
};
|
|
||||||
let tuple = arena.alloc((loc_expr1, loc_op, loc_expr2));
|
|
||||||
|
|
||||||
Expr::BinOp(tuple)
|
match parser.parse(arena, state) {
|
||||||
|
Ok((_, (loc_op, loc_expr2), state)) => {
|
||||||
|
let loc_expr1 = if spaces_before_op.is_empty() {
|
||||||
|
loc_expr1
|
||||||
|
} else {
|
||||||
|
// Attach the spaces retroactively to the expression preceding the operator.
|
||||||
|
arena
|
||||||
|
.alloc(loc_expr1.value)
|
||||||
|
.with_spaces_after(spaces_before_op, loc_expr1.region)
|
||||||
|
};
|
||||||
|
let tuple = arena.alloc((loc_expr1, loc_op, loc_expr2));
|
||||||
|
|
||||||
|
Ok((MadeProgress, Expr::BinOp(tuple), state))
|
||||||
|
}
|
||||||
|
Err((NoProgress, _, _)) => Ok((MadeProgress, loc_expr1.value, initial)),
|
||||||
|
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
|
||||||
}
|
}
|
||||||
None => loc_expr1.value,
|
}
|
||||||
},
|
}
|
||||||
);
|
|
||||||
|
|
||||||
expr_parser.parse(arena, state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the given Expr would parse the same way as a valid Pattern, convert it.
|
/// If the given Expr would parse the same way as a valid Pattern, convert it.
|
||||||
|
@ -1681,9 +1723,9 @@ fn loc_function_args_help<'a>(
|
||||||
EExpr::IndentStart,
|
EExpr::IndentStart,
|
||||||
EExpr::Start
|
EExpr::Start
|
||||||
)),
|
)),
|
||||||
one_of!(unary_negate_function_arg_help(min_indent), |a, s| {
|
one_of![unary_negate_function_arg_help(min_indent), |a, s| {
|
||||||
loc_parse_function_arg_help(min_indent, a, s)
|
loc_parse_function_arg_help(min_indent, a, s)
|
||||||
})
|
}]
|
||||||
),
|
),
|
||||||
|(spaces, loc_expr): (&'a [_], Located<Expr<'a>>)| {
|
|(spaces, loc_expr): (&'a [_], Located<Expr<'a>>)| {
|
||||||
if spaces.is_empty() {
|
if spaces.is_empty() {
|
||||||
|
@ -2033,49 +2075,6 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binop_help<'a>() -> impl Parser<'a, BinOp, EExpr<'a>> {
|
|
||||||
macro_rules! binop {
|
|
||||||
($word1:expr, $op:expr) => {
|
|
||||||
map!(
|
|
||||||
word1($word1, |row, col| EExpr::BinOp($op, row, col)),
|
|
||||||
|_| $op
|
|
||||||
)
|
|
||||||
};
|
|
||||||
($word1:expr, $word2:expr, $op:expr) => {
|
|
||||||
map!(
|
|
||||||
word2($word1, $word2, |row, col| EExpr::BinOp($op, row, col)),
|
|
||||||
|_| $op
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
one_of!(
|
|
||||||
// Sorted from highest to lowest predicted usage in practice,
|
|
||||||
// so that successful matches short-circuit as early as possible.
|
|
||||||
// The only exception to this is that operators which begin
|
|
||||||
// with other valid operators (e.g. "<=" begins with "<") must
|
|
||||||
// come before the shorter ones; otherwise, they will never
|
|
||||||
// be reached because the shorter one will pass and consume!
|
|
||||||
binop!(b'|', b'>', BinOp::Pizza),
|
|
||||||
binop!(b'=', b'=', BinOp::Equals),
|
|
||||||
binop!(b'!', b'=', BinOp::NotEquals),
|
|
||||||
binop!(b'&', b'&', BinOp::And),
|
|
||||||
binop!(b'|', b'|', BinOp::Or),
|
|
||||||
binop!(b'+', BinOp::Plus),
|
|
||||||
binop!(b'*', BinOp::Star),
|
|
||||||
binop!(b'-', BinOp::Minus),
|
|
||||||
binop!(b'/', b'/', BinOp::DoubleSlash),
|
|
||||||
binop!(b'/', BinOp::Slash),
|
|
||||||
binop!(b'<', b'=', BinOp::LessThanOrEq),
|
|
||||||
binop!(b'<', BinOp::LessThan),
|
|
||||||
binop!(b'>', b'=', BinOp::GreaterThanOrEq),
|
|
||||||
binop!(b'>', BinOp::GreaterThan),
|
|
||||||
binop!(b'^', BinOp::Caret),
|
|
||||||
binop!(b'%', b'%', BinOp::DoublePercent),
|
|
||||||
binop!(b'%', BinOp::Percent)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>> {
|
fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>> {
|
||||||
move |arena, state| {
|
move |arena, state| {
|
||||||
let (_, (parsed_elems, final_comments), state) = collection_trailing_sep_e!(
|
let (_, (parsed_elems, final_comments), state) = collection_trailing_sep_e!(
|
||||||
|
@ -2365,3 +2364,97 @@ fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, Number> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BINOP_CHAR_SET: &[u8] = b"+-/*=.<>:&|^?%!";
|
||||||
|
|
||||||
|
use crate::parser::{Col, Row};
|
||||||
|
|
||||||
|
fn operator<'a>() -> impl Parser<'a, BinOp, EExpr<'a>> {
|
||||||
|
|_, state| operator_help(EExpr::Start, EExpr::BadOperator, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn operator_help<'a, F, G, E>(
|
||||||
|
to_expectation: F,
|
||||||
|
to_error: G,
|
||||||
|
mut state: State<'a>,
|
||||||
|
) -> ParseResult<'a, BinOp, E>
|
||||||
|
where
|
||||||
|
F: Fn(Row, Col) -> E,
|
||||||
|
G: Fn(&'a [u8], Row, Col) -> E,
|
||||||
|
E: 'a,
|
||||||
|
{
|
||||||
|
let chomped = chomp_ops(state.bytes);
|
||||||
|
|
||||||
|
macro_rules! good {
|
||||||
|
($op:expr, $width:expr) => {{
|
||||||
|
state.column += $width;
|
||||||
|
state.bytes = &state.bytes[$width..];
|
||||||
|
|
||||||
|
Ok((MadeProgress, $op, state))
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! bad_made_progress {
|
||||||
|
($op:expr) => {{
|
||||||
|
Err((MadeProgress, to_error($op, state.line, state.column), state))
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
match chomped {
|
||||||
|
0 => Err((NoProgress, to_expectation(state.line, state.column), state)),
|
||||||
|
1 => {
|
||||||
|
let op = state.bytes[0];
|
||||||
|
match op {
|
||||||
|
b'+' => good!(BinOp::Plus, 1),
|
||||||
|
b'-' => good!(BinOp::Minus, 1),
|
||||||
|
b'*' => good!(BinOp::Star, 1),
|
||||||
|
b'/' => good!(BinOp::Slash, 1),
|
||||||
|
b'%' => good!(BinOp::Percent, 1),
|
||||||
|
b'^' => good!(BinOp::Caret, 1),
|
||||||
|
b'>' => good!(BinOp::GreaterThan, 1),
|
||||||
|
b'<' => good!(BinOp::LessThan, 1),
|
||||||
|
b'.' => {
|
||||||
|
// a `.` makes no progress, so it does not interfere with `.foo` access(or)
|
||||||
|
Err((NoProgress, to_error(b".", state.line, state.column), state))
|
||||||
|
}
|
||||||
|
_ => bad_made_progress!(&state.bytes[0..1]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let op0 = state.bytes[0];
|
||||||
|
let op1 = state.bytes[1];
|
||||||
|
|
||||||
|
match (op0, op1) {
|
||||||
|
(b'|', b'>') => good!(BinOp::Pizza, 2),
|
||||||
|
(b'=', b'=') => good!(BinOp::Equals, 2),
|
||||||
|
(b'!', b'=') => good!(BinOp::NotEquals, 2),
|
||||||
|
(b'>', b'=') => good!(BinOp::GreaterThanOrEq, 2),
|
||||||
|
(b'<', b'=') => good!(BinOp::LessThanOrEq, 2),
|
||||||
|
(b'&', b'&') => good!(BinOp::And, 2),
|
||||||
|
(b'|', b'|') => good!(BinOp::Or, 2),
|
||||||
|
(b'/', b'/') => good!(BinOp::DoubleSlash, 2),
|
||||||
|
(b'%', b'%') => good!(BinOp::DoublePercent, 2),
|
||||||
|
(b'-', b'>') => {
|
||||||
|
// makes no progress, so it does not interfere with `_ if isGood -> ...`
|
||||||
|
Err((NoProgress, to_error(b"->", state.line, state.column), state))
|
||||||
|
}
|
||||||
|
_ => bad_made_progress!(&state.bytes[0..2]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => bad_made_progress!(&state.bytes[0..chomped]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chomp_ops(bytes: &[u8]) -> usize {
|
||||||
|
let mut chomped = 0;
|
||||||
|
|
||||||
|
for c in bytes.iter() {
|
||||||
|
if !BINOP_CHAR_SET.contains(c) {
|
||||||
|
return chomped;
|
||||||
|
}
|
||||||
|
chomped += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chomped
|
||||||
|
}
|
||||||
|
|
|
@ -391,7 +391,7 @@ pub enum EExpr<'a> {
|
||||||
Access(Row, Col),
|
Access(Row, Col),
|
||||||
UnaryNot(Row, Col),
|
UnaryNot(Row, Col),
|
||||||
UnaryNegate(Row, Col),
|
UnaryNegate(Row, Col),
|
||||||
BinOp(roc_module::operator::BinOp, Row, Col),
|
BadOperator(&'a [u8], Row, Col),
|
||||||
|
|
||||||
Def(&'a SyntaxError<'a>, Row, Col),
|
Def(&'a SyntaxError<'a>, Row, Col),
|
||||||
Type(Type<'a>, Row, Col),
|
Type(Type<'a>, Row, Col),
|
||||||
|
|
|
@ -491,6 +491,29 @@ mod test_parse {
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn var_minus_two() {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let tuple = arena.alloc((
|
||||||
|
Located::new(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "x",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Located::new(0, 0, 1, 2, Minus),
|
||||||
|
Located::new(0, 0, 2, 3, Num("2")),
|
||||||
|
));
|
||||||
|
let expected = BinOp(tuple);
|
||||||
|
let actual = parse_expr_with(&arena, "x-2");
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_with_spaces() {
|
fn add_with_spaces() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
|
|
|
@ -221,6 +221,82 @@ fn to_expr_report<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EExpr::BadOperator(op, row, col) => {
|
||||||
|
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
|
||||||
|
let region = Region::from_rows_cols(*row, *col, *row, *col + op.len() as u16);
|
||||||
|
|
||||||
|
let suggestion = match *op {
|
||||||
|
b"|" => vec![
|
||||||
|
alloc.reflow("Maybe you want "),
|
||||||
|
alloc.parser_suggestion("||"),
|
||||||
|
alloc.reflow(" or "),
|
||||||
|
alloc.parser_suggestion("|>"),
|
||||||
|
alloc.reflow(" instead?"),
|
||||||
|
],
|
||||||
|
b"++" => vec![
|
||||||
|
alloc.reflow("To concatenate two lists or strings, try using "),
|
||||||
|
alloc.parser_suggestion("List.concat"),
|
||||||
|
alloc.reflow(" or "),
|
||||||
|
alloc.parser_suggestion("Str.concat"),
|
||||||
|
alloc.reflow(" instead."),
|
||||||
|
],
|
||||||
|
b":" => vec![alloc.stack(vec![
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow("The has-type operator "),
|
||||||
|
alloc.parser_suggestion(":"),
|
||||||
|
alloc.reflow(" can only occur in a definition's type signature, like"),
|
||||||
|
]),
|
||||||
|
alloc
|
||||||
|
.vcat(vec![
|
||||||
|
alloc.text("increment : I64 -> I64"),
|
||||||
|
alloc.text("increment = \\x -> x + 1"),
|
||||||
|
])
|
||||||
|
.indent(4),
|
||||||
|
])],
|
||||||
|
b"->" => vec![alloc.stack(vec![
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow("The arrow "),
|
||||||
|
alloc.parser_suggestion("->"),
|
||||||
|
alloc.reflow(" is only used to define cases in a "),
|
||||||
|
alloc.keyword("when"),
|
||||||
|
alloc.reflow("."),
|
||||||
|
]),
|
||||||
|
alloc
|
||||||
|
.vcat(vec![
|
||||||
|
alloc.text("when color is"),
|
||||||
|
alloc.text("Red -> \"stop!\"").indent(4),
|
||||||
|
alloc.text("Green -> \"go!\"").indent(4),
|
||||||
|
])
|
||||||
|
.indent(4),
|
||||||
|
])],
|
||||||
|
b"!" => vec![
|
||||||
|
alloc.reflow("The boolean negation operator "),
|
||||||
|
alloc.parser_suggestion("!"),
|
||||||
|
alloc.reflow(" must occur immediately before an expression, like "),
|
||||||
|
alloc.parser_suggestion("!(List.isEmpty primes)"),
|
||||||
|
alloc.reflow(". There cannot be a space between the "),
|
||||||
|
alloc.parser_suggestion("!"),
|
||||||
|
alloc.reflow(" and the expression after it."),
|
||||||
|
],
|
||||||
|
_ => vec![
|
||||||
|
alloc.reflow("I have no specific suggestion for this operator, "),
|
||||||
|
alloc.reflow("see TODO for the full list of operators in Roc."),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(r"This looks like an operator, but it's not one I recognize!"),
|
||||||
|
alloc.region_with_subregion(surroundings, region),
|
||||||
|
alloc.concat(suggestion),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
doc,
|
||||||
|
title: "UNKNOWN OPERATOR".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EExpr::Ident(_row, _col) => unreachable!("another branch would be taken"),
|
EExpr::Ident(_row, _col) => unreachable!("another branch would be taken"),
|
||||||
|
|
||||||
EExpr::QualifiedTag(row, col) => {
|
EExpr::QualifiedTag(row, col) => {
|
||||||
|
|
|
@ -812,20 +812,20 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
The 3rd branch of this `if` does not match all the previous branches:
|
The 3rd branch of this `if` does not match all the previous branches:
|
||||||
|
|
||||||
1│ if True then 2 else if False then 2 else "foo"
|
1│ if True then 2 else if False then 2 else "foo"
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
The 3rd branch is a string of type:
|
The 3rd branch is a string of type:
|
||||||
|
|
||||||
Str
|
Str
|
||||||
|
|
||||||
But all the previous branches have type:
|
But all the previous branches have type:
|
||||||
|
|
||||||
Num a
|
Num a
|
||||||
|
|
||||||
I need all branches in an `if` to have the same type!
|
I need all branches in an `if` to have the same type!
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -3159,12 +3159,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── ARGUMENTS BEFORE EQUALS ─────────────────────────────────────────────────────
|
── ARGUMENTS BEFORE EQUALS ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am in the middle of parsing a definition, but I got stuck here:
|
I am in the middle of parsing a definition, but I got stuck here:
|
||||||
|
|
||||||
1│ f x y = x
|
1│ f x y = x
|
||||||
^^^
|
^^^
|
||||||
|
|
||||||
Looks like you are trying to define a function. In roc, functions are
|
Looks like you are trying to define a function. In roc, functions are
|
||||||
always written as a lambda, like increment = \n -> n + 1.
|
always written as a lambda, like increment = \n -> n + 1.
|
||||||
"#
|
"#
|
||||||
|
@ -4020,12 +4020,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am trying to parse a qualified name here:
|
I am trying to parse a qualified name here:
|
||||||
|
|
||||||
1│ Foo.Bar
|
1│ Foo.Bar
|
||||||
^
|
^
|
||||||
|
|
||||||
This looks like a qualified tag name to me, but tags cannot be
|
This looks like a qualified tag name to me, but tags cannot be
|
||||||
qualified! Maybe you wanted a qualified name, something like
|
qualified! Maybe you wanted a qualified name, something like
|
||||||
Json.Decode.string?
|
Json.Decode.string?
|
||||||
|
@ -4045,12 +4045,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am trying to parse a qualified name here:
|
I am trying to parse a qualified name here:
|
||||||
|
|
||||||
1│ Foo.Bar.
|
1│ Foo.Bar.
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see an identifier next, like height. A complete
|
I was expecting to see an identifier next, like height. A complete
|
||||||
qualified name looks something like Json.Decode.string.
|
qualified name looks something like Json.Decode.string.
|
||||||
"#
|
"#
|
||||||
|
@ -4069,12 +4069,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I trying to parse a record field accessor here:
|
I trying to parse a record field accessor here:
|
||||||
|
|
||||||
1│ foo.bar.
|
1│ foo.bar.
|
||||||
^
|
^
|
||||||
|
|
||||||
Something like .name or .height that accesses a value from a record.
|
Something like .name or .height that accesses a value from a record.
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -4092,12 +4092,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am trying to parse a qualified name here:
|
I am trying to parse a qualified name here:
|
||||||
|
|
||||||
1│ @Foo.Bar
|
1│ @Foo.Bar
|
||||||
^
|
^
|
||||||
|
|
||||||
This looks like a qualified tag name to me, but tags cannot be
|
This looks like a qualified tag name to me, but tags cannot be
|
||||||
qualified! Maybe you wanted a qualified name, something like
|
qualified! Maybe you wanted a qualified name, something like
|
||||||
Json.Decode.string?
|
Json.Decode.string?
|
||||||
|
@ -4163,32 +4163,6 @@ mod test_reporting {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn invalid_operator() {
|
|
||||||
// NOTE: VERY BAD ERROR MESSAGE
|
|
||||||
report_problem_as(
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
main =
|
|
||||||
5 ** 3
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
── MISSING EXPRESSION ──────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
I am partway through parsing a definition, but I got stuck here:
|
|
||||||
|
|
||||||
1│ main =
|
|
||||||
2│ 5 ** 3
|
|
||||||
^
|
|
||||||
|
|
||||||
I was expecting to see an expression like 42 or "hello".
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tag_union_open() {
|
fn tag_union_open() {
|
||||||
report_problem_as(
|
report_problem_as(
|
||||||
|
@ -4718,12 +4692,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED TYPE ─────────────────────────────────────────────────────────────
|
── UNFINISHED TYPE ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am partway through 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
|
||||||
^
|
^
|
||||||
|
|
||||||
Note: I may be confused by indentation
|
Note: I may be confused by indentation
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -4905,13 +4879,13 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── MISSING EXPRESSION ──────────────────────────────────────────────────────────
|
── MISSING EXPRESSION ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am partway through parsing a definition, but I got stuck here:
|
I am partway through parsing a definition, but I got stuck here:
|
||||||
|
|
||||||
1│ when Just 4 is
|
1│ when Just 4 is
|
||||||
2│ Just 4 | ->
|
2│ Just 4 | ->
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see an expression like 42 or "hello".
|
I was expecting to see an expression like 42 or "hello".
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -4966,31 +4940,31 @@ mod test_reporting {
|
||||||
r#"
|
r#"
|
||||||
when 5 is
|
when 5 is
|
||||||
1 -> 2
|
1 -> 2
|
||||||
_
|
_
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── MISSING ARROW ───────────────────────────────────────────────────────────────
|
── MISSING ARROW ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am partway through parsing a `when` expression, but got stuck here:
|
I am partway through parsing a `when` expression, but got stuck here:
|
||||||
|
|
||||||
2│ 1 -> 2
|
2│ 1 -> 2
|
||||||
3│ _
|
3│ _
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see an arrow next.
|
I was expecting to see an arrow next.
|
||||||
|
|
||||||
Note: Sometimes I get confused by indentation, so try to make your `when`
|
Note: Sometimes I get confused by indentation, so try to make your `when`
|
||||||
look something like this:
|
look something like this:
|
||||||
|
|
||||||
when List.first plants is
|
when List.first plants is
|
||||||
Ok n ->
|
Ok n ->
|
||||||
n
|
n
|
||||||
|
|
||||||
Err _ ->
|
Err _ ->
|
||||||
200
|
200
|
||||||
|
|
||||||
Notice the indentation. All patterns are aligned, and each branch is
|
Notice the indentation. All patterns are aligned, and each branch is
|
||||||
indented a bit more than the corresponding pattern. That is important!
|
indented a bit more than the corresponding pattern. That is important!
|
||||||
"#
|
"#
|
||||||
|
@ -5009,13 +4983,13 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED ARGUMENT LIST ────────────────────────────────────────────────────
|
── UNFINISHED ARGUMENT LIST ────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am in the middle of parsing a function argument list, but I got
|
I am in the middle of parsing a function argument list, but I got
|
||||||
stuck at this comma:
|
stuck at this comma:
|
||||||
|
|
||||||
1│ \a,,b -> 1
|
1│ \a,,b -> 1
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting an argument pattern before this, so try adding an
|
I was expecting an argument pattern before this, so try adding an
|
||||||
argument before the comma and see if that helps?
|
argument before the comma and see if that helps?
|
||||||
"#
|
"#
|
||||||
|
@ -5034,13 +5008,13 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED ARGUMENT LIST ────────────────────────────────────────────────────
|
── UNFINISHED ARGUMENT LIST ────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am in the middle of parsing a function argument list, but I got
|
I am in the middle of parsing a function argument list, but I got
|
||||||
stuck at this comma:
|
stuck at this comma:
|
||||||
|
|
||||||
1│ \,b -> 1
|
1│ \,b -> 1
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting an argument pattern before this, so try adding an
|
I was expecting an argument pattern before this, so try adding an
|
||||||
argument before the comma and see if that helps?
|
argument before the comma and see if that helps?
|
||||||
"#
|
"#
|
||||||
|
@ -5062,23 +5036,23 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED WHEN ─────────────────────────────────────────────────────────────
|
── UNFINISHED WHEN ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I was partway through parsing a `when` expression, but I got stuck here:
|
I was partway through parsing a `when` expression, but I got stuck here:
|
||||||
|
|
||||||
3│ _ -> 2
|
3│ _ -> 2
|
||||||
^
|
^
|
||||||
|
|
||||||
I suspect this is a pattern that is not indented enough? (by 2 spaces)
|
I suspect this is a pattern that is not indented enough? (by 2 spaces)
|
||||||
|
|
||||||
Note: Here is an example of a valid `when` expression for reference.
|
Note: Here is an example of a valid `when` expression for reference.
|
||||||
|
|
||||||
when List.first plants is
|
when List.first plants is
|
||||||
Ok n ->
|
Ok n ->
|
||||||
n
|
n
|
||||||
|
|
||||||
Err _ ->
|
Err _ ->
|
||||||
200
|
200
|
||||||
|
|
||||||
Notice the indentation. All patterns are aligned, and each branch is
|
Notice the indentation. All patterns are aligned, and each branch is
|
||||||
indented a bit more than the corresponding pattern. That is important!
|
indented a bit more than the corresponding pattern. That is important!
|
||||||
"#
|
"#
|
||||||
|
@ -5093,7 +5067,7 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
x =
|
x =
|
||||||
if 5 == 5
|
if 5 == 5
|
||||||
then 2 else 3
|
then 2 else 3
|
||||||
|
|
||||||
x
|
x
|
||||||
|
@ -5102,12 +5076,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I was partway through parsing an `if` expression, but I got stuck here:
|
I was partway through parsing an `if` expression, but I got stuck here:
|
||||||
|
|
||||||
2│ if 5 == 5
|
2│ if 5 == 5
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see the `then` keyword next.
|
I was expecting to see the `then` keyword next.
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5126,12 +5100,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
── UNFINISHED IF ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I was partway through parsing an `if` expression, but I got stuck here:
|
I was partway through parsing an `if` expression, but I got stuck here:
|
||||||
|
|
||||||
1│ if 5 == 5 then 2
|
1│ if 5 == 5 then 2
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see the `else` keyword next.
|
I was expecting to see the `else` keyword next.
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5149,12 +5123,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am partway through started parsing a list, but I got stuck here:
|
I am partway through started parsing a list, but I got stuck here:
|
||||||
|
|
||||||
1│ [ 1, 2, , 3 ]
|
1│ [ 1, 2, , 3 ]
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see a list entry before this comma, so try adding a
|
I was expecting to see a list entry before this comma, so try adding a
|
||||||
list entry and see if that helps?
|
list entry and see if that helps?
|
||||||
"#
|
"#
|
||||||
|
@ -5167,21 +5141,21 @@ mod test_reporting {
|
||||||
report_problem_as(
|
report_problem_as(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
[ 1, 2,
|
[ 1, 2,
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am partway through started parsing a list, but I got stuck here:
|
I am partway through started parsing a list, but I got stuck here:
|
||||||
|
|
||||||
1│ [ 1, 2,
|
1│ [ 1, 2,
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting to see a closing square bracket before this, so try
|
I was expecting to see a closing square bracket before this, so try
|
||||||
adding a ] and see if that helps?
|
adding a ] and see if that helps?
|
||||||
|
|
||||||
Note: When I get stuck like this, it usually means that there is a
|
Note: When I get stuck like this, it usually means that there is a
|
||||||
missing parenthesis or bracket somewhere earlier. It could also be a
|
missing parenthesis or bracket somewhere earlier. It could also be a
|
||||||
stray keyword or operator.
|
stray keyword or operator.
|
||||||
|
@ -5195,7 +5169,7 @@ mod test_reporting {
|
||||||
report_problem_as(
|
report_problem_as(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
x = [ 1, 2,
|
x = [ 1, 2,
|
||||||
]
|
]
|
||||||
|
|
||||||
x
|
x
|
||||||
|
@ -5204,16 +5178,16 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
── UNFINISHED LIST ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I cannot find the end of this list:
|
I cannot find the end of this list:
|
||||||
|
|
||||||
1│ x = [ 1, 2,
|
1│ x = [ 1, 2,
|
||||||
^
|
^
|
||||||
|
|
||||||
You could change it to something like [ 1, 2, 3 ] or even just [].
|
You could change it to something like [ 1, 2, 3 ] or even just [].
|
||||||
Anything where there is an open and a close square bracket, and where
|
Anything where there is an open and a close square bracket, and where
|
||||||
the elements of the list are separated by commas.
|
the elements of the list are separated by commas.
|
||||||
|
|
||||||
Note: I may be confused by indentation
|
Note: I may be confused by indentation
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5231,15 +5205,15 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
This float literal contains an invalid digit:
|
This float literal contains an invalid digit:
|
||||||
|
|
||||||
1│ 1.1.1
|
1│ 1.1.1
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
Floating point literals can only contain the digits 0-9, or use
|
Floating point literals can only contain the digits 0-9, or use
|
||||||
scientific notation 10e4
|
scientific notation 10e4
|
||||||
|
|
||||||
Tip: Learn more about number literals at TODO
|
Tip: Learn more about number literals at TODO
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5253,15 +5227,15 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── WEIRD CODE POINT ────────────────────────────────────────────────────────────
|
── WEIRD CODE POINT ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am partway through parsing a unicode code point, but I got stuck
|
I am partway through parsing a unicode code point, but I got stuck
|
||||||
here:
|
here:
|
||||||
|
|
||||||
1│ "abc\u(zzzz)def"
|
1│ "abc\u(zzzz)def"
|
||||||
^
|
^
|
||||||
|
|
||||||
I was expecting a hexadecimal number, like \u(1100) or \u(00FF).
|
I was expecting a hexadecimal number, like \u(1100) or \u(00FF).
|
||||||
|
|
||||||
Learn more about working with unicode in roc at TODO
|
Learn more about working with unicode in roc at TODO
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5275,15 +5249,15 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
This string interpolation is invalid:
|
This string interpolation is invalid:
|
||||||
|
|
||||||
1│ "abc\(32)def"
|
1│ "abc\(32)def"
|
||||||
^^
|
^^
|
||||||
|
|
||||||
I was expecting an identifier, like \u(message) or
|
I was expecting an identifier, like \u(message) or
|
||||||
\u(LoremIpsum.text).
|
\u(LoremIpsum.text).
|
||||||
|
|
||||||
Learn more about string interpolation at TODO
|
Learn more about string interpolation at TODO
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5297,12 +5271,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
This unicode code point is invalid:
|
This unicode code point is invalid:
|
||||||
|
|
||||||
1│ "abc\u(110000)def"
|
1│ "abc\u(110000)def"
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
Learn more about working with unicode in roc at TODO
|
Learn more about working with unicode in roc at TODO
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5316,15 +5290,15 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── WEIRD ESCAPE ────────────────────────────────────────────────────────────────
|
── WEIRD ESCAPE ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I was partway through parsing a string literal, but I got stuck here:
|
I was partway through parsing a string literal, but I got stuck here:
|
||||||
|
|
||||||
1│ "abc\qdef"
|
1│ "abc\qdef"
|
||||||
^^
|
^^
|
||||||
|
|
||||||
This is not an escape sequence I recognize. After a backslash, I am
|
This is not an escape sequence I recognize. After a backslash, I am
|
||||||
looking for one of these:
|
looking for one of these:
|
||||||
|
|
||||||
- A newline: \n
|
- A newline: \n
|
||||||
- A caret return: \r
|
- A caret return: \r
|
||||||
- A tab: \t
|
- A tab: \t
|
||||||
|
@ -5344,12 +5318,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── ENDLESS STRING ──────────────────────────────────────────────────────────────
|
── ENDLESS STRING ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I cannot find the end of this string:
|
I cannot find the end of this string:
|
||||||
|
|
||||||
1│ "there is no end
|
1│ "there is no end
|
||||||
^
|
^
|
||||||
|
|
||||||
You could change it to something like "to be or not to be" or even
|
You could change it to something like "to be or not to be" or even
|
||||||
just "".
|
just "".
|
||||||
"#
|
"#
|
||||||
|
@ -5364,12 +5338,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── ENDLESS STRING ──────────────────────────────────────────────────────────────
|
── ENDLESS STRING ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I cannot find the end of this block string:
|
I cannot find the end of this block string:
|
||||||
|
|
||||||
1│ """there is no end
|
1│ """there is no end
|
||||||
^
|
^
|
||||||
|
|
||||||
You could change it to something like """to be or not to be""" or even
|
You could change it to something like """to be or not to be""" or even
|
||||||
just """""".
|
just """""".
|
||||||
"#
|
"#
|
||||||
|
@ -5390,20 +5364,20 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
This expression is used in an unexpected way:
|
This expression is used in an unexpected way:
|
||||||
|
|
||||||
3│ foo.if
|
3│ foo.if
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
This `foo` value is a:
|
This `foo` value is a:
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
But you are trying to use it as:
|
But you are trying to use it as:
|
||||||
|
|
||||||
{ if : a }b
|
{ if : a }b
|
||||||
|
|
||||||
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5421,9 +5395,9 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
The Num module does not expose a if value:
|
The Num module does not expose a if value:
|
||||||
|
|
||||||
1│ Num.if
|
1│ Num.if
|
||||||
^^^^^^
|
^^^^^^
|
||||||
"#
|
"#
|
||||||
|
@ -5442,12 +5416,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I trying to parse a record field accessor here:
|
I trying to parse a record field accessor here:
|
||||||
|
|
||||||
1│ Num.add . 23
|
1│ Num.add . 23
|
||||||
^
|
^
|
||||||
|
|
||||||
Something like .name or .height that accesses a value from a record.
|
Something like .name or .height that accesses a value from a record.
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5465,12 +5439,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am trying to parse a private tag here:
|
I am trying to parse a private tag here:
|
||||||
|
|
||||||
1│ Num.add @foo 23
|
1│ Num.add @foo 23
|
||||||
^
|
^
|
||||||
|
|
||||||
But after the `@` symbol I found a lowercase letter. All tag names
|
But after the `@` symbol I found a lowercase letter. All tag names
|
||||||
(global and private) must start with an uppercase letter, like @UUID
|
(global and private) must start with an uppercase letter, like @UUID
|
||||||
or @Secrets.
|
or @Secrets.
|
||||||
|
@ -5490,12 +5464,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am very confused by this field access:
|
I am very confused by this field access:
|
||||||
|
|
||||||
1│ @UUID.bar
|
1│ @UUID.bar
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
It looks like a record field access on a private tag.
|
It looks like a record field access on a private tag.
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5513,12 +5487,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am very confused by this field access
|
I am very confused by this field access
|
||||||
|
|
||||||
1│ .foo.bar
|
1│ .foo.bar
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
It looks like a field access on an accessor. I parse.client.name as
|
It looks like a field access on an accessor. I parse.client.name as
|
||||||
(.client).name. Maybe use an anonymous function like
|
(.client).name. Maybe use an anonymous function like
|
||||||
(\r -> r.client.name) instead?
|
(\r -> r.client.name) instead?
|
||||||
|
@ -5538,12 +5512,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I trying to parse a record field access here:
|
I trying to parse a record field access here:
|
||||||
|
|
||||||
1│ foo.100
|
1│ foo.100
|
||||||
^
|
^
|
||||||
|
|
||||||
So I expect to see a lowercase letter next, like .name or .height.
|
So I expect to see a lowercase letter next, like .name or .height.
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5561,12 +5535,12 @@ mod test_reporting {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
I am trying to parse an identifier here:
|
I am trying to parse an identifier here:
|
||||||
|
|
||||||
1│ \the_answer -> 100
|
1│ \the_answer -> 100
|
||||||
^
|
^
|
||||||
|
|
||||||
Underscores are not allowed in identifiers. Use camelCase instead!
|
Underscores are not allowed in identifiers. Use camelCase instead!
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -5606,4 +5580,126 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn argument_without_space() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
[ "foo", bar("") ]
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_operator() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
main =
|
||||||
|
5 ** 3
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNKNOWN OPERATOR ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
This looks like an operator, but it's not one I recognize!
|
||||||
|
|
||||||
|
1│ main =
|
||||||
|
2│ 5 ** 3
|
||||||
|
^^
|
||||||
|
|
||||||
|
I have no specific suggestion for this operator, see TODO for the full
|
||||||
|
list of operators in Roc.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn double_plus() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
main =
|
||||||
|
[] ++ []
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNKNOWN OPERATOR ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
This looks like an operator, but it's not one I recognize!
|
||||||
|
|
||||||
|
1│ main =
|
||||||
|
2│ [] ++ []
|
||||||
|
^^
|
||||||
|
|
||||||
|
To concatenate two lists or strings, try using List.concat or
|
||||||
|
Str.concat instead.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inline_hastype() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
main =
|
||||||
|
5 : I64
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── UNKNOWN OPERATOR ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
This looks like an operator, but it's not one I recognize!
|
||||||
|
|
||||||
|
1│ main =
|
||||||
|
2│ 5 : I64
|
||||||
|
^
|
||||||
|
|
||||||
|
The has-type operator : can only occur in a definition's type
|
||||||
|
signature, like
|
||||||
|
|
||||||
|
increment : I64 -> I64
|
||||||
|
increment = \x -> x + 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wild_case_arrow() {
|
||||||
|
// this is still bad, but changing the order and progress of other parsers should improve it
|
||||||
|
// down the line
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
main = 5 -> 3
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── MISSING EXPRESSION ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I am partway through parsing a definition, but I got stuck here:
|
||||||
|
|
||||||
|
1│ main = 5 -> 3
|
||||||
|
^
|
||||||
|
|
||||||
|
I was expecting to see an expression like 42 or "hello".
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue