correct module bugs

This commit is contained in:
Mark Thom
2018-03-04 21:35:30 -07:00
parent ba6d753a56
commit 0c66743db5
8 changed files with 203 additions and 140 deletions

View File

@@ -251,4 +251,15 @@ been exported to the toplevel. To export them, write
```
prolog> :- use_module(library(lists)).
prolog> :- use_module(library(control)).
```
To define modules inline at the REPL, use the ":{{"\"}}:" delimiters:
```
prolog> :{{
:- module(test, [local_member/2]).
:- use_module(library(lists)).
local_member(X, Xs) :- member(X, Xs).
}}:
```

View File

@@ -15,7 +15,7 @@ mod tests;
pub static LISTS: &str = include_str!("./prolog/lib/lists.pl");
pub static CONTROL: &str = include_str!("./prolog/lib/control.pl");
fn process_buffer(wam: &mut Machine, buffer: &str)
fn parse_and_compile_line(wam: &mut Machine, buffer: &str)
{
match parse_code(wam, buffer) {
Ok(packet) => {
@@ -39,20 +39,22 @@ fn prolog_repl() {
load_init_str(&mut wam, LISTS);
load_init_str(&mut wam, CONTROL);
loop {
print!("prolog> ");
let buffer = read();
match read() {
Input::Line(line) => parse_and_compile_line(&mut wam, line.as_str()),
Input::Batch(batch) => {
compile_listing(&mut wam, batch.as_str());
},
Input::Quit => break,
Input::Clear => {
wam.clear();
continue;
}
};
if buffer == "quit\n" {
break;
} else if buffer == "clear\n" {
wam.clear();
continue;
}
process_buffer(&mut wam, buffer.as_str());
wam.reset();
}
}

View File

@@ -133,18 +133,12 @@ impl PredicateClause {
pub type OpDirKey = (ClauseName, Fixity);
// name and fixity -> operator type and precedence.
pub type OpDir = HashMap<OpDirKey, (Specifier, usize)>;
pub type OpDir = HashMap<OpDirKey, (Specifier, usize, ClauseName)>;
pub type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize, ClauseName)>;
pub type CodeDir = HashMap<PredicateKey, (usize, ClauseName)>;
pub type PredicateKey = (ClauseName, usize); // name, arity.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum PredicateKeyType {
BuiltIn,
User
}
pub struct ModuleDecl {
pub name: ClauseName,
pub exports: Vec<PredicateKey>
@@ -377,7 +371,7 @@ impl From<ParserError> for EvalSession {
pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
impl OpDecl {
pub fn submit(&self, op_dir: &mut OpDir) -> Result<(), EvalError>
pub fn submit(&self, module: ClauseName, op_dir: &mut OpDir) -> Result<(), EvalError>
{
let (prec, spec, name) = (self.0, self.1, self.2.clone());
@@ -398,9 +392,9 @@ impl OpDecl {
if prec > 0 {
match spec {
XFY | XFX | YFX => op_dir.insert((name.clone(), Fixity::In),
(spec, prec)),
XF | YF => op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
FX | FY => op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
(spec, prec, module.clone())),
XF | YF => op_dir.insert((name.clone(), Fixity::Post), (spec, prec, module.clone())),
FX | FY => op_dir.insert((name.clone(), Fixity::Pre), (spec, prec, module.clone())),
_ => None
};
} else {

View File

@@ -628,154 +628,150 @@ pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
{
let mut code_dir = HashMap::new();
let mut op_dir = HashMap::new();
op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200));
op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200));
op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200));
let builtin = ClauseName::BuiltIn("builtin");
op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200, builtin.clone()));
op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200, builtin.clone()));
op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200, builtin.clone()));
// control operators.
op_dir.insert((clause_name!("\\+"), Fixity::Pre), (FY, 900));
op_dir.insert((clause_name!("="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("\\+"), Fixity::Pre), (FY, 900, builtin.clone()));
op_dir.insert((clause_name!("="), Fixity::In), (XFX, 700, builtin.clone()));
// arithmetic operators.
op_dir.insert((clause_name!("is"), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("+"), Fixity::In), (YFX, 500));
op_dir.insert((clause_name!("-"), Fixity::In), (YFX, 500));
op_dir.insert((clause_name!("/\\"), Fixity::In), (YFX, 500));
op_dir.insert((clause_name!("\\/"), Fixity::In), (YFX, 500));
op_dir.insert((clause_name!("xor"), Fixity::In), (YFX, 500));
op_dir.insert((clause_name!("//"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("/"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("div"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("*"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("-"), Fixity::Pre), (FY, 200));
op_dir.insert((clause_name!("rdiv"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("<<"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!(">>"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("mod"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("rem"), Fixity::In), (YFX, 400));
op_dir.insert((clause_name!("is"), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("+"), Fixity::In), (YFX, 500, builtin.clone()));
op_dir.insert((clause_name!("-"), Fixity::In), (YFX, 500, builtin.clone()));
op_dir.insert((clause_name!("/\\"), Fixity::In), (YFX, 500, builtin.clone()));
op_dir.insert((clause_name!("\\/"), Fixity::In), (YFX, 500, builtin.clone()));
op_dir.insert((clause_name!("xor"), Fixity::In), (YFX, 500, builtin.clone()));
op_dir.insert((clause_name!("//"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!("/"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!("div"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!("*"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!("-"), Fixity::Pre), (FY, 200, builtin.clone()));
op_dir.insert((clause_name!("rdiv"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!("<<"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!(">>"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!("mod"), Fixity::In), (YFX, 400, builtin.clone()));
op_dir.insert((clause_name!("rem"), Fixity::In), (YFX, 400, builtin.clone()));
// arithmetic comparison operators.
op_dir.insert((clause_name!(">"), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("<"), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("=\\="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("=:="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!(">="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("=<"), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!(">"), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("<"), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("=\\="), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("=:="), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!(">="), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("=<"), Fixity::In), (XFX, 700, builtin.clone()));
// control operators.
op_dir.insert((clause_name!(";"), Fixity::In), (XFY, 1100));
op_dir.insert((clause_name!("->"), Fixity::In), (XFY, 1050));
op_dir.insert((clause_name!(";"), Fixity::In), (XFY, 1100, builtin.clone()));
op_dir.insert((clause_name!("->"), Fixity::In), (XFY, 1050, builtin.clone()));
op_dir.insert((clause_name!("=.."), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("=="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("\\=="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("@=<"), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("@>="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("@<"), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("@>"), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("=@="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("\\=@="), Fixity::In), (XFX, 700));
let builtin = ClauseName::BuiltIn("builtin");
op_dir.insert((clause_name!("=.."), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("=="), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("\\=="), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("@=<"), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("@>="), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("@<"), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("@>"), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("=@="), Fixity::In), (XFX, 700, builtin.clone()));
op_dir.insert((clause_name!("\\=@="), Fixity::In), (XFX, 700, builtin.clone()));
// there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
// (an extra register is needed for the predicate name)
for arity in 0 .. 63 {
code_dir.insert((clause_name!("call"), arity),
(PredicateKeyType::BuiltIn, 0, builtin.clone()));
code_dir.insert((clause_name!("call"), arity), (0, builtin.clone()));
}
code_dir.insert((clause_name!("atomic"), 1),
(PredicateKeyType::BuiltIn, 1, builtin.clone()));
code_dir.insert((clause_name!("var"), 1),
(PredicateKeyType::BuiltIn, 3, builtin.clone()));
code_dir.insert((clause_name!("false"), 0),
(PredicateKeyType::BuiltIn, 61, builtin.clone()));
code_dir.insert((clause_name!("atomic"), 1), (1, builtin.clone()));
code_dir.insert((clause_name!("var"), 1), (3, builtin.clone()));
code_dir.insert((clause_name!("false"), 0), (61, builtin.clone()));
code_dir.insert((clause_name!("\\+"), 1),
(PredicateKeyType::BuiltIn, 62, builtin.clone()));
(62, builtin.clone()));
code_dir.insert((clause_name!("duplicate_term"), 2),
(PredicateKeyType::BuiltIn, 71, builtin.clone()));
(71, builtin.clone()));
code_dir.insert((clause_name!("catch"), 3),
(PredicateKeyType::BuiltIn, 5, builtin.clone()));
(5, builtin.clone()));
code_dir.insert((clause_name!("throw"), 1),
(PredicateKeyType::BuiltIn, 59, builtin.clone()));
(59, builtin.clone()));
code_dir.insert((clause_name!("="), 2),
(PredicateKeyType::BuiltIn, 73, builtin.clone()));
(73, builtin.clone()));
code_dir.insert((clause_name!("true"), 0),
(PredicateKeyType::BuiltIn, 75, builtin.clone()));
(75, builtin.clone()));
code_dir.insert((clause_name!(","), 2),
(PredicateKeyType::BuiltIn, 76, builtin.clone()));
(76, builtin.clone()));
code_dir.insert((clause_name!(";"), 2),
(PredicateKeyType::BuiltIn, 120, builtin.clone()));
(120, builtin.clone()));
code_dir.insert((clause_name!("->"), 2),
(PredicateKeyType::BuiltIn, 138, builtin.clone()));
(138, builtin.clone()));
code_dir.insert((clause_name!("functor"), 3),
(PredicateKeyType::BuiltIn, 146, builtin.clone()));
(146, builtin.clone()));
code_dir.insert((clause_name!("arg"), 3),
(PredicateKeyType::BuiltIn, 150, builtin.clone()));
(150, builtin.clone()));
code_dir.insert((clause_name!("integer"), 1),
(PredicateKeyType::BuiltIn, 147, builtin.clone()));
(147, builtin.clone()));
code_dir.insert((clause_name!("display"), 1),
(PredicateKeyType::BuiltIn, 192, builtin.clone()));
(192, builtin.clone()));
code_dir.insert((clause_name!("is"), 2),
(PredicateKeyType::BuiltIn, 194, builtin.clone()));
(194, builtin.clone()));
code_dir.insert((clause_name!(">"), 2),
(PredicateKeyType::BuiltIn, 196, builtin.clone()));
(196, builtin.clone()));
code_dir.insert((clause_name!("<"), 2),
(PredicateKeyType::BuiltIn, 198, builtin.clone()));
(198, builtin.clone()));
code_dir.insert((clause_name!(">="), 2),
(PredicateKeyType::BuiltIn, 200, builtin.clone()));
(200, builtin.clone()));
code_dir.insert((clause_name!("=<"), 2),
(PredicateKeyType::BuiltIn, 202, builtin.clone()));
(202, builtin.clone()));
code_dir.insert((clause_name!("=\\="), 2),
(PredicateKeyType::BuiltIn, 204, builtin.clone()));
(204, builtin.clone()));
code_dir.insert((clause_name!("=:="), 2),
(PredicateKeyType::BuiltIn, 206, builtin.clone()));
(206, builtin.clone()));
code_dir.insert((clause_name!("=.."), 2),
(PredicateKeyType::BuiltIn, 208, builtin.clone()));
(208, builtin.clone()));
code_dir.insert((clause_name!("length"), 2),
(PredicateKeyType::BuiltIn, 261, builtin.clone()));
(261, builtin.clone()));
code_dir.insert((clause_name!("setup_call_cleanup"), 3),
(PredicateKeyType::BuiltIn, 294, builtin.clone()));
(294, builtin.clone()));
code_dir.insert((clause_name!("call_with_inference_limit"), 3),
(PredicateKeyType::BuiltIn, 393, builtin.clone()));
(393, builtin.clone()));
code_dir.insert((clause_name!("compound"), 1),
(PredicateKeyType::BuiltIn, 372, builtin.clone()));
(372, builtin.clone()));
code_dir.insert((clause_name!("rational"), 1),
(PredicateKeyType::BuiltIn, 374, builtin.clone()));
(374, builtin.clone()));
code_dir.insert((clause_name!("string"), 1),
(PredicateKeyType::BuiltIn, 376, builtin.clone()));
(376, builtin.clone()));
code_dir.insert((clause_name!("float"), 1),
(PredicateKeyType::BuiltIn, 378, builtin.clone()));
(378, builtin.clone()));
code_dir.insert((clause_name!("nonvar"), 1),
(PredicateKeyType::BuiltIn, 380, builtin.clone()));
(380, builtin.clone()));
code_dir.insert((clause_name!("ground"), 1),
(PredicateKeyType::BuiltIn, 384, builtin.clone()));
(384, builtin.clone()));
code_dir.insert((clause_name!("=="), 2),
(PredicateKeyType::BuiltIn, 385, builtin.clone()));
(385, builtin.clone()));
code_dir.insert((clause_name!("\\=="), 2),
(PredicateKeyType::BuiltIn, 386, builtin.clone()));
(386, builtin.clone()));
code_dir.insert((clause_name!("@>="), 2),
(PredicateKeyType::BuiltIn, 387, builtin.clone()));
(387, builtin.clone()));
code_dir.insert((clause_name!("@=<"), 2),
(PredicateKeyType::BuiltIn, 388, builtin.clone()));
(388, builtin.clone()));
code_dir.insert((clause_name!("@>"), 2),
(PredicateKeyType::BuiltIn, 389, builtin.clone()));
(389, builtin.clone()));
code_dir.insert((clause_name!("@<"), 2),
(PredicateKeyType::BuiltIn, 390, builtin.clone()));
(390, builtin.clone()));
code_dir.insert((clause_name!("=@="), 2),
(PredicateKeyType::BuiltIn, 391, builtin.clone()));
(391, builtin.clone()));
code_dir.insert((clause_name!("\\=@="), 2),
(PredicateKeyType::BuiltIn, 392, builtin.clone()));
(392, builtin.clone()));
code_dir.insert((clause_name!("compare"), 3),
(PredicateKeyType::BuiltIn, 464, builtin.clone()));
(464, builtin.clone()));
(code_dir, op_dir)
}

