]> Repositorios git - scryer-prolog.git/commitdiff
add top level exception reporting, exceptions for call/N.
authorMark Thom <[email protected]>
Fri, 18 Aug 2017 00:20:58 +0000 (18:20 -0600)
committerMark Thom <[email protected]>
Fri, 18 Aug 2017 00:20:58 +0000 (18:20 -0600)
README.md
src/prolog/codegen.rs
src/prolog/io.rs
src/prolog/machine.rs
src/prolog/macros.rs

index 0f7fcca1eb9eb2a8fad4511238cb2198b170566d..26233865abbf906603e90ae19307d4ecab4e9471 100644 (file)
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ ideally, very fast) [Shen](http://shenlanguage.org) implementation.
 The following predicates are built-in to rusty-wam.
 
 * atomic/1
-* call/N (0 <= N <= 62)
+* call/N (1 <= N <= 63)
 * catch/3
 * duplicate_term/2
 * false/0
index 3e3acabb0076c7e4aa179f11159674f9771a2ea3..503771400829a2f67f21b8aa2767936a4a6317aa 100644 (file)
@@ -18,6 +18,7 @@ pub enum EvalSession<'a> {
     EntrySuccess,
     InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
     QueryFailure,
+    QueryFailureWithException(String),
     SubsequentQuerySuccess,
 }
 
index 89a4b49598f0cd989ebe2b7b96b955f33a7fa132..f971e4db0deb682399b7189b4c1cbc487112c729 100644 (file)
@@ -403,6 +403,10 @@ Each predicate must have the same name and arity.";
     }
 }
 
+fn error_string(e: &String) -> String {
+    format!("error: {}", e)
+}
+
 pub fn print(wam: &mut Machine, result: EvalSession) {
     match result {
         EvalSession::InitialQuerySuccess(alloc_locs, mut heap_locs) => {
@@ -451,6 +455,12 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
                         stdout.flush().unwrap();
                         return;
                     }
+
+                    if let &EvalSession::QueryFailureWithException(ref e) = &result {
+                        write!(stdout, "{}\n\r", error_string(e)).unwrap();
+                        stdout.flush().unwrap();
+                        return;
+                    }
                 } else {
                     break;
                 }
@@ -459,6 +469,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
             write!(stdout(), ".\n").unwrap();
         },
         EvalSession::QueryFailure => println!("false."),
+        EvalSession::QueryFailureWithException(e) => println!("{}", error_string(&e)),
         EvalSession::EntryFailure(msg) => println!("{}", msg),
         _ => {}
     };
