record compaction depth after reduce_op if '|' an operator (#1905)

This commit is contained in:
Mark
2023-09-23 00:19:54 -06:00
parent c547f67c54
commit 1c8cd85f6c
2 changed files with 43 additions and 9 deletions

View File

@@ -808,7 +808,7 @@ pub fn source_arity(terms: &[Term]) -> usize {
terms.len() 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 Term::Clause(_, ref name, ref mut subterms) = term {
if let Some(last_arg) = subterms.last() { if let Some(last_arg) = subterms.last() {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {

View File

@@ -58,6 +58,7 @@ struct TokenDesc {
tt: TokenType, tt: TokenType,
priority: usize, priority: usize,
spec: u32, spec: u32,
unfold_bounds: usize,
} }
pub(crate) fn as_partial_string( pub(crate) fn as_partial_string(
@@ -371,6 +372,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
tt: TokenType::Term, tt: TokenType::Term,
priority: td.priority, priority: td.priority,
spec, spec,
unfold_bounds: 0,
}); });
} }
} }
@@ -392,6 +394,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
tt: TokenType::Term, tt: TokenType::Term,
priority: td.priority, priority: td.priority,
spec, spec,
unfold_bounds: 0,
}); });
} }
} }
@@ -405,6 +408,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
tt: TokenType::Term, tt: TokenType::Term,
priority, priority,
spec: assoc, spec: assoc,
unfold_bounds: 0,
}); });
} }
@@ -460,7 +464,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
Token::End => TokenType::End, 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) { fn reduce_op(&mut self, priority: usize) {
@@ -602,14 +606,16 @@ impl<'a, R: CharRead> Parser<'a, R> {
} }
if let Some(&mut TokenDesc { if let Some(&mut TokenDesc {
ref mut tt,
ref mut priority, ref mut priority,
ref mut spec, ref mut spec,
ref mut tt, ref mut unfold_bounds,
}) = self.stack.last_mut() }) = self.stack.last_mut()
{ {
*tt = TokenType::Term; *tt = TokenType::Term;
*priority = 0; *priority = 0;
*spec = TERM; *spec = TERM;
*unfold_bounds = 0;
} }
return true; return true;
@@ -625,8 +631,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
} }
fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
if let Some(term) = self.terms.pop() { if let Some(mut term) = self.terms.pop() {
let op_desc = self.stack[index - 1]; let mut op_desc = self.stack[index - 1];
if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority {
/* '|' is a head-tail separator here, not /* '|' is a head-tail separator here, not
@@ -634,7 +640,26 @@ impl<'a, R: CharRead> Parser<'a, R> {
* terms it compacted out again. */ * terms it compacted out again. */
match (term.name(), term.arity()) { match (term.name(), term.arity()) {
(Some(name), 2) if name == atom!(",") => { (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; let arity = terms.len() - 1;
self.terms.extend(terms.into_iter()); self.terms.extend(terms.into_iter());
@@ -750,6 +775,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
tt: TokenType::Term, tt: TokenType::Term,
priority: 0, priority: 0,
spec: TERM, spec: TERM,
unfold_bounds: 0,
}); });
self.terms.push(match list { self.terms.push(match list {
@@ -975,6 +1001,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
), ),
Token::Literal(c) => { Token::Literal(c) => {
let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c); let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c);
if let Some(name) = atomized { if let Some(name) = atomized {
if !self.shift_op(name, op_dir)? { if !self.shift_op(name, op_dir)? {
self.shift(Token::Literal(c), 0, TERM); 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. /* '|' 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 * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78
*/ */
let bar_atom = atom!("|"); let (priority, spec) = get_op_desc(atom!("|"), op_dir)
let (priority, spec) = get_op_desc(bar_atom, op_dir)
.map(|CompositeOpDesc { inf, spec, .. }| (inf, spec)) .map(|CompositeOpDesc { inf, spec, .. }| (inf, spec))
.unwrap_or((1000, DELIMITER)); .unwrap_or((1000, DELIMITER));
let old_stack_len = self.stack.len();
self.reduce_op(priority); 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); self.shift(Token::HeadTailSeparator, priority, spec);
} }
Token::Comma => { Token::Comma => {