]> Repositorios git - scryer-prolog.git/commitdiff
record compaction depth after reduce_op if '|' an operator (#1905)
authorMark <[email protected]>
Sat, 23 Sep 2023 06:19:54 +0000 (00:19 -0600)
committerMark <[email protected]>
Sat, 23 Sep 2023 06:19:54 +0000 (00:19 -0600)
src/parser/ast.rs
src/parser/parser.rs

index 1351b044687b2b500e6e14ed84cf2b9f7346b165..a03602df078d1d56e29a73fbabf4ea1dad94d7df 100644 (file)
@@ -808,7 +808,7 @@ pub fn source_arity(terms: &[Term]) -> usize {
     terms.len()
 }
 
-fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
+pub(crate) fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
     if let Term::Clause(_, ref name, ref mut subterms) = term {
         if let Some(last_arg) = subterms.last() {
             if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
index 2160c764a34ef08d0c8b23cf80f04753c753fc01..57193239fc06cdb148e5759ff25f3de39c40b3d3 100644 (file)
@@ -58,6 +58,7 @@ struct TokenDesc {
     tt: TokenType,
     priority: usize,
     spec: u32,
+    unfold_bounds: usize,
 }
 
 pub(crate) fn as_partial_string(
@@ -371,6 +372,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                         tt: TokenType::Term,
                         priority: td.priority,
                         spec,
+                        unfold_bounds: 0,
                     });
                 }
             }
@@ -392,6 +394,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                         tt: TokenType::Term,
                         priority: td.priority,
                         spec,
+                        unfold_bounds: 0,
                     });
                 }
             }
@@ -405,6 +408,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             tt: TokenType::Term,
             priority,
             spec: assoc,
+            unfold_bounds: 0,
         });
     }
 
@@ -460,7 +464,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             Token::End => TokenType::End,
         };
 
-        self.stack.push(TokenDesc { tt, priority, spec });
+        self.stack.push(TokenDesc { tt, priority, spec, unfold_bounds: 0, });
     }
 
     fn reduce_op(&mut self, priority: usize) {
@@ -602,14 +606,16 @@ impl<'a, R: CharRead> Parser<'a, R> {
                     }
 
                     if let Some(&mut TokenDesc {
+                        ref mut tt,
                         ref mut priority,
                         ref mut spec,
-                        ref mut tt,
+                        ref mut unfold_bounds,
                     }) = self.stack.last_mut()
                     {
                         *tt = TokenType::Term;
                         *priority = 0;
                         *spec = TERM;
+                        *unfold_bounds = 0;
                     }
 
                     return true;
@@ -625,8 +631,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
     }
 
     fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
-        if let Some(term) = self.terms.pop() {
-            let op_desc = self.stack[index - 1];
+        if let Some(mut term) = self.terms.pop() {
+            let mut op_desc = self.stack[index - 1];
 
             if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority {
                 /* '|' is a head-tail separator here, not
@@ -634,7 +640,26 @@ impl<'a, R: CharRead> Parser<'a, R> {
                  * terms it compacted out again. */
                 match (term.name(), term.arity()) {
                     (Some(name), 2) if name == atom!(",") => {
-                        let terms = unfold_by_str(term, name); // notice: name == "," here.
+                        let terms = if op_desc.unfold_bounds == 0 {
+                            unfold_by_str(term, atom!(","))
+                        } else {
+                            let mut terms = vec![];
+
+                            while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) {
+                                terms.push(fst);
+                                term = snd;
+
+                                op_desc.unfold_bounds -= 2;
+
+                                if op_desc.unfold_bounds == 0 {
+                                    break;
+                                }
+                            }
+
+                            terms.push(term);
+                            terms
+                        };
+
                         let arity = terms.len() - 1;
 
                         self.terms.extend(terms.into_iter());
@@ -750,6 +775,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             tt: TokenType::Term,
             priority: 0,
             spec: TERM,
+            unfold_bounds: 0,
         });
 
         self.terms.push(match list {
@@ -975,6 +1001,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             ),
             Token::Literal(c) => {
                 let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c);
+
                 if let Some(name) = atomized {
                     if !self.shift_op(name, op_dir)? {
                         self.shift(Token::Literal(c), 0, TERM);
@@ -1018,13 +1045,20 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 /* '|' as an operator must have priority > 1000 and can only be infix.
                  * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78
                  */
-                let bar_atom = atom!("|");
-
-                let (priority, spec) = get_op_desc(bar_atom, op_dir)
+                let (priority, spec) = get_op_desc(atom!("|"), op_dir)
                     .map(|CompositeOpDesc { inf, spec, .. }| (inf, spec))
                     .unwrap_or((1000, DELIMITER));
 
+                let old_stack_len = self.stack.len();
+
                 self.reduce_op(priority);
+
+                let new_stack_len = self.stack.len();
+
+                if let Some(term_desc) = self.stack.last_mut() {
+                    term_desc.unfold_bounds = old_stack_len - new_stack_len;
+                }
+
                 self.shift(Token::HeadTailSeparator, priority, spec);
             }
             Token::Comma => {