]> Repositorios git - scryer-prolog.git/commitdiff
use machine-generated PartialEq instance for hashing Constant (#817)
authorMark Thom <[email protected]>
Fri, 12 Feb 2021 01:40:07 +0000 (18:40 -0700)
committerMark Thom <[email protected]>
Fri, 12 Feb 2021 01:40:23 +0000 (18:40 -0700)
Cargo.lock
crates/prolog_parser/src/ast.rs
crates/prolog_parser/src/lexer.rs
crates/prolog_parser/src/parser.rs
src/machine/preprocessor.rs

index 43771e591a1fad522fb979bed7aae99a2772e832..4224695441bce8ec9e9ec14398280d1327471f61 100644 (file)
@@ -881,6 +881,7 @@ dependencies = [
 name = "prolog_parser"
 version = "0.8.68"
 dependencies = [
+ "indexmap",
  "lexical",
  "num-rug-adapter",
  "ordered-float",
index 3b9a928713f1332b05508f4dd6fea0cc3dbaa0ac..f6703d1016e5b575e9ff3dc1e077f729309d30f6 100644 (file)
@@ -494,7 +494,7 @@ impl Hash for SharedOpDesc {
     }
 }
 
-#[derive(Debug, Clone, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Constant {
     Atom(ClauseName, Option<SharedOpDesc>),
     Char(char),
@@ -529,17 +529,22 @@ impl fmt::Display for Constant {
     }
 }
 
-impl PartialEq for Constant {
-    fn eq(&self, other: &Constant) -> bool {
-        match (self, other) {
-            (&Constant::Atom(ref atom, _), &Constant::Char(c))
+/*
+ * By defining constant_eq as the PartialEq instance of Constant, we
+ * sometimes hash constants it considers identical to the same value,
+ * which can make the WAM fail erroneously. This can be avoided by
+ * using the machine-generated PartialEq for hashing.
+ */
+pub fn constant_eq(arg: &Constant, other: &Constant) -> bool {
+    match (arg, other) {
+        (&Constant::Atom(ref atom, _), &Constant::Char(c))
             | (&Constant::Char(c), &Constant::Atom(ref atom, _)) => {
                 atom.is_char() && atom.as_str().starts_with(c)
             }
-            (&Constant::Atom(ref a1, _), &Constant::Atom(ref a2, _)) => a1.as_str() == a2.as_str(),
-            (&Constant::Char(c1), &Constant::Char(c2)) => c1 == c2,
-            (&Constant::Fixnum(n1), &Constant::Fixnum(n2)) => n1 == n2,
-            (&Constant::Fixnum(n1), &Constant::Integer(ref n2))
+        (&Constant::Atom(ref a1, _), &Constant::Atom(ref a2, _)) => a1.as_str() == a2.as_str(),
+        (&Constant::Char(c1), &Constant::Char(c2)) => c1 == c2,
+        (&Constant::Fixnum(n1), &Constant::Fixnum(n2)) => n1 == n2,
+        (&Constant::Fixnum(n1), &Constant::Integer(ref n2))
             | (&Constant::Integer(ref n2), &Constant::Fixnum(n1)) => {
                 if let Some(n2) = n2.to_isize() {
                     n1 == n2
@@ -547,19 +552,16 @@ impl PartialEq for Constant {
                     false
                 }
             }
-            (&Constant::Integer(ref n1), &Constant::Integer(ref n2)) => n1 == n2,
-            (&Constant::Rational(ref n1), &Constant::Rational(ref n2)) => n1 == n2,
-            (&Constant::Float(ref n1), &Constant::Float(ref n2)) => n1 == n2,
-            (&Constant::String(ref s1), &Constant::String(ref s2)) => s1 == s2,
-            (&Constant::EmptyList, &Constant::EmptyList) => true,
-            (&Constant::Usize(u1), &Constant::Usize(u2)) => u1 == u2,
-            _ => false,
-        }
+        (&Constant::Integer(ref n1), &Constant::Integer(ref n2)) => n1 == n2,
+        (&Constant::Rational(ref n1), &Constant::Rational(ref n2)) => n1 == n2,
+        (&Constant::Float(ref n1), &Constant::Float(ref n2)) => n1 == n2,
+        (&Constant::String(ref s1), &Constant::String(ref s2)) => s1 == s2,
+        (&Constant::EmptyList, &Constant::EmptyList) => true,
+        (&Constant::Usize(u1), &Constant::Usize(u2)) => u1 == u2,
+        _ => false,
     }
 }
 
-impl Eq for Constant {}
-
 impl Constant {
     pub fn to_atom(&self) -> Option<ClauseName> {
         match self {
@@ -703,7 +705,7 @@ impl AsRef<str> for ClauseName {
     }
 }
 
-#[derive(Debug, PartialEq, Eq, Clone)]
+#[derive(Debug, Clone)]
 pub enum Term {
     AnonVar,
     Clause(
index 75a3a91e176aaf1eec412f7b9091008d7942ed28..b9bda1d0f71371ae4057a5d4d7748330e51e24df 100644 (file)
@@ -33,7 +33,7 @@ macro_rules! consume_chars_with {
     };
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone)]
 pub enum Token {
     Constant(Constant),
     Var(Rc<Atom>),
@@ -49,6 +49,17 @@ pub enum Token {
     End,
 }
 
+impl Token {
+    #[inline]
+    pub(super) fn is_end(&self) -> bool {
+        if let Token::End = self {
+            true
+        } else {
+            false
+        }
+    }
+}
+
 pub struct Lexer<'a, R: Read> {
     pub(crate) atom_tbl: TabledData<Atom>,
     pub(crate) reader: &'a mut ParsingStream<R>,
index 60cebc905631def266c60e05c34b0de45a5f2341..f36552320a00adc77fcd8cd6e1cd0c659a9fb653 100644 (file)
@@ -200,7 +200,7 @@ fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError>
 
     loop {
         let token = lexer.next_token()?;
-        let at_end = Token::End == token;
+        let at_end = token.is_end();
 
         tokens.push(token);
 
index 4a8bd7b43c1d5e03bd04bfbb400750c14e9f5da9..dc0205337a990cd19f8c160ab19bc75713b4da2d 100644 (file)
@@ -174,7 +174,7 @@ pub(super) fn setup_module_export_list(
         export_list = *t2;
     }
 
-    if export_list.into_constant() != Some(Constant::EmptyList) {
+    if export_list.into_constant().map(|c| !constant_eq(&c, &Constant::EmptyList)).unwrap_or(true) {
         Err(CompilationError::InvalidModuleDecl)
     } else {
         Ok(exports)
@@ -273,7 +273,7 @@ fn setup_qualified_import(
         export_list = *t2;
     }
 
-    if export_list.into_constant() != Some(Constant::EmptyList) {
+    if export_list.into_constant().map(|c| !constant_eq(&c, &Constant::EmptyList)).unwrap_or(true) {
         Err(CompilationError::InvalidModuleDecl)
     } else {
         Ok((module_src, exports))