fix term expansion bug
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user