fn prolog_repl() {
let mut wam = Machine::new();
-
+
loop {
print!("prolog> ");
stdout().flush().unwrap();
fn mark_unsafe_vars(&self, mut unsafe_var_marker: UnsafeVarMarker, code: &mut Code) {
// target the last goal of the rule for handling unsafe variables.
// we use this weird logic to find the last goal.
- let index = if let &Line::Control(_) = code.last().unwrap() {
+ let right_index = if let &Line::Control(_) = code.last().unwrap() {
code.len() - 2
} else {
code.len() - 1
};
- if let Line::Query(_) = &code[index] {
+ let mut index = right_index;
+
+ if let Line::Query(_) = &code[right_index] {
+ while let Line::Query(_) = &code[index] { // index >= 0.
+ if index == 0 {
+ break;
+ } else {
+ index -= 1;
+ }
+ }
+
+ if let Line::Query(_) = &code[index] {} else {
+ index += 1;
+ }
+
unsafe_var_marker.record_unsafe_vars(&self.perm_vs);
for line in code.iter_mut() {
- if let &mut Line::Query(ref mut query) = line {
- unsafe_var_marker.mark_safe_vars(query);
+ if let &mut Line::Query(ref mut query_instr) = line {
+ unsafe_var_marker.mark_safe_vars(query_instr);
}
}
- }
- if let &mut Line::Query(ref mut query) = &mut code[index] {
- unsafe_var_marker.mark_unsafe_vars(query);
+ for index in index .. right_index + 1 {
+ if let &mut Line::Query(ref mut query_instr) = &mut code[index] {
+ unsafe_var_marker.mark_unsafe_vars(query_instr);
+ }
+ }
}
}
}
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
if !target.is_empty() {
- code.push(Line::Query(target));
+ for query_instr in target {
+ code.push(Line::Query(query_instr));
+ }
}
vr.get().norm()
term_loc, &mut target);
if !target.is_empty() {
- code.push(Line::Query(target));
+ for query_instr in target {
+ code.push(Line::Query(query_instr));
+ }
}
if use_default_call_policy {
}
},
&Term::Constant(_, ref c @ Constant::Number(_)) => {
- code.push(query![put_constant!(Level::Shallow,
- c.clone(),
- temp_v!(1))]);
+ code.push(Line::Query(put_constant!(Level::Shallow,
+ c.clone(),
+ temp_v!(1))));
if use_default_call_policy {
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
term_loc, &mut target);
if !target.is_empty() {
- code.push(Line::Query(target));
+ for query_instr in target {
+ code.push(Line::Query(query_instr));
+ }
}
code.push(get_level_and_unify!(cell.get().norm()));
if !fact.is_empty() {
unsafe_var_marker = self.mark_unsafe_fact_vars(&mut fact);
- code.push(Line::Fact(fact));
+
+ for fact_instr in fact {
+ code.push(Line::Fact(fact_instr));
+ }
}
let iter = ChunkedIterator::from_rule_body(p1, clauses);
self.mark_unsafe_fact_vars(&mut compiled_fact);
if !compiled_fact.is_empty() {
- code.push(Line::Fact(compiled_fact));
+ for fact_instr in compiled_fact {
+ code.push(Line::Fact(fact_instr));
+ }
}
}
let query = self.compile_target(iter, term_loc, is_exposed);
if !query.is_empty() {
- code.push(Line::Query(query));
+ for query_instr in query {
+ code.push(Line::Query(query_instr));
+ }
}
Self::add_conditional_call(code, term, num_perm_vars_left);
match clause {
&Line::Arithmetic(ref arith) =>
println!("{}", arith),
- &Line::Fact(ref fact) =>
- for fact_instr in fact {
- println!("{}", fact_instr);
- },
+ &Line::Fact(ref fact_instr) =>
+ println!("{}", fact_instr),
&Line::Cut(ref cut) =>
println!("{}", cut),
&Line::Choice(ref choice) =>
println!("{}", choice),
&Line::Indexing(ref indexing) =>
println!("{}", indexing),
- &Line::Query(ref query) =>
- for query_instr in query {
- println!("{}", query_instr);
- }
+ &Line::Query(ref query_instr) =>
+ println!("{}", query_instr)
}
}
}
let mut code = try!(cg.compile_query(&terms));
compile_appendix(&mut code, &queue, false, flags)?;
-
+
Ok((code, cg.take_vars()))
}
Err(e) => EvalSession::from(e)
},
TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => {
- let mut compiler = ListingCompiler::new(&wam.code_repo);
-
+ let mut compiler = ListingCompiler::new(&wam.code_repo, wam.code_size());
let indices = try_eval_session!(compile_decl(wam, &mut compiler, decl));
+
try_eval_session!(compiler.add_code(wam, vec![], indices));
EvalSession::EntrySuccess
}
pub struct ListingCompiler {
+ code_size_offset: usize,
non_counted_bt_preds: HashSet<PredicateKey>,
module: Option<Module>,
user_term_dir: TermDir,
impl ListingCompiler {
#[inline]
- pub fn new(code_repo: &CodeRepo) -> Self {
+ pub fn new(code_repo: &CodeRepo, code_size_offset: usize) -> Self {
ListingCompiler {
- module: None, non_counted_bt_preds: HashSet::new(),
+ code_size_offset,
+ non_counted_bt_preds: HashSet::new(),
+ module: None,
user_term_dir: TermDir::new(),
orig_term_expansion_lens: code_repo.term_dir_entry_len((clause_name!("term_expansion"), 2)),
orig_goal_expansion_lens: code_repo.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
.unwrap_or(ClauseName::BuiltIn("user"))
}
- fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>,
- wam: &Machine, code_dir: &mut CodeDir)
+ fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>, wam: &Machine,
+ code_dir: &mut CodeDir)
-> Result<Code, SessionError>
{
let mut code = vec![];
let arity = cl.arity();
cl.name().map(|name| (name, arity))
}).ok_or(SessionError::NamelessEntry)?;
-
+
let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
- let p = code.len() + wam.code_size();
+ let p = code.len() + self.code_size_offset;
let mut decl_code = compile_relation(&TopLevel::Predicate(decl), non_counted_bt,
wam.machine_flags())?;
Ok(self.add_non_counted_bt_flag(name, arity)),
Declaration::Op(op_decl) =>
op_decl.submit(self.get_module_name(), &mut indices.op_dir),
- Declaration::UseModule(name) =>
+ Declaration::UseModule(name) =>
self.use_module(name, code_repo, flags, wam_indices, indices),
Declaration::UseQualifiedModule(name, exports) =>
self.use_qualified_module(name, code_repo, flags, &exports, wam_indices, indices),
-> Result<GatherResult, SessionError>
{
let flags = wam.machine_flags();
- let wam_indices = &mut wam.indices;
-
- let atom_tbl = wam_indices.atom_tbl.clone();
+ let atom_tbl = wam.indices.atom_tbl.clone();
let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags,
- wam_indices, &mut wam.policies,
+ &mut wam.indices, &mut wam.policies,
&mut wam.code_repo);
let mut toplevel_results = vec![];
EvalSession::EntrySuccess
}
+/* This is a truncated version of compile_user_module, used for
+ compiling code composing special forms, ie. the code that calls
+ M:verify_attributes on attributed variables. */
+pub fn compile_special_form<R: Read>(wam: &mut Machine, src: R) -> Result<Code, SessionError>
+{
+ let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
+ setup_indices(wam, &mut indices)?;
+
+ let mut compiler = ListingCompiler::new(&wam.code_repo, 0);
+ let results = compiler.gather_items(wam, src, &mut indices)?;
+
+ compiler.generate_code(results.worker_results, wam, &mut indices.code_dir)
+}
+
#[inline]
pub fn compile_listing<R: Read>(wam: &mut Machine, src: R, indices: IndexStore) -> EvalSession
{
- let mut compiler = ListingCompiler::new(&wam.code_repo);
+ let mut compiler = ListingCompiler::new(&wam.code_repo, wam.code_size());
match compile_work(&mut compiler, wam, src, indices) {
EvalSession::Error(e) => EvalSession::Error(compiler.drop_expansions(wam, e)),
pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
- try_eval_session!(setup_indices(wam, &mut indices));
+ try_eval_session!(setup_indices(wam, &mut indices));
compile_listing(wam, src, indices)
}
}
}
- pub fn mark_safe_vars(&mut self, query: &mut CompiledQuery) {
- for query_instr in query.iter_mut() {
- match query_instr {
- &mut QueryInstruction::PutVariable(RegType::Temp(r), _) =>
- if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(r)) {
- *found = true;
- },
- &mut QueryInstruction::SetVariable(reg) =>
- if let Some(found) = self.unsafe_vars.get_mut(®) {
- *found = true;
- },
- _ => {}
- }
+ pub fn mark_safe_vars(&mut self, query_instr: &mut QueryInstruction) {
+ match query_instr {
+ &mut QueryInstruction::PutVariable(RegType::Temp(r), _) =>
+ if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(r)) {
+ *found = true;
+ },
+ &mut QueryInstruction::SetVariable(reg) =>
+ if let Some(found) = self.unsafe_vars.get_mut(®) {
+ *found = true;
+ },
+ _ => {}
}
}
- pub fn mark_unsafe_vars(&mut self, query: &mut CompiledQuery)
+ pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction)
{
- for query_instr in query.iter_mut() {
- match query_instr {
- &mut QueryInstruction::PutValue(RegType::Perm(i), arg) =>
- if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) {
- if !*found {
- *found = true;
- *query_instr = QueryInstruction::PutUnsafeValue(i, arg);
- }
- },
- &mut QueryInstruction::SetValue(reg) =>
- if let Some(found) = self.unsafe_vars.get_mut(®) {
- if !*found {
- *found = true;
- *query_instr = QueryInstruction::SetLocalValue(reg);
- }
- },
- _ => {}
- };
+ match query_instr {
+ &mut QueryInstruction::PutValue(RegType::Perm(i), arg) =>
+ if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) {
+ if !*found {
+ *found = true;
+ *query_instr = QueryInstruction::PutUnsafeValue(i, arg);
+ }
+ },
+ &mut QueryInstruction::SetValue(reg) =>
+ if let Some(found) = self.unsafe_vars.get_mut(®) {
+ if !*found {
+ *found = true;
+ *query_instr = QueryInstruction::SetLocalValue(reg);
+ }
+ },
+ _ => {}
}
}
}
pub(super) term_expanders: Code,
pub(super) code: Code,
pub(super) in_situ_code: Code,
+ pub(super) verify_attrs_code: Code,
pub(super) term_dir: TermDir
}
GetSCCCleaner,
InstallSCCCleaner,
InstallInferenceCounter,
+ ModuleOf,
RemoveCallPolicyCheck,
RemoveInferenceCounter,
RestoreCutPolicy,
GetDoubleQuotes,
InstallNewBlock,
ResetBlock,
+ RestoreCodePtrFromSpecialFormCP,
SetBall,
SetCutPointByDefault(RegType),
SetDoubleQuotes,
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
- &SystemClauseType::InstallInferenceCounter =>
- clause_name!("$install_inference_counter"),
- &SystemClauseType::RemoveCallPolicyCheck =>
- clause_name!("$remove_call_policy_check"),
- &SystemClauseType::RemoveInferenceCounter =>
- clause_name!("$remove_inference_counter"),
+ &SystemClauseType::InstallInferenceCounter => clause_name!("$install_inference_counter"),
+ &SystemClauseType::ModuleOf => clause_name!("$module_of"),
+ &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
+ &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
&SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
+ &SystemClauseType::RestoreCodePtrFromSpecialFormCP => clause_name!("$restore_p_from_sfcp"),
&SystemClauseType::SetBall => clause_name!("$set_ball"),
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
&SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"),
("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
- ("$install_scc_cleaner", 2) =>
- Some(SystemClauseType::InstallSCCCleaner),
- ("$install_inference_counter", 3) =>
- Some(SystemClauseType::InstallInferenceCounter),
- ("$remove_call_policy_check", 1) =>
- Some(SystemClauseType::RemoveCallPolicyCheck),
- ("$remove_inference_counter", 2) =>
- Some(SystemClauseType::RemoveInferenceCounter),
+ ("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
+ ("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
+ ("$module_of", 2) => Some(SystemClauseType::ModuleOf),
+ ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
+ ("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
+ ("$restore_p_from_sfcp", 0) => Some(SystemClauseType::RestoreCodePtrFromSpecialFormCP),
("$set_ball", 1) => Some(SystemClauseType::SetBall),
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
pub type CompiledFact = Vec<FactInstruction>;
-pub type CompiledQuery = Vec<QueryInstruction>;
-
pub enum Line {
Arithmetic(ArithmeticInstruction),
Choice(ChoiceInstruction),
Control(ControlInstruction),
Cut(CutInstruction),
- Fact(CompiledFact),
+ Fact(FactInstruction),
Indexing(IndexingInstruction),
IndexedChoice(IndexedChoiceInstruction),
- Query(CompiledQuery)
+ Query(QueryInstruction)
}
pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>;
pub(super) e: usize,
pub(super) num_of_args: usize,
pub(super) cp: LocalCodePtr,
+ pub(super) special_form_cp: CodePtr,
pub(super) fail: bool,
pub(crate) heap: Heap,
pub(super) mode: MachineMode,
e: 0,
num_of_args: 0,
cp: LocalCodePtr::default(),
+ special_form_cp: CodePtr::default(),
fail: false,
heap: Heap::with_capacity(256),
mode: MachineMode::Write,
self.pstr_tr = 0;
self.p = CodePtr::default();
self.cp = LocalCodePtr::default();
+ self.special_form_cp = CodePtr::default();
self.num_of_args = 0;
self.fail = false;
use prolog::heap_print::*;
use prolog::instructions::*;
+mod attributed_variables;
mod machine_errors;
pub(super) mod machine_state;
pub(super) mod term_expansion;
#[macro_use] mod machine_state_impl;
mod system_calls;
+use prolog::machine::attributed_variables::*;
use prolog::machine::machine_state::*;
use std::collections::{HashMap, VecDeque};
use std::ops::Index;
use std::rc::Rc;
-static BUILTINS: &str = include_str!("../lib/builtins.pl");
-
pub type InSituCodeDir = HashMap<PredicateKey, usize>;
pub struct IndexStore {
term_expanders: Code::new(),
code: Code::new(),
in_situ_code: Code::new(),
+ verify_attrs_code: Code::new(),
term_dir: TermDir::new()
}
}
}
}
-static LISTS: &str = include_str!("../lib/lists.pl");
-static CONTROL: &str = include_str!("../lib/control.pl");
-static QUEUES: &str = include_str!("../lib/queues.pl");
-static ERROR: &str = include_str!("../lib/error.pl");
-static TERMS: &str = include_str!("../lib/terms.pl");
-static DCGS: &str = include_str!("../lib/dcgs.pl");
-static ATTS: &str = include_str!("../lib/atts.pl");
+static BUILTINS: &str = include_str!("../lib/builtins.pl");
+static LISTS: &str = include_str!("../lib/lists.pl");
+static CONTROL: &str = include_str!("../lib/control.pl");
+static QUEUES: &str = include_str!("../lib/queues.pl");
+static ERROR: &str = include_str!("../lib/error.pl");
+static TERMS: &str = include_str!("../lib/terms.pl");
+static DCGS: &str = include_str!("../lib/dcgs.pl");
+static ATTS: &str = include_str!("../lib/atts.pl");
impl Machine {
+ fn compile_special_forms(&mut self) {
+ match compile_special_form(self, VERIFY_ATTRS.as_bytes()) {
+ Ok(code) => self.code_repo.verify_attrs_code = code,
+ Err(_e) => panic!("Machine::compile_special_forms() failed")
+ }
+ }
+
pub fn new() -> Self {
let mut wam = Machine {
machine_st: MachineState::new(),
compile_user_module(&mut wam, DCGS.as_bytes());
compile_user_module(&mut wam, ATTS.as_bytes());
+ wam.compile_special_forms();
wam
}
&Line::Control(ref control_instr) =>
self.execute_ctrl_instr(indices, &mut policies.call_policy,
&mut policies.cut_policy, control_instr),
- &Line::Fact(ref fact) => {
- for fact_instr in fact {
- if self.fail {
- break;
- }
-
- self.execute_fact_instr(&fact_instr);
- }
-
+ &Line::Fact(ref fact_instr) => {
+ self.execute_fact_instr(&fact_instr);
self.p += 1;
},
&Line::Indexing(ref indexing_instr) =>
self.execute_indexing_instr(&indexing_instr),
&Line::IndexedChoice(ref choice_instr) =>
self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy),
- &Line::Query(ref query) => {
- for query_instr in query {
- if self.fail {
- break;
- }
-
- self.execute_query_instr(&query_instr);
- }
-
+ &Line::Query(ref query_instr) => {
+ self.execute_query_instr(&query_instr);
self.p += 1;
}
}
}
};
},
+ &SystemClauseType::ModuleOf => {
+ let module = self.store(self.deref(self[temp_v!(2)].clone()));
+
+ match module {
+ Addr::Con(Constant::Atom(name, _)) => {
+ let module = Addr::Con(Constant::Atom(name.owning_module(), None));
+ let target = self[temp_v!(1)].clone();
+
+ self.unify(target, module);
+ },
+ Addr::Str(s) =>
+ match self.heap[s].clone() {
+ HeapCellValue::NamedStr(_, name, ..) => {
+ let module = Addr::Con(Constant::Atom(name.owning_module(), None));
+ let target = self[temp_v!(1)].clone();
+
+ self.unify(target, module);
+ },
+ _ => self.fail = true
+ },
+ _ => self.fail = true
+ };
+ },
&SystemClauseType::RemoveCallPolicyCheck => {
let restore_default =
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
None => panic!("remove_inference_counter: requires \\
CWILCallPolicy.")
},
+ &SystemClauseType::RestoreCodePtrFromSpecialFormCP => {
+ self.p = self.special_form_cp.clone();
+ return Ok(());
+ },
&SystemClauseType::RestoreCutPolicy => {
let restore_default =
if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
)
}
-macro_rules! query {
- [$($x:expr),+] => (
- Line::Query(vec![$($x),+])
- )
-}
-
macro_rules! heap_str {
($s:expr) => (
HeapCellValue::Addr(Addr::Str($s))
Ok(result)
}
- pub
- fn consume(&mut self, indices: &mut IndexStore) -> Result<Option<Declaration>, SessionError>
+ pub fn consume(&mut self, indices: &mut IndexStore) -> Result<Option<Declaration>, SessionError>
{
let mut preds = vec![];