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())?;
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());

View File

@@ -137,7 +137,7 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
}
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',
'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<Addr>,
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;

View File

@@ -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))
}
}

View File

@@ -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();
}
};

View File

@@ -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<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;
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();

View File

@@ -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 }
}