remove Bag

This commit is contained in:
Folkert 2021-02-08 00:33:29 +01:00
parent ca04411523
commit 2c9a80153d
11 changed files with 127 additions and 210 deletions

View file

@ -1,7 +1,7 @@
use const_format::concatcp; use const_format::concatcp;
use gen::{gen_and_eval, ReplOutput}; use gen::{gen_and_eval, ReplOutput};
use roc_gen::llvm::build::OptLevel; use roc_gen::llvm::build::OptLevel;
use roc_parse::parser::{Bag, SyntaxError}; use roc_parse::parser::SyntaxError;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator}; use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
use rustyline::Editor; use rustyline::Editor;
@ -191,11 +191,11 @@ pub fn main() -> io::Result<()> {
Ok(()) Ok(())
} }
fn report_parse_error<'a>(fail: Bag<'a, SyntaxError<'a>>) { fn report_parse_error<'a>(fail: SyntaxError<'a>) {
println!("TODO Gracefully report parse error in repl: {:?}", fail); println!("TODO Gracefully report parse error in repl: {:?}", fail);
} }
fn eval_and_format<'a>(src: &str) -> Result<String, Bag<'a, SyntaxError<'a>>> { fn eval_and_format<'a>(src: &str) -> Result<String, SyntaxError<'a>> {
gen_and_eval(src.as_bytes(), Triple::host(), OptLevel::Normal).map(|output| match output { gen_and_eval(src.as_bytes(), Triple::host(), OptLevel::Normal).map(|output| match output {
ReplOutput::NoProblems { expr, expr_type } => { ReplOutput::NoProblems { expr, expr_type } => {
format!("\n{} {}:{} {}", expr, PINK, END_COL, expr_type) format!("\n{} {}:{} {}", expr, PINK, END_COL, expr_type)

View file

@ -7,7 +7,7 @@ use roc_collections::all::{MutMap, MutSet};
use roc_fmt::annotation::Formattable; use roc_fmt::annotation::Formattable;
use roc_fmt::annotation::{Newlines, Parens}; use roc_fmt::annotation::{Newlines, Parens};
use roc_gen::llvm::build::{build_proc, build_proc_header, OptLevel}; use roc_gen::llvm::build::{build_proc, build_proc_header, OptLevel};
use roc_parse::parser::{Bag, SyntaxError}; use roc_parse::parser::SyntaxError;
use roc_types::pretty_print::{content_to_string, name_all_type_vars}; use roc_types::pretty_print::{content_to_string, name_all_type_vars};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::from_utf8_unchecked; use std::str::from_utf8_unchecked;
@ -22,7 +22,7 @@ pub fn gen_and_eval<'a>(
src: &[u8], src: &[u8],
target: Triple, target: Triple,
opt_level: OptLevel, opt_level: OptLevel,
) -> Result<ReplOutput, Bag<'a, SyntaxError<'a>>> { ) -> Result<ReplOutput, SyntaxError<'a>> {
use roc_reporting::report::{ use roc_reporting::report::{
can_problem, mono_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE, can_problem, mono_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE,
}; };

View file

@ -11,7 +11,7 @@ use crate::number_literal::number_literal;
use crate::parser::{ use crate::parser::{
self, allocated, and_then_with_indent_level, ascii_char, ascii_string, attempt, backtrackable, self, allocated, and_then_with_indent_level, ascii_char, ascii_string, attempt, backtrackable,
fail, map, newline_char, not, not_followed_by, optional, sep_by1, then, unexpected, fail, map, newline_char, not, not_followed_by, optional, sep_by1, then, unexpected,
unexpected_eof, Bag, Either, ParseResult, Parser, State, SyntaxError, unexpected_eof, Either, ParseResult, Parser, State, SyntaxError,
}; };
use crate::type_annotation; use crate::type_annotation;
use bumpalo::collections::string::String; use bumpalo::collections::string::String;
@ -100,7 +100,7 @@ macro_rules! loc_parenthetical_expr {
// Re-parse the Expr as a Pattern. // Re-parse the Expr as a Pattern.
let pattern = match expr_to_pattern(arena, &loc_expr.value) { let pattern = match expr_to_pattern(arena, &loc_expr.value) {
Ok(valid) => valid, Ok(valid) => valid,
Err(fail) => return Err((progress, Bag::from_state(arena, &state, fail), state)), Err(fail) => return Err((progress, fail, state)),
}; };
// Make sure we don't discard the spaces - might be comments in there! // Make sure we don't discard the spaces - might be comments in there!
@ -493,22 +493,14 @@ pub fn assigned_pattern_field_to_pattern<'a>(
fn equals_for_def<'a>() -> impl Parser<'a, (), SyntaxError<'a>> { fn equals_for_def<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|arena, state: State<'a>| match state.bytes.get(0) { |arena, state: State<'a>| match state.bytes.get(0) {
Some(b'=') => match state.bytes.get(1) { Some(b'=') => match state.bytes.get(1) {
Some(b'=') | Some(b'>') => Err(( Some(b'=') | Some(b'>') => Err((NoProgress, SyntaxError::ConditionFailed, state)),
NoProgress,
Bag::from_state(arena, &state, SyntaxError::ConditionFailed),
state,
)),
_ => { _ => {
let state = state.advance_without_indenting(arena, 1)?; let state = state.advance_without_indenting(arena, 1)?;
Ok((MadeProgress, (), state)) Ok((MadeProgress, (), state))
} }
}, },
_ => Err(( _ => Err((NoProgress, SyntaxError::ConditionFailed, state)),
NoProgress,
Bag::from_state(arena, &state, SyntaxError::ConditionFailed),
state,
)),
} }
} }
@ -738,22 +730,14 @@ fn parse_def_expr<'a>(
spaces_after_equals: &'a [CommentOrNewline<'a>], spaces_after_equals: &'a [CommentOrNewline<'a>],
) -> ParseResult<'a, Expr<'a>, SyntaxError<'a>> { ) -> ParseResult<'a, Expr<'a>, SyntaxError<'a>> {
if def_start_col < min_indent { if def_start_col < min_indent {
Err(( Err((NoProgress, SyntaxError::OutdentedTooFar, state))
NoProgress,
Bag::from_state(arena, &state, SyntaxError::OutdentedTooFar),
state,
))
// `<` because '=' should be same indent (or greater) as the entire def-expr // `<` because '=' should be same indent (or greater) as the entire def-expr
} else if equals_sign_indent < def_start_col { } else if equals_sign_indent < def_start_col {
let msg = format!( let msg = format!(
r"TODO the = in this declaration seems outdented. equals_sign_indent was {} and def_start_col was {}", r"TODO the = in this declaration seems outdented. equals_sign_indent was {} and def_start_col was {}",
equals_sign_indent, def_start_col equals_sign_indent, def_start_col
); );
Err(( Err((NoProgress, SyntaxError::NotYetImplemented(msg), state))
NoProgress,
Bag::from_state(arena, &state, SyntaxError::NotYetImplemented(msg)),
state,
))
} else { } else {
// Indented more beyond the original indent of the entire def-expr. // Indented more beyond the original indent of the entire def-expr.
let indented_more = def_start_col + 1; let indented_more = def_start_col + 1;
@ -831,21 +815,13 @@ fn parse_def_signature<'a>(
let original_indent = state.indent_col; let original_indent = state.indent_col;
if original_indent < min_indent { if original_indent < min_indent {
Err(( Err((NoProgress, SyntaxError::OutdentedTooFar, state))
NoProgress,
Bag::from_state(arena, &state, SyntaxError::OutdentedTooFar),
state,
))
// `<` because ':' should be same indent or greater // `<` because ':' should be same indent or greater
} else if colon_indent < original_indent { } else if colon_indent < original_indent {
Err(( Err((
NoProgress, NoProgress,
Bag::from_state( SyntaxError::NotYetImplemented(
arena, "TODO the : in this declaration seems outdented".to_string(),
&state,
SyntaxError::NotYetImplemented(
"TODO the : in this declaration seems outdented".to_string(),
),
), ),
state, state,
)) ))
@ -1336,9 +1312,7 @@ fn loc_ident_pattern<'a>(
Ident::Malformed(malformed) => { Ident::Malformed(malformed) => {
debug_assert!(!malformed.is_empty()); debug_assert!(!malformed.is_empty());
let bag = Bag::from_state(arena, &state, SyntaxError::InvalidPattern); Err((MadeProgress, SyntaxError::InvalidPattern, state))
Err((MadeProgress, bag, state))
} }
} }
} }
@ -1368,12 +1342,8 @@ mod when {
if case_indent < min_indent { if case_indent < min_indent {
return Err(( return Err((
progress, progress,
Bag::from_state( SyntaxError::NotYetImplemented(
arena, "TODO case wasn't indented enough".to_string(),
&state,
SyntaxError::NotYetImplemented(
"TODO case wasn't indented enough".to_string(),
),
), ),
state, state,
)); ));
@ -1440,11 +1410,10 @@ mod when {
} else { } else {
Err(( Err((
MadeProgress, MadeProgress,
Bag::from_state( arena, &state,
SyntaxError::NotYetImplemented( SyntaxError::NotYetImplemented(
"TODO additional branch didn't have same indentation as first branch".to_string(), "TODO additional branch didn't have same indentation as first branch".to_string(),
), ),
),
state, state,
)) ))
} }
@ -1702,8 +1671,7 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>>
(Some(loc_args), Some((_spaces_before_equals, Either::First(_equals_indent)))) => { (Some(loc_args), Some((_spaces_before_equals, Either::First(_equals_indent)))) => {
// We got args with an '=' after them, e.g. `foo a b = ...` This is a syntax error! // We got args with an '=' after them, e.g. `foo a b = ...` This is a syntax error!
let region = Region::across_all(loc_args.iter().map(|v| &v.region)); let region = Region::across_all(loc_args.iter().map(|v| &v.region));
let fail = let fail = SyntaxError::ArgumentsBeforeEquals(region);
Bag::from_state(arena, &state, SyntaxError::ArgumentsBeforeEquals(region));
Err((MadeProgress, fail, state)) Err((MadeProgress, fail, state))
} }
(None, Some((spaces_before_equals, Either::First(equals_indent)))) => { (None, Some((spaces_before_equals, Either::First(equals_indent)))) => {
@ -1778,14 +1746,10 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>>
Err(malformed) => { Err(malformed) => {
return Err(( return Err((
MadeProgress, MadeProgress,
Bag::from_state( SyntaxError::NotYetImplemented(format!(
arena, "TODO early return malformed pattern {:?}",
&state, malformed
SyntaxError::NotYetImplemented(format!( )),
"TODO early return malformed pattern {:?}",
malformed
)),
),
state, state,
)); ));
} }
@ -2014,9 +1978,7 @@ fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<
match assigned_expr_field_to_pattern(arena, &loc_assigned_field.value) { match assigned_expr_field_to_pattern(arena, &loc_assigned_field.value) {
Ok(value) => loc_patterns.push(Located { region, value }), Ok(value) => loc_patterns.push(Located { region, value }),
// an Expr became a pattern that should not be. // an Expr became a pattern that should not be.
Err(fail) => { Err(fail) => return Err((progress, fail, state)),
return Err((progress, Bag::from_state(arena, &state, fail), state))
}
} }
} }
@ -2054,9 +2016,7 @@ fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<
match assigned_expr_field_to_pattern(arena, &loc_assigned_field.value) { match assigned_expr_field_to_pattern(arena, &loc_assigned_field.value) {
Ok(value) => loc_patterns.push(Located { region, value }), Ok(value) => loc_patterns.push(Located { region, value }),
// an Expr became a pattern that should not be. // an Expr became a pattern that should not be.
Err(fail) => { Err(fail) => return Err((progress, fail, state)),
return Err((progress, Bag::from_state(arena, &state, fail), state))
}
} }
} }

View file

@ -1,7 +1,7 @@
use crate::ast::Attempting; use crate::ast::Attempting;
use crate::keyword; use crate::keyword;
use crate::parser::Progress::{self, *}; use crate::parser::Progress::{self, *};
use crate::parser::{peek_utf8_char, unexpected, Bag, ParseResult, Parser, State, SyntaxError}; use crate::parser::{peek_utf8_char, unexpected, ParseResult, Parser, State, SyntaxError};
use bumpalo::collections::string::String; use bumpalo::collections::string::String;
use bumpalo::collections::vec::Vec; use bumpalo::collections::vec::Vec;
use bumpalo::Bump; use bumpalo::Bump;
@ -399,11 +399,7 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, SyntaxError<'a>> {
{ {
// TODO Calculate the correct region based on state // TODO Calculate the correct region based on state
let region = Region::zero(); let region = Region::zero();
Err(( Err((MadeProgress, SyntaxError::ReservedKeyword(region), state))
MadeProgress,
Bag::from_state(arena, &state, SyntaxError::ReservedKeyword(region)),
state,
))
} else { } else {
Ok((MadeProgress, ident, state)) Ok((MadeProgress, ident, state))
} }

View file

@ -59,12 +59,9 @@ impl<'a> State<'a> {
self, self,
arena: &'a Bump, arena: &'a Bump,
min_indent: u16, min_indent: u16,
) -> Result<Self, (Bag<'a, SyntaxError<'a>>, Self)> { ) -> Result<Self, (SyntaxError<'a>, Self)> {
if self.indent_col < min_indent { if self.indent_col < min_indent {
Err(( Err((SyntaxError::OutdentedTooFar, self))
Bag::from_state(arena, &self, SyntaxError::OutdentedTooFar),
self,
))
} else { } else {
Ok(self) Ok(self)
} }
@ -84,10 +81,7 @@ impl<'a> State<'a> {
/// Increments the line, then resets column, indent_col, and is_indenting. /// Increments the line, then resets column, indent_col, and is_indenting.
/// Advances the input by 1, to consume the newline character. /// Advances the input by 1, to consume the newline character.
pub fn newline( pub fn newline(&self, arena: &'a Bump) -> Result<Self, (Progress, SyntaxError<'a>, Self)> {
&self,
arena: &'a Bump,
) -> Result<Self, (Progress, Bag<'a, SyntaxError<'a>>, Self)> {
match self.line.checked_add(1) { match self.line.checked_add(1) {
Some(line) => Ok(State { Some(line) => Ok(State {
bytes: &self.bytes[1..], bytes: &self.bytes[1..],
@ -100,7 +94,7 @@ impl<'a> State<'a> {
}), }),
None => Err(( None => Err((
Progress::NoProgress, Progress::NoProgress,
Bag::from_state(arena, &self, SyntaxError::TooManyLines), SyntaxError::TooManyLines,
self.clone(), self.clone(),
)), )),
} }
@ -114,7 +108,7 @@ impl<'a> State<'a> {
self, self,
arena: &'a Bump, arena: &'a Bump,
quantity: usize, quantity: usize,
) -> Result<Self, (Progress, Bag<'a, SyntaxError<'a>>, Self)> { ) -> Result<Self, (Progress, SyntaxError<'a>, Self)> {
match (self.column as usize).checked_add(quantity) { match (self.column as usize).checked_add(quantity) {
Some(column_usize) if column_usize <= u16::MAX as usize => { Some(column_usize) if column_usize <= u16::MAX as usize => {
Ok(State { Ok(State {
@ -134,7 +128,7 @@ impl<'a> State<'a> {
&self, &self,
arena: &'a Bump, arena: &'a Bump,
spaces: usize, spaces: usize,
) -> Result<Self, (Progress, Bag<'a, SyntaxError<'a>>, Self)> { ) -> Result<Self, (Progress, SyntaxError<'a>, Self)> {
match (self.column as usize).checked_add(spaces) { match (self.column as usize).checked_add(spaces) {
Some(column_usize) if column_usize <= u16::MAX as usize => { Some(column_usize) if column_usize <= u16::MAX as usize => {
// Spaces don't affect is_indenting; if we were previously indneting, // Spaces don't affect is_indenting; if we were previously indneting,
@ -187,13 +181,13 @@ impl<'a> State<'a> {
} }
/// Return a failing ParseResult for the given FailReason /// Return a failing ParseResult for the given FailReason
pub fn fail<T>( pub fn fail<T, X>(
self, self,
arena: &'a Bump, arena: &'a Bump,
progress: Progress, progress: Progress,
reason: SyntaxError<'a>, reason: X,
) -> Result<(Progress, T, Self), (Progress, Bag<'a, SyntaxError<'a>>, Self)> { ) -> Result<(Progress, T, Self), (Progress, X, Self)> {
Err((progress, Bag::from_state(arena, &self, reason), self)) Err((progress, reason, self))
} }
} }
@ -225,7 +219,7 @@ fn state_size() {
} }
pub type ParseResult<'a, Output, Error> = pub type ParseResult<'a, Output, Error> =
Result<(Progress, Output, State<'a>), (Progress, Bag<'a, Error>, State<'a>)>; Result<(Progress, Output, State<'a>), (Progress, Error, State<'a>)>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Progress { pub enum Progress {
@ -275,6 +269,22 @@ pub enum SyntaxError<'a> {
Type(Type<'a>), Type(Type<'a>),
} }
impl<'a> SyntaxError<'a> {
pub fn into_parse_problem(
self,
filename: std::path::PathBuf,
bytes: &'a [u8],
) -> ParseProblem<'a, SyntaxError<'a>> {
ParseProblem {
line: 0,
column: 0,
problem: self,
filename,
bytes,
}
}
}
type Row = u32; type Row = u32;
type Col = u16; type Col = u16;
@ -351,55 +361,6 @@ pub struct DeadEnd<'a, T> {
pub context_stack: ContextStack<'a>, pub context_stack: ContextStack<'a>,
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Bag<'a, T>(Vec<'a, DeadEnd<'a, T>>);
impl<'a, T> Bag<'a, T> {
pub fn new_in(arena: &'a Bump) -> Self {
Bag(Vec::new_in(arena))
}
pub fn from_state(arena: &'a Bump, state: &State<'a>, x: T) -> Self {
let mut dead_ends = Vec::with_capacity_in(1, arena);
let dead_end = DeadEnd {
line: state.line,
column: state.column,
problem: x,
context_stack: state.context_stack.clone(),
};
dead_ends.push(dead_end);
Bag(dead_ends)
}
fn pop(&mut self) -> Option<DeadEnd<'a, T>> {
self.0.pop()
}
pub fn into_parse_problem(
mut self,
filename: std::path::PathBuf,
bytes: &[u8],
) -> ParseProblem<'_, T> {
match self.pop() {
None => unreachable!("there is a parse error, but no problem"),
Some(dead_end) => {
let context_stack = dead_end.context_stack.into_vec();
ParseProblem {
line: dead_end.line,
column: dead_end.column,
problem: dead_end.problem,
context_stack,
filename,
bytes,
}
}
}
}
}
/// use std vec to escape the arena's lifetime bound /// use std vec to escape the arena's lifetime bound
/// since this is only used when there is in fact an error /// since this is only used when there is in fact an error
/// I think this is fine /// I think this is fine
@ -408,19 +369,12 @@ pub struct ParseProblem<'a, T> {
pub line: u32, pub line: u32,
pub column: u16, pub column: u16,
pub problem: T, pub problem: T,
pub context_stack: std::vec::Vec<ContextItem>,
pub filename: std::path::PathBuf, pub filename: std::path::PathBuf,
pub bytes: &'a [u8], pub bytes: &'a [u8],
} }
pub fn fail<'a, T>() -> impl Parser<'a, T, SyntaxError<'a>> { pub fn fail<'a, T>() -> impl Parser<'a, T, SyntaxError<'a>> {
move |arena, state: State<'a>| { move |arena, state: State<'a>| Err((NoProgress, SyntaxError::ConditionFailed, state))
Err((
NoProgress,
Bag::from_state(arena, &state, SyntaxError::ConditionFailed),
state,
))
}
} }
pub trait Parser<'a, Output, Error> { pub trait Parser<'a, Output, Error> {
@ -467,11 +421,9 @@ where
let after_parse = state.clone(); let after_parse = state.clone();
match by.parse(arena, state) { match by.parse(arena, state) {
Ok((_, _, state)) => Err(( Ok((_, _, state)) => {
NoProgress, Err((NoProgress, SyntaxError::ConditionFailed, original_state))
Bag::from_state(arena, &state, SyntaxError::ConditionFailed), }
original_state,
)),
Err(_) => Ok((progress, answer, after_parse)), Err(_) => Ok((progress, answer, after_parse)),
} }
}) })
@ -486,11 +438,7 @@ where
let original_state = state.clone(); let original_state = state.clone();
match parser.parse(arena, state) { match parser.parse(arena, state) {
Ok((_, _, _)) => Err(( Ok((_, _, _)) => Err((NoProgress, SyntaxError::ConditionFailed, original_state)),
NoProgress,
Bag::from_state(arena, &original_state, SyntaxError::ConditionFailed),
original_state,
)),
Err((_, _, _)) => Ok((NoProgress, (), original_state)), Err((_, _, _)) => Ok((NoProgress, (), original_state)),
} }
} }
@ -571,7 +519,7 @@ pub fn unexpected_eof<'a>(
arena: &'a Bump, arena: &'a Bump,
state: State<'a>, state: State<'a>,
chars_consumed: usize, chars_consumed: usize,
) -> (Progress, Bag<'a, SyntaxError<'a>>, State<'a>) { ) -> (Progress, SyntaxError<'a>, State<'a>) {
checked_unexpected(arena, state, chars_consumed, |region| { checked_unexpected(arena, state, chars_consumed, |region| {
SyntaxError::Eof(region) SyntaxError::Eof(region)
}) })
@ -582,7 +530,7 @@ pub fn unexpected<'a>(
chars_consumed: usize, chars_consumed: usize,
_attempting: Attempting, _attempting: Attempting,
state: State<'a>, state: State<'a>,
) -> (Progress, Bag<'a, SyntaxError<'a>>, State<'a>) { ) -> (Progress, SyntaxError<'a>, State<'a>) {
// NOTE state is the last argument because chars_consumed often depends on the state's fields // NOTE state is the last argument because chars_consumed often depends on the state's fields
// having state be the final argument prevents borrowing issues // having state be the final argument prevents borrowing issues
checked_unexpected(arena, state, chars_consumed, |region| { checked_unexpected(arena, state, chars_consumed, |region| {
@ -599,7 +547,7 @@ fn checked_unexpected<'a, F>(
state: State<'a>, state: State<'a>,
chars_consumed: usize, chars_consumed: usize,
problem_from_region: F, problem_from_region: F,
) -> (Progress, Bag<'a, SyntaxError<'a>>, State<'a>) ) -> (Progress, SyntaxError<'a>, State<'a>)
where where
F: FnOnce(Region) -> SyntaxError<'a>, F: FnOnce(Region) -> SyntaxError<'a>,
{ {
@ -617,13 +565,7 @@ where
end_line: state.line, end_line: state.line,
}; };
let problem = problem_from_region(region); (Progress::NoProgress, problem_from_region(region), state)
(
Progress::NoProgress,
Bag::from_state(arena, &state, problem),
state,
)
} }
_ => { _ => {
let (_progress, fail, state) = line_too_long(arena, state); let (_progress, fail, state) = line_too_long(arena, state);
@ -632,10 +574,7 @@ where
} }
} }
fn line_too_long<'a>( fn line_too_long<'a>(arena: &'a Bump, state: State<'a>) -> (Progress, SyntaxError<'a>, State<'a>) {
arena: &'a Bump,
state: State<'a>,
) -> (Progress, Bag<'a, SyntaxError<'a>>, State<'a>) {
let problem = SyntaxError::LineTooLong(state.line); let problem = SyntaxError::LineTooLong(state.line);
// Set column to MAX and advance the parser to end of input. // Set column to MAX and advance the parser to end of input.
// This way, all future parsers will fail on EOF, and then // This way, all future parsers will fail on EOF, and then
@ -654,11 +593,7 @@ fn line_too_long<'a>(
// TODO do we make progress in this case? // TODO do we make progress in this case?
// isn't this error fatal? // isn't this error fatal?
( (Progress::NoProgress, problem, state)
Progress::NoProgress,
Bag::from_state(arena, &state, problem),
state,
)
} }
/// A single ASCII char that isn't a newline. /// A single ASCII char that isn't a newline.
@ -987,7 +922,7 @@ where
pub fn fail_when_progress<'a, T, E>( pub fn fail_when_progress<'a, T, E>(
progress: Progress, progress: Progress,
fail: Bag<'a, E>, fail: E,
value: T, value: T,
state: State<'a>, state: State<'a>,
) -> ParseResult<'a, T, E> { ) -> ParseResult<'a, T, E> {
@ -1006,11 +941,9 @@ where
Ok((progress, output, next_state)) if predicate(&output) => { Ok((progress, output, next_state)) if predicate(&output) => {
Ok((progress, output, next_state)) Ok((progress, output, next_state))
} }
Ok((progress, _, _)) | Err((progress, _, _)) => Err(( Ok((progress, _, _)) | Err((progress, _, _)) => {
progress, Err((progress, SyntaxError::ConditionFailed, state))
Bag::from_state(arena, &state, SyntaxError::ConditionFailed), }
state,
)),
} }
} }
@ -1212,6 +1145,45 @@ macro_rules! one_of {
}; };
} }
#[macro_export]
macro_rules! one_of_with_error {
($toerror:expr; $p1:expr, $p2:expr) => {
move |arena: &'a bumpalo::Bump, state: $crate::parser::State<'a>| {
match $p1.parse(arena, state) {
valid @ Ok(_) => valid,
Err((MadeProgress, _, state)) => Err((MadeProgress, $toerror(state.line, state.column), state)),
Err((NoProgress, _, state)) => $p2.parse( arena, state),
}
}
};
($toerror:expr; $p1:expr, $($others:expr),+) => {
one_of_with_error!($toerror, $p1, one_of!($($others),+))
};
}
fn word1<'a, ToError, E>(word: u8, to_error: ToError) -> impl Parser<'a, (), E>
where
ToError: Fn(Row, Col) -> E,
E: 'a,
{
debug_assert_ne!(word, b'\n');
move |_arena: &'a Bump, state: State<'a>| match state.bytes.get(0) {
Some(x) if *x == word => Ok((
MadeProgress,
(),
State {
bytes: &state.bytes[1..],
column: state.column + 1,
..state
},
)),
_ => Err((NoProgress, to_error(state.line, state.column), state)),
}
}
#[macro_export] #[macro_export]
macro_rules! map { macro_rules! map {
($parser:expr, $transform:expr) => { ($parser:expr, $transform:expr) => {
@ -1580,11 +1552,7 @@ pub fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
if state.has_reached_end() { if state.has_reached_end() {
Ok((NoProgress, (), state)) Ok((NoProgress, (), state))
} else { } else {
Err(( Err((NoProgress, SyntaxError::ConditionFailed, state))
NoProgress,
Bag::from_state(arena, &state, SyntaxError::ConditionFailed),
state,
))
} }
} }
} }

