fix term expansion bug

This commit is contained in:
Mark Thom
2019-02-17 00:55:22 -07:00
parent b7dd76bf37
commit 023fec0d9d
6 changed files with 43 additions and 16 deletions

View File

@@ -255,7 +255,7 @@ impl ListingCompiler {
compile_appendix(&mut decl_code, &queue, non_counted_bt, wam.machine_flags())?; 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()); set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
code.extend(decl_code.into_iter()); code.extend(decl_code.into_iter());

View File

@@ -137,7 +137,7 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
} }
impl MachineState { impl MachineState {
pub fn numbervar(&self, addr: Addr) -> Option<Var> { pub fn numbervar(&self, offset: &BigInt, addr: Addr) -> Option<Var> {
static CHAR_CODES: [char; 26] = ['A','B','C','D','E','F','G','H','I','J', 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', 'K','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z']; 'U','V','W','X','Y','Z'];
@@ -145,6 +145,8 @@ impl MachineState {
match self.store(self.deref(addr)) { match self.store(self.deref(addr)) {
Addr::Con(Constant::Number(Number::Integer(ref n))) Addr::Con(Constant::Number(Number::Integer(ref n)))
if !n.is_negative() => { if !n.is_negative() => {
let n = offset + n.as_ref();
let i = n.mod_floor(&BigInt::from(26)).to_usize().unwrap(); let i = n.mod_floor(&BigInt::from(26)).to_usize().unwrap();
let j = n.div_floor(&BigInt::from(26)); let j = n.div_floor(&BigInt::from(26));
@@ -168,6 +170,7 @@ pub struct HCPrinter<'a, Outputter> {
heap_locs: ReverseHeapVarDict, heap_locs: ReverseHeapVarDict,
printed_vars: HashSet<Addr>, printed_vars: HashSet<Addr>,
last_item_idx: usize, last_item_idx: usize,
pub(crate) numbervars_offset: BigInt,
pub(crate) numbervars: bool, pub(crate) numbervars: bool,
pub(crate) quoted: bool, pub(crate) quoted: bool,
pub(crate) ignore_ops: bool pub(crate) ignore_ops: bool
@@ -275,6 +278,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
printed_vars: HashSet::new(), printed_vars: HashSet::new(),
last_item_idx: 0, last_item_idx: 0,
numbervars: false, numbervars: false,
numbervars_offset: BigInt::zero(),
quoted: false, quoted: false,
ignore_ops: false } ignore_ops: false }
} }
@@ -349,7 +353,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
let addr = iter.stack().last().cloned().unwrap(); let addr = iter.stack().last().cloned().unwrap();
// 7.10.4 // 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(); iter.stack().pop();
self.state_stack.push(TokenOrRedirect::NumberedVar(var)); self.state_stack.push(TokenOrRedirect::NumberedVar(var));
return; return;

View File

@@ -603,13 +603,13 @@ pub(crate) trait CallPolicy: Any {
ref addr if addr.is_ref() => { ref addr if addr.is_ref() => {
let stub = MachineError::functor_stub(clause_name!("if_"), 3); let stub = MachineError::functor_stub(clause_name!("if_"), 3);
let err = MachineError::instantiation_error(); let err = MachineError::instantiation_error();
Err(machine_st.error_form(err, stub)) Err(machine_st.error_form(err, stub))
}, },
addr => { addr => {
let stub = MachineError::functor_stub(clause_name!("if_"), 3); let stub = MachineError::functor_stub(clause_name!("if_"), 3);
let err = MachineError::type_error(ValidType::Boolean, addr); let err = MachineError::type_error(ValidType::Boolean, addr);
Err(machine_st.error_form(err, stub)) Err(machine_st.error_form(err, stub))
} }
} }

View File

@@ -10,6 +10,7 @@ use prolog::num::{ToPrimitive, Zero};
use prolog::num::bigint::{BigInt}; use prolog::num::bigint::{BigInt};
use std::collections::HashSet; use std::collections::HashSet;
use std::io::{stdout, Write};
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
@@ -653,6 +654,7 @@ impl MachineState {
let mut output = printer.print(addr); let mut output = printer.print(addr);
print!("{}", output.result()); print!("{}", output.result());
stdout().flush().unwrap();
} }
}; };

View File

@@ -3,6 +3,7 @@ use prolog_parser::parser::*;
use prolog::instructions::HeapCellValue; use prolog::instructions::HeapCellValue;
use prolog::machine::*; use prolog::machine::*;
use prolog::num::*;
use prolog::read::*; use prolog::read::*;
use std::cell::Cell; use std::cell::Cell;
@@ -287,12 +288,20 @@ impl<'a, R: Read> TermStream<'a, R> {
} }
impl MachineState { 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 output = PrinterOutputter::new();
let mut printer = HCPrinter::from_heap_locs(&self, output, &var_dict); let mut printer = HCPrinter::from_heap_locs(&self, output, &var_dict);
printer.quoted = true; printer.quoted = true;
printer.numbervars = 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(); printer.see_all_locs();
@@ -303,10 +312,10 @@ impl MachineState {
code_repo: &mut CodeRepo, term: &Term, hook: CompileTimeHook) code_repo: &mut CodeRepo, term: &Term, hook: CompileTimeHook)
-> Option<String> -> Option<String>
{ {
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; 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.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self[temp_v!(2)] = Addr::HeapCell(h); self[temp_v!(2)] = Addr::HeapCell(h);
@@ -319,7 +328,8 @@ impl MachineState {
self.reset(); self.reset();
None None
} else { } 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('.'); output.push_char('.');
self.reset(); self.reset();

View File

@@ -53,7 +53,7 @@ impl MachineState {
let mut parser = Parser::new(inner, atom_tbl, self.flags); let mut parser = Parser::new(inner, atom_tbl, self.flags);
let term = parser.read_term(composite_op!(op_dir))?; 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) { pub(crate) struct TermWriteResult {
let h = machine_st.heap.h; 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 queue = SubtermDeque::new();
let mut var_dict = HeapVarDict::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; continue;
} }
}, },
&TermRef::AnonVar(Level::Root) &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) =>
| &TermRef::Var(Level::Root, ..)
| &TermRef::Constant(Level::Root, ..) =>
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))), 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(_) => { &TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = queue.pop_front() { if let Some((arity, site_h)) = queue.pop_front() {
if arity > 1 { 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; 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); modify_head_of_queue(machine_st, &mut queue, term, h);
} }
(h, var_dict) TermWriteResult { heap_loc, var_dict, max_var_length }
} }