]> Repositorios git - scryer-prolog.git/commitdiff
make ParserError a struct with an enum kind field
authorSkgland <[email protected]>
Sat, 24 Jan 2026 02:24:02 +0000 (03:24 +0100)
committerBennet Bleßmann <[email protected]>
Sat, 24 Jan 2026 03:08:40 +0000 (04:08 +0100)
src/machine/streams.rs
src/machine/system_calls.rs
src/parser/ast.rs
src/parser/lexer.rs
src/parser/parser.rs
src/read.rs

index 0d88ca5846cd61f590f285c812e97ab42d8d70d4..760c684046a97463673c7172bf510105f9cb1f06 100644 (file)
@@ -1952,7 +1952,7 @@ impl MachineState {
     ) -> 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
index f676315375d27cf597a2f65be7dc9f6b92588325..59ba39758af4e6886738ccb5f74a8fb3ada5837b 100644 (file)
@@ -1016,7 +1016,7 @@ impl MachineState {
                             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()));
@@ -1026,7 +1026,7 @@ impl MachineState {
                     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()));
index 17caae2429903521e1c2e25f8126c427482ea5d8..18f2335d5d37c59d078063feacdb146dcf4d3e21 100644 (file)
@@ -447,71 +447,71 @@ impl Location {
 
 #[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
@@ -521,25 +521,18 @@ impl ParserError {
 
 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),
         }
     }
 }
index 7acf76b681adfd0e6448f2169e9baa158dfaa1aa..0d3f8941c0a8a48994c867409d3a12e7676ef0b1 100644 (file)
@@ -16,7 +16,10 @@ macro_rules! consume_chars_with {
             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),
             }
         }
@@ -103,6 +106,27 @@ impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
     }
 }
 
+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 {
@@ -197,7 +221,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
             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);
@@ -209,7 +233,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 self.skip_char(c);
                 Ok(true)
             } else {
-                Err(ParserError::NonPrologChar(self.location.clone()))
+                Err(self.located_error(ParserErrorKind::NonPrologChar))
             }
         } else {
             self.return_char('/');
@@ -226,7 +250,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
             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)
@@ -251,7 +275,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 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)
@@ -273,10 +297,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 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))
         }
     }
 
@@ -307,7 +334,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
             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)
@@ -348,7 +375,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
             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)
@@ -372,7 +399,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             '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);
@@ -390,7 +417,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         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())
         }
     }
 
@@ -416,14 +443,11 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         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())
         }
     }
 
@@ -435,7 +459,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             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);
@@ -466,7 +490,10 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             self.skip_char(c);
             Ok(token)
         } else {
-            Err(ParserError::MissingQuote(self.location.clone()))
+            Err({
+                let this = &self;
+                this.located_error(ParserErrorKind::MissingQuote)
+            })
         }
     }
 
@@ -497,7 +524,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 .map(NumberToken::Integer)
         } else {
             self.return_char(start);
-            Err(ParserError::ParseBigInt(self.location.clone()))
+            Err(self.parse_big_int_error())
         }
     }
 
@@ -528,7 +555,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 .map(NumberToken::Integer)
         } else {
             self.return_char(start);
-            Err(ParserError::ParseBigInt(self.location.clone()))
+            Err(self.parse_big_int_error())
         }
     }
 
@@ -559,7 +586,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 .map(NumberToken::Integer)
         } else {
             self.return_char(start);
-            Err(ParserError::ParseBigInt(self.location.clone()))
+            Err(self.parse_big_int_error())
         }
     }
 
@@ -632,14 +659,11 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                     }
                 }
             } 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),
             }
         }
@@ -677,7 +701,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             if decimal_digit_char!(c) {
                 Ok(c)
             } else {
-                Err(ParserError::ParseBigInt(self.location.clone()))
+                Err(self.parse_big_int_error())
             }
         } else {
             Ok(c)
@@ -699,7 +723,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             .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())
             })
     }
 
@@ -817,7 +841,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         } 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)
@@ -825,7 +849,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 })
             } 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)
@@ -833,7 +857,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 })
             } 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)
@@ -862,9 +886,9 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 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);
index eda980c9f5b92619902764dda09687f8069bcbd2..a72919089cc771fef29692a46e2b79c9716dff41 100644 (file)
@@ -254,7 +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() => {
-                return Err(ParserError::IncompleteReduction(lexer.location.clone()));
+                return Err(lexer.incomplete_reduction());
             }
             Err(e) => {
                 return Err(e);
@@ -697,11 +697,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
         } 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 {
@@ -714,9 +710,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
         };
 
         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;
@@ -784,11 +778,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
                         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
@@ -966,7 +956,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 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)| {
@@ -988,25 +978,19 @@ impl<'a, R: CharRead> Parser<'a, R> {
             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 => {
@@ -1039,11 +1023,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 | 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()),
                 _ => {}
             },
         }
@@ -1079,9 +1059,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
         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() {
@@ -1089,14 +1067,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 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()),
         }
     }
 }
index 9f578bf8b28fb89fc5d22a167b1393f4d20291da..a07f4d0990e53556b19dfb10ca039af91cbe8904 100644 (file)
@@ -52,9 +52,7 @@ pub(crate) fn error_after_read_term<R>(
 
         // 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());
         }
     }