View file

@ -2,7 +2,7 @@ use crate::ast::{Attempting, EscapedChar, StrLiteral, StrSegment};
use crate::expr; use crate::expr;
use crate::parser::Progress::*; use crate::parser::Progress::*;
use crate::parser::{ use crate::parser::{
allocated, ascii_char, ascii_hex_digits, loc, parse_utf8, unexpected, unexpected_eof, Bag, allocated, ascii_char, ascii_hex_digits, loc, parse_utf8, unexpected, unexpected_eof,
ParseResult, Parser, State, SyntaxError, ParseResult, Parser, State, SyntaxError,
}; };
use bumpalo::collections::vec::Vec; use bumpalo::collections::vec::Vec;
@ -291,14 +291,10 @@ where
// Ok((StrLiteral::Block(lines.into_bump_slice()), state)) // Ok((StrLiteral::Block(lines.into_bump_slice()), state))
Err(( Err((
MadeProgress, MadeProgress,
Bag::from_state( SyntaxError::NotYetImplemented(format!(
arena, "TODO parse this line in a block string: {:?}",
&state, line
SyntaxError::NotYetImplemented(format!( )),
"TODO parse this line in a block string: {:?}",
line
)),
),
state, state,
)) ))
} }

View file

@ -2,7 +2,7 @@ use crate::ast::{self, Attempting};
use crate::blankspace::space0_before; use crate::blankspace::space0_before;
use crate::expr::expr; use crate::expr::expr;
use crate::module::{header, module_defs}; use crate::module::{header, module_defs};
use crate::parser::{loc, Bag, Parser, State, SyntaxError}; use crate::parser::{loc, Parser, State, SyntaxError};
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_region::all::Located; use roc_region::all::Located;
@ -11,14 +11,14 @@ use roc_region::all::Located;
pub fn parse_expr_with<'a>( pub fn parse_expr_with<'a>(
arena: &'a Bump, arena: &'a Bump,
input: &'a str, input: &'a str,
) -> Result<ast::Expr<'a>, Bag<'a, SyntaxError<'a>>> { ) -> Result<ast::Expr<'a>, SyntaxError<'a>> {
parse_loc_with(arena, input).map(|loc_expr| loc_expr.value) parse_loc_with(arena, input).map(|loc_expr| loc_expr.value)
} }
pub fn parse_header_with<'a>( pub fn parse_header_with<'a>(
arena: &'a Bump, arena: &'a Bump,
input: &'a str, input: &'a str,
) -> Result<ast::Module<'a>, Bag<'a, SyntaxError<'a>>> { ) -> Result<ast::Module<'a>, SyntaxError<'a>> {
let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module); let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module);
let answer = header().parse(arena, state); let answer = header().parse(arena, state);
@ -31,7 +31,7 @@ pub fn parse_header_with<'a>(
pub fn parse_defs_with<'a>( pub fn parse_defs_with<'a>(
arena: &'a Bump, arena: &'a Bump,
input: &'a str, input: &'a str,
) -> Result<Vec<'a, Located<ast::Def<'a>>>, Bag<'a, SyntaxError<'a>>> { ) -> Result<Vec<'a, Located<ast::Def<'a>>>, SyntaxError<'a>> {
let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module); let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module);
let answer = module_defs().parse(arena, state); let answer = module_defs().parse(arena, state);
answer answer
@ -43,7 +43,7 @@ pub fn parse_defs_with<'a>(
pub fn parse_loc_with<'a>( pub fn parse_loc_with<'a>(
arena: &'a Bump, arena: &'a Bump,
input: &'a str, input: &'a str,
) -> Result<Located<ast::Expr<'a>>, Bag<'a, SyntaxError<'a>>> { ) -> Result<Located<ast::Expr<'a>>, SyntaxError<'a>> {
let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module); let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module);
let parser = space0_before(loc(expr(0)), 0); let parser = space0_before(loc(expr(0)), 0);
let answer = parser.parse(&arena, state); let answer = parser.parse(&arena, state);

