use prolog::read::*;
use prolog::write::*;
-use std::io::{Write, stdout};
+use std::io::{Write, stdin, stdout};
#[cfg(test)]
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() {
let mut wam = Machine::new();
stdout().flush().unwrap();
match read_toplevel(&mut wam) {
- Ok(Input::Term(term)) =>
- match compile_term(&mut wam, term) {
- Ok(packet) => {
- let result = compile_packet(&mut wam, packet);
- print(&mut wam, result);
- },
- Err(e) => print(&mut wam, EvalSession::from(e))
- },
- 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());
+ Ok(Input::Term(term)) => {
+ let result = compile_term(&mut wam, term);
+ print(&mut wam, result)
+ },
+ Ok(Input::Batch) => {
+ let stdin = stdin();
+ let result = compile_user_module(&mut wam, stdin.lock());
+
print(&mut wam, result);
},
Ok(Input::Quit) => break,
wam.clear();
continue;
},
- Err(e) => print(&mut wam, EvalSession::from(e))
+ Err(e) =>
+ print(&mut wam, EvalSession::from(e))
};
wam.reset();
}
}
-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.
fn compile_relation(tl: &TopLevel, non_counted_bt: bool, flags: MachineFlags) -> Result<Code, ParserError>
{
Ok((code, cg.take_vars()))
}
-fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSession
-{
- match tl {
- 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.")))
- }
- }
- }
+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);
+ parse_term(term, indices)
}
-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) =>
match compile_query(terms, queue, wam.machine_flags()) {
Ok((mut code, vars)) => wam.submit_query(code, vars),
Err(e) => EvalSession::from(e)
},
- TopLevelPacket::Decl(tl, queue) =>
- compile_decl(wam, tl, queue)
+ TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => {
+ 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> {
- wam: &'a mut Machine,
+pub struct ListingCompiler {
non_counted_bt_preds: HashSet<PredicateKey>,
- module: Option<Module>
+ module: Option<Module>,
}
-impl<'a> ListingCompiler<'a> {
- pub fn new(wam: &'a mut Machine) -> Self {
- ListingCompiler { wam,
- module: None,
- non_counted_bt_preds: HashSet::new() }
+impl ListingCompiler {
+ pub fn new() -> Self {
+ ListingCompiler { 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 {
self.module.as_ref()
.map(|module| module.module_decl.name.clone())
.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>
{
let mut code = vec![];
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,
- self.wam.machine_flags())?;
+ wam.machine_flags())?;
- compile_appendix(&mut decl_code, Vec::from(queue), non_counted_bt,
- self.wam.machine_flags())?;
+ compile_appendix(&mut decl_code, Vec::from(queue), non_counted_bt, wam.machine_flags())?;
let idx = code_dir.entry((name, arity)).or_insert(CodeIndex::default());
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
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 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.op_dir.extend(op_dir.into_iter());
- self.wam.add_module(module, code);
+ wam.add_module(module, code);
} else {
- self.wam.add_batched_code(code, code_dir);
- self.wam.add_batched_ops(op_dir);
+ wam.add_batched_code(code, code_dir)?;
+ wam.add_batched_ops(op_dir);
}
+
+ Ok(())
}
fn add_non_counted_bt_flag(&mut self, name: ClauseName, arity: usize) {
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>
{
match decl {
Declaration::Op(op_decl) =>
op_decl.submit(self.get_module_name(), &mut indices.op_dir),
Declaration::UseModule(name) =>
- if let Some(ref submodule) = self.wam.get_module(name.clone()) {
- Ok(use_module(&mut self.module, submodule, indices))
+ if let Some(submodule) = wam.take_module(name) {
+ self.use_module(submodule, wam, indices)
} else {
Err(SessionError::ModuleNotFound)
},
Declaration::UseQualifiedModule(name, exports) =>
- if let Some(ref submodule) = self.wam.get_module(name.clone()) {
- Ok(use_qualified_module(&mut self.module, submodule, &exports, indices))
+ if let Some(submodule) = wam.take_module(name) {
+ self.use_qualified_module(submodule, wam, &exports, indices)
} else {
Err(SessionError::ModuleNotFound)
},
Declaration::Module(module_decl) =>
if self.module.is_none() {
- // worker.source_mod = module_decl.name.clone();
- self.module = Some(Module::new(module_decl));
- Ok(())
+ Ok(self.module = Some(Module::new(module_decl)))
} else {
Err(SessionError::from(ParserError::InvalidModuleDecl))
}
}
}
-fn use_module(module: &mut Option<Module>, submodule: &Module, indices: &mut MachineCodeIndices)
-{
- indices.use_module(submodule);
-
- 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
+pub fn compile_listing<'a, R>(wam: &mut Machine, src: R, mut indices: MachineCodeIndices<'a>,
+ mut toplevel_indices: MachineCodeIndices<'a>)
+ -> EvalSession
+ where R: Read
{
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)) {
- 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));
- compiler.add_code(code, indices);
+ let module_code = try_eval_session!(compiler.generate_code(worker.results, wam,
+ &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
}
-pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
- let mut indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(),
- &mut HashMap::new());
-
+fn setup_indices(wam: &Machine, indices: &mut MachineCodeIndices) -> Result<(), SessionError> {
if let Some(ref builtins) = wam.modules.get(&clause_name!("builtins")) {
- indices.use_module(builtins);
+ indices.use_module(builtins)
} else {
- return EvalSession::from(SessionError::ModuleNotFound);
+ Err(SessionError::ModuleNotFound)
}
+}
+
+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)
+ compile_listing(wam, src, indices, default_machine_code_indices!())
}
false
}
}
+
+ #[inline]
+ pub fn module_name(&self) -> ClauseName {
+ self.0.borrow().1.clone()
+ }
}
#[derive(Clone)]
.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 {
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 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.
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
let name = name.defrock_brackets();
}
}
- 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() {
if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
}
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() {
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);
}
}
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 {
Declaration(Declaration),
Fact(Term),
pub type AllocVarDict = HashMap<Rc<Var>, VarData>;
pub enum SessionError {
- ImpermissibleEntry(String),
+ CannotOverwriteBuiltIn(String),
+ CannotOverwriteImport(String),
ModuleDoesNotContainExport,
ModuleNotFound,
NamelessEntry,
OpIsInfixAndPostFix,
ParserError(ParserError),
QueryFailure,
- QueryFailureWithException(String)
+ QueryFailureWithException(String),
+ UserPrompt
}
pub enum EvalSession {
use downcast::Any;
-use std::cell::RefCell;
use std::cmp::Ordering;
use std::io::stdin;
use std::mem::swap;
}
}
-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> {
state: &'a mut MachineState
}
}
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)
- 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) {
ClauseType::Named(name, _) => {
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 {
type Output = Line;
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) {
if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) {
if !code_idx.is_undefined() {
code: Code::new(),
code_dir: CodeDir::new(),
op_dir: default_op_dir(),
- // term_dir: TermDir::new(),
+ // term_dir: TermDir::new(),
modules: HashMap::new(),
cached_query: None
};
- let indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(),
- &mut HashMap::new());
-
- compile_listing(&mut wam, BUILTINS.as_bytes(), indices);
+ compile_listing(&mut wam, BUILTINS.as_bytes(),
+ default_machine_code_indices!(),
+ default_machine_code_indices!());
compile_user_module(&mut wam, LISTS.as_bytes());
compile_user_module(&mut wam, CONTROL.as_bytes());
compile_user_module(&mut wam, QUEUES.as_bytes());
- wam.use_module_in_toplevel(clause_name!("builtins"));
-
wam
}
pub fn machine_flags(&self) -> MachineFlags {
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]
pub fn failed(&self) -> bool {
pub fn atom_tbl(&self) -> TabledData<Atom> {
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 get_module(&self, name: ClauseName) -> Option<&Module> {
+ self.modules.get(&name)
}
- pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession
+ pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir) -> Result<(), SessionError>
{
- 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)
+ 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));
+ }
};
- self.modules.insert(name, module);
- result
- } else {
- EvalSession::from(SessionError::ModuleNotFound)
- }
- }
+ if idx.module_name().as_str() == "builtins" {
+ continue;
+ }
- pub fn get_module(&self, name: ClauseName) -> Option<&Module> {
- self.modules.get(&name)
- }
+ 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));
+ }
+ }
+ }
+ }
- 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());
+ 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) {
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());
+ #[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);
}
- 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();
+ #[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) {
+ self.modules.insert(module.module_decl.name.clone(), module);
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 {
while self.ms.p < end_ptr {
if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.ms.p {
match &self[LocalCodePtr::TopLevel(cn, p)] {
- &Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
+ &Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
self.record_var_places(cn, alloc_locs, heap_locs);
cn += 1;
},
{
let mut sorted_vars: Vec<(&Rc<Var>, &Addr)> = var_dir.iter().collect();
sorted_vars.sort_by_key(|ref v| v.0);
-
+
for (var, addr) in sorted_vars {
let fmt = TermFormatter {};
output = self.ms.print_var_eq(var.clone(), addr.clone(), var_dir, fmt, output);
--- /dev/null
+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)
+}
)
}
+macro_rules! default_machine_code_indices {
+ () => (
+ machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(),
+ &mut HashMap::new());
+ )
+}
+
macro_rules! put_constant {
($lvl:expr, $cons:expr, $r:expr) => (
QueryInstruction::PutConstant($lvl, $cons, $r)
pub enum Input {
Quit,
Clear,
- Line(String),
- Batch(String),
+ Batch,
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> {
let mut buffer = String::new();
stdin.read_line(&mut buffer).unwrap();
match &*buffer.trim() {
- ":{" => Ok(Input::Line(read_lines(&mut buffer, "}:"))),
- ":{{" => Ok(Input::Batch(read_lines(&mut buffer, "}}:"))),
- "quit" => Ok(Input::Quit),
- "clear" => Ok(Input::Clear),
- _ => {
+ "quit" => Ok(Input::Quit),
+ "clear" => Ok(Input::Clear),
+ "[user]" => Ok(Input::Batch),
+ _ => {
let mut parser = Parser::new(stdin.lock(), wam.atom_tbl(), wam.machine_flags());
parser.add_to_top(buffer.as_str());
Ok(Input::Term(parser.read_term(&wam.op_dir)?))
- }
+ }
}
}
if name.as_str() == "!" || name.as_str() == "blocked_!" {
Ok(QueryTerm::BlockedCut)
} else {
- let ct = indices.lookup(name, 0, None);
+ let ct = indices.get_clause_type(name, 0, None);
Ok(QueryTerm::Clause(r, ct, vec![], false))
},
Term::Var(_, ref v) if v.as_str() == "!" =>
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))
}
},
}
}
- 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 {
Term::Clause(r, name, mut subterms, fixity) =>
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| {
query_term.set_default_caller();
query_term
})
} 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>
{
let mut query_terms = vec![];
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)
}
- 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>
{
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 qt = query_terms.pop().unwrap();
}
}
- 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>
{
match term {
Term::Clause(r, name, mut terms, fixity) =>
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 {
- 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 {
let term = *terms.pop().unwrap();
Ok(TopLevel::Declaration(try!(setup_declaration(term))))
}
}
- fn try_terms_to_tls<Iter>(&mut self, idx: &mut MachineCodeIndices, terms: Iter, blocks_cuts: bool)
- -> Result<VecDeque<TopLevel>, ParserError>
- where Iter: IntoIterator<Item=Term>
+ fn try_terms_to_tls<I>(&mut self, indices: &mut MachineCodeIndices, terms: I, blocks_cuts: bool)
+ -> Result<VecDeque<TopLevel>, ParserError>
+ where I: IntoIterator<Item=Term>
{
let mut results = VecDeque::new();
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)
}
- 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();
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);
}
}
}
-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>
{
let mut rel_worker = RelationWorker::new();
TopLevelBatchWorker { parser: Parser::new(inner, atom_tbl, flags),
rel_worker: RelationWorker::new(),
results: vec![] }
- }
+ }
pub
fn consume(&mut self, indices: &mut MachineCodeIndices) -> Result<Option<Declaration>, SessionError>
impl fmt::Display for SessionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."),
&SessionError::QueryFailure => write!(f, "false."),
&SessionError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)),
- &SessionError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite {}.", msg),
&SessionError::OpIsInfixAndPostFix =>
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::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
+ &SessionError::UserPrompt => write!(f, "enter predicate at [user] prompt")
}
}
}