View File

@@ -446,30 +446,43 @@ pub fn parse_code(wam: &Machine, buffer: &str) -> Result<TopLevelPacket, ParserE
worker.parse_code(&wam.op_dir)
}
pub fn read() -> String {
let _ = stdout().flush();
pub enum Input {
Quit,
Clear,
Line(String),
Batch(String)
}
let mut buffer = String::new();
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() -> Input {
let _ = stdout().flush();
let mut buffer = String::new();
let stdin = stdin();
stdin.read_line(&mut buffer).unwrap();
if &*buffer.trim() == ":{" {
buffer.clear();
stdin.read_line(&mut buffer).unwrap();
while &*buffer.trim() != "}:" {
result += buffer.as_str();
buffer.clear();
stdin.read_line(&mut buffer).unwrap();
}
} else {
result = buffer;
match &*buffer.trim() {
":{" => Input::Line(read_lines(&mut buffer, "}:")),
":{{" => Input::Batch(read_lines(&mut buffer, "}}:")),
"quit" => Input::Quit,
"clear" => Input::Clear,
_ => Input::Line(buffer)
}
result
}
// throw errors if declaration or query found.
@@ -533,7 +546,7 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSe
{
match tl {
TopLevel::Declaration(Declaration::Op(op_decl)) => {
try_eval_session!(op_decl.submit(&mut wam.op_dir));
try_eval_session!(op_decl.submit(clause_name!("user"), &mut wam.op_dir));
EvalSession::EntrySuccess
},
TopLevel::Declaration(Declaration::UseModule(name)) =>
@@ -585,8 +598,10 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
let mut code = Vec::new();
let mut worker = TopLevelWorker::new(src_str.as_bytes(), wam.atom_tbl());
let tls = try_eval_session!(worker.parse_batch(&mut op_dir));
let tls = try_eval_session!(worker.parse_batch(&mut op_dir));
for tl in tls {
match tl {
TopLevelPacket::Query(..) =>
@@ -622,15 +637,14 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
try_eval_session!(compile_appendix(&mut decl_code, queue));
code.extend(decl_code.into_iter());
code_dir.insert((decl.name().unwrap(), decl.arity()),
(PredicateKeyType::User, p, get_module_name(&module)));
code_dir.insert((decl.name().unwrap(), decl.arity()), (p, get_module_name(&module)));
}
}
}
if let Some(mut module) = module {
module.code_dir = code_dir;
module.op_dir = op_dir;
module.code_dir.extend(code_dir.into_iter());
module.op_dir.extend(op_dir.into_iter());
wam.add_module(module, code);
} else {

View File

@@ -37,7 +37,7 @@ impl<'a> CodeDirs<'a> {
-> Option<(usize, ClauseName)>
{
let code_dir = self.get_current_code_dir(p);
code_dir.get(&(name, arity)).map(|idx| (idx.1, idx.2.clone()))
code_dir.get(&(name, arity)).cloned()
}
}

View File

@@ -17,7 +17,7 @@ use std::rc::Rc;
struct MachineCodeIndex<'a> {
code_dir: &'a mut CodeDir,
op_dir: &'a mut OpDir
op_dir: &'a mut OpDir,
}
pub struct Machine {
@@ -54,7 +54,7 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> {
fn code_dir(&mut self) -> &mut CodeDir {
self.code_dir
}
}
}
impl Machine {
@@ -73,7 +73,50 @@ impl Machine {
cached_query: None
}
}
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((_, ref mod_name)) if mod_name == &module_name => {
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));
}
}
}
},
_ => {}
};
}
}
pub fn failed(&self) -> bool {
self.ms.fail
}
@@ -83,10 +126,13 @@ impl Machine {
}
pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession {
self.remove_module(name.clone());
match self.modules.get(&name) {
Some(ref module) => {
let mut indices = MachineCodeIndex { code_dir: &mut self.code_dir,
op_dir: &mut self.op_dir };
indices.use_module(module)
},
None => EvalSession::from(EvalError::ModuleNotFound)
@@ -114,7 +160,7 @@ impl Machine {
pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession
{
match self.code_dir.get(&(name.clone(), arity)) {
Some(&(PredicateKeyType::BuiltIn, _, _)) =>
Some(&(_, ref mod_name)) if mod_name == &clause_name!("builtin") =>
return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", name, arity))),
_ => {}
};
@@ -122,7 +168,7 @@ impl Machine {
let offset = self.code.len();
self.code.extend(code.into_iter());
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset, clause_name!("user")));
self.code_dir.insert((name, arity), (offset, clause_name!("user")));
EvalSession::EntrySuccess
}