Always combine line,column into Position

This commit is contained in:
Joshua Warner 2021-12-22 20:32:46 -08:00
parent f19220473a
commit 4d7070ce3b
22 changed files with 1181 additions and 1293 deletions

View file

@ -1,17 +1,18 @@
use crate::ast::CommentOrNewline;
use crate::ast::Spaceable;
use crate::parser::{self, and, backtrackable, BadInputError, Col, Parser, Progress::*, Row};
use crate::parser::{self, and, backtrackable, BadInputError, Parser, Progress::*};
use crate::state::State;
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
use roc_region::all::Loc;
use roc_region::all::Position;
pub fn space0_around_ee<'a, P, S, E>(
parser: P,
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
indent_before_problem: fn(Row, Col) -> E,
indent_after_problem: fn(Row, Col) -> E,
space_problem: fn(BadInputError, Position) -> E,
indent_before_problem: fn(Position) -> E,
indent_after_problem: fn(Position) -> E,
) -> impl Parser<'a, Loc<S>, E>
where
S: Spaceable<'a>,
@ -35,9 +36,9 @@ where
pub fn space0_before_optional_after<'a, P, S, E>(
parser: P,
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
indent_before_problem: fn(Row, Col) -> E,
indent_after_problem: fn(Row, Col) -> E,
space_problem: fn(BadInputError, Position) -> E,
indent_before_problem: fn(Position) -> E,
indent_after_problem: fn(Position) -> E,
) -> impl Parser<'a, Loc<S>, E>
where
S: Spaceable<'a>,
@ -100,8 +101,8 @@ where
pub fn space0_before_e<'a, P, S, E>(
parser: P,
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
indent_problem: fn(Row, Col) -> E,
space_problem: fn(BadInputError, Position) -> E,
indent_problem: fn(Position) -> E,
) -> impl Parser<'a, Loc<S>, E>
where
S: Spaceable<'a>,
@ -127,8 +128,8 @@ where
pub fn space0_after_e<'a, P, S, E>(
parser: P,
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
indent_problem: fn(Row, Col) -> E,
space_problem: fn(BadInputError, Position) -> E,
indent_problem: fn(Position) -> E,
) -> impl Parser<'a, Loc<S>, E>
where
S: Spaceable<'a>,
@ -153,24 +154,24 @@ where
pub fn check_indent<'a, E>(
min_indent: u16,
indent_problem: fn(Row, Col) -> E,
indent_problem: fn(Position) -> E,
) -> impl Parser<'a, (), E>
where
E: 'a,
{
move |_, state: State<'a>| {
if state.column >= min_indent {
if state.pos.column >= min_indent {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, indent_problem(state.line, state.column), state))
Err((NoProgress, indent_problem(state.pos), state))
}
}
}
pub fn space0_e<'a, E>(
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
indent_problem: fn(Row, Col) -> E,
space_problem: fn(BadInputError, Position) -> E,
indent_problem: fn(Position) -> E,
) -> impl Parser<'a, &'a [CommentOrNewline<'a>], E>
where
E: 'a,
@ -181,8 +182,8 @@ where
#[inline(always)]
fn spaces_help_help<'a, E>(
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
indent_problem: fn(Row, Col) -> E,
space_problem: fn(BadInputError, Position) -> E,
indent_problem: fn(Position) -> E,
) -> impl Parser<'a, &'a [CommentOrNewline<'a>], E>
where
E: 'a,
@ -194,53 +195,49 @@ where
match eat_spaces(
state.bytes(),
state.line,
state.column,
state.pos,
comments_and_newlines,
) {
HasTab { row, col } => {
HasTab(pos) => {
// there was a tab character
let mut state = state;
state.line = row;
state.column = col;
state.pos = pos;
// TODO: it _seems_ like if we're changing the line/column, we should also be
// advancing the state by the corresponding number of bytes.
// Not doing this is likely a bug!
// state = state.advance(<something>);
Err((
MadeProgress,
space_problem(BadInputError::HasTab, row, col),
space_problem(BadInputError::HasTab, pos),
state,
))
}
Good {
row,
col,
pos,
bytes,
comments_and_newlines,
} => {
if bytes == state.bytes() {
Ok((NoProgress, &[] as &[_], state))
} else if state.line != row {
} else if state.pos.line != pos.line {
// we parsed at least one newline
state.indent_col = col;
state.indent_col = pos.column;
if col >= min_indent {
state.line = row;
state.column = col;
if pos.column >= min_indent {
state.pos = pos;
state = state.advance(state.bytes().len() - bytes.len());
Ok((MadeProgress, comments_and_newlines.into_bump_slice(), state))
} else {
Err((
MadeProgress,
indent_problem(state.line, state.column),
indent_problem(state.pos),
state,
))
}
} else {
state.column = col;
state.pos.column = pos.column;
state = state.advance(state.bytes().len() - bytes.len());
Ok((MadeProgress, comments_and_newlines.into_bump_slice(), state))
@ -252,21 +249,16 @@ where
enum SpaceState<'a> {
Good {
row: Row,
col: Col,
pos: Position,
bytes: &'a [u8],
comments_and_newlines: Vec<'a, CommentOrNewline<'a>>,
},
HasTab {
row: Row,
col: Col,
},
HasTab(Position),
}
fn eat_spaces<'a>(
mut bytes: &'a [u8],
mut row: Row,
mut col: Col,
mut pos: Position,
mut comments_and_newlines: Vec<'a, CommentOrNewline<'a>>,
) -> SpaceState<'a> {
use SpaceState::*;
@ -275,30 +267,30 @@ fn eat_spaces<'a>(
match c {
b' ' => {
bytes = &bytes[1..];
col += 1;
pos.column += 1;
}
b'\n' => {
bytes = &bytes[1..];
row += 1;
col = 0;
pos.line += 1;
pos.column = 0;
comments_and_newlines.push(CommentOrNewline::Newline);
}
b'\r' => {
bytes = &bytes[1..];
}
b'\t' => {
return HasTab { row, col };
return HasTab(pos);
}
b'#' => {
return eat_line_comment(&bytes[1..], row, col + 1, comments_and_newlines);
pos.column += 1;
return eat_line_comment(&bytes[1..], pos, comments_and_newlines);
}
_ => break,
}
}
Good {
row,
col,
pos,
bytes,
comments_and_newlines,
}
@ -306,8 +298,7 @@ fn eat_spaces<'a>(
fn eat_line_comment<'a>(
mut bytes: &'a [u8],
row: Row,
mut col: Col,
mut pos: Position,
mut comments_and_newlines: Vec<'a, CommentOrNewline<'a>>,
) -> SpaceState<'a> {
use SpaceState::*;
@ -316,7 +307,7 @@ fn eat_line_comment<'a>(
match bytes.get(1) {
Some(b' ') => {
bytes = &bytes[2..];
col += 2;
pos.column += 2;
true
}
@ -325,16 +316,17 @@ fn eat_line_comment<'a>(
bytes = &bytes[2..];
comments_and_newlines.push(CommentOrNewline::DocComment(""));
return eat_spaces(bytes, row + 1, 0, comments_and_newlines);
pos.line += 1;
pos.column = 0;
return eat_spaces(bytes, pos, comments_and_newlines);
}
None => {
// consume the second #
col += 1;
pos.column += 1;
bytes = &bytes[1..];
return Good {
row,
col,
pos,
bytes,
comments_and_newlines,
};
@ -347,13 +339,13 @@ fn eat_line_comment<'a>(
};
let initial = bytes;
let initial_col = col;
let initial_column = pos.column;
for c in bytes {
match c {
b'\t' => return HasTab { row, col },
b'\t' => return HasTab(pos),
b'\n' => {
let delta = (col - initial_col) as usize;
let delta = (pos.column - initial_column) as usize;
let comment = unsafe { std::str::from_utf8_unchecked(&initial[..delta]) };
if is_doc_comment {
@ -361,17 +353,19 @@ fn eat_line_comment<'a>(
} else {
comments_and_newlines.push(CommentOrNewline::LineComment(comment));
}
return eat_spaces(&bytes[1..], row + 1, 0, comments_and_newlines);
pos.line += 1;
pos.column = 0;
return eat_spaces(&bytes[1..], pos, comments_and_newlines);
}
_ => {
bytes = &bytes[1..];
col += 1;
pos.column += 1;
}
}
}
// We made it to the end of the bytes. This means there's a comment without a trailing newline.
let delta = (col - initial_col) as usize;
let delta = (pos.column - initial_column) as usize;
let comment = unsafe { std::str::from_utf8_unchecked(&initial[..delta]) };
if is_doc_comment {
@ -381,8 +375,7 @@ fn eat_line_comment<'a>(
}
Good {
row,
col,
pos,
bytes,
comments_and_newlines,
}

View file

@ -27,7 +27,7 @@ fn expr_end<'a>() -> impl Parser<'a, (), EExpr<'a>> {
} else {
Err((
NoProgress,
EExpr::BadExprEnd(state.line, state.column),
EExpr::BadExprEnd(state.pos),
state,
))
}
@ -184,7 +184,7 @@ fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, &'a str>, EExpr<'a
}
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _, state)) => {
Err((NoProgress, EExpr::Access(state.line, state.column), state))
Err((NoProgress, EExpr::Access(state.pos), state))
}
}
}
@ -192,7 +192,7 @@ fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, &'a str>, EExpr<'a
fn record_field_access<'a>() -> impl Parser<'a, &'a str, EExpr<'a>> {
skip_first!(
word1(b'.', EExpr::Access),
specialize(|_, r, c| EExpr::Access(r, c), lowercase_ident())
specialize(|_, pos| EExpr::Access(pos), lowercase_ident())
)
}
@ -243,13 +243,12 @@ fn parse_loc_term<'a>(
fn underscore_expression<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
move |arena: &'a Bump, state: State<'a>| {
let row = state.line;
let col = state.column;
let start = state.pos;
let (_, _, next_state) = word1(b'_', EExpr::Underscore).parse(arena, state)?;
let lowercase_ident_expr =
{ specialize(move |_, _, _| EExpr::End(row, col), lowercase_ident()) };
{ specialize(move |_, _| EExpr::End(start), lowercase_ident()) };
let (_, output, final_state) = optional(lowercase_ident_expr).parse(arena, next_state)?;
@ -295,7 +294,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
}
fn fail_expr_start_e<'a, T: 'a>() -> impl Parser<'a, T, EExpr<'a>> {
|_arena, state: State<'a>| Err((NoProgress, EExpr::Start(state.line, state.column), state))
|_arena, state: State<'a>| Err((NoProgress, EExpr::Start(state.pos), state))
}
fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> {
@ -313,11 +312,11 @@ fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> {
if state.bytes().starts_with(b"-") && !followed_by_whitespace {
// the negate is only unary if it is not followed by whitespace
let mut state = state.advance(1);
state.column += 1;
state.pos.column += 1;
Ok((MadeProgress, (), state))
} else {
// this is not a negated expression
Err((NoProgress, EExpr::UnaryNot(state.line, state.column), state))
Err((NoProgress, EExpr::UnaryNot(state.pos), state))
}
}
}
@ -412,7 +411,7 @@ impl<'a> ExprState<'a> {
argument_error: F,
) -> Result<Loc<Expr<'a>>, EExpr<'a>>
where
F: Fn(Region, Row, Col) -> EExpr<'a>,
F: Fn(Region, Position) -> EExpr<'a>,
{
if !self.operators.is_empty() {
// this `=` or `<-` likely occurred inline; treat it as an invalid operator
@ -423,7 +422,7 @@ impl<'a> ExprState<'a> {
};
let fail =
EExpr::BadOperator(opchar, loc_op.region.start_line, loc_op.region.start_col);
EExpr::BadOperator(opchar, loc_op.region.start());
Err(fail)
} else if !self.arguments.is_empty() {
@ -431,8 +430,7 @@ impl<'a> ExprState<'a> {
Err(argument_error(
region,
loc_op.region.start_line,
loc_op.region.start_col,
loc_op.region.start(),
))
} else {
self.consume_spaces(arena);
@ -449,7 +447,7 @@ impl<'a> ExprState<'a> {
if !self.operators.is_empty() {
// this `:` likely occurred inline; treat it as an invalid operator
let fail = EExpr::BadOperator(":", loc_op.region.start_line, loc_op.region.start_col);
let fail = EExpr::BadOperator(":", loc_op.region.start());
Err(fail)
} else {
@ -532,8 +530,10 @@ fn numeric_negate_expression<'a, T>(
) -> Loc<Expr<'a>> {
debug_assert_eq!(state.bytes().get(0), Some(&b'-'));
// for overflow reasons, we must make the unary minus part of the number literal.
let mut region = expr.region;
region.start_col -= 1;
let start = expr.region.start();
let region = Region::new(
Position { column: start.column - 1, ..start},
expr.region.end());
let new_expr = match &expr.value {
Expr::Num(string) => {
@ -789,14 +789,14 @@ fn parse_defs_end<'a>(
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, DefState<'a>, EExpr<'a>> {
let min_indent = start.col;
let min_indent = start.column;
let initial = state.clone();
let state = match space0_e(min_indent, EExpr::Space, EExpr::IndentStart).parse(arena, state) {
Err((MadeProgress, _, s)) => {
return Err((
MadeProgress,
EExpr::DefMissingFinalExpr(s.line, s.column),
EExpr::DefMissingFinalExpr(s.pos),
s,
));
}
@ -907,7 +907,7 @@ fn parse_defs_expr<'a>(
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
let min_indent = start.col;
let min_indent = start.column;
match parse_defs_end(options, start, def_state, arena, state) {
Err(bad) => Err(bad),
@ -924,7 +924,7 @@ fn parse_defs_expr<'a>(
Err((_, fail, state)) => {
return Err((
MadeProgress,
EExpr::DefMissingFinalExpr2(arena.alloc(fail), state.line, state.column),
EExpr::DefMissingFinalExpr2(arena.alloc(fail), state.pos),
state,
));
}
@ -989,7 +989,7 @@ fn parse_expr_operator<'a>(
}
BinOp::Assignment => {
let expr_region = expr_state.expr.region;
let indented_more = start.col + 1;
let indented_more = start.column + 1;
let call = expr_state
.validate_assignment_or_backpassing(arena, loc_op, EExpr::ElmStyleFunction)
@ -1020,8 +1020,7 @@ fn parse_expr_operator<'a>(
// this `=` likely occurred inline; treat it as an invalid operator
let fail = EExpr::BadOperator(
arena.alloc("="),
loc_op.region.start_line,
loc_op.region.start_col,
loc_op.region.start(),
);
return Err((MadeProgress, fail, state));
@ -1038,11 +1037,11 @@ fn parse_expr_operator<'a>(
}
BinOp::Backpassing => {
let expr_region = expr_state.expr.region;
let indented_more = start.col + 1;
let indented_more = start.column + 1;
let call = expr_state
.validate_assignment_or_backpassing(arena, loc_op, |_, r, c| {
EExpr::BadOperator("<-", r, c)
.validate_assignment_or_backpassing(arena, loc_op, |_, pos| {
EExpr::BadOperator("<-", pos)
})
.map_err(|fail| (MadeProgress, fail, state.clone()))?;
@ -1064,8 +1063,7 @@ fn parse_expr_operator<'a>(
// this `=` likely occurred inline; treat it as an invalid operator
let fail = EExpr::BadOperator(
"=",
loc_op.region.start_line,
loc_op.region.start_col,
loc_op.region.start()
);
return Err((MadeProgress, fail, state));
@ -1092,7 +1090,7 @@ fn parse_expr_operator<'a>(
}
BinOp::HasType => {
let expr_region = expr_state.expr.region;
let indented_more = start.col + 1;
let indented_more = start.column + 1;
let (expr, arguments) = expr_state
.validate_has_type(arena, loc_op)
@ -1173,8 +1171,7 @@ fn parse_expr_operator<'a>(
// this `:` likely occurred inline; treat it as an invalid operator
let fail = EExpr::BadOperator(
":",
loc_op.region.start_line,
loc_op.region.start_col,
loc_op.region.start(),
);
return Err((MadeProgress, fail, state));
@ -1300,7 +1297,7 @@ fn parse_expr_end<'a>(
// try multi-backpassing
if options.accept_multi_backpassing && state.bytes().starts_with(b",") {
state = state.advance(1);
state.column += 1;
state.pos.column += 1;
let (_, mut patterns, state) = specialize_ref(
EExpr::Pattern,
@ -1330,7 +1327,7 @@ fn parse_expr_end<'a>(
match word2(b'<', b'-', EExpr::BackpassArrow).parse(arena, state) {
Err((_, fail, state)) => Err((MadeProgress, fail, state)),
Ok((_, _, state)) => {
let min_indent = start.col;
let min_indent = start.column;
let parse_body = space0_before_e(
move |a, s| parse_loc_expr(min_indent + 1, a, s),
@ -1362,7 +1359,7 @@ fn parse_expr_end<'a>(
} else if options.check_for_arrow && state.bytes().starts_with(b"->") {
Err((
MadeProgress,
EExpr::BadOperator("->", state.line, state.column),
EExpr::BadOperator("->", state.pos),
state,
))
} else {
@ -1573,7 +1570,7 @@ pub fn defs<'a>(min_indent: u16) -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, EExpr
let (_, def_state, state) = parse_defs_end(options, start, def_state, arena, state)?;
let (_, final_space, state) =
space0_e(start.col, EExpr::Space, EExpr::IndentEnd).parse(arena, state)?;
space0_e(start.column, EExpr::Space, EExpr::IndentEnd).parse(arena, state)?;
let mut output = Vec::with_capacity_in(def_state.defs.len(), arena);
@ -1684,7 +1681,7 @@ mod when {
return Err((
progress,
// TODO maybe pass case_indent here?
EWhen::PatternAlignment(5, state.line, state.column),
EWhen::PatternAlignment(5, state.pos),
state,
));
}
@ -1724,7 +1721,7 @@ 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 (_, ((pattern_indent_level, loc_first_patterns), loc_first_guard), mut state) =
let (_, ((pattern_indent_level, loc_first_patterns), loc_first_guard), mut state): (_, ((_, _), _), State<'a>) =
branch_alternatives(min_indent, options, None).parse(arena, state)?;
let original_indent = pattern_indent_level;
@ -1752,7 +1749,7 @@ mod when {
let indent = pattern_indent_level - indent_col;
Err((
MadeProgress,
EWhen::PatternAlignment(indent, state.line, state.column),
EWhen::PatternAlignment(indent, state.pos),
state,
))
}
@ -1803,7 +1800,7 @@ mod when {
) -> impl Parser<
'a,
(
(Col, Vec<'a, Loc<Pattern<'a>>>),
(u16, Vec<'a, Loc<Pattern<'a>>>),
Option<Loc<Expr<'a>>>,
),
EWhen<'a>,
@ -1869,7 +1866,7 @@ mod when {
fn branch_alternatives_help<'a>(
min_indent: u16,
pattern_indent_level: Option<u16>,
) -> impl Parser<'a, (Col, Vec<'a, Loc<Pattern<'a>>>), EWhen<'a>> {
) -> impl Parser<'a, (u16, Vec<'a, Loc<Pattern<'a>>>), EWhen<'a>> {
move |arena, state: State<'a>| {
let initial = state.clone();
@ -1879,19 +1876,19 @@ mod when {
Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)),
Ok((_progress, spaces, state)) => {
match pattern_indent_level {
Some(wanted) if state.column > wanted => {
Some(wanted) if state.pos.column > wanted => {
// this branch is indented too much
Err((
NoProgress,
EWhen::IndentPattern(state.line, state.column),
EWhen::IndentPattern(state.pos),
initial,
))
}
Some(wanted) if state.column < wanted => {
let indent = wanted - state.column;
Some(wanted) if state.pos.column < wanted => {
let indent = wanted - state.pos.column;
Err((
NoProgress,
EWhen::PatternAlignment(indent, state.line, state.column),
EWhen::PatternAlignment(indent, state.pos),
initial,
))
}
@ -1900,7 +1897,7 @@ mod when {
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 pattern_indent_col = state.pos.column;
let parser = sep_by1(
word1(b'|', EWhen::Bar),
@ -2005,9 +2002,9 @@ fn expect_help<'a>(
let (_, condition, state) = space0_before_e(
specialize_ref(EExpect::Condition, move |arena, state| {
parse_loc_expr_with_options(start.col + 1, options, arena, state)
parse_loc_expr_with_options(start.column + 1, options, arena, state)
}),
start.col + 1,
start.column + 1,
EExpect::Space,
EExpect::IndentCondition,
)
@ -2187,7 +2184,7 @@ fn record_field_help<'a>(
move |arena, state: State<'a>| {
// You must have a field name, e.g. "email"
let (progress, loc_label, state) =
specialize(|_, r, c| ERecord::Field(r, c), loc!(lowercase_ident()))
specialize(|_, pos| ERecord::Field(pos), loc!(lowercase_ident()))
.parse(arena, state)?;
debug_assert_eq!(progress, MadeProgress);
@ -2238,7 +2235,7 @@ fn record_field_help<'a>(
fn record_updateable_identifier<'a>() -> impl Parser<'a, Expr<'a>, ERecord<'a>> {
specialize(
|_, r, c| ERecord::Updateable(r, c),
|_, pos| ERecord::Updateable(pos),
map_with_arena!(parse_ident, ident_to_expr),
)
}
@ -2390,8 +2387,6 @@ fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
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)
}
@ -2403,15 +2398,15 @@ fn operator_help<'a, F, G, E>(
mut state: State<'a>,
) -> ParseResult<'a, BinOp, E>
where
F: Fn(Row, Col) -> E,
G: Fn(&'a str, Row, Col) -> E,
F: Fn(Position) -> E,
G: Fn(&'a str, Position) -> E,
E: 'a,
{
let chomped = chomp_ops(state.bytes());
macro_rules! good {
($op:expr, $width:expr) => {{
state.column += $width;
state.pos.column += $width;
state = state.advance($width);
Ok((MadeProgress, $op, state))
@ -2420,12 +2415,12 @@ where
macro_rules! bad_made_progress {
($op:expr) => {{
Err((MadeProgress, to_error($op, state.line, state.column), state))
Err((MadeProgress, to_error($op, state.pos), state))
}};
}
match chomped {
"" => Err((NoProgress, to_expectation(state.line, state.column), state)),
"" => Err((NoProgress, to_expectation(state.pos), state)),
"+" => good!(BinOp::Plus, 1),
"-" => good!(BinOp::Minus, 1),
"*" => good!(BinOp::Star, 1),
@ -2436,7 +2431,7 @@ where
"<" => good!(BinOp::LessThan, 1),
"." => {
// a `.` makes no progress, so it does not interfere with `.foo` access(or)
Err((NoProgress, to_error(".", state.line, state.column), state))
Err((NoProgress, to_error(".", state.pos), state))
}
"=" => good!(BinOp::Assignment, 1),
":" => good!(BinOp::HasType, 1),
@ -2451,7 +2446,7 @@ where
"%%" => good!(BinOp::DoublePercent, 2),
"->" => {
// makes no progress, so it does not interfere with `_ if isGood -> ...`
Err((NoProgress, to_error("->", state.line, state.column), state))
Err((NoProgress, to_error("->", state.pos), state))
}
"<-" => good!(BinOp::Backpassing, 2),
_ => bad_made_progress!(chomped),

View file

@ -226,7 +226,7 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac
let (_, opt_shorthand, state) = maybe!(and!(
skip_second!(
specialize(|_, r, c| EPackageEntry::Shorthand(r, c), lowercase_ident()),
specialize(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()),
word1(b':', EPackageEntry::Colon)
),
space0_e(
@ -291,7 +291,7 @@ where
if chomped == 0 {
Ok((NoProgress, (), state))
} else {
state.column += chomped as u16;
state.pos.column += chomped as u16;
state = state.advance(chomped);
Ok((MadeProgress, (), state))
@ -318,7 +318,7 @@ pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName> {
|_, mut state: State<'a>| match chomp_package_part(state.bytes()) {
Err(progress) => Err((
progress,
EPackageName::Account(state.line, state.column),
EPackageName::Account(state.pos),
state,
)),
Ok(account) => {
@ -328,13 +328,13 @@ pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName> {
match chomp_package_part(&state.bytes()[chomped..]) {
Err(progress) => Err((
progress,
EPackageName::Pkg(state.line, state.column + chomped as u16),
EPackageName::Pkg(state.pos.bump_column(chomped as u16)),
state,
)),
Ok(pkg) => {
chomped += pkg.len();
state.column += chomped as u16;
state.pos.column += chomped as u16;
state = state.advance(chomped);
let value = PackageName { account, pkg };
@ -344,7 +344,7 @@ pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName> {
} else {
Err((
MadeProgress,
EPackageName::MissingSlash(state.line, state.column + chomped as u16),
EPackageName::MissingSlash(state.pos.bump_column(chomped as u16)),
state,
))
}

View file

@ -1,8 +1,9 @@
use crate::parser::Progress::{self, *};
use crate::parser::{BadInputError, Col, EExpr, ParseResult, Parser, Row};
use crate::parser::{BadInputError, EExpr, ParseResult, Parser};
use crate::state::State;
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
use roc_region::all::Position;
/// The parser accepts all of these in any position where any one of them could
/// appear. This way, canonicalization can give more helpful error messages like
@ -67,7 +68,7 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
Err((NoProgress, (), state))
} else {
let width = ident.len();
match state.advance_without_indenting_ee(width, |_, _| ()) {
match state.advance_without_indenting_ee(width, |_| ()) {
Ok(state) => Ok((MadeProgress, ident, state)),
Err(bad) => Err(bad),
}
@ -79,12 +80,12 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
pub fn tag_name<'a>() -> impl Parser<'a, &'a str, ()> {
move |arena, state: State<'a>| {
if state.bytes().starts_with(b"@") {
match chomp_private_tag(state.bytes(), state.line, state.column) {
Err(BadIdent::Start(_, _)) => Err((NoProgress, (), state)),
match chomp_private_tag(state.bytes(), state.pos) {
Err(BadIdent::Start(_)) => Err((NoProgress, (), state)),
Err(_) => Err((MadeProgress, (), state)),
Ok(ident) => {
let width = ident.len();
match state.advance_without_indenting_ee(width, |_, _| ()) {
match state.advance_without_indenting_ee(width, |_| ()) {
Ok(state) => Ok((MadeProgress, ident, state)),
Err(bad) => Err(bad),
}
@ -106,7 +107,7 @@ pub fn uppercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
Err(progress) => Err((progress, (), state)),
Ok(ident) => {
let width = ident.len();
match state.advance_without_indenting_ee(width, |_, _| ()) {
match state.advance_without_indenting_ee(width, |_| ()) {
Ok(state) => Ok((MadeProgress, ident, state)),
Err(bad) => Err(bad),
}
@ -122,7 +123,7 @@ pub fn unqualified_ident<'a>() -> impl Parser<'a, &'a str, ()> {
Err((MadeProgress, (), state))
} else {
let width = ident.len();
match state.advance_without_indenting_ee(width, |_, _| ()) {
match state.advance_without_indenting_ee(width, |_| ()) {
Ok(state) => Ok((MadeProgress, ident, state)),
Err(bad) => Err(bad),
}
@ -133,8 +134,8 @@ pub fn unqualified_ident<'a>() -> impl Parser<'a, &'a str, ()> {
macro_rules! advance_state {
($state:expr, $n:expr) => {
$state.advance_without_indenting_ee($n, |r, c| {
BadIdent::Space(crate::parser::BadInputError::LineTooLong, r, c)
$state.advance_without_indenting_ee($n, |pos| {
BadIdent::Space(crate::parser::BadInputError::LineTooLong, pos)
})
};
}
@ -151,7 +152,7 @@ pub fn parse_ident<'a>(arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Ide
if first == keyword {
return Err((
NoProgress,
EExpr::Start(initial.line, initial.column),
EExpr::Start(initial.pos),
initial,
));
}
@ -163,11 +164,11 @@ pub fn parse_ident<'a>(arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Ide
Ok((progress, ident, state))
}
Err((NoProgress, _, state)) => {
Err((NoProgress, EExpr::Start(state.line, state.column), state))
Err((NoProgress, EExpr::Start(state.pos), state))
}
Err((MadeProgress, fail, state)) => match fail {
BadIdent::Start(r, c) => Err((NoProgress, EExpr::Start(r, c), state)),
BadIdent::Space(e, r, c) => Err((NoProgress, EExpr::Space(e, r, c), state)),
BadIdent::Start(pos) => Err((NoProgress, EExpr::Start(pos), state)),
BadIdent::Space(e, pos) => Err((NoProgress, EExpr::Space(e, pos), state)),
_ => malformed_identifier(initial.bytes(), fail, state),
},
}
@ -182,8 +183,8 @@ fn malformed_identifier<'a>(
let delta = initial_bytes.len() - state.bytes().len();
let parsed_str = unsafe { std::str::from_utf8_unchecked(&initial_bytes[..chomped + delta]) };
state = state.advance_without_indenting_ee(chomped, |r, c| {
EExpr::Space(crate::parser::BadInputError::LineTooLong, r, c)
state = state.advance_without_indenting_ee(chomped, |pos| {
EExpr::Space(crate::parser::BadInputError::LineTooLong, pos)
})?;
Ok((MadeProgress, Ident::Malformed(parsed_str, problem), state))
@ -209,16 +210,16 @@ pub fn chomp_malformed(bytes: &[u8]) -> usize {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BadIdent {
Start(Row, Col),
Space(BadInputError, Row, Col),
Start(Position),
Space(BadInputError, Position),
Underscore(Row, Col),
QualifiedTag(Row, Col),
WeirdAccessor(Row, Col),
WeirdDotAccess(Row, Col),
WeirdDotQualified(Row, Col),
StrayDot(Row, Col),
BadPrivateTag(Row, Col),
Underscore(Position),
QualifiedTag(Position),
WeirdAccessor(Position),
WeirdDotAccess(Position),
WeirdDotQualified(Position),
StrayDot(Position),
BadPrivateTag(Position),
}
fn chomp_lowercase_part(buffer: &[u8]) -> Result<&str, Progress> {
@ -265,7 +266,7 @@ where
}
/// a `.foo` accessor function
fn chomp_accessor(buffer: &[u8], row: Row, col: Col) -> Result<&str, BadIdent> {
fn chomp_accessor(buffer: &[u8], pos: Position) -> Result<&str, BadIdent> {
// assumes the leading `.` has been chomped already
use encode_unicode::CharExt;
@ -274,20 +275,20 @@ fn chomp_accessor(buffer: &[u8], row: Row, col: Col) -> Result<&str, BadIdent> {
let chomped = name.len();
if let Ok(('.', _)) = char::from_utf8_slice_start(&buffer[chomped..]) {
Err(BadIdent::WeirdAccessor(row, col))
Err(BadIdent::WeirdAccessor(pos))
} else {
Ok(name)
}
}
Err(_) => {
// we've already made progress with the initial `.`
Err(BadIdent::StrayDot(row, col + 1))
Err(BadIdent::StrayDot(Position { line: pos.line, column: pos.column + 1 }))
}
}
}
/// a `@Token` private tag
fn chomp_private_tag(buffer: &[u8], row: Row, col: Col) -> Result<&str, BadIdent> {
fn chomp_private_tag(buffer: &[u8], pos: Position) -> Result<&str, BadIdent> {
// assumes the leading `@` has NOT been chomped already
debug_assert_eq!(buffer.get(0), Some(&b'@'));
use encode_unicode::CharExt;
@ -297,21 +298,20 @@ fn chomp_private_tag(buffer: &[u8], row: Row, col: Col) -> Result<&str, BadIdent
let width = 1 + name.len();
if let Ok(('.', _)) = char::from_utf8_slice_start(&buffer[width..]) {
Err(BadIdent::BadPrivateTag(row, col + width as u16))
Err(BadIdent::BadPrivateTag(pos.bump_column(width as u16)))
} else {
let value = unsafe { std::str::from_utf8_unchecked(&buffer[..width]) };
Ok(value)
}
}
Err(_) => Err(BadIdent::BadPrivateTag(row, col + 1)),
Err(_) => Err(BadIdent::BadPrivateTag(Position { line: pos.line, column: pos.column + 1})),
}
}
fn chomp_identifier_chain<'a>(
arena: &'a Bump,
buffer: &'a [u8],
row: Row,
col: Col,
pos: Position,
) -> Result<(u16, Ident<'a>), (u16, BadIdent)> {
use encode_unicode::CharExt;
@ -320,7 +320,7 @@ fn chomp_identifier_chain<'a>(
match char::from_utf8_slice_start(&buffer[chomped..]) {
Ok((ch, width)) => match ch {
'.' => match chomp_accessor(&buffer[1..], row, col) {
'.' => match chomp_accessor(&buffer[1..], pos) {
Ok(accessor) => {
let bytes_parsed = 1 + accessor.len();
@ -328,7 +328,7 @@ fn chomp_identifier_chain<'a>(
}
Err(fail) => return Err((1, fail)),
},
'@' => match chomp_private_tag(buffer, row, col) {
'@' => match chomp_private_tag(buffer, pos) {
Ok(tagname) => {
let bytes_parsed = tagname.len();
@ -342,10 +342,10 @@ fn chomp_identifier_chain<'a>(
first_is_uppercase = c.is_uppercase();
}
_ => {
return Err((0, BadIdent::Start(row, col)));
return Err((0, BadIdent::Start(pos)));
}
},
Err(_) => return Err((0, BadIdent::Start(row, col))),
Err(_) => return Err((0, BadIdent::Start(pos))),
}
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
@ -391,15 +391,15 @@ fn chomp_identifier_chain<'a>(
}
Err(0) if !module_name.is_empty() => Err((
chomped as u16,
BadIdent::QualifiedTag(row, chomped as u16 + col),
BadIdent::QualifiedTag(pos.bump_column(chomped as u16)),
)),
Err(1) if parts.is_empty() => Err((
chomped as u16 + 1,
BadIdent::WeirdDotQualified(row, chomped as u16 + col + 1),
BadIdent::WeirdDotQualified(pos.bump_column(chomped as u16 + 1)),
)),
Err(width) => Err((
chomped as u16 + width,
BadIdent::WeirdDotAccess(row, chomped as u16 + col + width),
BadIdent::WeirdDotAccess(pos.bump_column(chomped as u16 + width)),
)),
}
} else if let Ok(('_', _)) = char::from_utf8_slice_start(&buffer[chomped..]) {
@ -408,7 +408,7 @@ fn chomp_identifier_chain<'a>(
// to give good error messages for this case
Err((
chomped as u16 + 1,
BadIdent::Underscore(row, col + chomped as u16 + 1),
BadIdent::Underscore(pos.bump_column(chomped as u16 + 1)),
))
} else if first_is_uppercase {
// just one segment, starting with an uppercase letter; that's a global tag
@ -452,7 +452,7 @@ pub fn concrete_type<'a>() -> impl Parser<'a, (&'a str, &'a str), ()> {
move |_, state: State<'a>| match chomp_concrete_type(state.bytes()) {
Err(progress) => Err((progress, (), state)),
Ok((module_name, type_name, width)) => {
match state.advance_without_indenting_ee(width, |_, _| ()) {
match state.advance_without_indenting_ee(width, |_| ()) {
Ok(state) => Ok((MadeProgress, (module_name, type_name), state)),
Err(bad) => Err(bad),
}
@ -528,7 +528,7 @@ fn parse_ident_help<'a>(
arena: &'a Bump,
mut state: State<'a>,
) -> ParseResult<'a, Ident<'a>, BadIdent> {
match chomp_identifier_chain(arena, state.bytes(), state.line, state.column) {
match chomp_identifier_chain(arena, state.bytes(), state.pos) {
Ok((width, ident)) => {
state = advance_state!(state, width as usize)?;
Ok((MadeProgress, ident, state))

View file

@ -8,14 +8,14 @@ use crate::header::{
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
use crate::parser::Progress::{self, *};
use crate::parser::{
backtrackable, specialize, word1, word2, Col, EEffects, EExposes, EHeader, EImports, EPackages,
EProvides, ERequires, ETypedIdent, Parser, Row, SyntaxError,
backtrackable, specialize, word1, word2, EEffects, EExposes, EHeader, EImports, EPackages,
EProvides, ERequires, ETypedIdent, Parser, SyntaxError,
};
use crate::state::State;
use crate::string_literal;
use crate::type_annotation;
use bumpalo::collections::Vec;
use roc_region::all::Loc;
use roc_region::all::{Loc, Position};
fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|_arena, state: State<'a>| {
@ -24,7 +24,7 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
} else {
Err((
NoProgress,
SyntaxError::NotEndOfFile(state.line, state.column),
SyntaxError::NotEndOfFile(state.pos),
state,
))
}
@ -37,7 +37,7 @@ pub fn module_defs<'a>() -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, SyntaxError<'
let min_indent = 0;
skip_second!(
specialize(
|e, _, _| SyntaxError::Expr(e),
|e, _| SyntaxError::Expr(e),
crate::expr::defs(min_indent),
),
end_of_file()
@ -175,7 +175,7 @@ fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> {
|_, mut state: State<'a>| match chomp_module_name(state.bytes()) {
Ok(name) => {
let width = name.len();
state.column += width as u16;
state.pos.column += width as u16;
state = state.advance(width);
Ok((MadeProgress, ModuleName::new(name), state))
@ -316,7 +316,7 @@ struct ProvidesTo<'a> {
fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
one_of![
specialize(
|_, r, c| EProvides::Identifier(r, c),
|_, pos| EProvides::Identifier(pos),
map!(lowercase_ident(), To::ExistingPackage)
),
specialize(EProvides::Package, map!(package_or_path(), To::NewPackage))
@ -395,12 +395,12 @@ fn exposes_entry<'a, F, E>(
to_expectation: F,
) -> impl Parser<'a, Loc<Spaced<'a, ExposedName<'a>>>, E>
where
F: Fn(crate::parser::Row, crate::parser::Col) -> E,
F: Fn(Position) -> E,
F: Copy,
E: 'a,
{
loc!(map!(
specialize(|_, r, c| to_expectation(r, c), unqualified_ident()),
specialize(|_, pos| to_expectation(pos), unqualified_ident()),
|n| Spaced::Item(ExposedName::new(n))
))
}
@ -448,7 +448,7 @@ fn requires_rigids<'a>(
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, PlatformRigid<'a>>>>, ERequires<'a>> {
collection_trailing_sep_e!(
word1(b'{', ERequires::ListStart),
specialize(|_, r, c| ERequires::Rigid(r, c), loc!(requires_rigid())),
specialize(|_, pos| ERequires::Rigid(pos), loc!(requires_rigid())),
word1(b',', ERequires::ListEnd),
word1(b'}', ERequires::ListEnd),
min_indent,
@ -464,7 +464,7 @@ fn requires_rigid<'a>() -> impl Parser<'a, Spaced<'a, PlatformRigid<'a>>, ()> {
map!(
and!(
lowercase_ident(),
skip_first!(word2(b'=', b'>', |_, _| ()), uppercase_ident())
skip_first!(word2(b'=', b'>', |_| ()), uppercase_ident())
),
|(rigid, alias)| Spaced::Item(PlatformRigid { rigid, alias })
)
@ -525,10 +525,10 @@ fn exposes_values<'a>() -> impl Parser<
fn spaces_around_keyword<'a, E>(
min_indent: u16,
keyword: &'static str,
expectation: fn(Row, Col) -> E,
space_problem: fn(crate::parser::BadInputError, Row, Col) -> E,
indent_problem1: fn(Row, Col) -> E,
indent_problem2: fn(Row, Col) -> E,
expectation: fn(Position) -> E,
space_problem: fn(crate::parser::BadInputError, Position) -> E,
indent_problem1: fn(Position) -> E,
indent_problem2: fn(Position) -> E,
) -> impl Parser<'a, (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), E>
where
E: 'a,
@ -580,12 +580,12 @@ fn exposes_module<'a, F, E>(
to_expectation: F,
) -> impl Parser<'a, Loc<Spaced<'a, ModuleName<'a>>>, E>
where
F: Fn(crate::parser::Row, crate::parser::Col) -> E,
F: Fn(Position) -> E,
F: Copy,
E: 'a,
{
loc!(map!(
specialize(|_, r, c| to_expectation(r, c), module_name()),
specialize(|_, pos| to_expectation(pos), module_name()),
Spaced::Item
))
}
@ -688,14 +688,14 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
// e.g. `fx.`
let (_, type_shortname, state) = skip_second!(
specialize(|_, r, c| EEffects::Shorthand(r, c), lowercase_ident()),
specialize(|_, pos| EEffects::Shorthand(pos), lowercase_ident()),
word1(b'.', EEffects::ShorthandDot)
)
.parse(arena, state)?;
// the type name, e.g. Effects
let (_, (type_name, spaces_after_type_name), state) = and!(
specialize(|_, r, c| EEffects::TypeName(r, c), uppercase_ident()),
specialize(|_, pos| EEffects::TypeName(pos), uppercase_ident()),
space0_e(min_indent, EEffects::Space, EEffects::IndentListStart)
)
.parse(arena, state)?;
@ -738,7 +738,7 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
and!(
and!(
loc!(specialize(
|_, r, c| ETypedIdent::Identifier(r, c),
|_, pos| ETypedIdent::Identifier(pos),
lowercase_ident()
)),
space0_e(min_indent, ETypedIdent::Space, ETypedIdent::IndentHasType)
@ -767,16 +767,16 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
}
fn shortname<'a>() -> impl Parser<'a, &'a str, EImports> {
specialize(|_, r, c| EImports::Shorthand(r, c), lowercase_ident())
specialize(|_, pos| EImports::Shorthand(pos), lowercase_ident())
}
fn module_name_help<'a, F, E>(to_expectation: F) -> impl Parser<'a, ModuleName<'a>, E>
where
F: Fn(crate::parser::Row, crate::parser::Col) -> E,
F: Fn(Position) -> E,
E: 'a,
F: 'a,
{
specialize(move |_, r, c| to_expectation(r, c), module_name())
specialize(move |_, pos| to_expectation(pos), module_name())
}
#[inline(always)]

View file

@ -67,7 +67,7 @@ fn chomp_number_base<'a>(
let string = unsafe { std::str::from_utf8_unchecked(&bytes[..chomped]) };
let new = state.advance_without_indenting_ee(chomped + 2 + is_negative as usize, |_, _| {
let new = state.advance_without_indenting_ee(chomped + 2 + is_negative as usize, |_| {
ENumber::LineTooLong
})?;
@ -102,7 +102,7 @@ fn chomp_number_dec<'a>(
let string =
unsafe { std::str::from_utf8_unchecked(&state.bytes()[0..chomped + is_negative as usize]) };
let new = state.advance_without_indenting_ee(chomped + is_negative as usize, |_, _| {
let new = state.advance_without_indenting_ee(chomped + is_negative as usize, |_| {
ENumber::LineTooLong
})?;

View file

@ -1,7 +1,7 @@
use crate::state::State;
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
use roc_region::all::{Loc, Region};
use roc_region::all::{Loc, Region, Position};
use Progress::*;
#[derive(Debug, PartialEq, Eq)]
@ -63,151 +63,151 @@ pub enum SyntaxError<'a> {
Expr(EExpr<'a>),
Header(EHeader<'a>),
Space(BadInputError),
NotEndOfFile(Row, Col),
NotEndOfFile(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EHeader<'a> {
Provides(EProvides<'a>, Row, Col),
Exposes(EExposes, Row, Col),
Imports(EImports, Row, Col),
Requires(ERequires<'a>, Row, Col),
Packages(EPackages<'a>, Row, Col),
Effects(EEffects<'a>, Row, Col),
Provides(EProvides<'a>, Position),
Exposes(EExposes, Position),
Imports(EImports, Position),
Requires(ERequires<'a>, Position),
Packages(EPackages<'a>, Position),
Effects(EEffects<'a>, Position),
Space(BadInputError, Row, Col),
Start(Row, Col),
ModuleName(Row, Col),
AppName(EString<'a>, Row, Col),
PlatformName(EPackageName, Row, Col),
IndentStart(Row, Col),
Space(BadInputError, Position),
Start(Position),
ModuleName(Position),
AppName(EString<'a>, Position),
PlatformName(EPackageName, Position),
IndentStart(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EProvides<'a> {
Provides(Row, Col),
Open(Row, Col),
To(Row, Col),
IndentProvides(Row, Col),
IndentTo(Row, Col),
IndentListStart(Row, Col),
IndentListEnd(Row, Col),
IndentPackage(Row, Col),
ListStart(Row, Col),
ListEnd(Row, Col),
Identifier(Row, Col),
Package(EPackageOrPath<'a>, Row, Col),
Space(BadInputError, Row, Col),
Provides(Position),
Open(Position),
To(Position),
IndentProvides(Position),
IndentTo(Position),
IndentListStart(Position),
IndentListEnd(Position),
IndentPackage(Position),
ListStart(Position),
ListEnd(Position),
Identifier(Position),
Package(EPackageOrPath<'a>, Position),
Space(BadInputError, Position),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EExposes {
Exposes(Row, Col),
Open(Row, Col),
IndentExposes(Row, Col),
IndentListStart(Row, Col),
IndentListEnd(Row, Col),
ListStart(Row, Col),
ListEnd(Row, Col),
Identifier(Row, Col),
Space(BadInputError, Row, Col),
Exposes(Position),
Open(Position),
IndentExposes(Position),
IndentListStart(Position),
IndentListEnd(Position),
ListStart(Position),
ListEnd(Position),
Identifier(Position),
Space(BadInputError, Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ERequires<'a> {
Requires(Row, Col),
Open(Row, Col),
IndentRequires(Row, Col),
IndentListStart(Row, Col),
IndentListEnd(Row, Col),
ListStart(Row, Col),
ListEnd(Row, Col),
TypedIdent(ETypedIdent<'a>, Row, Col),
Rigid(Row, Col),
Space(BadInputError, Row, Col),
Requires(Position),
Open(Position),
IndentRequires(Position),
IndentListStart(Position),
IndentListEnd(Position),
ListStart(Position),
ListEnd(Position),
TypedIdent(ETypedIdent<'a>, Position),
Rigid(Position),
Space(BadInputError, Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ETypedIdent<'a> {
Space(BadInputError, Row, Col),
HasType(Row, Col),
IndentHasType(Row, Col),
Name(Row, Col),
Type(EType<'a>, Row, Col),
IndentType(Row, Col),
Identifier(Row, Col),
Space(BadInputError, Position),
HasType(Position),
IndentHasType(Position),
Name(Position),
Type(EType<'a>, Position),
IndentType(Position),
Identifier(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EPackages<'a> {
Open(Row, Col),
Space(BadInputError, Row, Col),
Packages(Row, Col),
IndentPackages(Row, Col),
ListStart(Row, Col),
ListEnd(Row, Col),
IndentListStart(Row, Col),
IndentListEnd(Row, Col),
PackageEntry(EPackageEntry<'a>, Row, Col),
Open(Position),
Space(BadInputError, Position),
Packages(Position),
IndentPackages(Position),
ListStart(Position),
ListEnd(Position),
IndentListStart(Position),
IndentListEnd(Position),
PackageEntry(EPackageEntry<'a>, Position),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EPackageName {
MissingSlash(Row, Col),
Account(Row, Col),
Pkg(Row, Col),
MissingSlash(Position),
Account(Position),
Pkg(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EPackageOrPath<'a> {
BadPath(EString<'a>, Row, Col),
BadPackage(EPackageName, Row, Col),
BadPath(EString<'a>, Position),
BadPackage(EPackageName, Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EPackageEntry<'a> {
BadPackageOrPath(EPackageOrPath<'a>, Row, Col),
Shorthand(Row, Col),
Colon(Row, Col),
IndentPackageOrPath(Row, Col),
Space(BadInputError, Row, Col),
BadPackageOrPath(EPackageOrPath<'a>, Position),
Shorthand(Position),
Colon(Position),
IndentPackageOrPath(Position),
Space(BadInputError, Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EEffects<'a> {
Space(BadInputError, Row, Col),
Effects(Row, Col),
Open(Row, Col),
IndentEffects(Row, Col),
ListStart(Row, Col),
ListEnd(Row, Col),
IndentListStart(Row, Col),
IndentListEnd(Row, Col),
TypedIdent(ETypedIdent<'a>, Row, Col),
ShorthandDot(Row, Col),
Shorthand(Row, Col),
TypeName(Row, Col),
Space(BadInputError, Position),
Effects(Position),
Open(Position),
IndentEffects(Position),
ListStart(Position),
ListEnd(Position),
IndentListStart(Position),
IndentListEnd(Position),
TypedIdent(ETypedIdent<'a>, Position),
ShorthandDot(Position),
Shorthand(Position),
TypeName(Position),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EImports {
Open(Row, Col),
Imports(Row, Col),
IndentImports(Row, Col),
IndentListStart(Row, Col),
IndentListEnd(Row, Col),
ListStart(Row, Col),
ListEnd(Row, Col),
Identifier(Row, Col),
ExposingDot(Row, Col),
ShorthandDot(Row, Col),
Shorthand(Row, Col),
ModuleName(Row, Col),
Space(BadInputError, Row, Col),
IndentSetStart(Row, Col),
IndentSetEnd(Row, Col),
SetStart(Row, Col),
SetEnd(Row, Col),
Open(Position),
Imports(Position),
IndentImports(Position),
IndentListStart(Position),
IndentListEnd(Position),
ListStart(Position),
ListEnd(Position),
Identifier(Position),
ExposingDot(Position),
ShorthandDot(Position),
Shorthand(Position),
ModuleName(Position),
Space(BadInputError, Position),
IndentSetStart(Position),
IndentSetEnd(Position),
SetStart(Position),
SetEnd(Position),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -223,13 +223,12 @@ pub enum BadInputError {
pub fn bad_input_to_syntax_error<'a>(
bad_input: BadInputError,
row: Row,
_col: Col,
pos: Position,
) -> SyntaxError<'a> {
use crate::parser::BadInputError::*;
match bad_input {
HasTab => SyntaxError::NotYetImplemented("call error on tabs".to_string()),
LineTooLong => SyntaxError::LineTooLong(row),
LineTooLong => SyntaxError::LineTooLong(pos.line),
TooManyLines => SyntaxError::TooManyLines,
BadUtf8 => SyntaxError::BadUtf8,
}
@ -243,8 +242,7 @@ impl<'a> SyntaxError<'a> {
bytes: &'a [u8],
) -> ParseProblem<'a, SyntaxError<'a>> {
ParseProblem {
line: 0,
column: 0,
pos: Position::default(),
problem: self,
filename,
bytes,
@ -253,55 +251,52 @@ impl<'a> SyntaxError<'a> {
}
}
pub type Row = u32;
pub type Col = u16;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EExpr<'a> {
Start(Row, Col),
End(Row, Col),
BadExprEnd(Row, Col),
Space(BadInputError, Row, Col),
Start(Position),
End(Position),
BadExprEnd(Position),
Space(BadInputError, Position),
Dot(Row, Col),
Access(Row, Col),
UnaryNot(Row, Col),
UnaryNegate(Row, Col),
BadOperator(&'a str, Row, Col),
Dot(Position),
Access(Position),
UnaryNot(Position),
UnaryNegate(Position),
BadOperator(&'a str, Position),
DefMissingFinalExpr(Row, Col),
DefMissingFinalExpr2(&'a EExpr<'a>, Row, Col),
Type(EType<'a>, Row, Col),
Pattern(&'a EPattern<'a>, Row, Col),
IndentDefBody(Row, Col),
IndentEquals(Row, Col),
IndentAnnotation(Row, Col),
Equals(Row, Col),
Colon(Row, Col),
DoubleColon(Row, Col),
Ident(Row, Col),
ElmStyleFunction(Region, Row, Col),
MalformedPattern(Row, Col),
QualifiedTag(Row, Col),
BackpassComma(Row, Col),
BackpassArrow(Row, Col),
DefMissingFinalExpr(Position),
DefMissingFinalExpr2(&'a EExpr<'a>, Position),
Type(EType<'a>, Position),
Pattern(&'a EPattern<'a>, Position),
IndentDefBody(Position),
IndentEquals(Position),
IndentAnnotation(Position),
Equals(Position),
Colon(Position),
DoubleColon(Position),
Ident(Position),
ElmStyleFunction(Region, Position),
MalformedPattern(Position),
QualifiedTag(Position),
BackpassComma(Position),
BackpassArrow(Position),
When(EWhen<'a>, Row, Col),
If(EIf<'a>, Row, Col),
When(EWhen<'a>, Position),
If(EIf<'a>, Position),
Expect(EExpect<'a>, Row, Col),
Expect(EExpect<'a>, Position),
Lambda(ELambda<'a>, Row, Col),
Underscore(Row, Col),
Lambda(ELambda<'a>, Position),
Underscore(Position),
InParens(EInParens<'a>, Row, Col),
Record(ERecord<'a>, Row, Col),
Str(EString<'a>, Row, Col),
Number(ENumber, Row, Col),
List(EList<'a>, Row, Col),
InParens(EInParens<'a>, Position),
Record(ERecord<'a>, Position),
Str(EString<'a>, Position),
Number(ENumber, Position),
List(EList<'a>, Position),
IndentStart(Row, Col),
IndentEnd(Row, Col),
IndentStart(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -312,265 +307,264 @@ pub enum ENumber {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EString<'a> {
Open(Row, Col),
Open(Position),
CodePtOpen(Row, Col),
CodePtEnd(Row, Col),
CodePtOpen(Position),
CodePtEnd(Position),
Space(BadInputError, Row, Col),
EndlessSingle(Row, Col),
EndlessMulti(Row, Col),
UnknownEscape(Row, Col),
Format(&'a EExpr<'a>, Row, Col),
FormatEnd(Row, Col),
Space(BadInputError, Position),
EndlessSingle(Position),
EndlessMulti(Position),
UnknownEscape(Position),
Format(&'a EExpr<'a>, Position),
FormatEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ERecord<'a> {
End(Row, Col),
Open(Row, Col),
End(Position),
Open(Position),
Updateable(Row, Col),
Field(Row, Col),
Colon(Row, Col),
QuestionMark(Row, Col),
Bar(Row, Col),
Ampersand(Row, Col),
Updateable(Position),
Field(Position),
Colon(Position),
QuestionMark(Position),
Bar(Position),
Ampersand(Position),
// TODO remove
Expr(&'a EExpr<'a>, Row, Col),
Expr(&'a EExpr<'a>, Position),
Space(BadInputError, Row, Col),
Space(BadInputError, Position),
IndentOpen(Row, Col),
IndentColon(Row, Col),
IndentBar(Row, Col),
IndentAmpersand(Row, Col),
IndentEnd(Row, Col),
IndentOpen(Position),
IndentColon(Position),
IndentBar(Position),
IndentAmpersand(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EInParens<'a> {
End(Row, Col),
Open(Row, Col),
End(Position),
Open(Position),
///
Expr(&'a EExpr<'a>, Row, Col),
Expr(&'a EExpr<'a>, Position),
///
Space(BadInputError, Row, Col),
Space(BadInputError, Position),
///
IndentOpen(Row, Col),
IndentEnd(Row, Col),
IndentOpen(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ELambda<'a> {
Space(BadInputError, Row, Col),
Start(Row, Col),
Arrow(Row, Col),
Comma(Row, Col),
Arg(Row, Col),
Space(BadInputError, Position),
Start(Position),
Arrow(Position),
Comma(Position),
Arg(Position),
// TODO make EEXpr
Pattern(EPattern<'a>, Row, Col),
Body(&'a EExpr<'a>, Row, Col),
IndentArrow(Row, Col),
IndentBody(Row, Col),
IndentArg(Row, Col),
Pattern(EPattern<'a>, Position),
Body(&'a EExpr<'a>, Position),
IndentArrow(Position),
IndentBody(Position),
IndentArg(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EList<'a> {
Open(Row, Col),
End(Row, Col),
Space(BadInputError, Row, Col),
Open(Position),
End(Position),
Space(BadInputError, Position),
Expr(&'a EExpr<'a>, Row, Col),
Expr(&'a EExpr<'a>, Position),
IndentOpen(Row, Col),
IndentEnd(Row, Col),
IndentOpen(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EWhen<'a> {
Space(BadInputError, Row, Col),
When(Row, Col),
Is(Row, Col),
Pattern(EPattern<'a>, Row, Col),
Arrow(Row, Col),
Bar(Row, Col),
Space(BadInputError, Position),
When(Position),
Is(Position),
Pattern(EPattern<'a>, Position),
Arrow(Position),
Bar(Position),
IfToken(Row, Col),
IfGuard(&'a EExpr<'a>, Row, Col),
IfToken(Position),
IfGuard(&'a EExpr<'a>, Position),
Condition(&'a EExpr<'a>, Row, Col),
Branch(&'a EExpr<'a>, Row, Col),
Condition(&'a EExpr<'a>, Position),
Branch(&'a EExpr<'a>, Position),
IndentIs(Row, Col),
IndentCondition(Row, Col),
IndentPattern(Row, Col),
IndentArrow(Row, Col),
IndentBranch(Row, Col),
IndentIfGuard(Row, Col),
PatternAlignment(u16, Row, Col),
IndentIs(Position),
IndentCondition(Position),
IndentPattern(Position),
IndentArrow(Position),
IndentBranch(Position),
IndentIfGuard(Position),
PatternAlignment(u16, Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EIf<'a> {
Space(BadInputError, Row, Col),
If(Row, Col),
Then(Row, Col),
Else(Row, Col),
Space(BadInputError, Position),
If(Position),
Then(Position),
Else(Position),
// TODO make EEXpr
Condition(&'a EExpr<'a>, Row, Col),
ThenBranch(&'a EExpr<'a>, Row, Col),
ElseBranch(&'a EExpr<'a>, Row, Col),
Condition(&'a EExpr<'a>, Position),
ThenBranch(&'a EExpr<'a>, Position),
ElseBranch(&'a EExpr<'a>, Position),
IndentCondition(Row, Col),
IndentIf(Row, Col),
IndentThenToken(Row, Col),
IndentElseToken(Row, Col),
IndentThenBranch(Row, Col),
IndentElseBranch(Row, Col),
IndentCondition(Position),
IndentIf(Position),
IndentThenToken(Position),
IndentElseToken(Position),
IndentThenBranch(Position),
IndentElseBranch(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EExpect<'a> {
Space(BadInputError, Row, Col),
Expect(Row, Col),
Condition(&'a EExpr<'a>, Row, Col),
Continuation(&'a EExpr<'a>, Row, Col),
IndentCondition(Row, Col),
Space(BadInputError, Position),
Expect(Position),
Condition(&'a EExpr<'a>, Position),
Continuation(&'a EExpr<'a>, Position),
IndentCondition(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EPattern<'a> {
Record(PRecord<'a>, Row, Col),
Underscore(Row, Col),
Record(PRecord<'a>, Position),
Underscore(Position),
Start(Row, Col),
End(Row, Col),
Space(BadInputError, Row, Col),
Start(Position),
End(Position),
Space(BadInputError, Position),
PInParens(PInParens<'a>, Row, Col),
NumLiteral(ENumber, Row, Col),
PInParens(PInParens<'a>, Position),
NumLiteral(ENumber, Position),
IndentStart(Row, Col),
IndentEnd(Row, Col),
AsIndentStart(Row, Col),
IndentStart(Position),
IndentEnd(Position),
AsIndentStart(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PRecord<'a> {
End(Row, Col),
Open(Row, Col),
End(Position),
Open(Position),
Field(Row, Col),
Colon(Row, Col),
Optional(Row, Col),
Field(Position),
Colon(Position),
Optional(Position),
Pattern(&'a EPattern<'a>, Row, Col),
Expr(&'a EExpr<'a>, Row, Col),
Pattern(&'a EPattern<'a>, Position),
Expr(&'a EExpr<'a>, Position),
Space(BadInputError, Row, Col),
Space(BadInputError, Position),
IndentOpen(Row, Col),
IndentColon(Row, Col),
IndentOptional(Row, Col),
IndentEnd(Row, Col),
IndentOpen(Position),
IndentColon(Position),
IndentOptional(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PInParens<'a> {
End(Row, Col),
Open(Row, Col),
Pattern(&'a EPattern<'a>, Row, Col),
End(Position),
Open(Position),
Pattern(&'a EPattern<'a>, Position),
Space(BadInputError, Row, Col),
IndentOpen(Row, Col),
IndentEnd(Row, Col),
Space(BadInputError, Position),
IndentOpen(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EType<'a> {
TRecord(ETypeRecord<'a>, Row, Col),
TTagUnion(ETypeTagUnion<'a>, Row, Col),
TInParens(ETypeInParens<'a>, Row, Col),
TApply(ETypeApply, Row, Col),
TBadTypeVariable(Row, Col),
TWildcard(Row, Col),
TInferred(Row, Col),
TRecord(ETypeRecord<'a>, Position),
TTagUnion(ETypeTagUnion<'a>, Position),
TInParens(ETypeInParens<'a>, Position),
TApply(ETypeApply, Position),
TBadTypeVariable(Position),
TWildcard(Position),
TInferred(Position),
///
TStart(Row, Col),
TEnd(Row, Col),
TSpace(BadInputError, Row, Col),
TFunctionArgument(Row, Col),
TStart(Position),
TEnd(Position),
TSpace(BadInputError, Position),
TFunctionArgument(Position),
///
TIndentStart(Row, Col),
TIndentEnd(Row, Col),
TAsIndentStart(Row, Col),
TIndentStart(Position),
TIndentEnd(Position),
TAsIndentStart(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ETypeRecord<'a> {
End(Row, Col),
Open(Row, Col),
End(Position),
Open(Position),
Field(Row, Col),
Colon(Row, Col),
Optional(Row, Col),
Type(&'a EType<'a>, Row, Col),
Field(Position),
Colon(Position),
Optional(Position),
Type(&'a EType<'a>, Position),
Space(BadInputError, Row, Col),
Space(BadInputError, Position),
IndentOpen(Row, Col),
IndentColon(Row, Col),
IndentOptional(Row, Col),
IndentEnd(Row, Col),
IndentOpen(Position),
IndentColon(Position),
IndentOptional(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ETypeTagUnion<'a> {
End(Row, Col),
Open(Row, Col),
End(Position),
Open(Position),
Type(&'a EType<'a>, Row, Col),
Type(&'a EType<'a>, Position),
Space(BadInputError, Row, Col),
Space(BadInputError, Position),
IndentOpen(Row, Col),
IndentEnd(Row, Col),
IndentOpen(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ETypeInParens<'a> {
End(Row, Col),
Open(Row, Col),
End(Position),
Open(Position),
///
Type(&'a EType<'a>, Row, Col),
Type(&'a EType<'a>, Position),
///
Space(BadInputError, Row, Col),
Space(BadInputError, Position),
///
IndentOpen(Row, Col),
IndentEnd(Row, Col),
IndentOpen(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ETypeApply {
///
StartNotUppercase(Row, Col),
End(Row, Col),
Space(BadInputError, Row, Col),
StartNotUppercase(Position),
End(Position),
Space(BadInputError, Position),
///
DoubleDot(Row, Col),
TrailingDot(Row, Col),
StartIsNumber(Row, Col),
DoubleDot(Position),
TrailingDot(Position),
StartIsNumber(Position),
}
#[derive(Debug)]
pub struct ParseProblem<'a, T> {
pub line: u32,
pub column: u16,
pub pos: Position,
pub problem: T,
pub filename: std::path::PathBuf,
pub bytes: &'a [u8],
@ -723,30 +717,30 @@ where
pub fn keyword_e<'a, ToError, E>(keyword: &'static str, if_error: ToError) -> impl Parser<'a, (), E>
where
ToError: Fn(Row, Col) -> E,
ToError: Fn(Position) -> E,
E: 'a,
{
move |_, mut state: State<'a>| {
let width = keyword.len();
if !state.bytes().starts_with(keyword.as_bytes()) {
return Err((NoProgress, if_error(state.line, state.column), state));
return Err((NoProgress, if_error(state.pos), state));
}
// the next character should not be an identifier character
// to prevent treating `whence` or `iffy` as keywords
match state.bytes().get(width) {
Some(next) if *next == b' ' || *next == b'#' || *next == b'\n' => {
state.column += width as u16;
state.pos.column += width as u16;
state = state.advance(width);
Ok((MadeProgress, (), state))
}
None => {
state.column += width as u16;
state.pos.column += width as u16;
state = state.advance(width);
Ok((MadeProgress, (), state))
}
Some(_) => Err((NoProgress, if_error(state.line, state.column), state)),
Some(_) => Err((NoProgress, if_error(state.pos), state)),
}
}
}
@ -944,7 +938,7 @@ pub fn sep_by1_e<'a, P, V, D, Val, Error>(
where
D: Parser<'a, (), Error>,
P: Parser<'a, Val, Error>,
V: Fn(Row, Col) -> Error,
V: Fn(Position) -> Error,
Error: 'a,
{
move |arena, state: State<'a>| {
@ -973,7 +967,7 @@ where
Err((NoProgress, _fail, state)) => {
return Err((
NoProgress,
to_element_error(state.line, state.column),
to_element_error(state.pos),
state,
));
}
@ -1001,7 +995,7 @@ where
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _fail, state)) => Err((
NoProgress,
to_element_error(state.line, state.column),
to_element_error(state.pos),
state,
)),
}
@ -1052,19 +1046,12 @@ macro_rules! loc {
move |arena, state: $crate::state::State<'a>| {
use roc_region::all::{Loc, Region};
let start_col = state.column;
let start_line = state.line;
let start = state.pos;
match $parser.parse(arena, state) {
Ok((progress, value, state)) => {
let end_col = state.column;
let end_line = state.line;
let region = Region {
start_line,
end_line,
start_col,
end_col,
};
let end = state.pos;
let region = Region::new(start, end);
Ok((progress, Loc { region, value }, state))
}
@ -1265,7 +1252,7 @@ macro_rules! one_of_with_error {
match $p1.parse(arena, state) {
valid @ Ok(_) => valid,
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state )),
Err((NoProgress, _, state)) => Err((MadeProgress, $toerror(state.line, state.column), state)),
Err((NoProgress, _, state)) => Err((MadeProgress, $toerror(state.pos), state)),
}
}
};
@ -1277,32 +1264,32 @@ macro_rules! one_of_with_error {
pub fn specialize<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
where
F: Fn(X, Row, Col) -> Y,
F: Fn(X, Position) -> Y,
P: Parser<'a, T, X>,
Y: 'a,
{
move |a, s| match parser.parse(a, s) {
Ok(t) => Ok(t),
Err((p, error, s)) => Err((p, map_error(error, s.line, s.column), s)),
Err((p, error, s)) => Err((p, map_error(error, s.pos), s)),
}
}
pub fn specialize_ref<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
where
F: Fn(&'a X, Row, Col) -> Y,
F: Fn(&'a X, Position) -> Y,
P: Parser<'a, T, X>,
Y: 'a,
X: 'a,
{
move |a, s| match parser.parse(a, s) {
Ok(t) => Ok(t),
Err((p, error, s)) => Err((p, map_error(a.alloc(error), s.line, s.column), s)),
Err((p, error, s)) => Err((p, map_error(a.alloc(error), s.pos), s)),
}
}
pub fn word1<'a, ToError, E>(word: u8, to_error: ToError) -> impl Parser<'a, (), E>
where
ToError: Fn(Row, Col) -> E,
ToError: Fn(Position) -> E,
E: 'a,
{
debug_assert_ne!(word, b'\n');
@ -1310,16 +1297,16 @@ where
move |_arena: &'a Bump, state: State<'a>| match state.bytes().get(0) {
Some(x) if *x == word => {
let mut state = state.advance(1);
state.column += 1;
state.pos.column += 1;
Ok((MadeProgress, (), state))
}
_ => Err((NoProgress, to_error(state.line, state.column), state)),
_ => Err((NoProgress, to_error(state.pos), state)),
}
}
pub fn word2<'a, ToError, E>(word_1: u8, word_2: u8, to_error: ToError) -> impl Parser<'a, (), E>
where
ToError: Fn(Row, Col) -> E,
ToError: Fn(Position) -> E,
E: 'a,
{
debug_assert_ne!(word_1, b'\n');
@ -1330,23 +1317,23 @@ where
move |_arena: &'a Bump, state: State<'a>| {
if state.bytes().starts_with(&needle) {
let mut state = state.advance(2);
state.column += 2;
state.pos.column += 2;
Ok((MadeProgress, (), state))
} else {
Err((NoProgress, to_error(state.line, state.column), state))
Err((NoProgress, to_error(state.pos), state))
}
}
}
pub fn check_indent<'a, TE, E>(min_indent: u16, to_problem: TE) -> impl Parser<'a, (), E>
where
TE: Fn(Row, Col) -> E,
TE: Fn(Position) -> E,
E: 'a,
{
move |_arena, state: State<'a>| {
dbg!(state.indent_col, min_indent);
if state.indent_col < min_indent {
Err((NoProgress, to_problem(state.line, state.column), state))
Err((NoProgress, to_problem(state.pos), state))
} else {
Ok((NoProgress, (), state))
}
@ -1473,7 +1460,7 @@ macro_rules! one_or_more {
}
Err((progress, _, new_state)) => Err((
progress,
$to_error(new_state.line, new_state.column),
$to_error(new_state.pos),
new_state,
)),
}

View file

@ -160,7 +160,7 @@ fn number_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
fn string_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
specialize(
|_, r, c| EPattern::Start(r, c),
|_, pos| EPattern::Start(pos),
map!(crate::string_literal::parse(), Pattern::StrLiteral),
)
}
@ -173,7 +173,7 @@ fn loc_ident_pattern_help<'a>(
let original_state = state.clone();
let (_, loc_ident, state) =
specialize(|_, r, c| EPattern::Start(r, c), loc!(parse_ident)).parse(arena, state)?;
specialize(|_, pos| EPattern::Start(pos), loc!(parse_ident)).parse(arena, state)?;
match loc_ident.value {
Ident::GlobalTag(tag) => {
@ -236,7 +236,7 @@ fn loc_ident_pattern_help<'a>(
if crate::keyword::KEYWORDS.contains(&parts[0]) {
Err((
NoProgress,
EPattern::End(original_state.line, original_state.column),
EPattern::End(original_state.pos),
original_state,
))
} else if module_name.is_empty() && parts.len() == 1 {
@ -308,10 +308,9 @@ fn lowercase_ident_pattern<'a>(
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, &'a str, EPattern<'a>> {
let row = state.line;
let col = state.column;
let pos = state.pos;
specialize(move |_, _, _| EPattern::End(row, col), lowercase_ident()).parse(arena, state)
specialize(move |_, _| EPattern::End(pos), lowercase_ident()).parse(arena, state)
}
#[inline(always)]
@ -344,10 +343,9 @@ fn record_pattern_field<'a>(min_indent: u16) -> impl Parser<'a, Loc<Pattern<'a>>
move |arena, state: State<'a>| {
// You must have a field name, e.g. "email"
// using the initial row/col is important for error reporting
let row = state.line;
let col = state.column;
let pos = state.pos;
let (progress, loc_label, state) = loc!(specialize(
move |_, _, _| PRecord::Field(row, col),
move |_, _| PRecord::Field(pos),
lowercase_ident()
))
.parse(arena, state)?;

View file

@ -1,5 +1,5 @@
use crate::parser::Progress::*;
use crate::parser::{BadInputError, Col, Progress, Row};
use crate::parser::{BadInputError, Progress};
use bumpalo::Bump;
use roc_region::all::{Position, Region};
use std::fmt;
@ -10,10 +10,8 @@ pub struct State<'a> {
/// The raw input bytes from the file.
bytes: &'a [u8],
/// Current line of the input
pub line: u32,
/// Current column of the input
pub column: u16,
/// Current position within the input (line/column)
pub pos: Position,
/// Current indentation level, in columns
/// (so no indent is col 1 - this saves an arithmetic operation.)
@ -24,8 +22,7 @@ impl<'a> State<'a> {
pub fn new(bytes: &'a [u8]) -> State<'a> {
State {
bytes,
line: 0,
column: 0,
pos: Position::default(),
indent_col: 0,
}
}
@ -41,12 +38,10 @@ impl<'a> State<'a> {
state
}
/// Returns whether the parser has reached the end of the input
/// Returns the current position
// TODO: replace this with just accessing the field
pub const fn get_position(&self) -> Position {
Position {
row: self.line,
col: self.column,
}
self.pos
}
/// Returns whether the parser has reached the end of the input
@ -64,10 +59,10 @@ impl<'a> State<'a> {
to_error: TE,
) -> Result<Self, (Progress, E, Self)>
where
TE: Fn(BadInputError, Row, Col) -> E,
TE: Fn(BadInputError, Position) -> E,
{
self.advance_without_indenting_ee(quantity, |r, c| {
to_error(BadInputError::LineTooLong, r, c)
self.advance_without_indenting_ee(quantity, |p| {
to_error(BadInputError::LineTooLong, p)
})
}
@ -77,18 +72,21 @@ impl<'a> State<'a> {
to_error: TE,
) -> Result<Self, (Progress, E, Self)>
where
TE: Fn(Row, Col) -> E,
TE: Fn(Position) -> E,
{
match (self.column as usize).checked_add(quantity) {
match (self.pos.column as usize).checked_add(quantity) {
Some(column_usize) if column_usize <= u16::MAX as usize => {
Ok(State {
bytes: &self.bytes[quantity..],
column: column_usize as u16,
pos: Position {
line: self.pos.line,
column: column_usize as u16,
},
// Once we hit a nonspace character, we are no longer indenting.
..self
})
}
_ => Err((NoProgress, to_error(self.line, self.column), self)),
_ => Err((NoProgress, to_error(self.pos), self)),
}
}
@ -97,15 +95,16 @@ impl<'a> State<'a> {
/// useful when parsing something "manually" (using input.chars())
/// and thus wanting a Region while not having access to loc().
pub fn len_region(&self, length: u16) -> Region {
Region {
start_col: self.column,
start_line: self.line,
end_col: self
.column
.checked_add(length)
.unwrap_or_else(|| panic!("len_region overflowed")),
end_line: self.line,
}
Region::new(self.pos,
Position {
line: self.pos.line,
column: self
.pos
.column
.checked_add(length)
.unwrap_or_else(|| panic!("len_region overflowed")),
}
)
}
/// Return a failing ParseResult for the given FailReason
@ -128,7 +127,7 @@ impl<'a> fmt::Debug for State<'a> {
Err(_) => write!(f, "\n\tbytes: [invalid utf8] {:?}", self.bytes)?,
}
write!(f, "\n\t(line, col): ({}, {}),", self.line, self.column)?;
write!(f, "\n\t(line, col): ({}, {}),", self.pos.line, self.pos.column)?;
write!(f, "\n\tindent_col: {}", self.indent_col)?;
write!(f, "\n}}")
}

View file

@ -19,12 +19,12 @@ fn ascii_hex_digits<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
// We didn't find any hex digits!
return Err((
NoProgress,
EString::CodePtEnd(state.line, state.column),
EString::CodePtEnd(state.pos),
state,
));
} else {
let state = state.advance_without_indenting_ee(buf.len(), |r, c| {
EString::Space(BadInputError::LineTooLong, r, c)
let state = state.advance_without_indenting_ee(buf.len(), |pos| {
EString::Space(BadInputError::LineTooLong, pos)
})?;
return Ok((MadeProgress, buf.into_bump_str(), state));
@ -33,7 +33,7 @@ fn ascii_hex_digits<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
Err((
NoProgress,
EString::CodePtEnd(state.line, state.column),
EString::CodePtEnd(state.pos),
state,
))
}
@ -41,8 +41,8 @@ fn ascii_hex_digits<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
macro_rules! advance_state {
($state:expr, $n:expr) => {
$state.advance_without_indenting_ee($n, |r, c| {
EString::Space(BadInputError::LineTooLong, r, c)
$state.advance_without_indenting_ee($n, |pos| {
EString::Space(BadInputError::LineTooLong, pos)
})
};
}
@ -65,7 +65,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
bytes = state.bytes()[1..].iter();
state = advance_state!(state, 1)?;
} else {
return Err((NoProgress, EString::Open(state.line, state.column), state));
return Err((NoProgress, EString::Open(state.pos), state));
}
// At the parsing stage we keep the entire raw string, because the formatter
@ -109,7 +109,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
Err(_) => {
return Err((
MadeProgress,
EString::Space(BadInputError::BadUtf8, state.line, state.column),
EString::Space(BadInputError::BadUtf8, state.pos),
state,
));
}
@ -203,7 +203,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
// error starting from where the open quote appeared.
return Err((
MadeProgress,
EString::EndlessSingle(state.line, state.column),
EString::EndlessSingle(state.pos),
state,
));
}
@ -296,7 +296,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
// escapable characters (\n, \t, \", \\, etc)
return Err((
MadeProgress,
EString::UnknownEscape(state.line, state.column),
EString::UnknownEscape(state.pos),
state,
));
}
@ -312,9 +312,9 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
Err((
MadeProgress,
if is_multiline {
EString::EndlessMulti(state.line, state.column)
EString::EndlessMulti(state.pos)
} else {
EString::EndlessSingle(state.line, state.column)
EString::EndlessSingle(state.pos)
},
state,
))

View file

@ -9,7 +9,7 @@ use crate::parser::{
use crate::state::State;
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
use roc_region::all::{Loc, Region};
use roc_region::all::{Loc, Region, Position};
pub fn located_help<'a>(
min_indent: u16,
@ -48,7 +48,7 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ET
}
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, EType<'a>> {
|_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.line, state.column), state))
|_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.pos), state))
}
fn term<'a>(min_indent: u16) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
@ -191,15 +191,14 @@ fn tag_type<'a>(min_indent: u16) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>>
}
}
use crate::parser::{Col, Row};
fn parse_tag_name<'a, F, E>(to_problem: F) -> impl Parser<'a, &'a str, E>
where
F: Fn(Row, Col) -> E,
F: Fn(Position) -> E,
E: 'a,
{
move |arena, state: State<'a>| match crate::ident::tag_name().parse(arena, state) {
Ok(good) => Ok(good),
Err((progress, _, state)) => Err((progress, to_problem(state.line, state.column), state)),
Err((progress, _, state)) => Err((progress, to_problem(state.pos), state)),
}
}
@ -213,10 +212,9 @@ fn record_type_field<'a>(
(move |arena, state: State<'a>| {
// You must have a field name, e.g. "email"
// using the initial row/col is important for error reporting
let row = state.line;
let col = state.column;
let pos = state.pos;
let (progress, loc_label, state) = loc!(specialize(
move |_, _, _| ETypeRecord::Field(row, col),
move |_, _| ETypeRecord::Field(pos),
lowercase_ident()
))
.parse(arena, state)?;
@ -370,7 +368,7 @@ fn expression<'a>(
),
|_, state: State<'a>| Err((
NoProgress,
EType::TFunctionArgument(state.line, state.column),
EType::TFunctionArgument(state.pos),
state
))
]
@ -464,7 +462,7 @@ fn parse_concrete_type<'a>(
Ok((MadeProgress, answer, state))
}
Err((NoProgress, _, state)) => {
Err((NoProgress, ETypeApply::End(state.line, state.column), state))
Err((NoProgress, ETypeApply::End(state.pos), state))
}
Err((MadeProgress, _, mut state)) => {
// we made some progress, but ultimately failed.
@ -474,8 +472,8 @@ fn parse_concrete_type<'a>(
let parsed_str =
unsafe { std::str::from_utf8_unchecked(&initial_bytes[..chomped + delta]) };
state = state.advance_without_indenting_ee(chomped, |r, c| {
ETypeApply::Space(crate::parser::BadInputError::LineTooLong, r, c)
state = state.advance_without_indenting_ee(chomped, |pos| {
ETypeApply::Space(crate::parser::BadInputError::LineTooLong, pos)
})?;
Ok((MadeProgress, TypeAnnotation::Malformed(parsed_str), state))
@ -495,7 +493,7 @@ fn parse_type_variable<'a>(
}
Err((progress, _, state)) => Err((
progress,
EType::TBadTypeVariable(state.line, state.column),
EType::TBadTypeVariable(state.pos),
state,
)),
}