From: Mark Thom Date: Sun, 17 Feb 2019 07:55:22 +0000 (-0700) Subject: fix term expansion bug X-Git-Tag: v0.8.110~246 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=023fec0d9d32166a3f6c9b7e58a4ce4d467a3f85;p=scryer-prolog.git fix term expansion bug --- diff --git a/src/prolog/compile.rs b/src/prolog/compile.rs index 21ea3585..041ee425 100644 --- a/src/prolog/compile.rs +++ b/src/prolog/compile.rs @@ -255,7 +255,7 @@ impl ListingCompiler { compile_appendix(&mut decl_code, &queue, non_counted_bt, wam.machine_flags())?; - let idx = code_dir.entry((name, arity)).or_insert(CodeIndex::default()); + let idx = code_dir.entry((name.clone(), arity)).or_insert(CodeIndex::default()); set_code_index!(idx, IndexPtr::Index(p), self.get_module_name()); code.extend(decl_code.into_iter()); diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 4ca1cf26..e379e9d1 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -137,7 +137,7 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool { } impl MachineState { - pub fn numbervar(&self, addr: Addr) -> Option { + pub fn numbervar(&self, offset: &BigInt, addr: Addr) -> Option { static CHAR_CODES: [char; 26] = ['A','B','C','D','E','F','G','H','I','J', 'K','L','M','N','O','P','Q','R','S','T', 'U','V','W','X','Y','Z']; @@ -145,6 +145,8 @@ impl MachineState { match self.store(self.deref(addr)) { Addr::Con(Constant::Number(Number::Integer(ref n))) if !n.is_negative() => { + let n = offset + n.as_ref(); + let i = n.mod_floor(&BigInt::from(26)).to_usize().unwrap(); let j = n.div_floor(&BigInt::from(26)); @@ -168,6 +170,7 @@ pub struct HCPrinter<'a, Outputter> { heap_locs: ReverseHeapVarDict, printed_vars: HashSet, last_item_idx: usize, + pub(crate) numbervars_offset: BigInt, pub(crate) numbervars: bool, pub(crate) quoted: bool, pub(crate) ignore_ops: bool @@ -275,6 +278,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> printed_vars: HashSet::new(), last_item_idx: 0, numbervars: false, + numbervars_offset: BigInt::zero(), quoted: false, ignore_ops: false } } @@ -349,7 +353,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> let addr = iter.stack().last().cloned().unwrap(); // 7.10.4 - if let Some(var) = iter.machine_st().numbervar(addr) { + if let Some(var) = iter.machine_st().numbervar(&self.numbervars_offset, addr) { iter.stack().pop(); self.state_stack.push(TokenOrRedirect::NumberedVar(var)); return; diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index ae6847c1..16838836 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -603,13 +603,13 @@ pub(crate) trait CallPolicy: Any { ref addr if addr.is_ref() => { let stub = MachineError::functor_stub(clause_name!("if_"), 3); let err = MachineError::instantiation_error(); - + Err(machine_st.error_form(err, stub)) }, addr => { let stub = MachineError::functor_stub(clause_name!("if_"), 3); let err = MachineError::type_error(ValidType::Boolean, addr); - + Err(machine_st.error_form(err, stub)) } } diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 1152c8c7..12385931 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -10,6 +10,7 @@ use prolog::num::{ToPrimitive, Zero}; use prolog::num::bigint::{BigInt}; use std::collections::HashSet; +use std::io::{stdout, Write}; use std::mem; use std::rc::Rc; @@ -653,6 +654,7 @@ impl MachineState { let mut output = printer.print(addr); print!("{}", output.result()); + stdout().flush().unwrap(); } }; diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index 2b336973..0674e8a3 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -3,6 +3,7 @@ use prolog_parser::parser::*; use prolog::instructions::HeapCellValue; use prolog::machine::*; +use prolog::num::*; use prolog::read::*; use std::cell::Cell; @@ -287,12 +288,20 @@ impl<'a, R: Read> TermStream<'a, R> { } impl MachineState { - fn print_with_locs(&self, target: usize, var_dict: &HeapVarDict) -> PrinterOutputter { + fn print_with_locs(&self, target: usize, max_var_length: usize, var_dict: &HeapVarDict) + -> PrinterOutputter + { let output = PrinterOutputter::new(); let mut printer = HCPrinter::from_heap_locs(&self, output, &var_dict); printer.quoted = true; printer.numbervars = true; + // the purpose of the offset is to avoid clashes with variable names that might + // occur after the addresses in the expanded term are substituted with the variable + // names in the pre-expansion term. This formula ensures that all generated "numbervars"- + // style variable names will be longer than the keys of the var_dict, and therefore + // not equal to any of them. + printer.numbervars_offset = pow(BigInt::from(10), max_var_length) * 26; printer.see_all_locs(); @@ -303,10 +312,10 @@ impl MachineState { code_repo: &mut CodeRepo, term: &Term, hook: CompileTimeHook) -> Option { - let (term_h, var_dict) = write_term_to_heap(term, self); + let term_write_result = write_term_to_heap(term, self); let h = self.heap.h; - self[temp_v!(1)] = Addr::HeapCell(term_h); + self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc); self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); self[temp_v!(2)] = Addr::HeapCell(h); @@ -319,7 +328,8 @@ impl MachineState { self.reset(); None } else { - let mut output = self.print_with_locs(h, &var_dict); + let &TermWriteResult { heap_loc: _, max_var_length, ref var_dict } = &term_write_result; + let mut output = self.print_with_locs(h, max_var_length, var_dict); output.push_char('.'); self.reset(); diff --git a/src/prolog/read.rs b/src/prolog/read.rs index 6dc39e3e..d72a813f 100644 --- a/src/prolog/read.rs +++ b/src/prolog/read.rs @@ -53,7 +53,7 @@ impl MachineState { let mut parser = Parser::new(inner, atom_tbl, self.flags); let term = parser.read_term(composite_op!(op_dir))?; - Ok(write_term_to_heap(&term, self).0) + Ok(write_term_to_heap(&term, self).heap_loc) } } @@ -73,9 +73,17 @@ fn modify_head_of_queue(machine_st: &mut MachineState, queue: &mut SubtermDeque, } } -pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> (usize, HeapVarDict) { - let h = machine_st.heap.h; +pub(crate) struct TermWriteResult { + pub(crate) heap_loc: usize, + pub(crate) max_var_length: usize, // maximum length of the variable names encountered. + pub(crate) var_dict: HeapVarDict, +} +pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult +{ + let heap_loc = machine_st.heap.h; + + let mut max_var_length = 0; let mut queue = SubtermDeque::new(); let mut var_dict = HeapVarDict::new(); @@ -108,10 +116,12 @@ pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> continue; } }, - &TermRef::AnonVar(Level::Root) - | &TermRef::Var(Level::Root, ..) - | &TermRef::Constant(Level::Root, ..) => + &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))), + &TermRef::Var(Level::Root, _, ref name) => { + max_var_length = std::cmp::max(max_var_length, name.len()); + machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))); + }, &TermRef::AnonVar(_) => { if let Some((arity, site_h)) = queue.pop_front() { if arity > 1 { @@ -134,6 +144,7 @@ pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> } } + max_var_length = std::cmp::max(max_var_length, var.len()); continue; }, _ => {} @@ -142,5 +153,5 @@ pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> modify_head_of_queue(machine_st, &mut queue, term, h); } - (h, var_dict) + TermWriteResult { heap_loc, var_dict, max_var_length } }