add provisional module support.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
use prolog::and_stack::*;
|
||||
use prolog::builtins::CodeDir;
|
||||
use prolog::ast::*;
|
||||
use prolog::copier::*;
|
||||
use prolog::num::{BigInt, BigUint, Zero, One};
|
||||
@@ -8,10 +7,40 @@ use prolog::tabled_rc::*;
|
||||
|
||||
use downcast::Any;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::mem::swap;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) struct CodeDirs<'a> {
|
||||
code_dir: &'a CodeDir,
|
||||
modules: &'a HashMap<ClauseName, Module>
|
||||
}
|
||||
|
||||
impl<'a> CodeDirs<'a> {
|
||||
pub(super) fn new(code_dir: &'a CodeDir, modules: &'a HashMap<ClauseName, Module>) -> Self {
|
||||
CodeDirs { code_dir, modules }
|
||||
}
|
||||
|
||||
fn get_current_code_dir(&self, p: &CodePtr) -> &CodeDir {
|
||||
let module_name = p.module_name();
|
||||
|
||||
match module_name {
|
||||
ClauseName::BuiltIn("user") | ClauseName::BuiltIn("builtin") =>
|
||||
self.code_dir,
|
||||
_ =>
|
||||
&self.modules.get(&module_name).unwrap().code_dir
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, name: ClauseName, arity: usize, p: &CodePtr)
|
||||
-> Option<(usize, ClauseName)>
|
||||
{
|
||||
let code_dir = self.get_current_code_dir(p);
|
||||
code_dir.get(&(name, arity)).map(|idx| (idx.1, idx.2.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct DuplicateTerm<'a> {
|
||||
state: &'a mut MachineState
|
||||
}
|
||||
@@ -184,36 +213,40 @@ pub struct MachineState {
|
||||
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
|
||||
|
||||
pub(crate) trait CallPolicy: Any {
|
||||
fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
|
||||
name: ClauseName, arity: usize)
|
||||
-> CallResult
|
||||
fn try_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
name: ClauseName, arity: usize)
|
||||
-> CallResult
|
||||
{
|
||||
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
|
||||
let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p);
|
||||
|
||||
match compiled_tl_index {
|
||||
Some(compiled_tl_index) => {
|
||||
machine_st.cp = machine_st.p + 1;
|
||||
let module_name = compiled_tl_index.1.clone();
|
||||
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index);
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index.0, module_name);
|
||||
},
|
||||
None => machine_st.fail = true
|
||||
};
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
|
||||
name: ClauseName, arity: usize)
|
||||
-> CallResult
|
||||
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
name: ClauseName, arity: usize)
|
||||
-> CallResult
|
||||
{
|
||||
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
|
||||
let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p);
|
||||
|
||||
match compiled_tl_index {
|
||||
Some(compiled_tl_index) => {
|
||||
let module_name = compiled_tl_index.1.clone();
|
||||
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index);
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index.0, module_name);
|
||||
},
|
||||
None => machine_st.fail = true
|
||||
};
|
||||
@@ -231,9 +264,9 @@ pub(crate) trait CallPolicy: Any {
|
||||
}
|
||||
|
||||
machine_st.e = machine_st.or_stack[b].e;
|
||||
machine_st.cp = machine_st.or_stack[b].cp;
|
||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
||||
|
||||
machine_st.or_stack[b].bp = machine_st.p + offset;
|
||||
machine_st.or_stack[b].bp = machine_st.p.clone() + offset;
|
||||
|
||||
let old_tr = machine_st.or_stack[b].tr;
|
||||
let curr_tr = machine_st.tr;
|
||||
@@ -261,9 +294,9 @@ pub(crate) trait CallPolicy: Any {
|
||||
}
|
||||
|
||||
machine_st.e = machine_st.or_stack[b].e;
|
||||
machine_st.cp = machine_st.or_stack[b].cp;
|
||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
||||
|
||||
machine_st.or_stack[b].bp = machine_st.p + 1;
|
||||
machine_st.or_stack[b].bp = machine_st.p.clone() + 1;
|
||||
|
||||
let old_tr = machine_st.or_stack[b].tr;
|
||||
let curr_tr = machine_st.tr;
|
||||
@@ -291,7 +324,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
}
|
||||
|
||||
machine_st.e = machine_st.or_stack[b].e;
|
||||
machine_st.cp = machine_st.or_stack[b].cp;
|
||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
||||
|
||||
let old_tr = machine_st.or_stack[b].tr;
|
||||
let curr_tr = machine_st.tr;
|
||||
@@ -322,7 +355,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
}
|
||||
|
||||
machine_st.e = machine_st.or_stack[b].e;
|
||||
machine_st.cp = machine_st.or_stack[b].cp;
|
||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
||||
|
||||
let old_tr = machine_st.or_stack[b].tr;
|
||||
let curr_tr = machine_st.tr;
|
||||
@@ -351,7 +384,7 @@ pub(crate) struct DefaultCallPolicy {}
|
||||
|
||||
impl CallPolicy for DefaultCallPolicy {}
|
||||
|
||||
pub(crate) struct CallWithInferenceLimitCallPolicy {
|
||||
pub(crate) struct CallWithInferenceLimitCallPolicy {
|
||||
pub(crate) prev_policy: Box<CallPolicy>,
|
||||
count: BigUint,
|
||||
limits: Vec<(BigUint, usize)>
|
||||
@@ -378,7 +411,7 @@ impl CallWithInferenceLimitCallPolicy {
|
||||
self.count += BigUint::one();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -418,19 +451,19 @@ impl CallWithInferenceLimitCallPolicy {
|
||||
}
|
||||
|
||||
impl CallPolicy for CallWithInferenceLimitCallPolicy {
|
||||
fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
|
||||
name: ClauseName, arity: usize)
|
||||
fn try_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
name: ClauseName, arity: usize)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.try_call(machine_st, code_dir, name, arity)?;
|
||||
self.prev_policy.try_call(machine_st, code_dirs, name, arity)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
|
||||
name: ClauseName, arity: usize)
|
||||
-> CallResult
|
||||
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
name: ClauseName, arity: usize)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.try_execute(machine_st, code_dir, name, arity)?;
|
||||
self.prev_policy.try_execute(machine_st, code_dirs, name, arity)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
@@ -527,10 +560,11 @@ impl CutPolicy for SetupCallCleanupCutPolicy {
|
||||
machine_st.p += 1;
|
||||
|
||||
if !self.out_of_cont_pts() {
|
||||
machine_st.cp = machine_st.p;
|
||||
machine_st.cp = machine_st.p.clone();
|
||||
machine_st.num_of_args = 0;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(354); // goto_call run_cleaners_without_handling/0, 354.
|
||||
// goto_call run_cleaners_without_handling/0, 354.
|
||||
machine_st.p = CodePtr::DirEntry(354, clause_name!("builtin"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use prolog::and_stack::*;
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::copier::*;
|
||||
use prolog::heap_iter::*;
|
||||
use prolog::heap_print::*;
|
||||
@@ -908,7 +907,8 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_internal_call_n(&mut self, call_policy: &mut Box<CallPolicy>, code_dir: &CodeDir)
|
||||
fn handle_internal_call_n<'a>(&mut self, call_policy: &mut Box<CallPolicy>,
|
||||
code_dirs: CodeDirs<'a>)
|
||||
{
|
||||
let arity = self.num_of_args + 1;
|
||||
let pred = self.registers[1].clone();
|
||||
@@ -921,7 +921,7 @@ impl MachineState {
|
||||
self.registers[arity - 1] = pred;
|
||||
|
||||
if let Some((name, arity)) = self.setup_call_n(arity - 1) {
|
||||
try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity));
|
||||
try_or_fail!(self, call_policy.try_execute(self, code_dirs, name, arity));
|
||||
}
|
||||
} else {
|
||||
self.fail = true;
|
||||
@@ -931,7 +931,7 @@ impl MachineState {
|
||||
fn goto_throw(&mut self) {
|
||||
self.num_of_args = 1;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(59);
|
||||
self.p = CodePtr::DirEntry(59, clause_name!("builtin"));
|
||||
}
|
||||
|
||||
fn throw_exception(&mut self, hcv: Vec<HeapCellValue>) {
|
||||
@@ -1209,10 +1209,10 @@ impl MachineState {
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) fn execute_built_in_instr(&mut self, code_dir: &CodeDir,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
instr: &BuiltInInstruction)
|
||||
pub(super) fn execute_built_in_instr<'a>(&mut self, code_dirs: CodeDirs<'a>,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
instr: &BuiltInInstruction)
|
||||
{
|
||||
match instr {
|
||||
&BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => {
|
||||
@@ -1253,7 +1253,7 @@ impl MachineState {
|
||||
&BuiltInInstruction::GetArgExecute =>
|
||||
try_or_fail!(self, {
|
||||
let val = self.try_get_arg();
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
val
|
||||
}),
|
||||
&BuiltInInstruction::GetCurrentBlock => {
|
||||
@@ -1537,7 +1537,7 @@ impl MachineState {
|
||||
self.fail = true;
|
||||
},
|
||||
&BuiltInInstruction::InternalCallN =>
|
||||
self.handle_internal_call_n(call_policy, code_dir),
|
||||
self.handle_internal_call_n(call_policy, code_dirs),
|
||||
&BuiltInInstruction::Fail => {
|
||||
self.fail = true;
|
||||
self.p += 1;
|
||||
@@ -1728,10 +1728,10 @@ impl MachineState {
|
||||
false
|
||||
}
|
||||
|
||||
pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
instr: &ControlInstruction)
|
||||
pub(super) fn execute_ctrl_instr<'a>(&mut self, code_dirs: CodeDirs<'a>,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
instr: &ControlInstruction)
|
||||
{
|
||||
match instr {
|
||||
&ControlInstruction::Allocate(num_cells) => {
|
||||
@@ -1749,7 +1749,7 @@ impl MachineState {
|
||||
let index = self.e + 1;
|
||||
|
||||
self.and_stack[index].e = self.e;
|
||||
self.and_stack[index].cp = self.cp;
|
||||
self.and_stack[index].cp = self.cp.clone();
|
||||
self.and_stack[index].global_index = gi;
|
||||
|
||||
self.and_stack.resize(index, num_cells);
|
||||
@@ -1760,48 +1760,49 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
self.and_stack.push(gi, self.e, self.cp, num_cells);
|
||||
self.and_stack.push(gi, self.e, self.cp.clone(), num_cells);
|
||||
self.e = self.and_stack.len() - 1;
|
||||
},
|
||||
&ControlInstruction::ArgCall => {
|
||||
self.cp = self.p + 1;
|
||||
self.cp = self.p.clone() + 1;
|
||||
self.num_of_args = 3;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(150);
|
||||
self.p = CodePtr::DirEntry(150, clause_name!("builtin"));
|
||||
},
|
||||
&ControlInstruction::ArgExecute => {
|
||||
self.num_of_args = 3;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(150);
|
||||
self.p = CodePtr::DirEntry(150, clause_name!("builtin"));
|
||||
},
|
||||
&ControlInstruction::Call(ref name, arity, _) =>
|
||||
try_or_fail!(self, call_policy.try_call(self, code_dir, name.clone(), arity)),
|
||||
try_or_fail!(self, call_policy.try_call(self, code_dirs, name.clone(), arity)),
|
||||
&ControlInstruction::CatchCall => {
|
||||
self.cp = self.p + 1;
|
||||
self.cp = self.p.clone() + 1;
|
||||
self.num_of_args = 3;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(5);
|
||||
self.p = CodePtr::DirEntry(5, clause_name!("builtin"));
|
||||
},
|
||||
&ControlInstruction::CatchExecute => {
|
||||
self.num_of_args = 3;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(5);
|
||||
self.p = CodePtr::DirEntry(5, clause_name!("builtin"));
|
||||
},
|
||||
&ControlInstruction::CallN(arity) =>
|
||||
if let Some((name, arity)) = self.setup_call_n(arity) {
|
||||
try_or_fail!(self, call_policy.try_call(self, code_dir, name, arity))
|
||||
try_or_fail!(self, call_policy.try_call(self, code_dirs, name, arity))
|
||||
},
|
||||
&ControlInstruction::CheckCpExecute => {
|
||||
let a = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
match a {
|
||||
Addr::Con(Constant::Usize(old_b)) if self.b > old_b + 1 => {
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
_ => {
|
||||
self.num_of_args = 2;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(366); // goto sgc_on_success/2, 366.
|
||||
// goto sgc_on_success/2, 366.
|
||||
self.p = CodePtr::DirEntry(366, clause_name!("builtin"));
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -1833,7 +1834,7 @@ impl MachineState {
|
||||
|
||||
self.unify(a1, c);
|
||||
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::CompareTermCall(qt) => {
|
||||
match qt {
|
||||
@@ -1855,12 +1856,12 @@ impl MachineState {
|
||||
_ => self.compare_term(qt)
|
||||
};
|
||||
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::Deallocate => {
|
||||
let e = self.e;
|
||||
|
||||
self.cp = self.and_stack[e].cp;
|
||||
self.cp = self.and_stack[e].cp.clone();
|
||||
self.e = self.and_stack[e].e;
|
||||
|
||||
self.p += 1;
|
||||
@@ -1881,7 +1882,7 @@ impl MachineState {
|
||||
|
||||
println!("{}", output.result());
|
||||
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::DuplicateTermCall => {
|
||||
self.duplicate_term();
|
||||
@@ -1889,7 +1890,7 @@ impl MachineState {
|
||||
},
|
||||
&ControlInstruction::DuplicateTermExecute => {
|
||||
self.duplicate_term();
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::DynamicIs => {
|
||||
let a = self[temp_v!(1)].clone();
|
||||
@@ -1904,7 +1905,7 @@ impl MachineState {
|
||||
},
|
||||
&ControlInstruction::EqExecute => {
|
||||
self.fail = self.eq_test();
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::GroundCall => {
|
||||
self.fail = self.ground_test();
|
||||
@@ -1912,13 +1913,13 @@ impl MachineState {
|
||||
},
|
||||
&ControlInstruction::GroundExecute => {
|
||||
self.fail = self.ground_test();
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::Execute(ref name, arity) =>
|
||||
try_or_fail!(self, call_policy.try_execute(self, code_dir, name.clone(), arity)),
|
||||
try_or_fail!(self, call_policy.try_execute(self, code_dirs, name.clone(), arity)),
|
||||
&ControlInstruction::ExecuteN(arity) =>
|
||||
if let Some((name, arity)) = self.setup_call_n(arity) {
|
||||
try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity))
|
||||
try_or_fail!(self, call_policy.try_execute(self, code_dirs, name, arity))
|
||||
},
|
||||
&ControlInstruction::FunctorCall =>
|
||||
try_or_fail!(self, {
|
||||
@@ -1929,7 +1930,7 @@ impl MachineState {
|
||||
&ControlInstruction::FunctorExecute =>
|
||||
try_or_fail!(self, {
|
||||
let val = self.try_functor();
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
val
|
||||
}),
|
||||
&ControlInstruction::GetCleanerCall => {
|
||||
@@ -1958,15 +1959,15 @@ impl MachineState {
|
||||
self.fail = true;
|
||||
},
|
||||
&ControlInstruction::GotoCall(p, arity) => {
|
||||
self.cp = self.p + 1;
|
||||
self.cp = self.p.clone() + 1;
|
||||
self.num_of_args = arity;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(p);
|
||||
self.p = CodePtr::DirEntry(p, clause_name!("builtin"));
|
||||
},
|
||||
&ControlInstruction::GotoExecute(p, arity) => {
|
||||
self.num_of_args = arity;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(p);
|
||||
self.p = CodePtr::DirEntry(p, clause_name!("builtin"));
|
||||
},
|
||||
&ControlInstruction::IsCall(r, ref at) => {
|
||||
let a1 = self[r].clone();
|
||||
@@ -1980,10 +1981,10 @@ impl MachineState {
|
||||
let a2 = try_or_fail!(self, self.get_number(at));
|
||||
|
||||
self.unify(a1, Addr::Con(Constant::Number(a2)));
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::JmpByCall(arity, offset) => {
|
||||
self.cp = self.p + 1;
|
||||
self.cp = self.p.clone() + 1;
|
||||
self.num_of_args = arity;
|
||||
self.b0 = self.b;
|
||||
self.p += offset;
|
||||
@@ -1999,12 +2000,12 @@ impl MachineState {
|
||||
},
|
||||
&ControlInstruction::NotEqExecute => {
|
||||
self.fail = !self.eq_test();
|
||||
self.p = self.cp;
|
||||
self.p = self.cp.clone();
|
||||
},
|
||||
&ControlInstruction::Proceed =>
|
||||
self.p = self.cp,
|
||||
self.p = self.cp.clone(),
|
||||
&ControlInstruction::ThrowCall => {
|
||||
self.cp = self.p + 1;
|
||||
self.cp = self.p.clone() + 1;
|
||||
self.goto_throw();
|
||||
},
|
||||
&ControlInstruction::ThrowExecute => {
|
||||
@@ -2023,9 +2024,9 @@ impl MachineState {
|
||||
|
||||
self.or_stack.push(gi,
|
||||
self.e,
|
||||
self.cp,
|
||||
self.cp.clone(),
|
||||
self.b,
|
||||
self.p + 1,
|
||||
self.p.clone() + 1,
|
||||
self.tr,
|
||||
self.heap.h,
|
||||
self.b0,
|
||||
@@ -2058,9 +2059,9 @@ impl MachineState {
|
||||
|
||||
self.or_stack.push(gi,
|
||||
self.e,
|
||||
self.cp,
|
||||
self.cp.clone(),
|
||||
self.b,
|
||||
self.p + offset,
|
||||
self.p.clone() + offset,
|
||||
self.tr,
|
||||
self.heap.h,
|
||||
self.b0,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::codegen::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::fixtures::*;
|
||||
use prolog::tabled_rc::*;
|
||||
|
||||
pub(crate) mod machine_state;
|
||||
@@ -17,13 +15,19 @@ use std::mem::swap;
|
||||
use std::ops::Index;
|
||||
use std::rc::Rc;
|
||||
|
||||
struct MachineCodeIndex<'a> {
|
||||
code_dir: &'a mut CodeDir,
|
||||
op_dir: &'a mut OpDir
|
||||
}
|
||||
|
||||
pub struct Machine {
|
||||
ms: MachineState,
|
||||
call_policy: Box<CallPolicy>,
|
||||
cut_policy: Box<CutPolicy>,
|
||||
code: Code,
|
||||
code_dir: CodeDir,
|
||||
op_dir: OpDir,
|
||||
pub op_dir: OpDir,
|
||||
modules: HashMap<ClauseName, Module>,
|
||||
cached_query: Option<Code>
|
||||
}
|
||||
|
||||
@@ -38,16 +42,26 @@ impl Index<CodePtr> for Machine {
|
||||
&None => panic!("Out-of-bounds top level index.")
|
||||
}
|
||||
},
|
||||
CodePtr::DirEntry(p) => &self.code[p]
|
||||
CodePtr::DirEntry(p, _) => &self.code[p]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SubModuleUser for MachineCodeIndex<'a> {
|
||||
fn op_dir(&mut self) -> &mut OpDir {
|
||||
self.op_dir
|
||||
}
|
||||
|
||||
fn code_dir(&mut self) -> &mut CodeDir {
|
||||
self.code_dir
|
||||
}
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub fn new() -> Self {
|
||||
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
|
||||
let (code, code_dir, op_dir) = build_code_dir();
|
||||
|
||||
let (code, code_dir, op_dir) = default_build();
|
||||
|
||||
Machine {
|
||||
ms: MachineState::new(atom_tbl),
|
||||
call_policy: Box::new(DefaultCallPolicy {}),
|
||||
@@ -55,6 +69,7 @@ impl Machine {
|
||||
code,
|
||||
code_dir,
|
||||
op_dir,
|
||||
modules: HashMap::new(),
|
||||
cached_query: None
|
||||
}
|
||||
}
|
||||
@@ -67,30 +82,62 @@ impl Machine {
|
||||
self.ms.atom_tbl.clone()
|
||||
}
|
||||
|
||||
pub fn add_user_code<'a>(&mut self, name: ClauseName, arity: usize, mut code: Code)
|
||||
-> EvalSession<'a>
|
||||
pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession {
|
||||
match self.modules.get(&name) {
|
||||
Some(ref module) => {
|
||||
let mut indices = MachineCodeIndex { code_dir: &mut self.code_dir,
|
||||
op_dir: &mut self.op_dir };
|
||||
indices.use_module(module)
|
||||
},
|
||||
None => EvalSession::from(EvalError::ModuleNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_module(&self, name: ClauseName) -> Option<&Module> {
|
||||
self.modules.get(&name)
|
||||
}
|
||||
|
||||
pub fn add_batched_code(&mut self, mut code: Code, code_dir: CodeDir) {
|
||||
self.code.append(&mut code);
|
||||
self.code_dir.extend(code_dir.into_iter());
|
||||
}
|
||||
|
||||
pub fn add_batched_ops(&mut self, op_dir: OpDir) {
|
||||
self.op_dir.extend(op_dir.into_iter());
|
||||
}
|
||||
|
||||
pub fn add_module(&mut self, module: Module, code: Code) {
|
||||
self.modules.insert(module.module_decl.name.clone(), module);
|
||||
self.code.extend(code.into_iter());
|
||||
}
|
||||
|
||||
pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession
|
||||
{
|
||||
match self.code_dir.get(&(name.clone(), arity)) {
|
||||
Some(&(PredicateKeyType::BuiltIn, _)) =>
|
||||
Some(&(PredicateKeyType::BuiltIn, _, _)) =>
|
||||
return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", name, arity))),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let offset = self.code.len();
|
||||
|
||||
self.code.append(&mut code);
|
||||
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
|
||||
self.code.extend(code.into_iter());
|
||||
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset, clause_name!("user")));
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
|
||||
pub fn code_size(&self) -> usize {
|
||||
self.code.len()
|
||||
}
|
||||
|
||||
fn cached_query_size(&self) -> usize {
|
||||
match &self.cached_query {
|
||||
&Some(ref query) => query.len(),
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn execute_instr(&mut self)
|
||||
{
|
||||
let instr = match self.ms.p {
|
||||
@@ -100,22 +147,26 @@ impl Machine {
|
||||
&None => return
|
||||
}
|
||||
},
|
||||
CodePtr::DirEntry(p) => &self.code[p]
|
||||
CodePtr::DirEntry(p, _) => &self.code[p]
|
||||
};
|
||||
|
||||
match instr {
|
||||
&Line::Arithmetic(ref arith_instr) =>
|
||||
self.ms.execute_arith_instr(arith_instr),
|
||||
&Line::BuiltIn(ref built_in_instr) =>
|
||||
self.ms.execute_built_in_instr(&self.code_dir, &mut self.call_policy,
|
||||
&mut self.cut_policy, built_in_instr),
|
||||
&Line::BuiltIn(ref built_in_instr) => {
|
||||
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
|
||||
self.ms.execute_built_in_instr(code_dirs, &mut self.call_policy,
|
||||
&mut self.cut_policy, built_in_instr);
|
||||
},
|
||||
&Line::Choice(ref choice_instr) =>
|
||||
self.ms.execute_choice_instr(choice_instr, &mut self.call_policy),
|
||||
&Line::Cut(ref cut_instr) =>
|
||||
self.ms.execute_cut_instr(cut_instr, &mut self.cut_policy),
|
||||
&Line::Control(ref control_instr) =>
|
||||
self.ms.execute_ctrl_instr(&self.code_dir, &mut self.call_policy,
|
||||
&mut self.cut_policy, control_instr),
|
||||
&Line::Control(ref control_instr) => {
|
||||
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
|
||||
self.ms.execute_ctrl_instr(code_dirs, &mut self.call_policy,
|
||||
&mut self.cut_policy, control_instr)
|
||||
},
|
||||
&Line::Fact(ref fact) => {
|
||||
for fact_instr in fact {
|
||||
if self.failed() {
|
||||
@@ -151,7 +202,7 @@ impl Machine {
|
||||
let b = self.ms.b - 1;
|
||||
|
||||
self.ms.b0 = self.ms.or_stack[b].b0;
|
||||
self.ms.p = self.ms.or_stack[b].bp;
|
||||
self.ms.p = self.ms.or_stack[b].bp.clone();
|
||||
|
||||
if let CodePtr::TopLevel(_, p) = self.ms.p {
|
||||
self.ms.fail = p == 0;
|
||||
@@ -173,14 +224,14 @@ impl Machine {
|
||||
}
|
||||
|
||||
match self.ms.p {
|
||||
CodePtr::DirEntry(p) if p < self.code.len() => {},
|
||||
CodePtr::DirEntry(p, _) if p < self.code.len() => {},
|
||||
_ => break
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn record_var_places<'a>(&self, chunk_num: usize,
|
||||
alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
|
||||
fn record_var_places(&self, chunk_num: usize, alloc_locs: &AllocVarDict,
|
||||
heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
for (var, var_data) in alloc_locs {
|
||||
match var_data {
|
||||
@@ -190,14 +241,14 @@ impl Machine {
|
||||
let r = var_data.as_reg_type().reg_num();
|
||||
let addr = self.ms.and_stack[e][r].clone();
|
||||
|
||||
heap_locs.insert(var, addr);
|
||||
heap_locs.insert(var.clone(), addr);
|
||||
},
|
||||
&VarData::Temp(cn, _, _) if cn == chunk_num => {
|
||||
let r = var_data.as_reg_type();
|
||||
|
||||
if r.reg_num() != 0 {
|
||||
let addr = self.ms[r].clone();
|
||||
heap_locs.insert(var, addr);
|
||||
heap_locs.insert(var.clone(), addr);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
@@ -205,7 +256,7 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
|
||||
fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());
|
||||
|
||||
@@ -237,7 +288,7 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn fail<'a>(&mut self) -> EvalSession<'a>
|
||||
fn fail(&mut self) -> EvalSession
|
||||
{
|
||||
if self.ms.ball.1.len() > 0 {
|
||||
let h = self.ms.heap.h;
|
||||
@@ -253,45 +304,8 @@ impl Machine {
|
||||
EvalSession::from(EvalError::QueryFailure)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a>
|
||||
{
|
||||
match decl {
|
||||
&Declaration::Op(prec, spec, ref name) => {
|
||||
if is_infix!(spec) {
|
||||
match self.op_dir.get(&(name.clone(), Fixity::Post)) {
|
||||
Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
if is_postfix!(spec) {
|
||||
match self.op_dir.get(&(name.clone(), Fixity::In)) {
|
||||
Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
if prec > 0 {
|
||||
match spec {
|
||||
XFY | XFX | YFX => self.op_dir.insert((name.clone(), Fixity::In),
|
||||
(spec, prec)),
|
||||
XF | YF => self.op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
|
||||
FX | FY => self.op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
|
||||
_ => None
|
||||
};
|
||||
} else {
|
||||
self.op_dir.remove(&(name.clone(), Fixity::Pre));
|
||||
self.op_dir.remove(&(name.clone(), Fixity::In));
|
||||
self.op_dir.remove(&(name.clone(), Fixity::Post));
|
||||
}
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
|
||||
|
||||
pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession
|
||||
{
|
||||
let mut heap_locs = HashMap::new();
|
||||
|
||||
@@ -305,12 +319,11 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn continue_query<'a>(&mut self, alloc_l: &AllocVarDict<'a>, heap_l: &mut HeapVarDict<'a>)
|
||||
-> EvalSession<'a>
|
||||
pub fn continue_query(&mut self, alloc_l: &AllocVarDict, heap_l: &mut HeapVarDict) -> EvalSession
|
||||
{
|
||||
if !self.or_stack_is_empty() {
|
||||
let b = self.ms.b - 1;
|
||||
self.ms.p = self.ms.or_stack[b].bp;
|
||||
self.ms.p = self.ms.or_stack[b].bp.clone();
|
||||
|
||||
if let CodePtr::TopLevel(_, 0) = self.ms.p {
|
||||
return EvalSession::from(EvalError::QueryFailure);
|
||||
@@ -356,8 +369,4 @@ impl Machine {
|
||||
self.cut_policy = Box::new(DefaultCutPolicy {});
|
||||
self.ms.reset();
|
||||
}
|
||||
|
||||
pub fn op_dir(&self) -> &OpDir {
|
||||
&self.op_dir
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user