Merge pull request #3241 from Skgland/parse-error-improvements
change `ParserError` type
This commit is contained in:
@@ -106,7 +106,7 @@ impl BranchStack {
|
|||||||
let branch_num = self
|
let branch_num = self
|
||||||
.last()
|
.last()
|
||||||
.map(|occurrences| occurrences.current_branch_num.clone())
|
.map(|occurrences| occurrences.current_branch_num.clone())
|
||||||
.unwrap_or_else(|| BranchNumber::default());
|
.unwrap_or_default();
|
||||||
|
|
||||||
BranchDesignator { branch_num }
|
BranchDesignator { branch_num }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct MachineError {
|
pub(crate) struct MachineError {
|
||||||
stub: MachineStub,
|
stub: MachineStub,
|
||||||
location: Option<(usize, usize)>, // line_num, col_num
|
location: Option<Location>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// from 7.12.2 b) of 13211-1:1995
|
// from 7.12.2 b) of 13211-1:1995
|
||||||
@@ -753,14 +753,15 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
|
pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
|
||||||
if let Some((line_num, _col_num)) = err.location {
|
if let Some(location) = err.location {
|
||||||
|
let line = location.line();
|
||||||
functor!(
|
functor!(
|
||||||
atom!("error"),
|
atom!("error"),
|
||||||
[
|
[
|
||||||
functor((err.stub)),
|
functor((err.stub)),
|
||||||
functor(
|
functor(
|
||||||
(atom!(":")),
|
(atom!(":")),
|
||||||
[functor(src), number(line_num, (&mut self.arena))]
|
[functor(src), number(line, (&mut self.arena))]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -853,9 +854,9 @@ impl From<ParserError> for CompilationError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CompilationError {
|
impl CompilationError {
|
||||||
pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
pub(crate) fn line_and_col_num(&self) -> Option<Location> {
|
||||||
match self {
|
match self {
|
||||||
CompilationError::ParserError(err) => err.line_and_col_num(),
|
CompilationError::ParserError(err) => err.location(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1952,7 +1952,7 @@ impl MachineState {
|
|||||||
) -> Result<Stream, ParserError> {
|
) -> Result<Stream, ParserError> {
|
||||||
match stream.peek_char() {
|
match stream.peek_char() {
|
||||||
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
|
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
|
||||||
Some(Err(e)) => Err(ParserError::IO(e)),
|
Some(Err(e)) => Err(ParserError::from(e)),
|
||||||
Some(Ok(c)) => {
|
Some(Ok(c)) => {
|
||||||
if c == '\u{feff}' {
|
if c == '\u{feff}' {
|
||||||
// skip UTF-8 BOM
|
// skip UTF-8 BOM
|
||||||
|
|||||||
@@ -1016,7 +1016,7 @@ impl MachineState {
|
|||||||
self.unify_fixnum(n, nx);
|
self.unify_fixnum(n, nx);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let err = ParserError::ParseBigInt(0, 0);
|
let err = parser.lexer.parse_big_int_error();
|
||||||
let err = self.syntax_error(err);
|
let err = self.syntax_error(err);
|
||||||
|
|
||||||
return Err(self.error_form(err, stub_gen()));
|
return Err(self.error_form(err, stub_gen()));
|
||||||
@@ -1026,9 +1026,7 @@ impl MachineState {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
let (line_num, col_num) = (lexer.line_num, lexer.col_num);
|
let err = lexer.unexpected_char(c);
|
||||||
|
|
||||||
let err = ParserError::UnexpectedChar(c, line_num, col_num);
|
|
||||||
let err = self.syntax_error(err);
|
let err = self.syntax_error(err);
|
||||||
|
|
||||||
return Err(self.error_form(err, stub_gen()));
|
return Err(self.error_form(err, stub_gen()));
|
||||||
@@ -9214,7 +9212,7 @@ impl Machine {
|
|||||||
stream.add_lines_read(parser.lines_read());
|
stream.add_lines_read(parser.lines_read());
|
||||||
}
|
}
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
stream.add_lines_read(parser.lexer.line_num);
|
stream.add_lines_read(parser.lexer.location.line());
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::offset_table::*;
|
use crate::offset_table::*;
|
||||||
use crate::parser::char_reader::*;
|
|
||||||
use crate::types::HeapCellValueTag;
|
use crate::types::HeapCellValueTag;
|
||||||
|
|
||||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||||
@@ -426,72 +425,92 @@ pub enum ArithmeticError {
|
|||||||
UninstantiatedVar,
|
UninstantiatedVar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Location {
|
||||||
|
pub(super) line: usize,
|
||||||
|
pub(super) column: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Location {
|
||||||
|
// beginning of file
|
||||||
|
pub(crate) const BOF: Self = Self { line: 0, column: 0 };
|
||||||
|
|
||||||
|
pub fn line(&self) -> usize {
|
||||||
|
self.line
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn column(&self) -> usize {
|
||||||
|
self.column
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParserError {
|
pub struct ParserError {
|
||||||
BackQuotedString(usize, usize),
|
pub(crate) location: Option<Location>,
|
||||||
|
pub(crate) kind: ParserErrorKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub(crate) enum ParserErrorKind {
|
||||||
|
BackQuotedString,
|
||||||
IO(IOError),
|
IO(IOError),
|
||||||
IncompleteReduction(usize, usize),
|
IncompleteReduction,
|
||||||
InfiniteFloat(usize, usize),
|
InfiniteFloat,
|
||||||
InvalidSingleQuotedCharacter(char),
|
InvalidSingleQuotedCharacter(char),
|
||||||
LexicalError(lexical::Error),
|
ParseFloat,
|
||||||
MissingQuote(usize, usize),
|
MissingQuote,
|
||||||
NonPrologChar(usize, usize),
|
NonPrologChar,
|
||||||
ParseBigInt(usize, usize),
|
ParseBigInt,
|
||||||
UnexpectedChar(char, usize, usize),
|
UnexpectedChar(char),
|
||||||
// UnexpectedEOF,
|
// UnexpectedEOF,
|
||||||
Utf8Error(usize, usize),
|
Utf8Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserError {
|
impl ParserError {
|
||||||
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
pub(crate) fn location(&self) -> Option<Location> {
|
||||||
match self {
|
self.location.as_ref().cloned()
|
||||||
&ParserError::BackQuotedString(line_num, col_num)
|
|
||||||
| &ParserError::IncompleteReduction(line_num, col_num)
|
|
||||||
| &ParserError::InfiniteFloat(line_num, col_num)
|
|
||||||
| &ParserError::MissingQuote(line_num, col_num)
|
|
||||||
| &ParserError::NonPrologChar(line_num, col_num)
|
|
||||||
| &ParserError::ParseBigInt(line_num, col_num)
|
|
||||||
| &ParserError::UnexpectedChar(_, line_num, col_num)
|
|
||||||
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_atom(&self) -> Atom {
|
pub(crate) fn as_atom(&self) -> Atom {
|
||||||
match self {
|
match &self.kind {
|
||||||
ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
|
ParserErrorKind::BackQuotedString => atom!("back_quoted_string"),
|
||||||
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
|
ParserErrorKind::IncompleteReduction => atom!("incomplete_reduction"),
|
||||||
ParserError::InvalidSingleQuotedCharacter(..) => {
|
ParserErrorKind::InvalidSingleQuotedCharacter(..) => {
|
||||||
atom!("invalid_single_quoted_character")
|
atom!("invalid_single_quoted_character")
|
||||||
}
|
}
|
||||||
ParserError::InfiniteFloat(..) => {
|
ParserErrorKind::InfiniteFloat => {
|
||||||
atom!("infinite_float")
|
atom!("infinite_float")
|
||||||
}
|
}
|
||||||
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
|
ParserErrorKind::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
|
||||||
atom!("unexpected_end_of_file")
|
atom!("unexpected_end_of_file")
|
||||||
}
|
}
|
||||||
ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => {
|
ParserErrorKind::IO(e) if e.kind() == ErrorKind::InvalidData => {
|
||||||
atom!("invalid_data")
|
atom!("invalid_data")
|
||||||
}
|
}
|
||||||
ParserError::IO(_) => atom!("input_output_error"),
|
ParserErrorKind::IO(_) => atom!("input_output_error"),
|
||||||
ParserError::LexicalError(_) => atom!("lexical_error"),
|
ParserErrorKind::ParseFloat => atom!("parse_float"),
|
||||||
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
ParserErrorKind::MissingQuote => atom!("missing_quote"),
|
||||||
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
|
ParserErrorKind::NonPrologChar => atom!("non_prolog_character"),
|
||||||
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
|
ParserErrorKind::ParseBigInt => atom!("cannot_parse_big_int"),
|
||||||
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
|
ParserErrorKind::UnexpectedChar(..) => atom!("unexpected_char"),
|
||||||
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
|
ParserErrorKind::Utf8Error => atom!("utf8_conversion_error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn unexpected_eof() -> Self {
|
pub(crate) fn unexpected_eof() -> Self {
|
||||||
ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof))
|
ParserError {
|
||||||
|
location: None,
|
||||||
|
kind: ParserErrorKind::IO(std::io::Error::from(ErrorKind::UnexpectedEof)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_unexpected_eof(&self) -> bool {
|
pub(crate) fn is_unexpected_eof(&self) -> bool {
|
||||||
if let ParserError::IO(e) = self {
|
if let ParserErrorKind::IO(e) = &self.kind {
|
||||||
e.kind() == ErrorKind::UnexpectedEof
|
e.kind() == ErrorKind::UnexpectedEof
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -499,24 +518,11 @@ impl ParserError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<lexical::Error> for ParserError {
|
|
||||||
fn from(e: lexical::Error) -> ParserError {
|
|
||||||
ParserError::LexicalError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IOError> for ParserError {
|
impl From<IOError> for ParserError {
|
||||||
fn from(e: IOError) -> ParserError {
|
fn from(e: IOError) -> ParserError {
|
||||||
ParserError::IO(e)
|
ParserError {
|
||||||
}
|
location: None,
|
||||||
}
|
kind: ParserErrorKind::IO(e),
|
||||||
|
|
||||||
impl From<&IOError> for ParserError {
|
|
||||||
fn from(error: &IOError) -> ParserError {
|
|
||||||
if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
|
|
||||||
ParserError::Utf8Error(0, 0)
|
|
||||||
} else {
|
|
||||||
ParserError::IO(error.kind().into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ macro_rules! consume_chars_with {
|
|||||||
match $e {
|
match $e {
|
||||||
Ok(Some(c)) => $token.push(c),
|
Ok(Some(c)) => $token.push(c),
|
||||||
Ok(None) => continue,
|
Ok(None) => continue,
|
||||||
Err($crate::parser::ast::ParserError::UnexpectedChar(..)) => break,
|
Err($crate::parser::ast::ParserError {
|
||||||
|
kind: $crate::parser::ast::ParserErrorKind::UnexpectedChar(..),
|
||||||
|
..
|
||||||
|
}) => break,
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,27 +94,45 @@ macro_rules! try_nt {
|
|||||||
pub(crate) struct Lexer<'a, R> {
|
pub(crate) struct Lexer<'a, R> {
|
||||||
pub(crate) reader: R,
|
pub(crate) reader: R,
|
||||||
pub(crate) machine_st: &'a mut MachineState,
|
pub(crate) machine_st: &'a mut MachineState,
|
||||||
pub(crate) line_num: usize,
|
pub(crate) location: Location,
|
||||||
pub(crate) col_num: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
|
impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("LexerParser")
|
f.debug_struct("LexerParser")
|
||||||
.field("reader", &"&'a mut R") // Hacky solution.
|
.field("reader", &"&'a mut R") // Hacky solution.
|
||||||
.field("line_num", &self.line_num)
|
.field("location", &self.location)
|
||||||
.field("col_num", &self.col_num)
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R> Lexer<'_, R> {
|
||||||
|
pub(crate) fn located_error(&self, kind: ParserErrorKind) -> ParserError {
|
||||||
|
ParserError {
|
||||||
|
location: Some(self.location.clone()),
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_big_int_error(&self) -> ParserError {
|
||||||
|
self.located_error(ParserErrorKind::ParseBigInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn incomplete_reduction(&self) -> ParserError {
|
||||||
|
self.located_error(ParserErrorKind::IncompleteReduction)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn unexpected_char(&self, c: char) -> ParserError {
|
||||||
|
self.located_error(ParserErrorKind::UnexpectedChar(c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, R: CharRead> Lexer<'a, R> {
|
impl<'a, R: CharRead> Lexer<'a, R> {
|
||||||
pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
|
pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reader: src,
|
reader: src,
|
||||||
machine_st,
|
machine_st,
|
||||||
line_num: 0,
|
location: Location::BOF,
|
||||||
col_num: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,10 +159,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
self.reader.consume(c.len_utf8());
|
self.reader.consume(c.len_utf8());
|
||||||
|
|
||||||
if new_line_char!(c) {
|
if new_line_char!(c) {
|
||||||
self.line_num += 1;
|
self.location.line += 1;
|
||||||
self.col_num = 0;
|
self.location.column = 0;
|
||||||
} else {
|
} else {
|
||||||
self.col_num += 1;
|
self.location.column += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,10 +221,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
|
|
||||||
match comment_loop() {
|
match comment_loop() {
|
||||||
Err(e) if e.is_unexpected_eof() => {
|
Err(e) if e.is_unexpected_eof() => {
|
||||||
return Err(ParserError::IncompleteReduction(
|
return Err(self.incomplete_reduction());
|
||||||
self.line_num,
|
|
||||||
self.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
@@ -215,7 +233,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::NonPrologChar(self.line_num, self.col_num))
|
Err(self.located_error(ParserErrorKind::NonPrologChar))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.return_char('/');
|
self.return_char('/');
|
||||||
@@ -232,7 +250,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
|
|
||||||
if !back_quote_char!(c2) {
|
if !back_quote_char!(c2) {
|
||||||
self.return_char(c);
|
self.return_char(c);
|
||||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
Err(self.unexpected_char(c))
|
||||||
} else {
|
} else {
|
||||||
self.skip_char(c2);
|
self.skip_char(c2);
|
||||||
Ok(c2)
|
Ok(c2)
|
||||||
@@ -257,7 +275,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
self.return_char(c);
|
self.return_char(c);
|
||||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
Err(self.unexpected_char(c))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.get_back_quoted_char().map(Some)
|
self.get_back_quoted_char().map(Some)
|
||||||
@@ -279,10 +297,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
Ok(token)
|
Ok(token)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::MissingQuote(self.line_num, self.col_num))
|
Err({
|
||||||
|
let this = &self;
|
||||||
|
this.located_error(ParserErrorKind::MissingQuote)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
Err(self.unexpected_char(c))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +334,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
|
|
||||||
if !single_quote_char!(c2) {
|
if !single_quote_char!(c2) {
|
||||||
self.return_char(c);
|
self.return_char(c);
|
||||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
Err(self.unexpected_char(c))
|
||||||
} else {
|
} else {
|
||||||
self.skip_char(c2);
|
self.skip_char(c2);
|
||||||
Ok(c2)
|
Ok(c2)
|
||||||
@@ -354,7 +375,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
|
|
||||||
if !double_quote_char!(c2) {
|
if !double_quote_char!(c2) {
|
||||||
self.return_char(c);
|
self.return_char(c);
|
||||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
Err(self.unexpected_char(c))
|
||||||
} else {
|
} else {
|
||||||
self.skip_char(c2);
|
self.skip_char(c2);
|
||||||
Ok(c2)
|
Ok(c2)
|
||||||
@@ -378,7 +399,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
't' => '\t',
|
't' => '\t',
|
||||||
'n' => '\n',
|
'n' => '\n',
|
||||||
'r' => '\r',
|
'r' => '\r',
|
||||||
c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)),
|
c => return Err(self.unexpected_char(c)),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
@@ -396,10 +417,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
if hexadecimal_digit_char!(c) {
|
if hexadecimal_digit_char!(c) {
|
||||||
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
|
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::IncompleteReduction(
|
Err(self.incomplete_reduction())
|
||||||
self.line_num,
|
|
||||||
self.col_num,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,17 +443,11 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
if backslash_char!(c) {
|
if backslash_char!(c) {
|
||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
u32::from_str_radix(&token, radix).map_or_else(
|
u32::from_str_radix(&token, radix).map_or_else(
|
||||||
|_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
|
|_| Err(self.parse_big_int_error()),
|
||||||
|n| {
|
|n| char::try_from(n).map_err(|_| self.located_error(ParserErrorKind::Utf8Error)),
|
||||||
char::try_from(n)
|
|
||||||
.map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num))
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::IncompleteReduction(
|
Err(self.incomplete_reduction())
|
||||||
self.line_num,
|
|
||||||
self.col_num,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,7 +459,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
Ok(c)
|
Ok(c)
|
||||||
} else {
|
} else {
|
||||||
if !backslash_char!(c) {
|
if !backslash_char!(c) {
|
||||||
return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num));
|
return Err(self.unexpected_char(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
@@ -478,7 +490,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
Ok(token)
|
Ok(token)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::MissingQuote(self.line_num, self.col_num))
|
Err({
|
||||||
|
let this = &self;
|
||||||
|
this.located_error(ParserErrorKind::MissingQuote)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,7 +524,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
.map(NumberToken::Integer)
|
.map(NumberToken::Integer)
|
||||||
} else {
|
} else {
|
||||||
self.return_char(start);
|
self.return_char(start);
|
||||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
Err(self.parse_big_int_error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +555,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
.map(NumberToken::Integer)
|
.map(NumberToken::Integer)
|
||||||
} else {
|
} else {
|
||||||
self.return_char(start);
|
self.return_char(start);
|
||||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
Err(self.parse_big_int_error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,7 +586,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
.map(NumberToken::Integer)
|
.map(NumberToken::Integer)
|
||||||
} else {
|
} else {
|
||||||
self.return_char(start);
|
self.return_char(start);
|
||||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
Err(self.parse_big_int_error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,11 +659,11 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(ParserError::InvalidSingleQuotedCharacter(c));
|
return Err(self.located_error(ParserErrorKind::InvalidSingleQuotedCharacter(c)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.get_back_quoted_string() {
|
match self.get_back_quoted_string() {
|
||||||
Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)),
|
Ok(_) => return Err(self.located_error(ParserErrorKind::BackQuotedString)),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,7 +684,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
) -> Result<(F64Offset, OrderedFloat<f64>), ParserError> {
|
) -> Result<(F64Offset, OrderedFloat<f64>), ParserError> {
|
||||||
self.return_char(token.pop().unwrap());
|
self.return_char(token.pop().unwrap());
|
||||||
|
|
||||||
let n = parse_float_lossy(&token)?;
|
let n = self.parse_float_lossy(&token)?;
|
||||||
let offset = float_alloc!(n, self.machine_st.arena);
|
let offset = float_alloc!(n, self.machine_st.arena);
|
||||||
|
|
||||||
Ok((offset, OrderedFloat(n)))
|
Ok((offset, OrderedFloat(n)))
|
||||||
@@ -686,7 +701,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
if decimal_digit_char!(c) {
|
if decimal_digit_char!(c) {
|
||||||
Ok(c)
|
Ok(c)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
|
Err(self.parse_big_int_error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(c)
|
Ok(c)
|
||||||
@@ -708,7 +723,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
Integer::from_str_radix(token, radix)
|
Integer::from_str_radix(token, radix)
|
||||||
.map(|n| GInteger::Integer(arena_alloc!(n, &mut self.machine_st.arena)))
|
.map(|n| GInteger::Integer(arena_alloc!(n, &mut self.machine_st.arena)))
|
||||||
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
|
.map_err(|_| self.parse_big_int_error())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,7 +821,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let n = parse_float_lossy(&token)?;
|
let n = self.parse_float_lossy(&token)?;
|
||||||
let offset = float_alloc!(n, self.machine_st.arena);
|
let offset = float_alloc!(n, self.machine_st.arena);
|
||||||
|
|
||||||
Ok(NumberToken::Float(offset, OrderedFloat(n)))
|
Ok(NumberToken::Float(offset, OrderedFloat(n)))
|
||||||
@@ -815,7 +830,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
.map(|(offset, fl)| NumberToken::Float(offset, fl))
|
.map(|(offset, fl)| NumberToken::Float(offset, fl))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let n = parse_float_lossy(&token)?;
|
let n = self.parse_float_lossy(&token)?;
|
||||||
let offset = float_alloc!(n, self.machine_st.arena);
|
let offset = float_alloc!(n, self.machine_st.arena);
|
||||||
Ok(NumberToken::Float(offset, OrderedFloat(n)))
|
Ok(NumberToken::Float(offset, OrderedFloat(n)))
|
||||||
}
|
}
|
||||||
@@ -826,7 +841,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
} else if token.starts_with('0') && token.len() == 1 {
|
} else if token.starts_with('0') && token.len() == 1 {
|
||||||
if c == 'x' {
|
if c == 'x' {
|
||||||
self.hexadecimal_constant(c).or_else(|e| {
|
self.hexadecimal_constant(c).or_else(|e| {
|
||||||
if let ParserError::ParseBigInt(..) = e {
|
if let ParserErrorKind::ParseBigInt = e.kind {
|
||||||
self.parse_integer(&token).map(NumberToken::Integer)
|
self.parse_integer(&token).map(NumberToken::Integer)
|
||||||
} else {
|
} else {
|
||||||
Err(e)
|
Err(e)
|
||||||
@@ -834,7 +849,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
})
|
})
|
||||||
} else if c == 'o' {
|
} else if c == 'o' {
|
||||||
self.octal_constant(c).or_else(|e| {
|
self.octal_constant(c).or_else(|e| {
|
||||||
if let ParserError::ParseBigInt(..) = e {
|
if let ParserErrorKind::ParseBigInt = e.kind {
|
||||||
self.parse_integer(&token).map(NumberToken::Integer)
|
self.parse_integer(&token).map(NumberToken::Integer)
|
||||||
} else {
|
} else {
|
||||||
Err(e)
|
Err(e)
|
||||||
@@ -842,7 +857,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
})
|
})
|
||||||
} else if c == 'b' {
|
} else if c == 'b' {
|
||||||
self.binary_constant(c).or_else(|e| {
|
self.binary_constant(c).or_else(|e| {
|
||||||
if let ParserError::ParseBigInt(..) = e {
|
if let ParserErrorKind::ParseBigInt = e.kind {
|
||||||
self.parse_integer(&token).map(NumberToken::Integer)
|
self.parse_integer(&token).map(NumberToken::Integer)
|
||||||
} else {
|
} else {
|
||||||
Err(e)
|
Err(e)
|
||||||
@@ -871,9 +886,9 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
self.get_single_quoted_char()
|
self.get_single_quoted_char()
|
||||||
.map(|c| NumberToken::Integer(GInteger::Fixnum(Fixnum::build_with(c))))
|
.map(|c| NumberToken::Integer(GInteger::Fixnum(Fixnum::build_with(c))))
|
||||||
.or_else(|err| {
|
.or_else(|err| {
|
||||||
match err {
|
match &err.kind {
|
||||||
ParserError::UnexpectedChar('\'', ..) => {}
|
ParserErrorKind::UnexpectedChar('\'', ..) => {}
|
||||||
err => return Err(err),
|
_ => return Err(err),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.return_char(c);
|
self.return_char(c);
|
||||||
@@ -954,7 +969,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
Ok(NumberToken::Partial(token_string)) => match self.parse_integer(&token_string) {
|
Ok(NumberToken::Partial(token_string)) => match self.parse_integer(&token_string) {
|
||||||
Ok(n) => Ok(Token::Literal(n.to_literal())),
|
Ok(n) => Ok(Token::Literal(n.to_literal())),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let n = parse_float_lossy(&token_string)?;
|
let n = self.parse_float_lossy(&token_string)?;
|
||||||
let offset = float_alloc!(n, self.machine_st.arena);
|
let offset = float_alloc!(n, self.machine_st.arena);
|
||||||
Ok(Token::Literal(Literal::F64(offset, OrderedFloat(n))))
|
Ok(Token::Literal(Literal::F64(offset, OrderedFloat(n))))
|
||||||
}
|
}
|
||||||
@@ -1068,14 +1083,17 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_float_lossy(token: &str) -> Result<f64, ParserError> {
|
fn parse_float_lossy(&self, token: &str) -> Result<f64, ParserError> {
|
||||||
const FORMAT: u128 = lexical::format::STANDARD;
|
const FORMAT: u128 = lexical::format::STANDARD;
|
||||||
let options = lexical::ParseFloatOptions::builder()
|
let Ok(options) = lexical::ParseFloatOptions::builder().lossy(true).build() else {
|
||||||
.lossy(true)
|
return Err(self.located_error(ParserErrorKind::ParseFloat));
|
||||||
.build()
|
};
|
||||||
.unwrap();
|
|
||||||
let n = lexical::parse_with_options::<f64, _, FORMAT>(token.as_bytes(), &options)?;
|
let Ok(n) = lexical::parse_with_options::<f64, _, FORMAT>(token.as_bytes(), &options)
|
||||||
|
else {
|
||||||
|
return Err(self.located_error(ParserErrorKind::ParseFloat));
|
||||||
|
};
|
||||||
Ok(n)
|
Ok(n)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -254,10 +254,7 @@ pub fn read_tokens<R: CharRead>(lexer: &mut Lexer<'_, R>) -> Result<Vec<Token>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => {
|
Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => {
|
||||||
return Err(ParserError::IncompleteReduction(
|
return Err(lexer.incomplete_reduction());
|
||||||
lexer.line_num,
|
|
||||||
lexer.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
@@ -700,12 +697,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
} else {
|
} else {
|
||||||
let term = match self.terms.pop() {
|
let term = match self.terms.pop() {
|
||||||
Some(term) => term,
|
Some(term) => term,
|
||||||
_ => {
|
_ => return Err(self.lexer.incomplete_reduction()),
|
||||||
return Err(ParserError::IncompleteReduction(
|
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.stack[idx].priority > 1000 {
|
if self.stack[idx].priority > 1000 {
|
||||||
@@ -718,10 +710,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if arity > self.terms.len() {
|
if arity > self.terms.len() {
|
||||||
return Err(ParserError::IncompleteReduction(
|
return Err(self.lexer.incomplete_reduction());
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let idx = self.terms.len() - arity;
|
let idx = self.terms.len() - arity;
|
||||||
@@ -789,12 +778,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
|
|
||||||
let term = match self.terms.pop() {
|
let term = match self.terms.pop() {
|
||||||
Some(term) => term,
|
Some(term) => term,
|
||||||
_ => {
|
_ => return Err(self.lexer.incomplete_reduction()),
|
||||||
return Err(ParserError::IncompleteReduction(
|
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.terms
|
self.terms
|
||||||
@@ -972,10 +956,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
self.negate_number(n, negate_rat_rc, Literal::Rational)
|
self.negate_number(n, negate_rat_rc, Literal::Rational)
|
||||||
}
|
}
|
||||||
Token::Literal(Literal::F64(_offset, n)) if n.is_infinite() => {
|
Token::Literal(Literal::F64(_offset, n)) if n.is_infinite() => {
|
||||||
return Err(ParserError::InfiniteFloat(
|
return Err(self.lexer.located_error(ParserErrorKind::InfiniteFloat));
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Token::Literal(Literal::F64(offset, n)) => {
|
Token::Literal(Literal::F64(offset, n)) => {
|
||||||
self.negate_number((offset, n), negate_f64, |(offset, n)| {
|
self.negate_number((offset, n), negate_f64, |(offset, n)| {
|
||||||
@@ -997,28 +978,19 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
|
Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
|
||||||
Token::Close => {
|
Token::Close => {
|
||||||
if !self.reduce_term() && !self.reduce_brackets() {
|
if !self.reduce_term() && !self.reduce_brackets() {
|
||||||
return Err(ParserError::IncompleteReduction(
|
return Err(self.lexer.incomplete_reduction());
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER),
|
Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER),
|
||||||
Token::CloseList => {
|
Token::CloseList => {
|
||||||
if !self.reduce_list()? {
|
if !self.reduce_list()? {
|
||||||
return Err(ParserError::IncompleteReduction(
|
return Err(self.lexer.incomplete_reduction());
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER),
|
Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER),
|
||||||
Token::CloseCurly => {
|
Token::CloseCurly => {
|
||||||
if !self.reduce_curly()? {
|
if !self.reduce_curly()? {
|
||||||
return Err(ParserError::IncompleteReduction(
|
return Err(self.lexer.incomplete_reduction());
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::HeadTailSeparator => {
|
Token::HeadTailSeparator => {
|
||||||
@@ -1051,12 +1023,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
| Some(TokenType::OpenList)
|
| Some(TokenType::OpenList)
|
||||||
| Some(TokenType::OpenCurly)
|
| Some(TokenType::OpenCurly)
|
||||||
| Some(TokenType::HeadTailSeparator)
|
| Some(TokenType::HeadTailSeparator)
|
||||||
| Some(TokenType::Comma) => {
|
| Some(TokenType::Comma) => return Err(self.lexer.incomplete_reduction()),
|
||||||
return Err(ParserError::IncompleteReduction(
|
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1066,12 +1033,12 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_lines_read(&mut self, lines_read: usize) {
|
pub fn add_lines_read(&mut self, lines_read: usize) {
|
||||||
self.lexer.line_num += lines_read;
|
self.lexer.location.line += lines_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lines_read(&self) -> usize {
|
pub fn lines_read(&self) -> usize {
|
||||||
self.lexer.line_num
|
self.lexer.location.line
|
||||||
}
|
}
|
||||||
|
|
||||||
// on success, returns the parsed term and the number of lines read.
|
// on success, returns the parsed term and the number of lines read.
|
||||||
@@ -1092,10 +1059,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
self.reduce_op(1400);
|
self.reduce_op(1400);
|
||||||
|
|
||||||
if self.terms.len() > 1 || self.stack.len() > 1 {
|
if self.terms.len() > 1 || self.stack.len() > 1 {
|
||||||
return Err(ParserError::IncompleteReduction(
|
return Err(self.lexer.incomplete_reduction());
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.terms.pop() {
|
match self.terms.pop() {
|
||||||
@@ -1103,16 +1067,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
if self.terms.is_empty() {
|
if self.terms.is_empty() {
|
||||||
Ok(term)
|
Ok(term)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::IncompleteReduction(
|
Err(self.lexer.incomplete_reduction())
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(ParserError::IncompleteReduction(
|
_ => Err(self.lexer.incomplete_reduction()),
|
||||||
self.lexer.line_num,
|
|
||||||
self.lexer.col_num,
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,12 +48,11 @@ pub(crate) fn error_after_read_term<R>(
|
|||||||
parser: &Parser<R>,
|
parser: &Parser<R>,
|
||||||
) -> CompilationError {
|
) -> CompilationError {
|
||||||
if err.is_unexpected_eof() {
|
if err.is_unexpected_eof() {
|
||||||
let line_num = parser.lexer.line_num;
|
let location = &parser.lexer.location;
|
||||||
let col_num = parser.lexer.col_num;
|
|
||||||
|
|
||||||
// rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
|
// rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
|
||||||
if !(line_num == prior_num_lines_read && col_num == 0) {
|
if !(location.line() == prior_num_lines_read && location.column() == 0) {
|
||||||
return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num));
|
return CompilationError::from(parser.lexer.incomplete_reduction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user