]> Repositorios git - scryer-prolog.git/commitdiff
fix term expansion bug
authorMark Thom <[email protected]>
Sun, 17 Feb 2019 07:55:22 +0000 (00:55 -0700)
committerMark Thom <[email protected]>
Sun, 17 Feb 2019 07:55:22 +0000 (00:55 -0700)
src/prolog/compile.rs
src/prolog/heap_print.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/system_calls.rs
src/prolog/machine/term_expansion.rs
src/prolog/read.rs

index 21ea358574a94a917994c03bcfb76763cd021fcd..041ee425032c811c5a28d58058ff4a566c000234 100644 (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());
index 4ca1cf267fc105b6f7d2f5540aadd56497408eda..e379e9d1fd91691d168c00badbc5ff25362d41bf 100644 (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;
index ae6847c13e634dfaecfab3b10fcf9d60f8e65d27..1683883672a13f764c9c9a1fda8c45e8c0e4ba38 100644 (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))
                     }
                 }
index 1152c8c760fd9ddf710b0ecc0b9dc690f3b9653e..123859313e73e54825b26e06dc29b4ea70bec203 100644 (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();
             }
         };
 
index 2b336973e3093caf5550953d7148e8da586cec69..0674e8a3a8b6141c8dc76f8de06243e1b9cdc7d5 100644 (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();
index 6dc39e3e85c119f9aa91781cfabf20f44ba1434f..d72a813fdd2d4ed8f9ae64063fbe3d037423950a 100644 (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 }
 }