[[package]]
name = "prolog_parser"
version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rusty-wam"
-version = "0.7.10"
+version = "0.7.11"
dependencies = [
"downcast 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "prolog_parser 0.7.12",
+ "prolog_parser 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
"checksum ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58d25b6c0e47b20d05226d288ff434940296e7e2f8b877975da32f862152241f"
+"checksum prolog_parser 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bbf4229f9ff4f5826367591b0c76de86093c9ea8a8c4a8f2ac7cc66668788ce9"
"checksum redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ab105df655884ede59d45b7070c8a65002d921461ee813a024558ca16030eea0"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
[package]
name = "rusty-wam"
-version = "0.7.10"
+version = "0.7.11"
repository = "https://github.com/mthom/rusty-wam"
description = "The Warren Abstract Machine in Rust."
downcast = "0.9.1"
num = "0.2"
ordered-float = "0.5.0"
-prolog_parser = { path = "../prolog_parser", version = "0.7.12" }
+prolog_parser = "0.7.12"
[dependencies.termion]
version = "1.4.0"
\ No newline at end of file
* `writeq/1`
## Tutorial
-To enter a multi-clause predicate, the brackets ":{" and "}:" are used
-as delimiters. They must be contained entirely within their own lines.
+To enter a multi-clause predicate, the directive "[user]" is used.
For example,
```
-prolog> :{
+prolog> [user]
+(type Enter + Ctrl-D to terminate the stream when finished)
p(f(f(X)), h(W), Y) :- g(W), h(W), f(X).
p(X, Y, Z) :- h(Y), z(Z).
-}:
-prolog> :{
-h(x).
-h(y).
+prolog> [user]
+(type Enter + Ctrl-D to terminate the stream when finished)
+h(x). h(y).
h(z).
-}:
-```
-
-Single clause predicates can be entered without brackets, as in
-```
-prolog> p(X) :- q(X).
-prolog> f(s).
-prolog> z(Z).
```
+In the example, `Enter + Ctrl-D` is used to terminate the standard
+input stream. The instructive message is always printed.
Queries are issued as
```
prolog> ?- p(X, Y, Z).
```
-Given the above work, the result of the query will be
-```
-prolog> ?- p(X, Y, Z).
-true
-Y = x
-X = _0
-Z = _2
-```
-
Pressing `SPACE` will backtrack through other possible answers, if any exist.
Pressing `.` will abort the search and return to the prompt.
Wildcards work as well:
```
-prolog> :{
+prolog> [user]
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).
-}:
prolog> ?- member(X, [a, b, c]).
true .
X = a ;
```
and so do conjunctive queries:
```
-prolog> f(X) :- g(X).
-prolog> :{
+prolog> [user]
+f(X) :- g(X).
+prolog> [user]
g(x). g(y). g(z).
-}:
-prolog> h(call(f, X)).
+prolog> [user]
+h(call(f, X)).
prolog> ?- h(X), X.
true .
X = call(f, x) ;
prolog> :- use_module(library(control)).
```
-To define modules inline at the REPL, use the ":{{" and "}}:"
-delimiters:
+The [user] prompt can also be used to define modules inline at the
+REPL:
```
-prolog> :{{
+prolog> [user]
:- module(test, [local_member/2]).
:- use_module(library(lists)).
local_member(X, Xs) :- member(X, Xs).
-}}:
```
`use_module` directives can be qualified by adding a list of imports:
use std::collections::{HashMap, HashSet, VecDeque};
use std::io::Read;
use std::mem;
-use std::ops::DerefMut;
#[allow(dead_code)]
fn print_code(code: &Code) {
}
fn package_term(wam: &mut Machine, term: Term) -> Result<TopLevelPacket, ParserError> {
- let mut code_dir = wam.code_dir.borrow_mut();
- let indices = machine_code_indices!(code_dir.deref_mut(), &mut wam.op_dir, &mut wam.modules);
-
- parse_term(term, indices)
+ let code_dir = wam.code_dir.clone();
+ let indices = machine_code_indices!(&mut CodeDir::new(), &mut wam.op_dir, &mut wam.modules);
+
+ consume_term(code_dir, term, indices)
}
pub fn compile_term(wam: &mut Machine, term: Term) -> 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
+pub
+fn compile_listing<'a, R: Read>(wam: &mut Machine, src: R, mut indices: MachineCodeIndices<'a>,
+ mut toplevel_indices: MachineCodeIndices<'a>)
+ -> EvalSession
{
let mut worker = TopLevelBatchWorker::new(src, wam.atom_tbl(), wam.machine_flags(),
wam.code_dir.clone());
}
}
-#[derive(Clone, Copy,PartialEq)]
+#[derive(Clone, Copy, PartialEq)]
pub enum IndexPtr {
Undefined, Index(usize),
Module // This is a resolved module call. The module
#[inline]
pub fn module_name(&self) -> ClauseName {
- self.0.borrow().1.clone()
+ self.0.borrow().1.clone()
}
}
}
set_code_index!(code_idx, idx.0, idx.1);
-
return;
}
}
};
- if idx.module_name().as_str() == "builtins" {
- continue;
- }
-
if let Some(ref existing_idx) = self.code_dir.borrow().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() {
+ if !existing_idx.is_undefined() && !idx.is_undefined() {
+ // allow the overwriting of user-level predicates by all other predicates.
+ if existing_idx.module_name().as_str() == "user" {
+ continue;
+ }
+
+ if existing_idx.module_name().as_str() != idx.module_name().as_str() {
let err_str = format!("{}/{} from module {}", key.0, key.1,
existing_idx.module_name().as_str());
return Err(SessionError::CannotOverwriteImport(err_str));
}
}
+ // error detection has finished, so update the master index of keys.
+ for (key, idx) in code_dir {
+ if let Some(ref mut master_idx) = self.code_dir.borrow_mut().get_mut(&key) {
+ // ensure we don't double borrow if master_idx == idx.
+ // we don't need to modify anything in that case.
+ if !Rc::ptr_eq(&master_idx.0, &idx.0) {
+ set_code_index!(master_idx, idx.0.borrow().0, idx.module_name());
+ }
+
+ continue;
+ }
+
+ self.code_dir.borrow_mut().insert(key.clone(), idx.clone());
+ }
+
self.code.extend(code.into_iter());
- Ok(self.code_dir.borrow_mut().extend(code_dir.into_iter()))
+ Ok(())
}
#[inline]
mod and_stack;
#[macro_use] mod macros;
#[macro_use] mod allocator;
-mod toplevel;
+pub mod toplevel;
pub mod machine;
pub mod compile;
mod arithmetic;
use prolog::iterators::*;
use prolog::machine::*;
use prolog::machine::machine_state::MachineState;
+use prolog::toplevel::*;
use std::collections::VecDeque;
use std::io::{Read, stdin};
match &*buffer.trim() {
"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(composite_op!(&wam.op_dir))?))
- }
+ "[user]" => {
+ println!("(type Enter + Ctrl-D to terminate the stream when finished)");
+ Ok(Input::Batch)
+ },
+ _ => Ok(Input::Term(parse_term(wam, buffer.as_bytes())?))
}
}
{
fn get_code_index(&mut self, name: ClauseName, arity: usize) -> CodeIndex {
let idx_opt = self.local.code_dir.get(&(name.clone(), arity)).cloned()
- .or_else(|| self.static_code_dir.clone().and_then(|code_dir| {
- code_dir.borrow().get(&(name.clone(), arity)).cloned()
- }));
+ .or_else(|| {
+ self.static_code_dir.clone().and_then(|code_dir| {
+ code_dir.borrow().get(&(name.clone(), arity)).cloned()
+ })
+ });
if let Some(idx) = idx_opt {
- idx.clone()
+ self.local.code_dir.insert((name, arity), idx.clone());
+ idx
} else {
let idx = CodeIndex::default();
self.local.code_dir.insert((name, arity), idx.clone());
}
}
-pub fn parse_term<'a>(term: Term, mut indices: MachineCodeIndices<'a>) -> Result<TopLevelPacket, ParserError>
+// used to parse queries. mostly.
+pub fn parse_term<R: Read>(wam: &Machine, buf: R) -> Result<Term, ParserError>
+{
+ let mut parser = Parser::new(buf, wam.atom_tbl(), wam.machine_flags());
+ parser.read_term(composite_op!(&wam.op_dir))
+}
+
+pub
+fn consume_term<'a>(static_code_dir: Rc<RefCell<CodeDir>>, term: Term,
+ mut indices: MachineCodeIndices<'a>)
+ -> Result<TopLevelPacket, ParserError>
{
let mut rel_worker = RelationWorker::new();
- let mut indices = composite_indices!(&mut indices);
+ let mut indices = composite_indices!(false, &mut indices, static_code_dir);
let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?;
let results = rel_worker.parse_queue(&mut indices)?;
-use prolog_parser::ast::*;
-
use prolog::heap_print::*;
use prolog::instructions::*;
use prolog::compile::*;
use prolog::machine::*;
+use prolog::toplevel::*;
use std::collections::HashSet;
use std::mem::swap;
{
wam.reset();
- match parse_code(wam, buffer) {
- Ok(tl) =>
- match compile_packet(wam, tl) {
- EvalSession::InitialQuerySuccess(_, _) |
- EvalSession::EntrySuccess |
- EvalSession::SubsequentQuerySuccess =>
- true,
- _ => false
- },
- Err(e) => panic!("syntax_error({})", e.as_str())
+ match compile_user_module(wam, buffer.as_bytes()) {
+ EvalSession::InitialQuerySuccess(_, _) |
+ EvalSession::EntrySuccess |
+ EvalSession::SubsequentQuerySuccess =>
+ true,
+ _ => false
}
}
{
wam.reset();
- match parse_code(wam, buffer) {
- Ok(tl) =>
- match compile_packet(wam, tl) {
+ match parse_term(&wam, buffer.as_bytes()) {
+ Ok(term) =>
+ match compile_term(wam, term) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output(wam, alloc_locs, heap_locs),
EvalSession::EntrySuccess => true,
}
}
+#[allow(dead_code)]
+pub fn submit_query_without_results(wam: &mut Machine, buffer: &str) -> bool {
+ wam.reset();
+
+ match parse_term(&wam, buffer.as_bytes()) {
+ Ok(term) =>
+ match compile_term(wam, term) {
+ EvalSession::InitialQuerySuccess(..)
+ | EvalSession::EntrySuccess => true,
+ _ => false
+ },
+ Err(e) => panic!("syntax_error({})", e.as_str())
+ }
+}
+
#[allow(dead_code)]
pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
result: Vec<HashSet<String>>, limit: usize)
{
wam.reset();
- match parse_code(wam, buffer) {
- Ok(tl) =>
- match compile_packet(wam, tl) {
+ match parse_term(&wam, buffer.as_bytes()) {
+ Ok(term) =>
+ match compile_term(wam, term) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output_with_limit(wam, alloc_locs,
heap_locs, limit),
#[allow(unused_macros)]
macro_rules! assert_prolog_failure {
($wam: expr, $buf: expr) => (
- assert_eq!(submit($wam, $buf), false)
+ assert_eq!(submit_query_without_results($wam, $buf), false)
)
}
assert!(submit_query($wam, $query, vec![$(expand_strs!($res)),*]))
);
($wam:expr, $buf:expr) => (
- assert_eq!(submit($wam, $buf), true)
+ assert_eq!(submit_query_without_results($wam, $buf), true)
)
}
{
let mut wam = Machine::new();
- wam.use_module_in_toplevel(clause_name!("lists"));
+ submit(&mut wam, ":- use_module(library(lists)).");
compile_user_module(&mut wam, "
:- module(my_lists, [local_member/2, reverse/2]).
assert_prolog_success!(&mut wam, "?- my_lists:reverse([a,b,c], [c,b,a]).");
compile_user_module(&mut wam, "
-:- use_module(library(my_lists), [local_member/2]).
:- module(my_lists_2, [local_member/2]).
+:- use_module(library(my_lists), [local_member/2]).
".as_bytes());
assert_prolog_success!(&mut wam, "?- my_lists_2:local_member(1, [1,2,3]).");
{
let mut wam = Machine::new();
- wam.use_module_in_toplevel(clause_name!("lists"));
- wam.use_module_in_toplevel(clause_name!("control"));
+ submit(&mut wam, ":- use_module(library(lists)).");
+ submit(&mut wam, ":- use_module(library(control)).");
assert_prolog_failure!(&mut wam, "?- atom(X).");
assert_prolog_success!(&mut wam, "?- atom(a).");
assert_prolog_success!(&mut wam, "?- X = [a,b,c|\"abc\"].",
[["X = [a, b, c, a, b, c]"]]);
- submit(&mut wam, "?- set_prolog_flag(double_quotes, atom).");
+ assert_prolog_success!(&mut wam, "?- set_prolog_flag(double_quotes, atom).");
assert_prolog_success!(&mut wam, "?- matcher(X, Y).",
[["X = [a, b, c | _1]", "Y = _1"]]);
assert_prolog_failure!(&mut wam, "?- matcher(\"abcdef\", Y).");
- submit(&mut wam, "?- set_prolog_flag(double_quotes, chars).");
+ assert_prolog_success!(&mut wam, "?- set_prolog_flag(double_quotes, chars).");
assert_prolog_success!(&mut wam, "?- X = \"abc\", X = ['a' | Y], set_prolog_flag(double_quotes, atom).",
[["X = \"abc\"", "Y = \"bc\""]]);
// partial strings.
- submit(&mut wam, "?- set_prolog_flag(double_quotes, chars).");
+ assert_prolog_success!(&mut wam, "?- set_prolog_flag(double_quotes, chars).");
assert_prolog_failure!(&mut wam, "?- Y = 5, partial_string(\"abc\", Y).");
assert_prolog_success!(&mut wam, "?- partial_string(\"abc\", X).",