indexmap = "1.0.2"
[dependencies]
-cfg-if = "0.1.7"
dirs = "2.0.2"
downcast = "0.10.0"
indexmap = "1.0.2"
* `throw/1`
* `true/0`
* `unify_with_occurs_check/2`
+* `use_module/{1,2}`
* `user:goal_expansion/2`
* `user:term_expansion/2`
* `var/1`
#[macro_use]
-extern crate cfg_if;
-#[macro_use]
extern crate downcast;
extern crate indexmap;
#[macro_use]
extern crate prolog_parser;
#[macro_use]
extern crate ref_thread_local;
-
-cfg_if! {
- if #[cfg(feature = "readline_rs_compat")] {
- extern crate readline_rs_compat;
- }
-}
-
extern crate termion;
mod prolog;
mod tests;
fn main() {
-// #[cfg(feature = "readline_rs_compat")]
-// readline::readline_initialize();
-
- let mut wam = Machine::new(readline::input_stream());
- wam.run_toplevel();
+ let mut wam = Machine::new(readline::input_stream());
+ wam.run_top_level();
}
&SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) => {
clause_name!("$submit_query_and_print_results")
}
+ &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
+ &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
+ clause_name!("$use_qualified_module")
+ }
+ &SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => {
+ clause_name!("$use_module_from_file")
+ }
+ &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
+ clause_name!("$use_qualified_module_from_file")
+ }
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
+ ("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
+ ("$use_module_from_file", 1) =>
+ Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)),
+ ("$use_qualified_module", 2) =>
+ Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)),
+ ("$use_qualified_module_from_file", 2) =>
+ Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
("$variant", 2) => Some(SystemClauseType::Variant),
("$write_term", 5) => Some(SystemClauseType::WriteTerm),
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
target.push(Target::move_to_register(r, k));
- self.contents.remove(&k);
+ self.contents.swap_remove(&k);
self.contents.insert(r.reg_num(), var.clone());
self.record_register(var, r);
});
iter.stack().pop();
- self.cyclic_terms.remove(&addr);
+ self.cyclic_terms.swap_remove(&addr);
None
}
}
match compile_work_impl(&mut compiler, wam, indices, results) {
EvalSession::Error(e) => Err(e),
_ => Ok(module_name),
- }
+ }
}
pub(super)
Err(SessionError::InvalidFileName(filename))
})?;
- let file_stem = path.file_stem().unwrap().to_string_lossy();
+ let file_stem = path.file_stem().unwrap().to_string_lossy();
load_module(wam, &file_stem, parsing_stream(file_handle))
}
if name.owning_module() == module.module_decl.name {
wam.indices
.dynamic_code_dir
- .remove(&(name.owning_module(), name, arity));
+ .swap_remove(&(name.owning_module(), name, arity));
}
}
Ok(())
}
+pub(super)
fn load_library(wam: &mut Machine, name: ClauseName) -> Result<ClauseName, SessionError> {
match LIBRARIES.borrow().get(name.as_str()) {
Some(code) => load_module(wam, name.as_str(), parsing_stream(code.as_bytes())),
pub enum REPLCodePtr {
CompileBatch,
SubmitQueryAndPrintResults,
+ UseModule,
+ UseQualifiedModule,
+ UseModuleFromFile,
+ UseQualifiedModuleFromFile
}
#[derive(Clone, PartialEq)]
pub fn local(&self) -> LocalCodePtr {
match self {
&CodePtr::BuiltInClause(_, ref local)
- | &CodePtr::CallN(_, ref local)
- | &CodePtr::Local(ref local) => local.clone(),
+ | &CodePtr::CallN(_, ref local)
+ | &CodePtr::Local(ref local) => local.clone(),
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
&CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p,
}
fn partial_cmp(&self, other: &LocalCodePtr) -> Option<Ordering> {
match (self, other) {
(&LocalCodePtr::InSituDirEntry(p1), &LocalCodePtr::InSituDirEntry(ref p2))
- | (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2))
- | (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2))
- | (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2))
- | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
+ | (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2))
+ | (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2))
+ | (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2))
+ | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
p1.partial_cmp(p2)
}
(_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less),
fn add_assign(&mut self, rhs: usize) {
match self {
&mut LocalCodePtr::InSituDirEntry(ref mut p)
- | &mut LocalCodePtr::UserGoalExpansion(ref mut p)
- | &mut LocalCodePtr::UserTermExpansion(ref mut p)
- | &mut LocalCodePtr::DirEntry(ref mut p)
- | &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs,
+ | &mut LocalCodePtr::UserGoalExpansion(ref mut p)
+ | &mut LocalCodePtr::UserTermExpansion(ref mut p)
+ | &mut LocalCodePtr::DirEntry(ref mut p)
+ | &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs,
}
}
}
fn add(self, rhs: usize) -> Self::Output {
match self {
p @ CodePtr::REPL(..)
- | p @ CodePtr::VerifyAttrInterrupt(_)
- | p @ CodePtr::DynamicTransaction(..) => p,
+ | p @ CodePtr::VerifyAttrInterrupt(_)
+ | p @ CodePtr::DynamicTransaction(..) => p,
CodePtr::Local(local) => CodePtr::Local(local + rhs),
CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => {
CodePtr::Local(local + rhs)
#[inline]
pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
- self.dynamic_code_dir.remove(&(module, name, arity));
+ self.dynamic_code_dir.swap_remove(&(module, name, arity));
}
#[inline]
#[inline]
pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
- self.modules.remove(&name)
+ self.modules.swap_remove(&name)
}
#[inline]
}
}
- pub(super) fn reset(&mut self) {
+ pub fn reset(&mut self) {
self.hb = 0;
self.e = 0;
self.b = 0;
self.machine_st.reset();
}
- pub fn run_toplevel(&mut self) {
+ pub fn run_top_level(&mut self) {
use std::env;
- use prolog::machine::compile::load_module_from_file;
- for filename in env::args() {
- load_module_from_file(self, &filename);
+ let mut filename_atoms = vec![];
+
+ // the first of these is the path to the scryer-prolog executable, so skip
+ // it.
+ for filename in env::args().skip(1) {
+ let atom = atom!(filename, self.indices.atom_tbl);
+ filename_atoms.push(Addr::Con(atom));
}
-
+
+ let list_addr =
+ Addr::HeapCell(self.machine_st.heap.to_list(filename_atoms.into_iter()));
+
+ self.machine_st[temp_v!(1)] = list_addr;
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
+
self.run_query(&AllocVarDict::new());
}
);
wam.compile_special_forms();
- wam.compile_top_level();
compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()));
compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()));
compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()));
+ compile_user_module(&mut wam, parsing_stream(SI.as_bytes()));
+ wam.compile_top_level();
wam.compile_scryerrc();
wam
return;
}
+ fn extract_predicate_indicator_list(&mut self) -> Vec<PredicateKey>
+ {
+ let export_list = self.machine_st[temp_v!(2)].clone();
+ let mut export_list = self.machine_st.store(self.machine_st.deref(export_list));
+ let mut exports = vec![];
+
+ while let Addr::Lis(l) = export_list {
+ match &self.machine_st.heap[l] {
+ &HeapCellValue::Addr(Addr::Str(s)) => {
+ let name = match &self.machine_st.heap[s+1] {
+ &HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
+ name.clone(),
+ _ =>
+ unreachable!()
+ };
+
+ let arity = match &self.machine_st.heap[s+2] {
+ &HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
+ arity.to_usize().unwrap(),
+ _ =>
+ unreachable!()
+ };
+
+ exports.push((name, arity));
+ }
+ _ => unreachable!()
+ }
+
+ export_list = self.machine_st.heap[l+1].as_addr(l+1);
+ }
+
+ exports
+ }
+
+ fn use_module<ToSource>(&mut self, to_src: ToSource)
+ where ToSource: Fn(ClauseName) -> ModuleSource
+ {
+ // the term expander will overwrite the cached query, so save it here.
+ let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
+
+ let module_spec = self.machine_st[temp_v!(1)].clone();
+ let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
+ Addr::Con(Constant::Atom(name, _)) => name,
+ _ => unreachable!()
+ };
+
+ let load_result = match to_src(name) {
+ ModuleSource::Library(name) =>
+ if !self.indices.modules.contains_key(&name) {
+ load_library(self, name)
+ } else {
+ Ok(name)
+ },
+ ModuleSource::File(name) => load_module_from_file(self, name.as_str())
+ };
+
+ let result = load_result.and_then(|name| {
+ let module = self.indices.take_module(name).unwrap();
+
+ // remove previous exports.
+ self.indices.remove_module(clause_name!("user"), &module);
+ self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?;
+
+ Ok(self.indices.insert_module(module))
+ });
+
+ self.code_repo.cached_query = cached_query;
+
+ if let Err(e) = result {
+ self.throw_session_error(e, (clause_name!("use_module"), 1));
+ }
+ }
+
+ fn use_qualified_module<ToSource>(&mut self, to_src: ToSource)
+ where ToSource: Fn(ClauseName) -> ModuleSource
+ {
+ // the term expander will overwrite the cached query, so save it here.
+ let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
+
+ let module_spec = self.machine_st[temp_v!(1)].clone();
+ let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
+ Addr::Con(Constant::Atom(name, _)) => name,
+ _ => unreachable!()
+ };
+
+ let exports = self.extract_predicate_indicator_list();
+
+ let load_result = match to_src(name) {
+ ModuleSource::Library(name) =>
+ if !self.indices.modules.contains_key(&name) {
+ load_library(self, name)
+ } else {
+ Ok(name)
+ },
+ ModuleSource::File(name) => load_module_from_file(self, name.as_str())
+ };
+
+ let result = load_result.and_then(|name| {
+ let module = self.indices.take_module(name).unwrap();
+
+ // remove previous exports.
+ self.indices.remove_module(clause_name!("user"), &module);
+ self.indices.use_qualified_module(&mut self.code_repo,
+ self.machine_st.flags,
+ &module,
+ &exports)?;
+
+ Ok(self.indices.insert_module(module))
+ });
+
+ self.code_repo.cached_query = cached_query;
+
+ if let Err(e) = result {
+ self.throw_session_error(e, (clause_name!("use_module"), 1));
+ }
+ }
+
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
match code_ptr {
REPLCodePtr::CompileBatch => {
let src = readline::input_stream();
readline::set_prompt(false);
-
- match compile_user_module(self, src) {
- EvalSession::Error(e) => self.throw_session_error(e, (clause_name!("repl"), 0)),
- _ => {}
- };
+
+ if let EvalSession::Error(e) = compile_user_module(self, src) {
+ self.throw_session_error(e, (clause_name!("repl"), 0));
+ }
}
REPLCodePtr::SubmitQueryAndPrintResults => {
let term = self.machine_st[temp_v!(1)].clone();
self.handle_eval_session(result, snapshot);
}
+ REPLCodePtr::UseModule =>
+ self.use_module(ModuleSource::Library),
+ REPLCodePtr::UseModuleFromFile =>
+ self.use_module(ModuleSource::File),
+ REPLCodePtr::UseQualifiedModule =>
+ self.use_qualified_module(ModuleSource::Library),
+ REPLCodePtr::UseQualifiedModuleFromFile =>
+ self.use_qualified_module(ModuleSource::File)
}
self.machine_st.p = CodePtr::Local(p);
}
pub(super) fn run_query(&mut self, alloc_locs: &AllocVarDict) {
- let end_ptr = top_level_code_ptr!(0, self.code_repo.size_of_cached_query());
+ self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
+ let end_ptr = CodePtr::Local(self.machine_st.cp);
while self.machine_st.p < end_ptr {
if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.machine_st.p {
where
Outputter: HCValueOutputter,
{
- let mut sorted_vars: Vec<_> = self.machine_st.heap_locs.iter().collect();
- sorted_vars.sort_by_key(|ref v| v.0);
-
- for (var, addr) in sorted_vars {
+ for (var, addr) in self.machine_st.heap_locs.iter() {
let addr = self.machine_st.store(self.machine_st.deref(addr.clone()));
output = self
.machine_st
where
Outputter: HCValueOutputter,
{
- let mut sorted_vars: Vec<(&Rc<Var>, &Addr)> = self.machine_st.heap_locs.iter().collect();
- sorted_vars.sort_by_key(|ref v| v.0);
-
- for (var, addr) in sorted_vars {
+ for (var, addr) in self.machine_st.heap_locs.iter() {
output = self.machine_st.print_var_eq(
var.clone(),
addr.clone(),
self.p.local() + 1
};
- self.p = CodePtr::REPL(repl_code_ptr, p);
- return Ok(());
+ Ok(self.p = CodePtr::REPL(repl_code_ptr, p))
}
fn truncate_if_no_lifted_heap_diff<AddrConstr>(&mut self, addr_constr: AddrConstr)
_ => unreachable!(),
};
- indices.global_variables.remove(&key);
+ indices.global_variables.swap_remove(&key);
}
&SystemClauseType::RemoveCallPolicyCheck => {
let restore_default = match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
terms: Vec<Box<Term>>,
blocks_cuts: bool,
) -> Result<TopLevel, ParserError> {
+ /*
match setup_declaration(terms.iter().cloned().collect()) {
Ok(Declaration::Op(..)) => {} // this is now a predicate call in the query context.
Ok(decl) => return Ok(TopLevel::Declaration(decl)),
_ => {}
};
-
+ */
Ok(TopLevel::Query(self.setup_query(
indices,
terms,
+/*
+ * inserting the modules should not result in the insertion of
+ * code. this is because they're already loaded by this point -- see
+ * Machine::new.
+*/
+
+:- use_module(library(lists)).
+:- use_module(library(si)).
+
+'$repl'(ListOfModules) :-
+ maplist('$use_list_of_modules', ListOfModules),
+ false.
+'$repl'(_) :- '$repl'.
+
+'$use_list_of_modules'(Module) :-
+ catch(use_module(Module), E, '$print_exception'(E)).
+
'$repl' :-
catch('$read_and_match', E, '$print_exception'(E)),
false. %% this is for GC, until we get actual GC.
write_term('caught: ', [quoted(false)]),
writeq(E),
nl.
+
+'$predicate_indicator'(Source, PI) :-
+ ( nonvar(PI) ->
+ ( PI = Name / Arity ->
+ ( var(Name) -> throw(error(instantiation_error, Source))
+ ; integer(Arity) ->
+ ( \+ atom(Name) -> throw(error(type_error(atom, Name), Source))
+ ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), Source))
+ ; true
+ )
+ ; throw(error(type_error(integer, Arity), Source))
+ )
+ ; throw(error(type_error(predicate_indicator, PI), Source))
+ )
+ ; throw(error(instantiation_error, Source))
+ ).
+
+use_module(Module) :-
+ ( nonvar(Module) ->
+ ( Module = library(Filename) -> '$use_module'(Filename)
+ ; atom(Module) -> '$use_module_from_file'(Module)
+ ; throw(error(invalid_module_specifier, use_module/1))
+ )
+ ; throw(error(instantiation_error, use_module/1))
+ ).
+
+use_module(Module, QualifiedExports) :-
+ ( nonvar(Module) ->
+ ( list_si(QualifiedExports) ->
+ maplist('$predicate_indicator'(use_module/2), QualifiedExports), !,
+ ( Module = library(Filename) -> '$use_qualified_module'(Filename, QualifiedExports)
+ ; atom(Module) -> '$use_qualified_module_from_file'(Module, QualifiedExports)
+ ; throw(error(invalid_module_specifier, use_module/2))
+ )
+ ; throw(error(type_error(list, QualifiedExports), use_module/2))
+ )
+ ; throw(error(instantiation_error, use_module/2))
+ ).
REPLCodePtr::SubmitQueryAndPrintResults => {
write!(f, "REPLCodePtr::SubmitQueryAndPrintResults")
}
+ REPLCodePtr::UseModule =>
+ write!(f, "REPLCodePtr::UseModule"),
+ REPLCodePtr::UseQualifiedModule =>
+ write!(f, "REPLCodePtr::UseQualifiedModule"),
+ REPLCodePtr::UseModuleFromFile =>
+ write!(f, "REPLCodePtr::UseModuleFromFile"),
+ REPLCodePtr::UseQualifiedModuleFromFile =>
+ write!(f, "REPLCodePtr::UseQualifiedModuleFromFile")
}
}
}