]> Repositorios git - scryer-prolog.git/commitdiff
streamline inputs.
authorMark Thom <[email protected]>
Fri, 14 Sep 2018 01:44:50 +0000 (19:44 -0600)
committerMark Thom <[email protected]>
Fri, 14 Sep 2018 01:44:50 +0000 (19:44 -0600)
Cargo.lock
Cargo.toml
README.md
src/prolog/compile.rs
src/prolog/instructions.rs
src/prolog/machine/mod.rs
src/prolog/mod.rs
src/prolog/read.rs
src/prolog/toplevel.rs
src/tests.rs

index 6ed1a05ac0252d686aeaa65acff1abece249dd08..194d28b32121614136b0dfb8a5288335e9c93b0d 100644 (file)
@@ -87,6 +87,7 @@ dependencies = [
 [[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)",
@@ -107,12 +108,12 @@ dependencies = [
 
 [[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)",
 ]
 
@@ -151,6 +152,7 @@ source = "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"
index 3ed2e17ec07fad5013a71e500a00f2f5bd2fe022..c08a0796467287e72dca35e79dbc91208b0f2f79 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "rusty-wam"
-version = "0.7.10"
+version = "0.7.11"
 authors = ["Mark Thom <[email protected]>"]
 repository = "https://github.com/mthom/rusty-wam"
 description = "The Warren Abstract Machine in Rust."
@@ -10,7 +10,7 @@ license = "BSD-3-Clause"
 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
index f81e78664156d39f75280a963fec151dfce6eba4..06ebae93aee83e6b1ba57f88d14e77343b4e9548 100644 (file)
--- a/README.md
+++ b/README.md
@@ -169,53 +169,36 @@ The following predicates are built-in to rusty-wam.
 * `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 ;
@@ -225,11 +208,12 @@ false.
 ```
 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) ;
@@ -289,16 +273,15 @@ prolog> :- use_module(library(lists)).
 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:
index 385eeb19c7571d9a8ed623ad72cdf50d09db6cac..a8949429b6215c68ac9dffd4d28f08532ef2dca9 100644 (file)
@@ -9,7 +9,6 @@ use prolog::toplevel::*;
 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) {
@@ -98,10 +97,10 @@ fn compile_query(terms: Vec<QueryTerm>, queue: Vec<TopLevel>, flags: MachineFlag
 }
 
 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
@@ -262,10 +261,10 @@ impl ListingCompiler {
     }
 }
 
-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());
index a19642dc3c38a02927bc921436910c399027d07c..d2d6636c5ffbccdbd887826f1d371aecec47ca59 100644 (file)
@@ -770,7 +770,7 @@ impl HeapCellValue {
     }
 }
 
-#[derive(Clone, Copy,PartialEq)]
+#[derive(Clone, Copy, PartialEq)]
 pub enum IndexPtr {
     Undefined, Index(usize),
     Module // This is a resolved module call. The module
@@ -794,7 +794,7 @@ impl CodeIndex {
 
     #[inline]
     pub fn module_name(&self) -> ClauseName {
-        self.0.borrow().1.clone()
+        self.0.borrow().1.clone()        
     }
 }
 
index 16dfc389946584de4b6c8fbf7ca6ec7234a6cce2..234907477514eee9f762f1e2de74fa403148225a 100644 (file)
@@ -105,7 +105,6 @@ impl<'a> SubModuleUser for MachineCodeIndices<'a> {
             }
 
             set_code_index!(code_idx, idx.0, idx.1);
-
             return;
         }
 
@@ -169,14 +168,15 @@ impl Machine {
                 }
             };
 
-            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));
@@ -185,8 +185,23 @@ impl Machine {
             }
         }
 
+        // 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]
index 4c77f937399fb106066980d6965bb0e5c4274d13..a546e118201078c75a2da1931865600326ad09c5 100644 (file)
@@ -6,7 +6,7 @@ extern crate prolog_parser;
 mod and_stack;
 #[macro_use] mod macros;
 #[macro_use] mod allocator;
-mod toplevel;
+pub mod toplevel;
 pub mod machine;
 pub mod compile;
 mod arithmetic;
index 888b4454dbce0b2c40bb1e94d5919ee559042697..a0db1fdc893dd2955005c2b0b7cf8ea894fc2f91 100644 (file)
@@ -5,6 +5,7 @@ use prolog::instructions::*;
 use prolog::iterators::*;
 use prolog::machine::*;
 use prolog::machine::machine_state::MachineState;
+use prolog::toplevel::*;
 
 use std::collections::VecDeque;
 use std::io::{Read, stdin};
@@ -38,13 +39,11 @@ pub fn read_toplevel(wam: &Machine) -> Result<Input, ParserError> {
     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())?))
     }
 }
 
index b4b7f832c72ebcef4e75e302ca7a6d81cecbfbe5..198dda1f78955b69c43dbfc5d8338aab4b236fe9 100644 (file)
@@ -36,12 +36,15 @@ impl<'a, 'b : 'a> CompositeIndices<'a, 'b>
 {
     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());
@@ -666,10 +669,20 @@ impl RelationWorker {
     }
 }
 
-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)?;
index e8e40271844b44be7d3c6cc5a34b84feb7284622..34e2c2840c4d4586ff861641434c47ce0651e218 100644 (file)
@@ -1,9 +1,8 @@
-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;
@@ -120,16 +119,12 @@ pub fn submit(wam: &mut Machine, buffer: &str) -> bool
 {
     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
     }
 }
 
@@ -138,9 +133,9 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
 {
     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,
@@ -150,6 +145,21 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
     }
 }
 
+#[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)
@@ -157,9 +167,9 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
 {
     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),
@@ -187,7 +197,7 @@ macro_rules! assert_prolog_success_with_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)
     )
 }
 
@@ -197,7 +207,7 @@ macro_rules! assert_prolog_success {
         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)
     )
 }
 
@@ -1342,7 +1352,7 @@ fn test_queries_on_modules()
 {
     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]).
@@ -1357,8 +1367,8 @@ reverse(Xs, Ys) :- lists:reverse(Xs, Ys).
     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]).");
@@ -1371,8 +1381,8 @@ fn test_queries_on_builtins()
 {
     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).");
@@ -1876,19 +1886,19 @@ fn test_queries_on_string_lists()
     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).",