index a04d53612d960d66ab42bd3a959f5c10334857c3..f58bc73d6205fed26894614b76af0cb8d2e99d17 100644 (file)
@@ -51,7 +51,7 @@ impl<'a> DuplicateTerm<'a> {
 
 impl<'a> Index<usize> for DuplicateTerm<'a> {
     type Output = HeapCellValue;
-    
+
     fn index(&self, index: usize) -> &Self::Output {
         &self.state.heap[index]
     }
@@ -72,7 +72,7 @@ impl<'a> CopierTarget for DuplicateTerm<'a> {
     fn threshold(&self) -> usize {
         self.state.h
     }
-    
+
     fn push(&mut self, hcv: HeapCellValue) {
         self.state.heap.push(hcv);
         self.state.h += 1;
@@ -105,7 +105,7 @@ impl<'a> DuplicateBallTerm<'a> {
 
 impl<'a> Index<usize> for DuplicateBallTerm<'a> {
     type Output = HeapCellValue;
-    
+
     fn index(&self, index: usize) -> &Self::Output {
         if index < self.heap_boundary {
             &self.state.heap[index]
@@ -136,9 +136,9 @@ impl<'a> CopierTarget for DuplicateBallTerm<'a> {
     fn threshold(&self) -> usize {
         self.heap_boundary + self.state.ball.1.len()
     }
-    
+
     fn push(&mut self, hcv: HeapCellValue) {
-        self.state.ball.1.push(hcv);        
+        self.state.ball.1.push(hcv);
     }
 
     fn store(&self, a: Addr) -> Addr {
@@ -284,9 +284,6 @@ impl Machine {
 
     fn execute_instr(&mut self)
     {
-        // can't use self[ptr] or self.index(ptr) to set the value of
-        // instr! instr is then typed as Line, not &Line. WHY????
-        // This is a compiler bug. Has to be.
         let instr = match self.ms.p {
             CodePtr::TopLevel(_, p) => {
                 match &self.cached_query {
@@ -377,7 +374,7 @@ impl Machine {
             };
         }
     }
-    
+
     fn record_var_places<'a>(&self,
                              chunk_num: usize,
                              alloc_locs: &AllocVarDict<'a>,
@@ -409,10 +406,6 @@ impl Machine {
 
         while self.ms.p < end_ptr {
             if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
-                //TODO: Shouldn't have to work nearly this hard!! Why
-                // are we only recording addresses, for instance? Why
-                // not just offsets into the heap? Not like they
-                // change.
                 if let &Line::Control(ref ctrl_instr) = &self[CodePtr::TopLevel(cn, p)] {
                     if ctrl_instr.is_jump_instr() {
                         self.record_var_places(cn, alloc_locs, heap_locs);
@@ -432,6 +425,18 @@ impl Machine {
         }
     }
 
+    fn fail<'a>(&mut self) -> EvalSession<'a>
+    {
+        if self.ms.ball.1.len() > 0 {
+            let h = self.ms.h;
+            self.ms.copy_and_align_ball_to_heap();
+
+            EvalSession::QueryFailureWithException(self.print_term(&Addr::HeapCell(h)))
+        } else {
+            EvalSession::QueryFailure
+        }
+    }
+
     pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
     {
         let mut heap_locs = HashMap::new();
@@ -440,16 +445,14 @@ impl Machine {
         self.run_query(&alloc_locs, &mut heap_locs);
 
         if self.failed() {
-            EvalSession::QueryFailure
+            self.fail()
         } else {
             EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
         }
     }
 
-    pub fn continue_query<'a>(&mut self,
-                              alloc_locs: &AllocVarDict<'a>,
-                              heap_locs: &mut HeapVarDict<'a>)
-                              -> EvalSession
+    pub fn continue_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
+                              -> EvalSession<'a>
     {
         if !self.or_stack_is_empty() {
             let b = self.ms.b - 1;
@@ -462,7 +465,7 @@ impl Machine {
             self.run_query(alloc_locs, heap_locs);
 
             if self.failed() {
-                EvalSession::QueryFailure
+                self.fail()
             } else {
                 EvalSession::SubsequentQuerySuccess
             }
@@ -471,14 +474,58 @@ impl Machine {
         }
     }
 
+    fn print_term(&self, addr: &Addr) -> String
+    {
+        let mut viewer = HeapCellViewer::new(&self.ms.heap,
+                                             &self.ms.and_stack,
+                                             addr);
+
+        let mut result = String::new();
+
+        while let Some(view) = viewer.next() {
+            match view {
+                CellView::Con(&Constant::BlockNum(integer)) =>
+                    result += integer.to_string().as_str(),
+                CellView::Con(&Constant::EmptyList) =>
+                    result += "[]",
+                CellView::Con(&Constant::Atom(ref atom)) =>
+                    result += atom.as_str(),
+                CellView::HeapVar(cell_num) => {
+                    result += "_";
+                    result += cell_num.to_string().as_str();
+                },
+                CellView::StackVar(_, cell_num) => {
+                        result += "s_";
+                    result += cell_num.to_string().as_str();
+                },
+                CellView::Str(_, ref name) =>
+                    result += name.as_str(),
+                CellView::TToken(TToken::Bar) => {
+                    match viewer.peek() {
+                        Some(CellView::Con(&Constant::EmptyList)) => {
+                            viewer.next();
+                        },
+                        Some(CellView::TToken(TToken::LSBracket(loc))) => {
+                            result += ", ";
+
+                            viewer.next();
+                            viewer.remove_token(loc);
+                        },
+                        _ => result += " | "
+                    };
+                },
+                CellView::TToken(token) =>
+                    result += token.as_str()
+            };
+        }
+
+        result
+    }
+
     pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
         let mut result = String::new();
 
         for (var, addr) in var_dir {
-            let mut viewer = HeapCellViewer::new(&self.ms.heap,
-                                                 &self.ms.and_stack,
-                                                 addr);
-
             if result != "" {
                 result += "\n\r";
             }
@@ -486,42 +533,7 @@ impl Machine {
             result += var.as_str();
             result += " = ";
 
-            while let Some(view) = viewer.next() {
-                match view {
-                    CellView::Con(&Constant::BlockNum(integer)) =>
-                        result += integer.to_string().as_str(),
-                    CellView::Con(&Constant::EmptyList) =>
-                        result += "[]",
-                    CellView::Con(&Constant::Atom(ref atom)) =>
-                        result += atom.as_str(),
-                    CellView::HeapVar(cell_num) => {
-                        result += "_";
-                        result += cell_num.to_string().as_str();
-                    },
-                    CellView::StackVar(_, cell_num) => {
-                        result += "s_";
-                        result += cell_num.to_string().as_str();
-                    },
-                    CellView::Str(_, ref name) =>
-                        result += name.as_str(),
-                    CellView::TToken(TToken::Bar) => {
-                        match viewer.peek() {
-                            Some(CellView::Con(&Constant::EmptyList)) => {
-                                viewer.next();
-                            },
-                            Some(CellView::TToken(TToken::LSBracket(loc))) => {
-                                result += ", ";
-
-                                viewer.next();
-                                viewer.remove_token(loc);
-                            },
-                            _ => result += " | "
-                        };
-                    },
-                    CellView::TToken(token) =>
-                        result += token.as_str()
-                };
-            }
+            result += self.print_term(addr).as_str();
         }
 
         result
@@ -565,7 +577,7 @@ impl MachineState {
                        ball: (0, Vec::new())
         }
     }
-    
+
     fn num_frames(&self) -> usize {
         self.and_stack.len() + self.or_stack.len()
     }
@@ -1143,15 +1155,38 @@ impl MachineState {
         }
     }
 
+    fn goto_throw(&mut self) {
+        self.num_of_args = 1;
+        self.b0 = self.b;
+        self.p  = CodePtr::DirEntry(59);
+    }
+
+    fn throw_exception(&mut self, mut hcv: Vec<HeapCellValue>) {
+        let h = self.h;
+        
+        self.registers[1] = Addr::HeapCell(h);
+        self.h += hcv.len();
+        
+        self.heap.append(&mut hcv);        
+        self.goto_throw();
+    }
+
     fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey>
     {
-        let addr = self.deref(self.registers[arity].clone());
+        let addr = self.store(self.deref(self.registers[arity].clone()));
 
-        let (name, narity) = match self.store(addr) {
+        let (name, narity) = match addr {
             Addr::Str(a) => {
                 let result = self.heap[a].clone();
 
                 if let HeapCellValue::NamedStr(narity, name) = result {
+                    if narity + arity > 63 {
+                        self.throw_exception(functor!("representation_error",
+                                                      1,
+                                                      [atom!("exceeds_max_arity")]));
+                        return None;
+                    }
+
                     for i in (1 .. arity).rev() {
                         self.registers[i + narity] = self.registers[i].clone();
                     }
@@ -1167,8 +1202,15 @@ impl MachineState {
                 }
             },
             Addr::Con(Constant::Atom(name)) => (name, 0),
+            Addr::HeapCell(_) | Addr::StackCell(_, _) => {
+                self.throw_exception(functor!("instantiation_error", 0, []));
+                return None;
+            },
             _ => {
-                self.fail = true;
+                self.throw_exception(functor!("type_error",
+                                              2,
+                                              [atom!("callable"),
+                                               HeapCellValue::from(addr)]));
                 return None;
             }
         };
@@ -1176,22 +1218,39 @@ impl MachineState {
         Some((name, arity + narity - 1))
     }
 
+    fn copy_and_align_ball_to_heap(&mut self) {
+        let diff = self.ball.0 - self.h;
+
+        for heap_value in self.ball.1.iter().cloned() {
+            self.heap.push(match heap_value {
+                HeapCellValue::Con(c) => HeapCellValue::Con(c),
+                HeapCellValue::Lis(a) => HeapCellValue::Lis(a - diff),
+                HeapCellValue::Ref(Ref::HeapCell(hc)) =>
+                    HeapCellValue::Ref(Ref::HeapCell(hc - diff)),
+                HeapCellValue::Str(s) => HeapCellValue::Str(s - diff),
+                _ => heap_value
+            });
+        }
+
+        self.h += self.ball.1.len();
+    }
+
     fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
     {
         match instr {
             &BuiltInInstruction::DuplicateTerm => {
                 let old_h = self.h;
-                
+
                 let a1 = self[temp_v!(1)].clone();
                 let a2 = self[temp_v!(2)].clone();
 
                 // drop the mutable references contained in gadget
                 // once the term has been duplicated.
-                {   
-                    let mut gadget = DuplicateTerm::new(self);                    
+                {
+                    let mut gadget = DuplicateTerm::new(self);
                     gadget.duplicate_term(a1);
                 }
-                
+
                 self.unify(Addr::HeapCell(old_h), a2);
 
                 self.p += 1;
@@ -1216,31 +1275,18 @@ impl MachineState {
                 self.p += 1;
             },
             &BuiltInInstruction::GetBall => {
-                let addr = self.store(self.deref(self[temp_v!(1)].clone()));                
+                let addr = self.store(self.deref(self[temp_v!(1)].clone()));
                 let h = self.h;
 
                 if self.ball.1.len() > 0 {
-                    let diff = self.ball.0 - h;
-                    
-                    for heap_value in self.ball.1.iter().cloned() {
-                        self.heap.push(match heap_value {
-                            HeapCellValue::Con(c) => HeapCellValue::Con(c),
-                            HeapCellValue::Lis(a) => HeapCellValue::Lis(a - diff),
-                            HeapCellValue::Ref(Ref::HeapCell(hc)) =>
-                                HeapCellValue::Ref(Ref::HeapCell(hc - diff)),
-                            HeapCellValue::Str(s) => HeapCellValue::Str(s - diff),
-                            _ => heap_value
-                        });
-                    }
-                                        
-                    self.h += self.ball.1.len();
+                    self.copy_and_align_ball_to_heap();
                 } else {
                     self.fail = true;
                     return;
                 }
 
                 let ball = self.heap[h].as_addr(h);
-                
+
                 match addr.as_ref() {
                     Some(r) => {
                         self.bind(r, ball);
@@ -1254,11 +1300,11 @@ impl MachineState {
 
                 {
                     self.ball.0 = self.h;
-                    
-                    let mut duplicator = DuplicateBallTerm::new(self);                
+
+                    let mut duplicator = DuplicateBallTerm::new(self);
                     duplicator.duplicate_term(addr);
                 }
-                
+
                 self.p += 1;
             },
             &BuiltInInstruction::CleanUpBlock => {
@@ -1322,7 +1368,7 @@ impl MachineState {
             &BuiltInInstruction::Fail => {
                 self.fail = true;
                 self.p += 1;
-            }            
+            }
         };
     }
 
@@ -1349,7 +1395,7 @@ impl MachineState {
                 self.num_of_args = 3;
                 self.b0 = self.b;
                 self.p  = CodePtr::DirEntry(5);
-            },            
+            },
             &ControlInstruction::CallN(arity) =>
                 if let Some((name, arity)) = self.setup_call_n(arity) {
                     self.try_call_predicate(code_dir, name, arity);
@@ -1377,14 +1423,10 @@ impl MachineState {
                 self.p = self.cp,
             &ControlInstruction::ThrowCall => {
                 self.cp = self.p + 1;
-                self.num_of_args = 1;
-                self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(59);
+                self.goto_throw();
             },
             &ControlInstruction::ThrowExecute => {
-                self.num_of_args = 1;
-                self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(59);
+                self.goto_throw();
             }
         };
     }
index 077c52b7fc23566b6ebe361b853b7ee0acec22d7..2686cb63c0d0572d7491c67085b688a851d9b467 100644 (file)
@@ -22,6 +22,22 @@ macro_rules! query {
     )
 }
 
+macro_rules! functor {
+    ($name:expr, $len:expr, [$($args:expr),*]) => {{
+        if $len > 0 {
+            vec![ HeapCellValue::NamedStr($len, String::from($name)), $($args),* ]
+        } else {
+            vec![ atom!($name) ]
+        }
+    }}
+}
+
+macro_rules! atom {
+    ($name:expr) => (
+        HeapCellValue::Con(Constant::Atom(String::from($name)))
+    )
+}
+
 macro_rules! fact {
     [$($x:expr),+] => (
         Line::Fact(vec![$($x),+])