add top level exception reporting, exceptions for call/N.
This commit is contained in:
@@ -47,7 +47,7 @@ ideally, very fast) [Shen](http://shenlanguage.org) implementation.
|
|||||||
The following predicates are built-in to rusty-wam.
|
The following predicates are built-in to rusty-wam.
|
||||||
|
|
||||||
* atomic/1
|
* atomic/1
|
||||||
* call/N (0 <= N <= 62)
|
* call/N (1 <= N <= 63)
|
||||||
* catch/3
|
* catch/3
|
||||||
* duplicate_term/2
|
* duplicate_term/2
|
||||||
* false/0
|
* false/0
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ pub enum EvalSession<'a> {
|
|||||||
EntrySuccess,
|
EntrySuccess,
|
||||||
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
|
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
|
||||||
QueryFailure,
|
QueryFailure,
|
||||||
|
QueryFailureWithException(String),
|
||||||
SubsequentQuerySuccess,
|
SubsequentQuerySuccess,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
pub fn print(wam: &mut Machine, result: EvalSession) {
|
||||||
match result {
|
match result {
|
||||||
EvalSession::InitialQuerySuccess(alloc_locs, mut heap_locs) => {
|
EvalSession::InitialQuerySuccess(alloc_locs, mut heap_locs) => {
|
||||||
@@ -451,6 +455,12 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
|
|||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let &EvalSession::QueryFailureWithException(ref e) = &result {
|
||||||
|
write!(stdout, "{}\n\r", error_string(e)).unwrap();
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -459,6 +469,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
|
|||||||
write!(stdout(), ".\n").unwrap();
|
write!(stdout(), ".\n").unwrap();
|
||||||
},
|
},
|
||||||
EvalSession::QueryFailure => println!("false."),
|
EvalSession::QueryFailure => println!("false."),
|
||||||
|
EvalSession::QueryFailureWithException(e) => println!("{}", error_string(&e)),
|
||||||
EvalSession::EntryFailure(msg) => println!("{}", msg),
|
EvalSession::EntryFailure(msg) => println!("{}", msg),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -284,9 +284,6 @@ impl Machine {
|
|||||||
|
|
||||||
fn execute_instr(&mut self)
|
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 {
|
let instr = match self.ms.p {
|
||||||
CodePtr::TopLevel(_, p) => {
|
CodePtr::TopLevel(_, p) => {
|
||||||
match &self.cached_query {
|
match &self.cached_query {
|
||||||
@@ -409,10 +406,6 @@ impl Machine {
|
|||||||
|
|
||||||
while self.ms.p < end_ptr {
|
while self.ms.p < end_ptr {
|
||||||
if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
|
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 let &Line::Control(ref ctrl_instr) = &self[CodePtr::TopLevel(cn, p)] {
|
||||||
if ctrl_instr.is_jump_instr() {
|
if ctrl_instr.is_jump_instr() {
|
||||||
self.record_var_places(cn, alloc_locs, heap_locs);
|
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>
|
pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
|
||||||
{
|
{
|
||||||
let mut heap_locs = HashMap::new();
|
let mut heap_locs = HashMap::new();
|
||||||
@@ -440,16 +445,14 @@ impl Machine {
|
|||||||
self.run_query(&alloc_locs, &mut heap_locs);
|
self.run_query(&alloc_locs, &mut heap_locs);
|
||||||
|
|
||||||
if self.failed() {
|
if self.failed() {
|
||||||
EvalSession::QueryFailure
|
self.fail()
|
||||||
} else {
|
} else {
|
||||||
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
|
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn continue_query<'a>(&mut self,
|
pub fn continue_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
|
||||||
alloc_locs: &AllocVarDict<'a>,
|
-> EvalSession<'a>
|
||||||
heap_locs: &mut HeapVarDict<'a>)
|
|
||||||
-> EvalSession
|
|
||||||
{
|
{
|
||||||
if !self.or_stack_is_empty() {
|
if !self.or_stack_is_empty() {
|
||||||
let b = self.ms.b - 1;
|
let b = self.ms.b - 1;
|
||||||
@@ -462,7 +465,7 @@ impl Machine {
|
|||||||
self.run_query(alloc_locs, heap_locs);
|
self.run_query(alloc_locs, heap_locs);
|
||||||
|
|
||||||
if self.failed() {
|
if self.failed() {
|
||||||
EvalSession::QueryFailure
|
self.fail()
|
||||||
} else {
|
} else {
|
||||||
EvalSession::SubsequentQuerySuccess
|
EvalSession::SubsequentQuerySuccess
|
||||||
}
|
}
|
||||||
@@ -471,20 +474,13 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
|
fn print_term(&self, addr: &Addr) -> String
|
||||||
let mut result = String::new();
|
{
|
||||||
|
|
||||||
for (var, addr) in var_dir {
|
|
||||||
let mut viewer = HeapCellViewer::new(&self.ms.heap,
|
let mut viewer = HeapCellViewer::new(&self.ms.heap,
|
||||||
&self.ms.and_stack,
|
&self.ms.and_stack,
|
||||||
addr);
|
addr);
|
||||||
|
|
||||||
if result != "" {
|
let mut result = String::new();
|
||||||
result += "\n\r";
|
|
||||||
}
|
|
||||||
|
|
||||||
result += var.as_str();
|
|
||||||
result += " = ";
|
|
||||||
|
|
||||||
while let Some(view) = viewer.next() {
|
while let Some(view) = viewer.next() {
|
||||||
match view {
|
match view {
|
||||||
@@ -522,6 +518,22 @@ impl Machine {
|
|||||||
result += token.as_str()
|
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 {
|
||||||
|
if result != "" {
|
||||||
|
result += "\n\r";
|
||||||
|
}
|
||||||
|
|
||||||
|
result += var.as_str();
|
||||||
|
result += " = ";
|
||||||
|
|
||||||
|
result += self.print_term(addr).as_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
@@ -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>
|
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) => {
|
Addr::Str(a) => {
|
||||||
let result = self.heap[a].clone();
|
let result = self.heap[a].clone();
|
||||||
|
|
||||||
if let HeapCellValue::NamedStr(narity, name) = result {
|
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() {
|
for i in (1 .. arity).rev() {
|
||||||
self.registers[i + narity] = self.registers[i].clone();
|
self.registers[i + narity] = self.registers[i].clone();
|
||||||
}
|
}
|
||||||
@@ -1167,8 +1202,15 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Addr::Con(Constant::Atom(name)) => (name, 0),
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1176,6 +1218,23 @@ impl MachineState {
|
|||||||
Some((name, arity + narity - 1))
|
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)
|
fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
|
||||||
{
|
{
|
||||||
match instr {
|
match instr {
|
||||||
@@ -1220,20 +1279,7 @@ impl MachineState {
|
|||||||
let h = self.h;
|
let h = self.h;
|
||||||
|
|
||||||
if self.ball.1.len() > 0 {
|
if self.ball.1.len() > 0 {
|
||||||
let diff = self.ball.0 - h;
|
self.copy_and_align_ball_to_heap();
|
||||||
|
|
||||||
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();
|
|
||||||
} else {
|
} else {
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
return;
|
return;
|
||||||
@@ -1377,14 +1423,10 @@ impl MachineState {
|
|||||||
self.p = self.cp,
|
self.p = self.cp,
|
||||||
&ControlInstruction::ThrowCall => {
|
&ControlInstruction::ThrowCall => {
|
||||||
self.cp = self.p + 1;
|
self.cp = self.p + 1;
|
||||||
self.num_of_args = 1;
|
self.goto_throw();
|
||||||
self.b0 = self.b;
|
|
||||||
self.p = CodePtr::DirEntry(59);
|
|
||||||
},
|
},
|
||||||
&ControlInstruction::ThrowExecute => {
|
&ControlInstruction::ThrowExecute => {
|
||||||
self.num_of_args = 1;
|
self.goto_throw();
|
||||||
self.b0 = self.b;
|
|
||||||
self.p = CodePtr::DirEntry(59);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
macro_rules! fact {
|
||||||
[$($x:expr),+] => (
|
[$($x:expr),+] => (
|
||||||
Line::Fact(vec![$($x),+])
|
Line::Fact(vec![$($x),+])
|
||||||
|
|||||||
Reference in New Issue
Block a user