View file

@ -4,7 +4,7 @@ use crate::expr::{global_tag, private_tag};
use crate::ident::join_module_parts; use crate::ident::join_module_parts;
use crate::keyword; use crate::keyword;
use crate::parser::{ use crate::parser::{
allocated, ascii_char, ascii_string, not, optional, peek_utf8_char, unexpected, Bag, Either, allocated, ascii_char, ascii_string, not, optional, peek_utf8_char, unexpected, Either,
ParseResult, Parser, ParseResult, Parser,
Progress::{self, *}, Progress::{self, *},
State, SyntaxError, State, SyntaxError,
@ -269,11 +269,7 @@ fn expression<'a>(
let msg = let msg =
"TODO: Decide the correct error to return for 'Invalid function signature'" "TODO: Decide the correct error to return for 'Invalid function signature'"
.to_string(); .to_string();
Err(( Err((progress, SyntaxError::NotYetImplemented(msg), state))
progress,
Bag::from_state(arena, &state, SyntaxError::NotYetImplemented(msg)),
state,
))
} }
} }
} }

View file

@ -83,7 +83,8 @@ pub fn parse_problem<'b>(
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
alloc.concat(vec![ alloc.concat(vec![
alloc.reflow("Unexpected token "), alloc.reflow("Unexpected token "),
context(alloc, &parse_problem.context_stack, "here"), // context(alloc, &parse_problem.context_stack, "here"),
todo!(),
alloc.text(":"), alloc.text(":"),
]), ]),
alloc.region(region), alloc.region(region),

