provisional changes to module insertion
This commit is contained in:
35
src/main.rs
35
src/main.rs
@@ -11,22 +11,11 @@ use prolog::machine::*;
|
|||||||
use prolog::read::*;
|
use prolog::read::*;
|
||||||
use prolog::write::*;
|
use prolog::write::*;
|
||||||
|
|
||||||
use std::io::{Write, stdout};
|
use std::io::{Write, stdin, stdout};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
fn parse_and_compile_line(wam: &mut Machine, buffer: &str)
|
|
||||||
{
|
|
||||||
match parse_code(wam, buffer) {
|
|
||||||
Ok(packet) => {
|
|
||||||
let result = compile_packet(wam, packet);
|
|
||||||
print(wam, result);
|
|
||||||
},
|
|
||||||
Err(e) => print(wam, EvalSession::from(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prolog_repl() {
|
fn prolog_repl() {
|
||||||
let mut wam = Machine::new();
|
let mut wam = Machine::new();
|
||||||
|
|
||||||
@@ -35,17 +24,14 @@ fn prolog_repl() {
|
|||||||
stdout().flush().unwrap();
|
stdout().flush().unwrap();
|
||||||
|
|
||||||
match read_toplevel(&mut wam) {
|
match read_toplevel(&mut wam) {
|
||||||
Ok(Input::Term(term)) =>
|
Ok(Input::Term(term)) => {
|
||||||
match compile_term(&mut wam, term) {
|
let result = compile_term(&mut wam, term);
|
||||||
Ok(packet) => {
|
print(&mut wam, result)
|
||||||
let result = compile_packet(&mut wam, packet);
|
},
|
||||||
print(&mut wam, result);
|
Ok(Input::Batch) => {
|
||||||
},
|
let stdin = stdin();
|
||||||
Err(e) => print(&mut wam, EvalSession::from(e))
|
let result = compile_user_module(&mut wam, stdin.lock());
|
||||||
},
|
|
||||||
Ok(Input::Line(line)) => parse_and_compile_line(&mut wam, line.as_str()),
|
|
||||||
Ok(Input::Batch(batch)) => {
|
|
||||||
let result = compile_user_module(&mut wam, batch.as_bytes());
|
|
||||||
print(&mut wam, result);
|
print(&mut wam, result);
|
||||||
},
|
},
|
||||||
Ok(Input::Quit) => break,
|
Ok(Input::Quit) => break,
|
||||||
@@ -53,7 +39,8 @@ fn prolog_repl() {
|
|||||||
wam.clear();
|
wam.clear();
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
Err(e) => print(&mut wam, EvalSession::from(e))
|
Err(e) =>
|
||||||
|
print(&mut wam, EvalSession::from(e))
|
||||||
};
|
};
|
||||||
|
|
||||||
wam.reset();
|
wam.reset();
|
||||||
|
|||||||
@@ -38,22 +38,6 @@ fn print_code(code: &Code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
|
|
||||||
{
|
|
||||||
let atom_tbl = wam.atom_tbl();
|
|
||||||
let flags = wam.machine_flags();
|
|
||||||
|
|
||||||
let indices = machine_code_indices!(&mut wam.code_dir, &mut wam.op_dir, &mut HashMap::new());
|
|
||||||
|
|
||||||
let mut worker = TopLevelWorker::new(buffer.as_bytes(), atom_tbl, flags, indices);
|
|
||||||
worker.parse_code()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_term(wam: &mut Machine, term: Term) -> Result<TopLevelPacket, ParserError> {
|
|
||||||
let indices = machine_code_indices!(&mut wam.code_dir, &mut wam.op_dir, &mut HashMap::new());
|
|
||||||
parse_term(term, indices)
|
|
||||||
}
|
|
||||||
|
|
||||||
// throw errors if declaration or query found.
|
// throw errors if declaration or query found.
|
||||||
fn compile_relation(tl: &TopLevel, non_counted_bt: bool, flags: MachineFlags) -> Result<Code, ParserError>
|
fn compile_relation(tl: &TopLevel, non_counted_bt: bool, flags: MachineFlags) -> Result<Code, ParserError>
|
||||||
{
|
{
|
||||||
@@ -112,69 +96,79 @@ fn compile_query(terms: Vec<QueryTerm>, queue: Vec<TopLevel>, flags: MachineFlag
|
|||||||
Ok((code, cg.take_vars()))
|
Ok((code, cg.take_vars()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSession
|
fn package_term(wam: &mut Machine, term: Term) -> Result<TopLevelPacket, ParserError> {
|
||||||
{
|
let indices = machine_code_indices!(&mut wam.code_dir, &mut wam.op_dir, &mut wam.modules);
|
||||||
match tl {
|
parse_term(term, indices)
|
||||||
TopLevel::Declaration(Declaration::Op(op_decl)) => {
|
|
||||||
try_eval_session!(op_decl.submit(clause_name!("user"), &mut wam.op_dir));
|
|
||||||
EvalSession::EntrySuccess
|
|
||||||
},
|
|
||||||
TopLevel::Declaration(Declaration::UseModule(name)) =>
|
|
||||||
wam.use_module_in_toplevel(name),
|
|
||||||
TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)) =>
|
|
||||||
wam.use_qualified_module_in_toplevel(name, exports),
|
|
||||||
TopLevel::Declaration(_) =>
|
|
||||||
EvalSession::from(ParserError::InvalidModuleDecl),
|
|
||||||
_ => {
|
|
||||||
let name = try_eval_session!(if let Some(name) = tl.name() {
|
|
||||||
match ClauseType::from(name.clone(), tl.arity(), None) {
|
|
||||||
ClauseType::Named(..) | ClauseType::Op(..) =>
|
|
||||||
Ok(name),
|
|
||||||
_ => {
|
|
||||||
let err_str = format!("{}/{}", name.as_str(), tl.arity());
|
|
||||||
Err(SessionError::ImpermissibleEntry(err_str))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(SessionError::NamelessEntry)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut code = try_eval_session!(compile_relation(&tl, false, wam.machine_flags()));
|
|
||||||
try_eval_session!(compile_appendix(&mut code, queue, false, wam.machine_flags()));
|
|
||||||
|
|
||||||
if !code.is_empty() {
|
|
||||||
wam.add_user_code(name, tl.arity(), code)
|
|
||||||
} else {
|
|
||||||
EvalSession::from(SessionError::ImpermissibleEntry(String::from("no code generated.")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_packet(wam: &mut Machine, tl: TopLevelPacket) -> EvalSession
|
pub fn compile_term(wam: &mut Machine, term: Term) -> EvalSession
|
||||||
{
|
{
|
||||||
match tl {
|
let packet = try_eval_session!(package_term(wam, term));
|
||||||
|
|
||||||
|
match packet {
|
||||||
TopLevelPacket::Query(terms, queue) =>
|
TopLevelPacket::Query(terms, queue) =>
|
||||||
match compile_query(terms, queue, wam.machine_flags()) {
|
match compile_query(terms, queue, wam.machine_flags()) {
|
||||||
Ok((mut code, vars)) => wam.submit_query(code, vars),
|
Ok((mut code, vars)) => wam.submit_query(code, vars),
|
||||||
Err(e) => EvalSession::from(e)
|
Err(e) => EvalSession::from(e)
|
||||||
},
|
},
|
||||||
TopLevelPacket::Decl(tl, queue) =>
|
TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => {
|
||||||
compile_decl(wam, tl, queue)
|
let mut compiler = ListingCompiler::new();
|
||||||
|
let mut indices = default_machine_code_indices!();
|
||||||
|
|
||||||
|
try_eval_session!(compiler.process_decl(decl, wam, &mut indices));
|
||||||
|
try_eval_session!(compiler.add_code(wam, vec![], indices));
|
||||||
|
|
||||||
|
EvalSession::EntrySuccess
|
||||||
|
},
|
||||||
|
_ => EvalSession::from(SessionError::UserPrompt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ListingCompiler<'a> {
|
pub struct ListingCompiler {
|
||||||
wam: &'a mut Machine,
|
|
||||||
non_counted_bt_preds: HashSet<PredicateKey>,
|
non_counted_bt_preds: HashSet<PredicateKey>,
|
||||||
module: Option<Module>
|
module: Option<Module>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ListingCompiler<'a> {
|
impl ListingCompiler {
|
||||||
pub fn new(wam: &'a mut Machine) -> Self {
|
pub fn new() -> Self {
|
||||||
ListingCompiler { wam,
|
ListingCompiler { module: None, non_counted_bt_preds: HashSet::new() }
|
||||||
module: None,
|
}
|
||||||
non_counted_bt_preds: HashSet::new() }
|
|
||||||
|
fn use_module(&mut self, submodule: Module, wam: &mut Machine,
|
||||||
|
indices: &mut MachineCodeIndices) -> Result<(), SessionError>
|
||||||
|
{
|
||||||
|
let mod_name = self.get_module_name();
|
||||||
|
|
||||||
|
indices.use_module(&submodule)?;
|
||||||
|
|
||||||
|
if let &mut Some(ref mut module) = &mut self.module {
|
||||||
|
module.remove_module(mod_name, &submodule);
|
||||||
|
module.use_module(&submodule)?;
|
||||||
|
} else {
|
||||||
|
wam.remove_module(&submodule);
|
||||||
|
}
|
||||||
|
|
||||||
|
wam.insert_module(submodule);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_qualified_module(&mut self, submodule: Module, wam: &mut Machine,
|
||||||
|
exports: &Vec<PredicateKey>, indices: &mut MachineCodeIndices)
|
||||||
|
-> Result<(), SessionError>
|
||||||
|
{
|
||||||
|
let mod_name = self.get_module_name();
|
||||||
|
|
||||||
|
indices.use_qualified_module(&submodule, exports)?;
|
||||||
|
|
||||||
|
if let &mut Some(ref mut module) = &mut self.module {
|
||||||
|
module.remove_module(mod_name, &submodule);
|
||||||
|
module.use_qualified_module(&submodule, exports)?;
|
||||||
|
} else {
|
||||||
|
wam.remove_module(&submodule);
|
||||||
|
}
|
||||||
|
|
||||||
|
wam.insert_module(submodule);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_module_name(&self) -> ClauseName {
|
fn get_module_name(&self) -> ClauseName {
|
||||||
@@ -183,7 +177,8 @@ impl<'a> ListingCompiler<'a> {
|
|||||||
.unwrap_or(ClauseName::BuiltIn("user"))
|
.unwrap_or(ClauseName::BuiltIn("user"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_code(&mut self, decls: Vec<(Predicate, VecDeque<TopLevel>)>, code_dir: &mut CodeDir)
|
fn generate_code(&mut self, decls: Vec<(Predicate, VecDeque<TopLevel>)>,
|
||||||
|
wam: &Machine, code_dir: &mut CodeDir)
|
||||||
-> Result<Code, SessionError>
|
-> Result<Code, SessionError>
|
||||||
{
|
{
|
||||||
let mut code = vec![];
|
let mut code = vec![];
|
||||||
@@ -196,12 +191,11 @@ impl<'a> ListingCompiler<'a> {
|
|||||||
|
|
||||||
let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
|
let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
|
||||||
|
|
||||||
let p = code.len() + self.wam.code_size();
|
let p = code.len() + wam.code_size();
|
||||||
let mut decl_code = compile_relation(&TopLevel::Predicate(decl), non_counted_bt,
|
let mut decl_code = compile_relation(&TopLevel::Predicate(decl), non_counted_bt,
|
||||||
self.wam.machine_flags())?;
|
wam.machine_flags())?;
|
||||||
|
|
||||||
compile_appendix(&mut decl_code, Vec::from(queue), non_counted_bt,
|
compile_appendix(&mut decl_code, Vec::from(queue), non_counted_bt, wam.machine_flags())?;
|
||||||
self.wam.machine_flags())?;
|
|
||||||
|
|
||||||
let idx = code_dir.entry((name, arity)).or_insert(CodeIndex::default());
|
let idx = code_dir.entry((name, arity)).or_insert(CodeIndex::default());
|
||||||
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
|
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
|
||||||
@@ -212,26 +206,30 @@ impl<'a> ListingCompiler<'a> {
|
|||||||
Ok(code)
|
Ok(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_code(self, code: Code, indices: MachineCodeIndices) {
|
fn add_code(&mut self, wam: &mut Machine, code: Code, indices: MachineCodeIndices)
|
||||||
|
-> Result<(), SessionError>
|
||||||
|
{
|
||||||
let code_dir = mem::replace(indices.code_dir, HashMap::new());
|
let code_dir = mem::replace(indices.code_dir, HashMap::new());
|
||||||
let op_dir = mem::replace(indices.op_dir, HashMap::new());
|
let op_dir = mem::replace(indices.op_dir, HashMap::new());
|
||||||
|
|
||||||
if let Some(mut module) = self.module {
|
if let Some(mut module) = self.module.take() {
|
||||||
module.code_dir.extend(as_module_code_dir(code_dir));
|
module.code_dir.extend(as_module_code_dir(code_dir));
|
||||||
module.op_dir.extend(op_dir.into_iter());
|
module.op_dir.extend(op_dir.into_iter());
|
||||||
|
|
||||||
self.wam.add_module(module, code);
|
wam.add_module(module, code);
|
||||||
} else {
|
} else {
|
||||||
self.wam.add_batched_code(code, code_dir);
|
wam.add_batched_code(code, code_dir)?;
|
||||||
self.wam.add_batched_ops(op_dir);
|
wam.add_batched_ops(op_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_non_counted_bt_flag(&mut self, name: ClauseName, arity: usize) {
|
fn add_non_counted_bt_flag(&mut self, name: ClauseName, arity: usize) {
|
||||||
self.non_counted_bt_preds.insert((name, arity));
|
self.non_counted_bt_preds.insert((name, arity));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_decl(&mut self, decl: Declaration, indices: &mut MachineCodeIndices)
|
fn process_decl(&mut self, decl: Declaration, wam: &mut Machine, indices: &mut MachineCodeIndices)
|
||||||
-> Result<(), SessionError>
|
-> Result<(), SessionError>
|
||||||
{
|
{
|
||||||
match decl {
|
match decl {
|
||||||
@@ -240,22 +238,20 @@ impl<'a> ListingCompiler<'a> {
|
|||||||
Declaration::Op(op_decl) =>
|
Declaration::Op(op_decl) =>
|
||||||
op_decl.submit(self.get_module_name(), &mut indices.op_dir),
|
op_decl.submit(self.get_module_name(), &mut indices.op_dir),
|
||||||
Declaration::UseModule(name) =>
|
Declaration::UseModule(name) =>
|
||||||
if let Some(ref submodule) = self.wam.get_module(name.clone()) {
|
if let Some(submodule) = wam.take_module(name) {
|
||||||
Ok(use_module(&mut self.module, submodule, indices))
|
self.use_module(submodule, wam, indices)
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::ModuleNotFound)
|
Err(SessionError::ModuleNotFound)
|
||||||
},
|
},
|
||||||
Declaration::UseQualifiedModule(name, exports) =>
|
Declaration::UseQualifiedModule(name, exports) =>
|
||||||
if let Some(ref submodule) = self.wam.get_module(name.clone()) {
|
if let Some(submodule) = wam.take_module(name) {
|
||||||
Ok(use_qualified_module(&mut self.module, submodule, &exports, indices))
|
self.use_qualified_module(submodule, wam, &exports, indices)
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::ModuleNotFound)
|
Err(SessionError::ModuleNotFound)
|
||||||
},
|
},
|
||||||
Declaration::Module(module_decl) =>
|
Declaration::Module(module_decl) =>
|
||||||
if self.module.is_none() {
|
if self.module.is_none() {
|
||||||
// worker.source_mod = module_decl.name.clone();
|
Ok(self.module = Some(Module::new(module_decl)))
|
||||||
self.module = Some(Module::new(module_decl));
|
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::from(ParserError::InvalidModuleDecl))
|
Err(SessionError::from(ParserError::InvalidModuleDecl))
|
||||||
}
|
}
|
||||||
@@ -263,50 +259,46 @@ impl<'a> ListingCompiler<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_module(module: &mut Option<Module>, submodule: &Module, indices: &mut MachineCodeIndices)
|
pub fn compile_listing<'a, R>(wam: &mut Machine, src: R, mut indices: MachineCodeIndices<'a>,
|
||||||
{
|
mut toplevel_indices: MachineCodeIndices<'a>)
|
||||||
indices.use_module(submodule);
|
-> EvalSession
|
||||||
|
where R: Read
|
||||||
if let &mut Some(ref mut module) = module {
|
|
||||||
module.use_module(submodule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn use_qualified_module(module: &mut Option<Module>, submodule: &Module, exports: &Vec<PredicateKey>,
|
|
||||||
indices: &mut MachineCodeIndices)
|
|
||||||
{
|
|
||||||
indices.use_qualified_module(submodule, exports);
|
|
||||||
|
|
||||||
if let &mut Some(ref mut module) = module {
|
|
||||||
module.use_qualified_module(submodule, exports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub
|
|
||||||
fn compile_listing<R: Read>(wam: &mut Machine, src: R, mut indices: MachineCodeIndices) -> EvalSession
|
|
||||||
{
|
{
|
||||||
let mut worker = TopLevelBatchWorker::new(src, wam.atom_tbl(), wam.machine_flags());
|
let mut worker = TopLevelBatchWorker::new(src, wam.atom_tbl(), wam.machine_flags());
|
||||||
let mut compiler = ListingCompiler::new(wam);
|
let mut compiler = ListingCompiler::new();
|
||||||
|
let mut toplevel_results = vec![];
|
||||||
|
|
||||||
while let Some(decl) = try_eval_session!(worker.consume(&mut indices)) {
|
while let Some(decl) = try_eval_session!(worker.consume(&mut indices)) {
|
||||||
try_eval_session!(compiler.process_decl(decl, &mut indices));
|
if decl.is_module_decl() {
|
||||||
|
toplevel_indices.copy_and_swap(&mut indices);
|
||||||
|
mem::swap(&mut worker.results, &mut toplevel_results);
|
||||||
|
}
|
||||||
|
|
||||||
|
try_eval_session!(compiler.process_decl(decl, wam, &mut indices));
|
||||||
}
|
}
|
||||||
|
|
||||||
let code = try_eval_session!(compiler.generate_code(worker.results, &mut indices.code_dir));
|
let module_code = try_eval_session!(compiler.generate_code(worker.results, wam,
|
||||||
compiler.add_code(code, indices);
|
&mut indices.code_dir));
|
||||||
|
let toplvl_code = try_eval_session!(compiler.generate_code(toplevel_results, wam,
|
||||||
|
&mut toplevel_indices.code_dir));
|
||||||
|
|
||||||
|
try_eval_session!(compiler.add_code(wam, module_code, indices));
|
||||||
|
try_eval_session!(compiler.add_code(wam, toplvl_code, toplevel_indices));
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
EvalSession::EntrySuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
|
fn setup_indices(wam: &Machine, indices: &mut MachineCodeIndices) -> Result<(), SessionError> {
|
||||||
let mut indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(),
|
|
||||||
&mut HashMap::new());
|
|
||||||
|
|
||||||
if let Some(ref builtins) = wam.modules.get(&clause_name!("builtins")) {
|
if let Some(ref builtins) = wam.modules.get(&clause_name!("builtins")) {
|
||||||
indices.use_module(builtins);
|
indices.use_module(builtins)
|
||||||
} else {
|
} else {
|
||||||
return EvalSession::from(SessionError::ModuleNotFound);
|
Err(SessionError::ModuleNotFound)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
compile_listing(wam, src, indices)
|
|
||||||
|
pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
|
||||||
|
let mut indices = default_machine_code_indices!();
|
||||||
|
try_eval_session!(setup_indices(&wam, &mut indices));
|
||||||
|
|
||||||
|
compile_listing(wam, src, indices, default_machine_code_indices!())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -791,6 +791,11 @@ impl CodeIndex {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn module_name(&self) -> ClauseName {
|
||||||
|
self.0.borrow().1.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -1033,20 +1038,54 @@ pub fn as_module_code_dir(code_dir: CodeDir) -> ModuleCodeDir {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubModuleUser for Module {
|
|
||||||
fn op_dir(&mut self) -> &mut OpDir {
|
|
||||||
&mut self.op_dir
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
|
|
||||||
self.code_dir.insert((name, arity), idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait SubModuleUser {
|
pub trait SubModuleUser {
|
||||||
fn op_dir(&mut self) -> &mut OpDir;
|
fn op_dir(&mut self) -> &mut OpDir;
|
||||||
|
fn remove_code_index(&mut self, key: PredicateKey);
|
||||||
|
fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option<CodeIndex>;
|
||||||
|
|
||||||
fn insert_dir_entry(&mut self, ClauseName, usize, ModuleCodeIndex);
|
fn insert_dir_entry(&mut self, ClauseName, usize, ModuleCodeIndex);
|
||||||
|
|
||||||
|
fn remove_module(&mut self, mod_name: ClauseName, module: &Module) {
|
||||||
|
for (name, arity) in module.module_decl.exports.iter().cloned() {
|
||||||
|
let name = name.defrock_brackets();
|
||||||
|
|
||||||
|
match self.get_code_index((name.clone(), arity), mod_name.clone()) {
|
||||||
|
Some(CodeIndex (ref code_idx)) => {
|
||||||
|
if &code_idx.borrow().1 != &module.module_decl.name {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.remove_code_index((name.clone(), arity));
|
||||||
|
|
||||||
|
// remove or respecify ops.
|
||||||
|
if arity == 2 {
|
||||||
|
if let Some((_, _, mod_name)) = self.op_dir().get(&(name.clone(), Fixity::In)).cloned()
|
||||||
|
{
|
||||||
|
if mod_name == module.module_decl.name {
|
||||||
|
self.op_dir().remove(&(name.clone(), Fixity::In));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if arity == 1 {
|
||||||
|
if let Some((_, _, mod_name)) = self.op_dir().get(&(name.clone(), Fixity::Pre)).cloned()
|
||||||
|
{
|
||||||
|
if mod_name == module.module_decl.name {
|
||||||
|
self.op_dir().remove(&(name.clone(), Fixity::Pre));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_, _, mod_name)) = self.op_dir().get(&(name.clone(), Fixity::Post)).cloned()
|
||||||
|
{
|
||||||
|
if mod_name == module.module_decl.name {
|
||||||
|
self.op_dir().remove(&(name.clone(), Fixity::Post));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns true on successful import.
|
// returns true on successful import.
|
||||||
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
|
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
|
||||||
let name = name.defrock_brackets();
|
let name = name.defrock_brackets();
|
||||||
@@ -1076,7 +1115,8 @@ pub trait SubModuleUser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_qualified_module(&mut self, submodule: &Module, exports: &Vec<PredicateKey>) -> EvalSession
|
fn use_qualified_module(&mut self, submodule: &Module, exports: &Vec<PredicateKey>)
|
||||||
|
-> Result<(), SessionError>
|
||||||
{
|
{
|
||||||
for (name, arity) in exports.iter().cloned() {
|
for (name, arity) in exports.iter().cloned() {
|
||||||
if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
|
if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
|
||||||
@@ -1084,21 +1124,39 @@ pub trait SubModuleUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !self.import_decl(name, arity, submodule) {
|
if !self.import_decl(name, arity, submodule) {
|
||||||
return EvalSession::from(SessionError::ModuleDoesNotContainExport);
|
return Err(SessionError::ModuleDoesNotContainExport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_module(&mut self, submodule: &Module) -> EvalSession {
|
fn use_module(&mut self, submodule: &Module) -> Result<(), SessionError> {
|
||||||
for (name, arity) in submodule.module_decl.exports.iter().cloned() {
|
for (name, arity) in submodule.module_decl.exports.iter().cloned() {
|
||||||
if !self.import_decl(name, arity, submodule) {
|
if !self.import_decl(name, arity, submodule) {
|
||||||
return EvalSession::from(SessionError::ModuleDoesNotContainExport);
|
return Err(SessionError::ModuleDoesNotContainExport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubModuleUser for Module {
|
||||||
|
fn op_dir(&mut self) -> &mut OpDir {
|
||||||
|
&mut self.op_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option<CodeIndex> {
|
||||||
|
self.code_dir.get(&key).cloned().map(CodeIndex::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_code_index(&mut self, key: PredicateKey) {
|
||||||
|
self.code_dir.remove(&key);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
|
||||||
|
self.code_dir.insert((name, arity), idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1110,6 +1168,13 @@ pub enum Declaration {
|
|||||||
UseQualifiedModule(ClauseName, Vec<PredicateKey>)
|
UseQualifiedModule(ClauseName, Vec<PredicateKey>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Declaration {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_module_decl(&self) -> bool {
|
||||||
|
if let &Declaration::Module(_) = self { true } else { false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum TopLevel {
|
pub enum TopLevel {
|
||||||
Declaration(Declaration),
|
Declaration(Declaration),
|
||||||
Fact(Term),
|
Fact(Term),
|
||||||
@@ -1224,14 +1289,16 @@ pub type HeapVarDict = HashMap<Rc<Var>, Addr>;
|
|||||||
pub type AllocVarDict = HashMap<Rc<Var>, VarData>;
|
pub type AllocVarDict = HashMap<Rc<Var>, VarData>;
|
||||||
|
|
||||||
pub enum SessionError {
|
pub enum SessionError {
|
||||||
ImpermissibleEntry(String),
|
CannotOverwriteBuiltIn(String),
|
||||||
|
CannotOverwriteImport(String),
|
||||||
ModuleDoesNotContainExport,
|
ModuleDoesNotContainExport,
|
||||||
ModuleNotFound,
|
ModuleNotFound,
|
||||||
NamelessEntry,
|
NamelessEntry,
|
||||||
OpIsInfixAndPostFix,
|
OpIsInfixAndPostFix,
|
||||||
ParserError(ParserError),
|
ParserError(ParserError),
|
||||||
QueryFailure,
|
QueryFailure,
|
||||||
QueryFailureWithException(String)
|
QueryFailureWithException(String),
|
||||||
|
UserPrompt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EvalSession {
|
pub enum EvalSession {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use prolog::or_stack::*;
|
|||||||
|
|
||||||
use downcast::Any;
|
use downcast::Any;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
use std::mem::swap;
|
use std::mem::swap;
|
||||||
@@ -68,67 +67,6 @@ impl<'a> CodeDirs<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CodeDirsAdapter<'a> {
|
|
||||||
fn get_code_index(&self, PredicateKey, ClauseName) -> Option<CodeIndex>;
|
|
||||||
fn get_op(&self, OpDirKey) -> Option<(Specifier, usize, ClauseName)>;
|
|
||||||
fn op_dir(&self) -> &OpDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_code_index(code_dir: &CodeDir, modules: &ModuleDir, key: PredicateKey, module: ClauseName)
|
|
||||||
-> Option<CodeIndex>
|
|
||||||
{
|
|
||||||
match module.as_str() {
|
|
||||||
"user" | "builtin" => code_dir.get(&key).cloned(),
|
|
||||||
_ => modules.get(&module).and_then(|ref module| {
|
|
||||||
module.code_dir.get(&key).cloned().map(CodeIndex::from)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CodeDirsAdapter<'a> for MachineCodeIndices<'a> {
|
|
||||||
fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option<CodeIndex> {
|
|
||||||
get_code_index(&self.code_dir, &self.modules, key, module)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> {
|
|
||||||
self.op_dir.get(&key).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_dir(&self) -> &OpDir {
|
|
||||||
&self.op_dir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CodeDirsAdapter<'a> for CodeDirs<'a> {
|
|
||||||
fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option<CodeIndex> {
|
|
||||||
get_code_index(&self.code_dir, &self.modules, key, module)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> {
|
|
||||||
self.op_dir.get(&key).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_dir(&self) -> &OpDir {
|
|
||||||
&self.op_dir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CodeDirsAdapter<'a> for &'a Module {
|
|
||||||
fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option<CodeIndex> {
|
|
||||||
self.code_dir.get(&key)
|
|
||||||
.cloned()
|
|
||||||
.map(|ModuleCodeIndex(ptr, module)| CodeIndex(Rc::new(RefCell::new((ptr, module)))))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> {
|
|
||||||
self.op_dir.get(&key).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_dir(&self) -> &OpDir {
|
|
||||||
&self.op_dir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) struct DuplicateTerm<'a> {
|
pub(super) struct DuplicateTerm<'a> {
|
||||||
state: &'a mut MachineState
|
state: &'a mut MachineState
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,18 @@ pub struct MachineCodeIndices<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MachineCodeIndices<'a> {
|
impl<'a> MachineCodeIndices<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn copy_and_swap(&mut self, other: &mut MachineCodeIndices<'a>) {
|
||||||
|
*self.code_dir = other.code_dir.clone();
|
||||||
|
*self.op_dir = other.op_dir.clone();
|
||||||
|
|
||||||
|
swap(&mut self.code_dir, &mut other.code_dir);
|
||||||
|
swap(&mut self.op_dir, &mut other.op_dir);
|
||||||
|
swap(&mut self.modules, &mut other.modules);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super)
|
pub(super)
|
||||||
fn lookup(&mut self, name: ClauseName, arity: usize, fixity: Option<Fixity>) -> ClauseType
|
fn get_clause_type(&mut self, name: ClauseName, arity: usize, fixity: Option<Fixity>) -> ClauseType
|
||||||
{
|
{
|
||||||
match ClauseType::from(name, arity, fixity) {
|
match ClauseType::from(name, arity, fixity) {
|
||||||
ClauseType::Named(name, _) => {
|
ClauseType::Named(name, _) => {
|
||||||
@@ -67,6 +77,17 @@ pub struct Machine {
|
|||||||
cached_query: Option<Code>
|
cached_query: Option<Code>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_code_index(code_dir: &CodeDir, modules: &ModuleDir, key: PredicateKey, module: ClauseName)
|
||||||
|
-> Option<CodeIndex>
|
||||||
|
{
|
||||||
|
match module.as_str() {
|
||||||
|
"user" | "builtin" => code_dir.get(&key).cloned(),
|
||||||
|
_ => modules.get(&module).and_then(|ref module| {
|
||||||
|
module.code_dir.get(&key).cloned().map(CodeIndex::from)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Index<LocalCodePtr> for Machine {
|
impl Index<LocalCodePtr> for Machine {
|
||||||
type Output = Line;
|
type Output = Line;
|
||||||
|
|
||||||
@@ -88,6 +109,14 @@ impl<'a> SubModuleUser for MachineCodeIndices<'a> {
|
|||||||
self.op_dir
|
self.op_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option<CodeIndex> {
|
||||||
|
get_code_index(&self.code_dir, &self.modules, key, module)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_code_index(&mut self, key: PredicateKey) {
|
||||||
|
self.code_dir.remove(&key);
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
|
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
|
||||||
if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) {
|
if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) {
|
||||||
if !code_idx.is_undefined() {
|
if !code_idx.is_undefined() {
|
||||||
@@ -121,17 +150,14 @@ impl Machine {
|
|||||||
cached_query: None
|
cached_query: None
|
||||||
};
|
};
|
||||||
|
|
||||||
let indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(),
|
compile_listing(&mut wam, BUILTINS.as_bytes(),
|
||||||
&mut HashMap::new());
|
default_machine_code_indices!(),
|
||||||
|
default_machine_code_indices!());
|
||||||
compile_listing(&mut wam, BUILTINS.as_bytes(), indices);
|
|
||||||
|
|
||||||
compile_user_module(&mut wam, LISTS.as_bytes());
|
compile_user_module(&mut wam, LISTS.as_bytes());
|
||||||
compile_user_module(&mut wam, CONTROL.as_bytes());
|
compile_user_module(&mut wam, CONTROL.as_bytes());
|
||||||
compile_user_module(&mut wam, QUEUES.as_bytes());
|
compile_user_module(&mut wam, QUEUES.as_bytes());
|
||||||
|
|
||||||
wam.use_module_in_toplevel(clause_name!("builtins"));
|
|
||||||
|
|
||||||
wam
|
wam
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,53 +166,6 @@ impl Machine {
|
|||||||
self.ms.flags
|
self.ms.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_module(&mut self, module_name: ClauseName) {
|
|
||||||
let iter = if let Some(submodule) = self.modules.get(&module_name) {
|
|
||||||
submodule.module_decl.exports.iter().cloned()
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (name, arity) in iter {
|
|
||||||
let name = name.defrock_brackets();
|
|
||||||
|
|
||||||
match self.code_dir.get(&(name.clone(), arity)).cloned() {
|
|
||||||
Some(CodeIndex (ref code_idx)) => {
|
|
||||||
if &code_idx.borrow().1 != &module_name {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.code_dir.remove(&(name.clone(), arity));
|
|
||||||
|
|
||||||
// remove or respecify ops.
|
|
||||||
if arity == 2 {
|
|
||||||
if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::In)).cloned()
|
|
||||||
{
|
|
||||||
if mod_name == module_name {
|
|
||||||
self.op_dir.remove(&(name.clone(), Fixity::In));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if arity == 1 {
|
|
||||||
if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::Pre)).cloned()
|
|
||||||
{
|
|
||||||
if mod_name == module_name {
|
|
||||||
self.op_dir.remove(&(name.clone(), Fixity::Pre));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::Post)).cloned()
|
|
||||||
{
|
|
||||||
if mod_name == module_name {
|
|
||||||
self.op_dir.remove(&(name.clone(), Fixity::Post));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn failed(&self) -> bool {
|
pub fn failed(&self) -> bool {
|
||||||
self.ms.fail
|
self.ms.fail
|
||||||
@@ -197,85 +176,69 @@ impl Machine {
|
|||||||
self.ms.atom_tbl.clone()
|
self.ms.atom_tbl.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_qualified_module_in_toplevel(&mut self, name: ClauseName, exports: Vec<PredicateKey>)
|
|
||||||
-> EvalSession
|
|
||||||
{
|
|
||||||
self.remove_module(name.clone());
|
|
||||||
|
|
||||||
if let Some(mut module) = self.modules.remove(&name) {
|
|
||||||
let result = {
|
|
||||||
let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir,
|
|
||||||
&mut self.modules);
|
|
||||||
indices.use_qualified_module(&mut module, &exports)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.modules.insert(name, module);
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
EvalSession::from(SessionError::ModuleNotFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession
|
|
||||||
{
|
|
||||||
self.remove_module(name.clone());
|
|
||||||
|
|
||||||
if let Some(mut module) = self.modules.remove(&name) {
|
|
||||||
let result = {
|
|
||||||
let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir,
|
|
||||||
&mut self.modules);
|
|
||||||
indices.use_module(&mut module)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.modules.insert(name, module);
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
EvalSession::from(SessionError::ModuleNotFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_module(&self, name: ClauseName) -> Option<&Module> {
|
pub fn get_module(&self, name: ClauseName) -> Option<&Module> {
|
||||||
self.modules.get(&name)
|
self.modules.get(&name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_batched_code(&mut self, mut code: Code, code_dir: CodeDir) {
|
pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir) -> Result<(), SessionError>
|
||||||
self.code.append(&mut code);
|
{
|
||||||
self.code_dir.extend(code_dir.into_iter());
|
for (ref key, ref idx) in code_dir.iter() {
|
||||||
|
match ClauseType::from(key.0.clone(), key.1, None) {
|
||||||
|
ClauseType::Named(..) | ClauseType::Op(..) => {},
|
||||||
|
_ => {
|
||||||
|
// ensure we don't try to overwrite the name/arity of a builtin.
|
||||||
|
let err_str = format!("{}/{}", key.0, key.1);
|
||||||
|
return Err(SessionError::CannotOverwriteBuiltIn(err_str));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if idx.module_name().as_str() == "builtins" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref existing_idx) = self.code_dir.get(&key) {
|
||||||
|
// ensure we don't try to overwrite an existing predicate from a different module.
|
||||||
|
if !existing_idx.is_undefined() {
|
||||||
|
if existing_idx.module_name() != idx.module_name() {
|
||||||
|
let err_str = format!("{}/{} from module {}", key.0, key.1,
|
||||||
|
existing_idx.module_name().as_str());
|
||||||
|
return Err(SessionError::CannotOverwriteImport(err_str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.code.extend(code.into_iter());
|
||||||
|
Ok(self.code_dir.extend(code_dir.into_iter()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn add_batched_ops(&mut self, op_dir: OpDir) {
|
pub fn add_batched_ops(&mut self, op_dir: OpDir) {
|
||||||
self.op_dir.extend(op_dir.into_iter());
|
self.op_dir.extend(op_dir.into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn remove_module(&mut self, module: &Module) {
|
||||||
|
let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir, &mut self.modules);
|
||||||
|
indices.remove_module(clause_name!("user"), module);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
|
||||||
|
self.modules.remove(&name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn insert_module(&mut self, module: Module) {
|
||||||
|
self.modules.insert(module.module_decl.name.clone(), module);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn add_module(&mut self, module: Module, code: Code) {
|
pub fn add_module(&mut self, module: Module, code: Code) {
|
||||||
self.modules.insert(module.module_decl.name.clone(), module);
|
self.modules.insert(module.module_decl.name.clone(), module);
|
||||||
self.code.extend(code.into_iter());
|
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(&CodeIndex (ref idx)) if idx.borrow().1 != clause_name!("user") =>
|
|
||||||
if !(&CodeIndex(idx.clone())).is_undefined() {
|
|
||||||
return EvalSession::from(SessionError::ImpermissibleEntry(format!("{}/{}",
|
|
||||||
name,
|
|
||||||
arity)))
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
let offset = self.code.len();
|
|
||||||
|
|
||||||
self.code.extend(code.into_iter());
|
|
||||||
//self.term_dir.insert((name.clone(), arity), pred);
|
|
||||||
|
|
||||||
let idx = self.code_dir.entry((name, arity))
|
|
||||||
.or_insert(CodeIndex::from((offset, clause_name!("user"))));
|
|
||||||
|
|
||||||
set_code_index!(idx, IndexPtr::Index(offset), clause_name!("user"));
|
|
||||||
EvalSession::EntrySuccess
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn code_size(&self) -> usize {
|
pub fn code_size(&self) -> usize {
|
||||||
self.code.len()
|
self.code.len()
|
||||||
}
|
}
|
||||||
|
|||||||
54
src/prolog/machine/term_writer.rs
Normal file
54
src/prolog/machine/term_writer.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
use prolog_parser::ast::*;
|
||||||
|
|
||||||
|
use prolog::heap_iter::*;
|
||||||
|
use prolog::instructions::*;
|
||||||
|
use prolog::machine::machine_state::MachineState;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub fn term_write(machine_st: &MachineState, addr: Addr) -> Result<Term, ParserError>
|
||||||
|
{
|
||||||
|
let pre_order_iter = HCPreOrderIterator::new(machine_st, addr);
|
||||||
|
let post_order_iter = HCPostOrderIterator::new(pre_order_iter);
|
||||||
|
|
||||||
|
let mut stack = vec![];
|
||||||
|
|
||||||
|
for value in post_order_iter {
|
||||||
|
match value {
|
||||||
|
HeapCellValue::NamedStr(arity, ref name, fixity)
|
||||||
|
if stack.len() >= arity => {
|
||||||
|
let stack_len = stack.len();
|
||||||
|
let subterms: Vec<_> = stack.drain(stack_len - arity ..).collect();
|
||||||
|
|
||||||
|
stack.push(Box::new(Term::Clause(Cell::default(), name.clone(), subterms,
|
||||||
|
fixity)));
|
||||||
|
},
|
||||||
|
HeapCellValue::Addr(Addr::Con(constant)) =>
|
||||||
|
stack.push(Box::new(Term::Constant(Cell::default(), constant))),
|
||||||
|
HeapCellValue::Addr(Addr::Lis(_))
|
||||||
|
if stack.len() >= 2 => {
|
||||||
|
let stack_len = stack.len();
|
||||||
|
let mut iter = stack.drain(stack_len - 2 ..);
|
||||||
|
|
||||||
|
let head = iter.next().unwrap();
|
||||||
|
let tail = iter.next().unwrap();
|
||||||
|
|
||||||
|
stack.push(Box::new(Term::Cons(Cell::default(), head, tail)));
|
||||||
|
},
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(h)) =>
|
||||||
|
stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}", h))))),
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
|
||||||
|
stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}_{}", sc, fr))))),
|
||||||
|
_ => return Err(ParserError::IncompleteReduction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(term) = stack.pop() {
|
||||||
|
if stack.is_empty() {
|
||||||
|
return Ok(*term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(ParserError::IncompleteReduction)
|
||||||
|
}
|
||||||
@@ -216,6 +216,13 @@ macro_rules! machine_code_indices {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! default_machine_code_indices {
|
||||||
|
() => (
|
||||||
|
machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(),
|
||||||
|
&mut HashMap::new());
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! put_constant {
|
macro_rules! put_constant {
|
||||||
($lvl:expr, $cons:expr, $r:expr) => (
|
($lvl:expr, $cons:expr, $r:expr) => (
|
||||||
QueryInstruction::PutConstant($lvl, $cons, $r)
|
QueryInstruction::PutConstant($lvl, $cons, $r)
|
||||||
|
|||||||
@@ -25,27 +25,10 @@ impl<'a> TermRef<'a> {
|
|||||||
pub enum Input {
|
pub enum Input {
|
||||||
Quit,
|
Quit,
|
||||||
Clear,
|
Clear,
|
||||||
Line(String),
|
Batch,
|
||||||
Batch(String),
|
|
||||||
Term(Term)
|
Term(Term)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_lines(buffer: &mut String, end_delim: &str) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
let stdin = stdin();
|
|
||||||
|
|
||||||
buffer.clear();
|
|
||||||
stdin.read_line(buffer).unwrap();
|
|
||||||
|
|
||||||
while &*buffer.trim() != end_delim {
|
|
||||||
result += buffer.as_str();
|
|
||||||
buffer.clear();
|
|
||||||
stdin.read_line(buffer).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_toplevel(wam: &Machine) -> Result<Input, ParserError> {
|
pub fn read_toplevel(wam: &Machine) -> Result<Input, ParserError> {
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
|
|
||||||
@@ -53,11 +36,10 @@ pub fn read_toplevel(wam: &Machine) -> Result<Input, ParserError> {
|
|||||||
stdin.read_line(&mut buffer).unwrap();
|
stdin.read_line(&mut buffer).unwrap();
|
||||||
|
|
||||||
match &*buffer.trim() {
|
match &*buffer.trim() {
|
||||||
":{" => Ok(Input::Line(read_lines(&mut buffer, "}:"))),
|
"quit" => Ok(Input::Quit),
|
||||||
":{{" => Ok(Input::Batch(read_lines(&mut buffer, "}}:"))),
|
"clear" => Ok(Input::Clear),
|
||||||
"quit" => Ok(Input::Quit),
|
"[user]" => Ok(Input::Batch),
|
||||||
"clear" => Ok(Input::Clear),
|
_ => {
|
||||||
_ => {
|
|
||||||
let mut parser = Parser::new(stdin.lock(), wam.atom_tbl(), wam.machine_flags());
|
let mut parser = Parser::new(stdin.lock(), wam.atom_tbl(), wam.machine_flags());
|
||||||
|
|
||||||
parser.add_to_top(buffer.as_str());
|
parser.add_to_top(buffer.as_str());
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ impl RelationWorker {
|
|||||||
if name.as_str() == "!" || name.as_str() == "blocked_!" {
|
if name.as_str() == "!" || name.as_str() == "blocked_!" {
|
||||||
Ok(QueryTerm::BlockedCut)
|
Ok(QueryTerm::BlockedCut)
|
||||||
} else {
|
} else {
|
||||||
let ct = indices.lookup(name, 0, None);
|
let ct = indices.get_clause_type(name, 0, None);
|
||||||
Ok(QueryTerm::Clause(r, ct, vec![], false))
|
Ok(QueryTerm::Clause(r, ct, vec![], false))
|
||||||
},
|
},
|
||||||
Term::Var(_, ref v) if v.as_str() == "!" =>
|
Term::Var(_, ref v) if v.as_str() == "!" =>
|
||||||
@@ -462,7 +462,7 @@ impl RelationWorker {
|
|||||||
Err(ParserError::InadmissibleQueryTerm)
|
Err(ParserError::InadmissibleQueryTerm)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let ct = indices.lookup(name, terms.len(), fixity);
|
let ct = indices.get_clause_type(name, terms.len(), fixity);
|
||||||
Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
|
Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -496,24 +496,24 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_query_term(&mut self, idx: &mut MachineCodeIndices, term: Term) -> Result<QueryTerm, ParserError>
|
fn pre_query_term(&mut self, indices: &mut MachineCodeIndices, term: Term) -> Result<QueryTerm, ParserError>
|
||||||
{
|
{
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(r, name, mut subterms, fixity) =>
|
Term::Clause(r, name, mut subterms, fixity) =>
|
||||||
if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
|
if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
|
||||||
self.to_query_term(idx, *subterms.pop().unwrap())
|
self.to_query_term(indices, *subterms.pop().unwrap())
|
||||||
.map(|mut query_term| {
|
.map(|mut query_term| {
|
||||||
query_term.set_default_caller();
|
query_term.set_default_caller();
|
||||||
query_term
|
query_term
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
self.to_query_term(idx, Term::Clause(r, name, subterms, fixity))
|
self.to_query_term(indices, Term::Clause(r, name, subterms, fixity))
|
||||||
},
|
},
|
||||||
_ => self.to_query_term(idx, term)
|
_ => self.to_query_term(indices, term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_query(&mut self, idx: &mut MachineCodeIndices, terms: Vec<Box<Term>>, blocks_cuts: bool)
|
fn setup_query(&mut self, indices: &mut MachineCodeIndices, terms: Vec<Box<Term>>, blocks_cuts: bool)
|
||||||
-> Result<Vec<QueryTerm>, ParserError>
|
-> Result<Vec<QueryTerm>, ParserError>
|
||||||
{
|
{
|
||||||
let mut query_terms = vec![];
|
let mut query_terms = vec![];
|
||||||
@@ -541,18 +541,18 @@ impl RelationWorker {
|
|||||||
mark_cut_variable(&mut subterm);
|
mark_cut_variable(&mut subterm);
|
||||||
}
|
}
|
||||||
|
|
||||||
query_terms.push(self.pre_query_term(idx, subterm)?);
|
query_terms.push(self.pre_query_term(indices, subterm)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(query_terms)
|
Ok(query_terms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_rule(&mut self, idx: &mut MachineCodeIndices, mut terms: Vec<Box<Term>>, blocks_cuts: bool)
|
fn setup_rule(&mut self, indices: &mut MachineCodeIndices, mut terms: Vec<Box<Term>>, blocks_cuts: bool)
|
||||||
-> Result<Rule, ParserError>
|
-> Result<Rule, ParserError>
|
||||||
{
|
{
|
||||||
let post_head_terms = terms.drain(1..).collect();
|
let post_head_terms = terms.drain(1..).collect();
|
||||||
let mut query_terms = try!(self.setup_query(idx, post_head_terms, blocks_cuts));
|
let mut query_terms = try!(self.setup_query(indices, post_head_terms, blocks_cuts));
|
||||||
let clauses = query_terms.drain(1 ..).collect();
|
let clauses = query_terms.drain(1 ..).collect();
|
||||||
let qt = query_terms.pop().unwrap();
|
let qt = query_terms.pop().unwrap();
|
||||||
|
|
||||||
@@ -565,15 +565,15 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_term_to_tl(&mut self, idx: &mut MachineCodeIndices, term: Term, blocks_cuts: bool)
|
fn try_term_to_tl(&mut self, indices: &mut MachineCodeIndices, term: Term, blocks_cuts: bool)
|
||||||
-> Result<TopLevel, ParserError>
|
-> Result<TopLevel, ParserError>
|
||||||
{
|
{
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(r, name, mut terms, fixity) =>
|
Term::Clause(r, name, mut terms, fixity) =>
|
||||||
if name.as_str() == "?-" {
|
if name.as_str() == "?-" {
|
||||||
Ok(TopLevel::Query(try!(self.setup_query(idx, terms, blocks_cuts))))
|
Ok(TopLevel::Query(try!(self.setup_query(indices, terms, blocks_cuts))))
|
||||||
} else if name.as_str() == ":-" && terms.len() > 1 {
|
} else if name.as_str() == ":-" && terms.len() > 1 {
|
||||||
Ok(TopLevel::Rule(try!(self.setup_rule(idx, terms, blocks_cuts))))
|
Ok(TopLevel::Rule(try!(self.setup_rule(indices, terms, blocks_cuts))))
|
||||||
} else if name.as_str() == ":-" && terms.len() == 1 {
|
} else if name.as_str() == ":-" && terms.len() == 1 {
|
||||||
let term = *terms.pop().unwrap();
|
let term = *terms.pop().unwrap();
|
||||||
Ok(TopLevel::Declaration(try!(setup_declaration(term))))
|
Ok(TopLevel::Declaration(try!(setup_declaration(term))))
|
||||||
@@ -584,25 +584,25 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_terms_to_tls<Iter>(&mut self, idx: &mut MachineCodeIndices, terms: Iter, blocks_cuts: bool)
|
fn try_terms_to_tls<I>(&mut self, indices: &mut MachineCodeIndices, terms: I, blocks_cuts: bool)
|
||||||
-> Result<VecDeque<TopLevel>, ParserError>
|
-> Result<VecDeque<TopLevel>, ParserError>
|
||||||
where Iter: IntoIterator<Item=Term>
|
where I: IntoIterator<Item=Term>
|
||||||
{
|
{
|
||||||
let mut results = VecDeque::new();
|
let mut results = VecDeque::new();
|
||||||
|
|
||||||
for term in terms.into_iter() {
|
for term in terms.into_iter() {
|
||||||
results.push_back(self.try_term_to_tl(idx, term, blocks_cuts)?);
|
results.push_back(self.try_term_to_tl(indices, term, blocks_cuts)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_queue(&mut self, idx: &mut MachineCodeIndices) -> Result<VecDeque<TopLevel>, ParserError>
|
fn parse_queue(&mut self, indices: &mut MachineCodeIndices) -> Result<VecDeque<TopLevel>, ParserError>
|
||||||
{
|
{
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
|
|
||||||
while let Some(terms) = self.queue.pop_front() {
|
while let Some(terms) = self.queue.pop_front() {
|
||||||
let clauses = merge_clauses(&mut self.try_terms_to_tls(idx, terms, false)?)?;
|
let clauses = merge_clauses(&mut self.try_terms_to_tls(indices, terms, false)?)?;
|
||||||
queue.push_back(clauses);
|
queue.push_back(clauses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,37 +614,6 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TopLevelWorker<'a, R: Read> {
|
|
||||||
pub parser: Parser<R>,
|
|
||||||
indices: MachineCodeIndices<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, R: Read> TopLevelWorker<'a, R> {
|
|
||||||
pub fn new(inner: R, atom_tbl: TabledData<Atom>, flags: MachineFlags,
|
|
||||||
indices: MachineCodeIndices<'a>)
|
|
||||||
-> Self
|
|
||||||
{
|
|
||||||
TopLevelWorker { parser: Parser::new(inner, atom_tbl, flags), indices }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_code(&mut self) -> Result<TopLevelPacket, ParserError>
|
|
||||||
{
|
|
||||||
let mut rel_worker = RelationWorker::new();
|
|
||||||
|
|
||||||
let terms = self.parser.read(self.indices.op_dir)?;
|
|
||||||
let mut tls = rel_worker.try_terms_to_tls(&mut self.indices, terms, true)?;
|
|
||||||
let results = rel_worker.parse_queue(&mut self.indices)?;
|
|
||||||
|
|
||||||
let tl = merge_clauses(&mut tls)?;
|
|
||||||
|
|
||||||
if tls.is_empty() {
|
|
||||||
Ok(deque_to_packet(tl, results))
|
|
||||||
} else {
|
|
||||||
Err(ParserError::InconsistentEntry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_term(term: Term, mut indices: MachineCodeIndices) -> Result<TopLevelPacket, ParserError>
|
pub fn parse_term(term: Term, mut indices: MachineCodeIndices) -> Result<TopLevelPacket, ParserError>
|
||||||
{
|
{
|
||||||
let mut rel_worker = RelationWorker::new();
|
let mut rel_worker = RelationWorker::new();
|
||||||
|
|||||||
@@ -193,15 +193,19 @@ impl fmt::Display for IndexingInstruction {
|
|||||||
impl fmt::Display for SessionError {
|
impl fmt::Display for SessionError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
&SessionError::CannotOverwriteBuiltIn(ref msg) =>
|
||||||
|
write!(f, "cannot overwrite {}", msg),
|
||||||
|
&SessionError::CannotOverwriteImport(ref msg) =>
|
||||||
|
write!(f, "cannot overwrite import {}", msg),
|
||||||
&SessionError::ModuleNotFound => write!(f, "module not found."),
|
&SessionError::ModuleNotFound => write!(f, "module not found."),
|
||||||
&SessionError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."),
|
&SessionError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."),
|
||||||
&SessionError::QueryFailure => write!(f, "false."),
|
&SessionError::QueryFailure => write!(f, "false."),
|
||||||
&SessionError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)),
|
&SessionError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)),
|
||||||
&SessionError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite {}.", msg),
|
|
||||||
&SessionError::OpIsInfixAndPostFix =>
|
&SessionError::OpIsInfixAndPostFix =>
|
||||||
write!(f, "cannot define an op to be both postfix and infix."),
|
write!(f, "cannot define an op to be both postfix and infix."),
|
||||||
&SessionError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."),
|
&SessionError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."),
|
||||||
&SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
|
&SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
|
||||||
|
&SessionError::UserPrompt => write!(f, "enter predicate at [user] prompt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user