fail when end of input is not reached by parser

This commit is contained in:
Folkert 2021-02-01 16:38:14 +01:00
parent 37f17da27e
commit 8f5df8b7b8
4 changed files with 45 additions and 7 deletions

View file

@ -3385,9 +3385,23 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
let mut module_timing = header.module_timing;
let parse_start = SystemTime::now();
let parse_state = parser::State::new(&header.src, Attempting::Module);
let (parsed_defs, _) = module_defs()
.parse(&arena, parse_state)
.expect("TODO gracefully handle parse error on module defs. IMPORTANT: Bail out entirely if there are any BadUtf8 problems! That means the whole source file is not valid UTF-8 and any other errors we report may get mis-reported. We rely on this for safety in an `unsafe` block later on in this function.");
let parsed_defs = match module_defs().parse(&arena, parse_state) {
Ok((success, _state)) => success,
Err((fail, state)) => {
use roc_parse::parser::FailReason;
match fail.reason {
FailReason::BadUtf8 => panic!(
r"TODO gracefully handle parse error on module defs. IMPORTANT: Bail out entirely if there are any BadUtf8 problems! That means the whole source file is not valid UTF-8 and any other errors we report may get mis-reported. We rely on this for safety in an `unsafe` block later on in this function."
),
_ => panic!(
"Parser Error\nmodule: {:?}\nattempting: {:?}\n(line, col): {:?}\n",
header.module_id,
fail.attempting,
(state.line, state.column)
),
}
}
};
let parsed_defs = parsed_defs.into_bump_slice();

View file

@ -8,8 +8,8 @@ use crate::header::{
};
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
use crate::parser::{
self, ascii_char, ascii_string, loc, optional, peek_utf8_char, peek_utf8_char_at, unexpected,
unexpected_eof, Either, ParseResult, Parser, State,
self, ascii_char, ascii_string, end_of_file, loc, optional, peek_utf8_char, peek_utf8_char_at,
unexpected, unexpected_eof, Either, ParseResult, Parser, State,
};
use crate::string_literal;
use crate::type_annotation;
@ -290,7 +290,11 @@ pub fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>> {
#[inline(always)]
pub fn module_defs<'a>() -> impl Parser<'a, Vec<'a, Located<Def<'a>>>> {
zero_or_more!(space0_around(loc(def(0)), 0))
// this parses just the defs
let defs = zero_or_more!(space0_around(loc(def(0)), 0));
// but when parsing a file, we really want to reach the end of the file
skip_second!(defs, end_of_file())
}
struct ProvidesTo<'a> {

View file

@ -75,6 +75,11 @@ impl<'a> State<'a> {
self.original_len - self.bytes.len()
}
/// Returns whether the parser has reached the end of the input
pub fn has_reached_end(&self) -> bool {
self.bytes.len() == 0
}
/// Increments the line, then resets column, indent_col, and is_indenting.
/// Advances the input by 1, to consume the newline character.
pub fn newline(&self) -> Result<Self, (Fail, Self)> {
@ -1278,3 +1283,18 @@ pub fn parse_utf8(bytes: &[u8]) -> Result<&str, FailReason> {
Err(_) => Err(FailReason::BadUtf8),
}
}
pub fn end_of_file<'a>() -> impl Parser<'a, ()> {
|_arena: &'a Bump, state: State<'a>| {
if state.has_reached_end() {
Ok(((), state))
} else {
let fail = Fail {
attempting: state.attempting,
reason: FailReason::ConditionFailed,
};
Err((fail, state))
}
}
}

View file

@ -854,7 +854,7 @@ mod solve_expr {
infer_eq(
indoc!(
r#"
\f -> (\a, b -> f b a),
\f -> (\a, b -> f b a)
"#
),
"(a, b -> c) -> (b, a -> c)",