) -> Result<Stream, ParserError> {
match stream.peek_char() {
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)) => {
if c == '\u{feff}' {
// skip UTF-8 BOM
self.unify_fixnum(n, nx);
}
_ => {
- let err = ParserError::ParseBigInt(parser.lexer.location.clone());
+ let err = parser.lexer.parse_big_int_error();
let err = self.syntax_error(err);
return Err(self.error_form(err, stub_gen()));
return Ok(());
}
Ok(c) => {
- let err = ParserError::UnexpectedChar(c, lexer.location);
+ let err = lexer.unexpected_char(c);
let err = self.syntax_error(err);
return Err(self.error_form(err, stub_gen()));
#[allow(dead_code)]
#[derive(Debug)]
-pub enum ParserError {
- BackQuotedString(Location),
+pub struct ParserError {
+ pub(crate) location: Option<Location>,
+ pub(crate) kind: ParserErrorKind,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum ParserErrorKind {
+ BackQuotedString,
IO(IOError),
- IncompleteReduction(Location),
- InfiniteFloat(Location),
- InvalidSingleQuotedCharacter(char, Location),
+ IncompleteReduction,
+ InfiniteFloat,
+ InvalidSingleQuotedCharacter(char),
LexicalError(lexical::Error),
- MissingQuote(Location),
- NonPrologChar(Location),
- ParseBigInt(Location),
- UnexpectedChar(char, Location),
+ MissingQuote,
+ NonPrologChar,
+ ParseBigInt,
+ UnexpectedChar(char),
// UnexpectedEOF,
- Utf8Error(Option<Location>),
+ Utf8Error,
}
impl ParserError {
pub fn location(&self) -> Option<Location> {
- match self {
- ParserError::BackQuotedString(location)
- | ParserError::InvalidSingleQuotedCharacter(_, location)
- | ParserError::IncompleteReduction(location)
- | ParserError::InfiniteFloat(location)
- | ParserError::MissingQuote(location)
- | ParserError::NonPrologChar(location)
- | ParserError::ParseBigInt(location)
- | ParserError::UnexpectedChar(_, location) => Some(location.clone()),
- ParserError::Utf8Error(location) => location.as_ref().cloned(),
- ParserError::IO(_) | ParserError::LexicalError(_) => None,
- }
+ self.location.as_ref().cloned()
}
pub fn as_atom(&self) -> Atom {
- match self {
- ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
- ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
- ParserError::InvalidSingleQuotedCharacter(..) => {
+ match &self.kind {
+ ParserErrorKind::BackQuotedString => atom!("back_quoted_string"),
+ ParserErrorKind::IncompleteReduction => atom!("incomplete_reduction"),
+ ParserErrorKind::InvalidSingleQuotedCharacter(..) => {
atom!("invalid_single_quoted_character")
}
- ParserError::InfiniteFloat(..) => {
+ ParserErrorKind::InfiniteFloat => {
atom!("infinite_float")
}
- ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
+ ParserErrorKind::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
atom!("unexpected_end_of_file")
}
- ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => {
+ ParserErrorKind::IO(e) if e.kind() == ErrorKind::InvalidData => {
atom!("invalid_data")
}
- ParserError::IO(_) => atom!("input_output_error"),
- ParserError::LexicalError(_) => atom!("lexical_error"),
- ParserError::MissingQuote(..) => atom!("missing_quote"),
- ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
- ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
- ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
- ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
+ ParserErrorKind::IO(_) => atom!("input_output_error"),
+ ParserErrorKind::LexicalError(_) => atom!("lexical_error"),
+ ParserErrorKind::MissingQuote => atom!("missing_quote"),
+ ParserErrorKind::NonPrologChar => atom!("non_prolog_character"),
+ ParserErrorKind::ParseBigInt => atom!("cannot_parse_big_int"),
+ ParserErrorKind::UnexpectedChar(..) => atom!("unexpected_char"),
+ ParserErrorKind::Utf8Error => atom!("utf8_conversion_error"),
}
}
#[inline]
pub 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]
pub fn is_unexpected_eof(&self) -> bool {
- if let ParserError::IO(e) = self {
+ if let ParserErrorKind::IO(e) = &self.kind {
e.kind() == ErrorKind::UnexpectedEof
} else {
false
impl From<lexical::Error> for ParserError {
fn from(e: lexical::Error) -> ParserError {
- ParserError::LexicalError(e)
+ ParserError {
+ location: None,
+ kind: ParserErrorKind::LexicalError(e),
+ }
}
}
impl From<IOError> for ParserError {
fn from(e: IOError) -> ParserError {
- ParserError::IO(e)
- }
-}
-
-impl From<&IOError> for ParserError {
- fn from(error: &IOError) -> ParserError {
- if let Some(_utf8_error) = error
- .get_ref()
- .and_then(|e| e.downcast_ref::<BadUtf8Error>())
- {
- ParserError::Utf8Error(None)
- } else {
- ParserError::IO(error.kind().into())
+ ParserError {
+ location: None,
+ kind: ParserErrorKind::IO(e),
}
}
}
match $e {
Ok(Some(c)) => $token.push(c),
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),
}
}
}
}
+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> {
pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
Self {
match comment_loop() {
Err(e) if e.is_unexpected_eof() => {
- return Err(ParserError::IncompleteReduction(self.location.clone()));
+ return Err(self.incomplete_reduction());
}
Err(e) => {
return Err(e);
self.skip_char(c);
Ok(true)
} else {
- Err(ParserError::NonPrologChar(self.location.clone()))
+ Err(self.located_error(ParserErrorKind::NonPrologChar))
}
} else {
self.return_char('/');
if !back_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.location.clone()))
+ Err(self.unexpected_char(c))
} else {
self.skip_char(c2);
Ok(c2)
Ok(None)
} else {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.location.clone()))
+ Err(self.unexpected_char(c))
}
} else {
self.get_back_quoted_char().map(Some)
self.skip_char(c);
Ok(token)
} else {
- Err(ParserError::MissingQuote(self.location.clone()))
+ Err({
+ let this = &self;
+ this.located_error(ParserErrorKind::MissingQuote)
+ })
}
} else {
- Err(ParserError::UnexpectedChar(c, self.location.clone()))
+ Err(self.unexpected_char(c))
}
}
if !single_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.location.clone()))
+ Err(self.unexpected_char(c))
} else {
self.skip_char(c2);
Ok(c2)
if !double_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.location.clone()))
+ Err(self.unexpected_char(c))
} else {
self.skip_char(c2);
Ok(c2)
't' => '\t',
'n' => '\n',
'r' => '\r',
- c => return Err(ParserError::UnexpectedChar(c, self.location.clone())),
+ c => return Err(self.unexpected_char(c)),
};
self.skip_char(c);
if hexadecimal_digit_char!(c) {
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
} else {
- Err(ParserError::IncompleteReduction(self.location.clone()))
+ Err(self.incomplete_reduction())
}
}
if backslash_char!(c) {
self.skip_char(c);
u32::from_str_radix(&token, radix).map_or_else(
- |_| Err(ParserError::ParseBigInt(self.location.clone())),
- |n| {
- char::try_from(n)
- .map_err(|_| ParserError::Utf8Error(Some(self.location.clone())))
- },
+ |_| Err(self.parse_big_int_error()),
+ |n| char::try_from(n).map_err(|_| self.located_error(ParserErrorKind::Utf8Error)),
)
} else {
- Err(ParserError::IncompleteReduction(self.location.clone()))
+ Err(self.incomplete_reduction())
}
}
Ok(c)
} else {
if !backslash_char!(c) {
- return Err(ParserError::UnexpectedChar(c, self.location.clone()));
+ return Err(self.unexpected_char(c));
}
self.skip_char(c);
self.skip_char(c);
Ok(token)
} else {
- Err(ParserError::MissingQuote(self.location.clone()))
+ Err({
+ let this = &self;
+ this.located_error(ParserErrorKind::MissingQuote)
+ })
}
}
.map(NumberToken::Integer)
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.location.clone()))
+ Err(self.parse_big_int_error())
}
}
.map(NumberToken::Integer)
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.location.clone()))
+ Err(self.parse_big_int_error())
}
}
.map(NumberToken::Integer)
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.location.clone()))
+ Err(self.parse_big_int_error())
}
}
}
}
} else {
- return Err(ParserError::InvalidSingleQuotedCharacter(
- c,
- self.location.clone(),
- ));
+ return Err(self.located_error(ParserErrorKind::InvalidSingleQuotedCharacter(c)));
}
} else {
match self.get_back_quoted_string() {
- Ok(_) => return Err(ParserError::BackQuotedString(self.location.clone())),
+ Ok(_) => return Err(self.located_error(ParserErrorKind::BackQuotedString)),
Err(e) => return Err(e),
}
}
if decimal_digit_char!(c) {
Ok(c)
} else {
- Err(ParserError::ParseBigInt(self.location.clone()))
+ Err(self.parse_big_int_error())
}
} else {
Ok(c)
.or_else(|_| {
Integer::from_str_radix(token, radix)
.map(|n| GInteger::Integer(arena_alloc!(n, &mut self.machine_st.arena)))
- .map_err(|_| ParserError::ParseBigInt(self.location.clone()))
+ .map_err(|_| self.parse_big_int_error())
})
}
} else if token.starts_with('0') && token.len() == 1 {
if c == 'x' {
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)
} else {
Err(e)
})
} else if c == 'o' {
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)
} else {
Err(e)
})
} else if c == 'b' {
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)
} else {
Err(e)
self.get_single_quoted_char()
.map(|c| NumberToken::Integer(GInteger::Fixnum(Fixnum::build_with(c))))
.or_else(|err| {
- match err {
- ParserError::UnexpectedChar('\'', ..) => {}
- err => return Err(err),
+ match &err.kind {
+ ParserErrorKind::UnexpectedChar('\'', ..) => {}
+ _ => return Err(err),
}
self.return_char(c);
}
}
Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => {
- return Err(ParserError::IncompleteReduction(lexer.location.clone()));
+ return Err(lexer.incomplete_reduction());
}
Err(e) => {
return Err(e);
} else {
let term = match self.terms.pop() {
Some(term) => term,
- _ => {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ))
- }
+ _ => return Err(self.lexer.incomplete_reduction()),
};
if self.stack[idx].priority > 1000 {
};
if arity > self.terms.len() {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ));
+ return Err(self.lexer.incomplete_reduction());
}
let idx = self.terms.len() - arity;
let term = match self.terms.pop() {
Some(term) => term,
- _ => {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ))
- }
+ _ => return Err(self.lexer.incomplete_reduction()),
};
self.terms
self.negate_number(n, negate_rat_rc, Literal::Rational)
}
Token::Literal(Literal::F64(_offset, n)) if n.is_infinite() => {
- return Err(ParserError::InfiniteFloat(self.lexer.location.clone()));
+ return Err(self.lexer.located_error(ParserErrorKind::InfiniteFloat));
}
Token::Literal(Literal::F64(offset, n)) => {
self.negate_number((offset, n), negate_f64, |(offset, n)| {
Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
Token::Close => {
if !self.reduce_term() && !self.reduce_brackets() {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ));
+ return Err(self.lexer.incomplete_reduction());
}
}
Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER),
Token::CloseList => {
if !self.reduce_list()? {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ));
+ return Err(self.lexer.incomplete_reduction());
}
}
Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER),
Token::CloseCurly => {
if !self.reduce_curly()? {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ));
+ return Err(self.lexer.incomplete_reduction());
}
}
Token::HeadTailSeparator => {
| Some(TokenType::OpenList)
| Some(TokenType::OpenCurly)
| Some(TokenType::HeadTailSeparator)
- | Some(TokenType::Comma) => {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ))
- }
+ | Some(TokenType::Comma) => return Err(self.lexer.incomplete_reduction()),
_ => {}
},
}
self.reduce_op(1400);
if self.terms.len() > 1 || self.stack.len() > 1 {
- return Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ));
+ return Err(self.lexer.incomplete_reduction());
}
match self.terms.pop() {
if self.terms.is_empty() {
Ok(term)
} else {
- Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- ))
+ Err(self.lexer.incomplete_reduction())
}
}
- _ => Err(ParserError::IncompleteReduction(
- self.lexer.location.clone(),
- )),
+ _ => Err(self.lexer.incomplete_reduction()),
}
}
}
// rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
if !(location.line() == prior_num_lines_read && location.column() == 0) {
- return CompilationError::from(ParserError::IncompleteReduction(
- parser.lexer.location.clone(),
- ));
+ return CompilationError::from(parser.lexer.incomplete_reduction());
}
}