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())?;
|
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());
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user