View file

@ -19,7 +19,7 @@ use roc_parse::ast::StrLiteral;
use roc_parse::ast::{self, Attempting}; use roc_parse::ast::{self, Attempting};
use roc_parse::blankspace::space0_before; use roc_parse::blankspace::space0_before;
use roc_parse::expr::expr; use roc_parse::expr::expr;
use roc_parse::parser::{loc, Bag, Parser, State, SyntaxError}; use roc_parse::parser::{loc, Parser, State, SyntaxError};
use roc_problem::can::{Problem, RuntimeError}; use roc_problem::can::{Problem, RuntimeError};
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
use roc_types::subs::{VarStore, Variable}; use roc_types::subs::{VarStore, Variable};
@ -232,7 +232,7 @@ pub fn str_to_expr2<'a>(
env: &mut Env<'a>, env: &mut Env<'a>,
scope: &mut Scope, scope: &mut Scope,
region: Region, region: Region,
) -> Result<(Expr2, self::Output), Bag<'a, SyntaxError<'a>>> { ) -> Result<(Expr2, self::Output), SyntaxError<'a>> {
let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module); let state = State::new_in(arena, input.trim().as_bytes(), Attempting::Module);
let parser = space0_before(loc(expr(0)), 0); let parser = space0_before(loc(expr(0)), 0);
let parse_res = parser.parse(&arena, state); let parse_res = parser.parse(&arena, state);

View file

@ -21,8 +21,8 @@ pub struct File<'a> {
#[derive(Debug)] #[derive(Debug)]
pub enum ReadError<'a> { pub enum ReadError<'a> {
Read(std::io::Error), Read(std::io::Error),
ParseDefs(parser::Bag<'a, SyntaxError<'a>>), ParseDefs(SyntaxError<'a>),
ParseHeader(parser::Bag<'a, SyntaxError<'a>>), ParseHeader(SyntaxError<'a>),
DoesntHaveRocExtension, DoesntHaveRocExtension,
} }