115 Commits

Author SHA1 Message Date
Mark Thom
9e54b1406c Merge pull request #338 from triska/master
also include a newline in portray_clause/1
2020-04-12 20:35:48 -03:00
Markus Triska
f52c9772a7 also include a newline in portray_clause/1 2020-04-13 01:24:15 +02:00
Mark Thom
ea5203d8c3 Merge pull request #337 from triska/master
ADDED: provide a rudimentary version of portray_clause/1
2020-04-12 20:10:21 -03:00
Mark Thom
0fad2f9953 make write_term_to_chars work with variable terms (#335) 2020-04-12 18:10:45 -06:00
Mark Thom
d3a9392421 provide read_term_from_chars/2 (#334) 2020-04-12 17:26:11 -06:00
Markus Triska
208927544d ADDED: provide a rudimentary version of portray_clause/1
At the moment, library(format) seems to be a fitting place.
In the eventual library organization, portray_clause/1 and
related predicates may be moved to their own dedicated library.
2020-04-13 01:04:52 +02:00
Mark Thom
7621155a89 change wording of QueryCannotBePostedAsFact to QueryCannotBeDefinedAsFact, remove old commented code in read.rs 2020-04-12 16:01:53 -06:00
Mark Thom
4ddc4ebf46 Merge pull request #333 from triska/master
incorporate the latest improvements in the description of partial strings
2020-04-12 16:00:01 -03:00
Markus Triska
786f0b5ca2 incorporate the latest improvements in the description of partial strings
As of 6e4b76a3b4, the use of
partial_string/3 can be replaced by (=)/2 in this example.
2020-04-12 20:46:22 +02:00
Mark Thom
b4ff429bfa Merge pull request #332 from triska/master
ENHANCED: ~w now supports compound terms, and ~q is now also available
2020-04-12 15:00:20 -03:00
Mark Thom
f2cf0ec459 move write_term_to_chars/3 to src/prolog/lib/charsio.pl 2020-04-12 14:42:39 -06:00
Mark Thom
0380d70a46 add write_term_to_chars/3 to iso_ext.pl (#288) 2020-04-12 14:29:28 -06:00
Mark Thom
28099b9812 correct misleading error for modules (#300) 2020-04-12 12:51:59 -06:00
Mark Thom
2ce4f602c0 be more judicious with at_cdr in print_string (#295) 2020-04-12 12:18:15 -06:00
Mark Thom
5e81fb4754 throw exception when attempting to post query as goal (#329) 2020-04-12 12:07:41 -06:00
Markus Triska
c9f1a95343 ENHANCED: ~w now supports compound terms, and ~q is now also available 2020-04-12 19:56:01 +02:00
Mark Thom
97d8d07947 recognize empty lists as partial strings (#328) 2020-04-11 23:08:15 -06:00
Mark Thom
4f0adad78e remove string/1, use a more general test for the partial_string/1 type test (#328) 2020-04-11 22:47:52 -06:00
Mark Thom
0499005db5 throw error when trying to use partial lists as DCG terminal-sequence (#286) 2020-04-11 22:40:29 -06:00
Mark Thom
aedffb3cfe remove unnecessary use of partial_string in bimetatrans example 2020-04-11 22:02:17 -06:00
Mark Thom
fff96e69db Merge pull request #310 from triska/bimeta_example
Bimeta example
2020-04-11 22:03:10 -03:00
Mark Thom
abc99c9dd8 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-04-11 21:59:25 -06:00
Mark Thom
6e4b76a3b4 compile special instructions for partial strings when recognized 2020-04-11 21:53:28 -06:00
Mark Thom
92d8642133 do not accept [X|Xs] patterns as DCG non-terminals (#286) 2020-04-11 21:52:45 -06:00
Mark Thom
184124586b Merge pull request #320 from triska/master
add library(freeze) to make zcompare/3 work
2020-04-09 12:26:31 -03:00
Markus Triska
4d32b6976a add library(freeze) to make zcompare/3 work 2020-04-08 22:09:59 +02:00
Mark Thom
45a99e576d Merge pull request #318 from triska/master
extend description of strings and partial strings
2020-04-08 16:59:13 -03:00
Markus Triska
fac6d54986 extend description of strings and partial strings
Also, explain in more detail what this feature means to Prolog
application programmers, and the strategic direction of Scryer.
2020-04-08 21:07:00 +02:00
Mark Thom
036c35729c Merge pull request #316 from triska/master
clpz_monotonic/0 --> monotonic/0
2020-04-08 13:18:42 -03:00
Markus Triska
e442fddc66 tuples_in/2 now works 2020-04-08 17:49:06 +02:00
Mark Thom
a3c3afba48 fix list index offset bug (#314) 2020-04-06 16:15:36 -06:00
Markus Triska
794ceac440 clpz_monotonic/0 --> monotonic/0 2020-04-06 23:05:57 +02:00
Mark Thom
6299d41cda mark clp(X) item as completed, restore clp(Z) library description 2020-04-05 21:26:27 -03:00
Mark Thom
2e5ce0249e Merge pull request #312 from triska/master
ADDED: CLP(ℤ), Constraint Logic Programming over Integers
2020-04-05 21:14:11 -03:00
Mark Thom
560298655b consolidate Cargo.lock 2020-04-05 20:34:49 -06:00
Mark Thom
4086df27b2 merge with master 2020-04-05 20:33:45 -06:00
Mark Thom
d76ae413c4 use fixnums in place of bignums where possible 2020-04-05 20:32:16 -06:00
Markus Triska
8b1df2e9ca ADDED: CLP(ℤ), Constraint Logic Programming over Integers
library(clpz) implements declarative integer arithmetic.

The most important predicates for reasoning about integers are:

    (#=)/2    equality
    (#\=)/2   disequality
    (#<)/2    less than
    (#>)/2    greater than
    (#=<)/2   less than or equal to
    (#>=)/2   greater than or equal to

In addition, the library provides several global constraints, such as
all_distinct/1 and global_cardinality/2, and reification predicates
that reflect the truth values of constraints into integer variables.

Enumeration predicates such label/1 and labeling/2 can be used to
search for solutions over finite domains.

Almost all Prolog programs also reason about integers. Therefore, I
recommend to add this library to your .scryerrc configuration file so
that declarative integer arithmetic is available in all your programs.

More information about CLP(ℤ):

    https://www.metalevel.at/prolog/clpz

Enjoy!
2020-04-06 01:59:41 +02:00
Mark Thom
c8855f97e8 allocate empty partial strings 2020-04-05 02:55:30 -06:00
Mark Thom
bbf1aa1668 use copy_term/3 to print residual goals (#254) 2020-04-05 02:55:04 -06:00
Mark Thom
141f3bcec3 harmonize partial strings with complete strings (#276), make Addr a copyable type 2020-04-03 10:22:46 -06:00
Mark Thom
8f11fd7c62 Merge pull request #306 from srenatus/sr/version-argument
main: add -v/--version flag
2020-04-03 00:35:51 -03:00
Mark Thom
9f960c25a5 add bimetatrans_ruleml.pl to examples 2020-03-30 20:00:08 -06:00
Markus Triska
11a616917a introduce and use nonterminal list//1
Example:

    ?- phrase(list(Ls), Ls0).
       Ls = [], Ls0 = []
    ;  Ls = [_A], Ls0 = [_A]
    ;  Ls = [_A,_B], Ls0 = [_A,_B]
    ;  Ls = [_A,_B,_C], Ls0 = [_A,_B,_C]
    ;  ...
2020-03-31 01:28:16 +02:00
Markus Triska
a89f03f27d embed literal lists directly in DCGs
Example use of direct embedding:

    ?- phrase("abc", Ls0, Ls).
       Ls0 = [a,b,c|Ls].
2020-03-31 01:24:15 +02:00
Markus Triska
3faf36440c naming: partial_list_ws//1 --> list_ws//1
A DCG describes a list, so "list" is an appropriate name.
2020-03-31 01:23:00 +02:00
Stephan Renatus
45d4f46024 main: skip args[0]
This is a bit pedantic, it's unlikely that the executable would be
called `-v` or `--version`. However, it seems slightly more correct to
disregard argv[0] when checking flags.
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-03-28 09:07:44 +01:00
Stephan Renatus
896f2aeb74 main: add -v/--version flag
Added a new dependency to take care of pulling in the version from git
at build time.

Args handling is minimalistic, but there wasn't any before, so I figured
this might do for now. (Eventually, some proper `--help` and usage
output might come in handy?)

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-03-27 19:59:50 +01:00
Mark Thom
7de39611f3 Merge pull request #305 from srenatus/sr/typo
examples/least_time.pl: fix typo
2020-03-27 14:35:17 -03:00
Stephan Renatus
7e6be23287 examples/least_time.pl: fix typo
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-03-27 18:29:17 +01:00
Mark Thom
cac76d4739 Merge branch 'master' into develop 2020-03-26 22:01:25 -06:00
Mark Thom
194e5dc94e initial commit for merge 2020-03-26 22:01:23 -06:00
Mark Thom
f7629362d7 Merge branch 'master' of https://github.com/mthom/rusty-wam 2020-03-19 20:42:37 -06:00
Mark Thom
ea0c396114 add least_time example 2020-03-19 20:42:11 -06:00
Mark Thom
057e2d8056 provide contextual information in the return value of try_in_situ_result 2020-03-19 20:41:58 -06:00
Mark Thom
487fe21e25 #278 2020-03-19 17:49:17 -06:00
Mark Thom
54dce9b60e Merge pull request #294 from triska/format
ENHANCED: format_//2 now supports ~a, ~d, ~Nd, ~D, ~ND, ~Nn, ~i and ~*
2020-03-19 20:00:40 -03:00
Markus Triska
f09a3142a6 ENHANCED: format_//2 now supports ~a, ~d, ~Nd, ~D, ~ND, ~Nn, ~i and ~* 2020-03-19 21:51:53 +01:00
Mark Thom
121c8d8a48 Merge pull request #293 from triska/documentation
update toplevel interaction
2020-03-17 13:55:05 -03:00
Markus Triska
b9561ec8db update toplevel interaction 2020-03-17 17:42:57 +01:00
Mark Thom
b1d8eff019 remove Addr::PStrTail (#276) 2020-03-17 02:03:29 -06:00
Mark Thom
f9c4a40d60 add set_input/1, set_output/1 2020-03-15 23:29:21 -06:00
Mark Thom
8e318f76a7 correct contextual quoting of chars 2020-03-15 21:15:42 -06:00
Mark Thom
7d21ea93a6 Merge pull request #289 from triska/documentation
include a short overview of notable libraries
2020-03-15 12:09:44 -03:00
Mark Thom
8630ba4a2d Merge pull request #291 from triska/toplevel
Two small toplevel features
2020-03-15 12:09:25 -03:00
Markus Triska
17a448e045 support 'h' to print help message during toplevel interaction 2020-03-15 13:42:51 +01:00
Markus Triska
7ff11dce35 support 'p' to reprint answer with max depth, allowing w -> p -> w ... 2020-03-15 13:26:49 +01:00
Markus Triska
e2a4854bcf include a short overview of notable libraries 2020-03-15 11:43:32 +01:00
Mark Thom
bef96e231d use max_depth at toplevel, allowing full printing of terms with the 'w' keypress (#287), put disjunctions on new lines (#278) 2020-03-15 00:35:59 -06:00
Mark Thom
325df8a6e3 add provisional max_depth option to write_term, speed printing of non-cyclic terms 2020-03-15 00:09:20 -06:00
Mark Thom
3620f72b6c output strings more efficiently 2020-03-14 18:17:11 -06:00
Mark Thom
42a90b2d40 don't emit overwriting warnings for term_expansion/2 or goal_expansion/2 2020-03-14 14:18:01 -06:00
Mark Thom
97aab6950c correct DCG descriptions of lists (#286) 2020-03-14 14:14:26 -06:00
Mark Thom
31258247b3 Give new answer variables readable names (#279) 2020-03-14 03:04:11 -06:00
Mark Thom
beed4e8aa8 print strings as strings only in the term expander 2020-03-13 21:05:25 -06:00
Mark Thom
c60a0bc062 print strings as strings (#285) 2020-03-13 18:24:13 -06:00
Mark Thom
733c2d4152 eliminate inner_numbervar_count 2020-03-13 17:12:35 -06:00
Mark Thom
79b5857f72 Merge pull request #284 from triska/master
ADDED: library(format), describing strings with format_//2
2020-03-13 17:06:27 -03:00
Mark Thom
7260eba26a allow module export of nonterminals (#281) 2020-03-13 15:40:03 -06:00
Mark Thom
7e7a1b2caf properly handle '\n' when quoted and not (#283, #280) 2020-03-13 15:32:56 -06:00
Mark Thom
99181e3302 fix -names (#275) 2020-03-13 13:49:12 -06:00
Mark Thom
d57d2b96d6 Revert "fix $VAR-names (#275) and properly print single control chars (#280)"
This reverts commit d3eb31e4c3.
2020-03-13 13:47:58 -06:00
Markus Triska
24bed8c548 ADDED: library(format), describing strings with format_//2
This library provides the nonterminal format_//2 to describe
formatted strings. format/2 is provided for impure output.

Usage:
======

phrase(format_(FormatString, Arguments), Ls)

format_//2 describes a list of characters Ls that are formatted
according to FormatString. FormatString is a string (i.e.,
a list of characters) that specifies the layout of Ls.
The characters in FormatString are used literally, except
for the following tokens with special meaning:

  ~w    use the next available argument from Arguments here,
        which must be atomic (a current limitation)
  ~f    use the next argument here, a floating point number
  ~Nf   where N is an integer: format the float argument
        using N digits after the decimal point
  ~s    use the next argument here, which must be a string
  ~N|   where N is an integer: place a tab stop at text column N
  ~N+   where N is an integer: place a tab stop N characters
        after the previous tab stop (or start of line)
  ~t    distribute spaces evenly between the two closest tabstops
  ~`Ct  like ~t, use character C instead of spaces to fill the space
  ~n    newline
  ~~    the literal ~

The predicate format/2 is like format_//2, except that it outputs
the text on the terminal instead of describing it declaratively.

If at all possible, format_//2 should be used, to stress pure parts
that enable easy testing etc. If necessary, you can emit the list Ls
with maplist(write, Ls).

The entire library only works if the Prolog flag double_quotes
is set to chars, the default value in Scryer Prolog. This should
also stay that way, to encourage a sensible environment.

Example:

?- phrase(format_("~s~n~`.t~w!~12|", ["hello",there]), Cs).
%@ Cs = [h,e,l,l,o,'\n','.','.','.','.','.','.',t,h,e,r,e,!] ;
%@ false.
2020-03-13 20:46:53 +01:00
Mark Thom
6c9e704aa8 sort variables in findall_with_existential before computing set difference (#282), trawl back changes of (#279) 2020-03-13 13:18:47 -06:00
Mark Thom
d3eb31e4c3 fix $VAR-names (#275) and properly print single control chars (#280) 2020-03-13 02:48:40 -06:00
Mark Thom
698b01f85a give new answer variables readable names (#279) 2020-03-13 02:40:06 -06:00
Mark Thom
4c88e97330 add current_output, printing of stream terms 2020-03-11 00:38:01 -06:00
Mark Thom
25babff827 add streams.rs, consume them in place of the old PrologStream 2020-03-09 11:56:16 -06:00
Mark Thom
23e833c69e update README.md 2020-03-08 18:02:06 -06:00
Mark Thom
22bb3fe876 replace termion with crossterm 2020-03-08 18:01:54 -06:00
Mark Thom
eee10d3ee7 fix broken conformity tests, quote left paren 2020-03-08 16:49:47 -06:00
Mark Thom
c7591045af represent the current_dir as an absolute path, not a relative one. (#262) 2020-03-07 16:00:10 -07:00
Mark Thom
6ddfef6383 count single character atoms as characters when generating first argument indices 2020-03-06 21:19:53 -07:00
Mark Thom
9852e30b39 compare characters directly in term comparison tests 2020-03-05 12:50:11 -07:00
Mark Thom
2d3ce32314 switch to representation error for partial strings (#267) 2020-03-01 23:21:35 -07:00
Mark Thom
d8e0bea110 correct handling of strings and partial strings as lists, print bar operator with surrounding spaces (#274) 2020-03-01 00:00:40 -07:00
Mark Thom
b2cf6a6ea8 update README 2020-02-29 15:23:48 -07:00
Mark Thom
2ebcd673c8 add s pointers for strings and partial strings, put_unsafe_value calls store earlier to avoid unnecessary heap writes (#273) 2020-02-28 23:42:40 -07:00
Mark Thom
aa5f186a96 allow set_prolog_flag in declarations 2020-02-28 21:42:22 -07:00
Mark Thom
934f73f696 remove cyclic_term/1 2020-02-27 16:19:48 -07:00
Mark Thom
993c6f0e7b actually do lco, and mark unsafe variables before the goals where they last occur, not just in the last goal 2020-02-27 16:17:20 -07:00
Mark Thom
1d79e22468 mention rustup.rs in README (#261) 2020-02-23 13:22:56 -07:00
Mark Thom
8ba92d8b99 update prolog_parser version, allow ('|') operator in DCGs (#274) 2020-02-23 13:16:14 -07:00
Mark Thom
af23258152 remove setof/3, bagof/3 non-determinism (#270) 2020-02-22 15:13:01 -07:00
Mark Thom
b2e50b42a3 rename non_iso.pl to iso_ext.pl (#265) 2020-02-22 00:58:37 -07:00
Mark Thom
003b4d0218 add comparisons between partial strings and string constants (#263) 2020-02-22 00:51:27 -07:00
Mark Thom
545472f9c4 correct misreported error in toplevel loop (#272) 2020-02-21 21:09:59 -07:00
Mark Thom
8f781c27f9 remove same_length/2 from clpb.pl 2020-02-21 17:21:15 -07:00
Mark Thom
589dc34b99 make partial strings accept characters (#268) 2020-02-21 13:08:03 -07:00
Mark Thom
564622e38b partial_string/3 should accept empty lists (#264) 2020-02-21 12:55:33 -07:00
Mark Thom
d3744d6f66 identify ground partial strings under (==) (#269) 2020-02-21 12:51:23 -07:00
Mark Thom
2613ef0633 adopt compatibility predicates from clpb and clpz into lists and pairs libraries 2020-02-21 12:48:15 -07:00
Mark Thom
be3cdcd71a fix #255 (I think?) 2020-02-21 01:02:52 -07:00
Mark Thom
d48ac09e25 correct PStrLocation offset bug in copier.rs 2020-02-20 10:59:42 -07:00
Mark Thom
e5a0ba7bf3 revert to older between.pl 2020-02-20 10:07:45 -07:00
67 changed files with 19461 additions and 5199 deletions

333
Cargo.lock generated
View File

@@ -1,5 +1,10 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "arc-swap"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.5" version = "0.3.5"
@@ -24,7 +29,7 @@ version = "0.3.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -48,7 +53,7 @@ dependencies = [
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.1.0" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -73,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.7" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -81,7 +86,7 @@ name = "cloudabi"
version = "0.0.3" version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -94,16 +99,39 @@ name = "crossbeam-utils"
version = "0.6.6" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "crossterm"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossterm_winapi 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossterm_winapi"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "2.0.2" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -112,7 +140,7 @@ name = "dirs-sys"
version = "0.3.4" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -148,6 +176,40 @@ name = "fuchsia-cprng"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "git-version"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"git-version-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "git-version-macro"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "gmp-mpfr-sys" name = "gmp-mpfr-sys"
version = "1.1.14" version = "1.1.14"
@@ -162,6 +224,23 @@ name = "indexmap"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@@ -172,7 +251,7 @@ name = "lexical"
version = "2.1.0" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -181,7 +260,7 @@ name = "lexical-core"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -192,12 +271,20 @@ name = "libc"
version = "0.2.62" version = "0.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lock_api"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.8" version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -210,14 +297,53 @@ name = "memchr"
version = "2.2.1" version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mio"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.14.1" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -227,9 +353,9 @@ name = "nix"
version = "0.15.0" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -306,6 +432,33 @@ dependencies = [
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "parking_lot"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "0.4.30" version = "0.4.30"
@@ -314,9 +467,17 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "proc-macro2"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "prolog_parser" name = "prolog_parser"
version = "0.8.40" version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -334,6 +495,14 @@ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "quote"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.3.1" version = "0.3.1"
@@ -373,14 +542,6 @@ name = "redox_syscall"
version = "0.1.51" version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.3.1" version = "0.3.1"
@@ -422,9 +583,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rustyline" name = "rustyline"
version = "5.0.3" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -441,25 +603,55 @@ name = "ryu"
version = "0.2.7" version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.118" version = "0.8.118"
dependencies = [ dependencies = [
"crossterm 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"downcast 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "downcast 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"git-version 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"prolog_parser 0.8.40 (registry+https://github.com/rust-lang/crates.io-index)", "prolog_parser 0.8.49 (registry+https://github.com/rust-lang/crates.io-index)",
"ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "signal-hook"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
"signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "signal-hook-registry"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "slab"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "0.6.13" version = "0.6.13"
@@ -468,6 +660,11 @@ dependencies = [
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "smallvec"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "stackvector" name = "stackvector"
version = "1.0.2" version = "1.0.2"
@@ -491,6 +688,16 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "syn"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.10.2" version = "0.10.2"
@@ -502,16 +709,6 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.3.0" version = "1.3.0"
@@ -527,6 +724,11 @@ name = "unicode-xid"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unicode_reader" name = "unicode_reader"
version = "1.0.0" version = "1.0.0"
@@ -554,6 +756,11 @@ name = "void"
version = "1.0.2" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.8" version = "0.3.8"
@@ -563,6 +770,11 @@ dependencies = [
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi-i686-pc-windows-gnu" name = "winapi-i686-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@@ -573,36 +785,58 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata] [metadata]
"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" "checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55"
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" "checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" "checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum crossterm 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8a3223215bc00c666d6be730e88aef245ad4a4f837e87a16c347e8acf701643"
"checksum crossterm_winapi 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "057b7146d02fb50175fd7dbe5158f6097f33d02831f43b4ee8ae4ddf67b68f5c"
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
"checksum downcast 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" "checksum downcast 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum git-version 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "94918e83f1e01dedc2e361d00ce9487b14c58c7f40bab148026fa39d42cb41e2"
"checksum git-version-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657"
"checksum gmp-mpfr-sys 1.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72592cd7513feefa5e41414825c42e839120d2f09e10c6094105d066072955fb" "checksum gmp-mpfr-sys 1.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72592cd7513feefa5e41414825c42e839120d2f09e10c6094105d066072955fb"
"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356" "checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356"
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c106ed999697325a540c43d66a8d5175668cd96d7eb0bdba03a3bd98256cd698" "checksum lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c106ed999697325a540c43d66a8d5175668cd96d7eb0bdba03a3bd98256cd698"
"checksum lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82e023e062f1d25f807ad182008fba1b46538e999f908a08cc0c29e084462e" "checksum lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82e023e062f1d25f807ad182008fba1b46538e999f908a08cc0c29e084462e"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
@@ -613,35 +847,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6" "checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6"
"checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" "checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc"
"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1"
"checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum prolog_parser 0.8.40 (registry+https://github.com/rust-lang/crates.io-index)" = "013131c03328aef02b069e6b325b01fb47597034af169b8b8a1bb8f2cfab0868" "checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
"checksum prolog_parser 0.8.49 (registry+https://github.com/rust-lang/crates.io-index)" = "82f46113e58039861f82f6b6cdaca94c0997eda2c7317a4c4f13d549c4601eec"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" "checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
"checksum ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6" "checksum ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
"checksum rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "592f3a1bba452fcfb91127354012c2b3aa580b266caef1923b16638057c038b5" "checksum rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "592f3a1bba452fcfb91127354012c2b3aa580b266caef1923b16638057c038b5"
"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4795e277e6e57dec9df62b515cd4991371daa80e8dc8d80d596e58722b89c417" "checksum rustyline 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de64be8eecbe428b6924f1d8430369a01719fbb182c26fa431ddbb0a95f5315d"
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
"checksum signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "10b9f3a1686a29f53cfd91ee5e3db3c12313ec02d33765f02c1a9645a1811e2c"
"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
"checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6" "checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6"
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum unicode_reader 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f886d405a2be65db804cb1088f969dbd99528a9eec9bcf941584b17de4cd3034" "checksum unicode_reader 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f886d405a2be65db804cb1088f969dbd99528a9eec9bcf941584b17de4cd3034"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"

View File

@@ -16,16 +16,17 @@ default = ["rug", "prolog_parser/rug"]
num = ["num-rug-adapter", "prolog_parser/num"] num = ["num-rug-adapter", "prolog_parser/num"]
[dependencies] [dependencies]
crossterm = "0.16.0"
dirs = "2.0.2" dirs = "2.0.2"
downcast = "0.10.0" downcast = "0.10.0"
git-version = "0.3.4"
indexmap = "1.0.2" indexmap = "1.0.2"
lazy_static = "1.4.0" lazy_static = "1.4.0"
libc = "0.2.62" libc = "0.2.62"
nix = "0.15.0" nix = "0.15.0"
num-rug-adapter = { optional = true, version = "0.1.1" } num-rug-adapter = { optional = true, version = "0.1.1" }
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = { version = "0.8.40", default-features = false } prolog_parser = { version = "0.8.49", default-features = false }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
rug = { version = "1.4.0", optional = true } rug = { version = "1.4.0", optional = true }
rustyline = "5.0.3" rustyline = "6.0.0"
termion = "1.4.0"

163
README.md
View File

@@ -30,7 +30,7 @@ Extend Scryer Prolog to include the following, among other features:
- [x] Built-in predicates for list processing and top-level declarative - [x] Built-in predicates for list processing and top-level declarative
control (`setup_call_cleanup/3`, `call_with_inference_limit/3`, control (`setup_call_cleanup/3`, `call_with_inference_limit/3`,
etc.) etc.)
- [x] ~~Default representation of strings as list of chars, using a packed - [x] ~~Default representation of strings as lists of characters, using a packed
internal representation.~~ internal representation.~~
- [x] `term_expansion/2` and `goal_expansion/2`. - [x] `term_expansion/2` and `goal_expansion/2`.
- [x] Definite Clause Grammars. - [x] Definite Clause Grammars.
@@ -52,11 +52,11 @@ Extend Scryer Prolog to include the following, among other features:
"Delimited Continuations for Prolog"). "Delimited Continuations for Prolog").
- [x] Tabling library based on delimited continuations - [x] Tabling library based on delimited continuations
(documented in "Tabling as a Library with Delimited Control"). (documented in "Tabling as a Library with Delimited Control").
- [x] A _redone_ representation of strings as difference list of - [x] A _redone_ representation of strings as difference lists of
chars, using a packed internal representation. characters, using a packed internal representation.
- [ ] clp(B) and clp() as builtin libraries (_in progress_). - [x] clp(B) and clp() as builtin libraries.
- [ ] Streams and predicates for stream control (_in progress_). - [ ] Streams and predicates for stream control (_in progress_).
- [ ] An incremental compacting garbage collector satisfying the five - [ ] A compacting garbage collector satisfying the five
properties of "Precise Garbage Collection in Prolog." properties of "Precise Garbage Collection in Prolog."
- [ ] Mode declarations. - [ ] Mode declarations.
@@ -92,8 +92,14 @@ strings.
First, install the latest stable version of First, install the latest stable version of
[Rust](https://www.rust-lang.org/en-US/install.html) using your [Rust](https://www.rust-lang.org/en-US/install.html) using your
preferred method. Then install Scryer Prolog with cargo, preferred method. Scryer tends to use features from newer Rust
like so: releases, whereas Rust packages in Linux distributions, Macports,
etc. tend to lag behind. [rustup](http://rustup.rs) will keep your
Rust updated to the latest stable release; any existing Rust
distribution should be uninstalled from your system before rustup is
used.
Scryer Prolog can be installed with cargo, like so:
``` ```
$> cargo install scryer-prolog $> cargo install scryer-prolog
@@ -117,11 +123,6 @@ $> cargo run [--release]
The optional `--release` flag will perform various optimizations, The optional `--release` flag will perform various optimizations,
producing a faster executable. producing a faster executable.
Note on compatibility: Scryer Prolog should work on Linux, Mac OS X,
and BSD variants on which Rust runs. Windows support hinges on
rustyline and Termion being functional in that environment, which to
my knowledge is not presently the case.
## Tutorial ## Tutorial
To enter a multi-clause predicate, the directive "[user]" is used. To enter a multi-clause predicate, the directive "[user]" is used.
@@ -155,11 +156,10 @@ Wildcards work as well:
member(X, [X|_]). member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs). member(X, [_|Xs]) :- member(X, Xs).
?- member(X, [a, b, c]). ?- member(X, [a, b, c]).
true . X = a
X = a ; ; X = b
X = b ; ; X = c
X = c ; ; false.
false.
``` ```
and so do conjunctive queries: and so do conjunctive queries:
``` ```
@@ -169,10 +169,9 @@ f(X) :- g(X).
g(x). g(y). g(z). g(x). g(y). g(z).
h(call(f, X)). h(call(f, X)).
?- h(X), X. ?- h(X), X.
true . X = call(f,x)
X = call(f, x) ; ; X = call(f,y)
X = call(f, y) ; ; X = call(f,z).
X = call(f, z).
``` ```
Note that the values of variables belonging to successful queries are Note that the values of variables belonging to successful queries are
@@ -190,46 +189,128 @@ Scryer supports dynamic operators. Using the built-in
arithmetic operators with the usual precedences, arithmetic operators with the usual precedences,
``` ```
?- write_canonical(-5 + 3 - (2 * 4) // 8). ?- write_canonical(-5 + 3 - (2 * 4) // 8), nl.
-(+(-(5), 3), //(*(2, 4), 8)) -(+(-5,3),//(*(2,4),8))
true. true.
``` ```
New operators can be defined using the `op` declaration. New operators can be defined using the `op` declaration.
### Partial strings ### Strings and partial strings
Scryer has three specialized non-ISO predicates for handling so-called In Scryer Prolog, the default value of the Prolog flag `double_quotes`
"partial strings." Partial strings imitate difference lists of is `chars`, which is also the recommended setting. This means that
characters, but their characters are packed in UTF-8 format, a much double-quoted strings are interpreted as lists of *characters*, in the
more efficient alternative to how lists of characters are represented tradition of Marseille&nbsp;Prolog.
in many other Prologs.
To use partial strings, the `non_iso` library must be loaded: For example, the following query succeeds:
`?- use_module(library(non_iso)).` ```
?- "abc" = [a,b,c].
true.
```
If `X` is a free variable, the query Internally, strings are represented very compactly in packed
UTF-8&nbsp;encoding. A naive representation of strings as lists of
characters would use one memory&nbsp;cell per character, one
memory&nbsp;cell per list constructor, and one memory&nbsp;cell for
each tail that occurs in the list. Since one memory&nbsp;cell takes
8&nbsp;bytes on 64-bit machines, the packed representation used by
Scryer&nbsp;Prolog yields an up&nbsp;to **24-fold&nbsp;reduction** of
memory usage, and corresponding reduction of memory&nbsp;accesses when
creating and processing strings.
`?- partial_string("abc", X, _), X = [a, b, c | Y], partial_string(X), Scryer Prolog uses the same efficient encoding for *partial* strings,
partial_string_tail(X, Tail), Tail == Y.` which appear to Prolog code as partial lists of characters. The
predicate `partial_string/3` from `library(iso_ext)` lets you
construct partial&nbsp;strings explicitly. For example:
will succeed, posting: ```
?- partial_string("abc", Ls0, Ls).
Ls0 = [a,b,c|Ls].
```
`Tail = Y, X = [a,b,c|Y].` In this case, and as the answer illustrates, `Ls0` is
indistinguishable from a partial&nbsp;list with tail&nbsp;`Ls`, while
the efficient packed representation is used internally.
By all appearances, partial strings are plain Prolog lists. An important design goal of Scryer Prolog is to *automatically* use
the efficient string representation whenever possible. Therefore, it
is only very rarely necessary to use `partial_string/3` explicitly. In
the above example, posting <tt>Ls0&nbsp;=&nbsp;[a,b,c|Ls]</tt> yields
the exact same internal representation, and has the advantage that
only the standard predicate&nbsp;`(=)/2` is used.
Definite clause grammars as provided by `library(dcgs)` are ideally
suited for reasoning about strings.
### Modules ### Modules
Scryer has a simple predicate-based module system. It provides a Scryer has a simple predicate-based module system. It provides a
way to separate units of code into distinct namespaces, for both way to separate units of code into distinct namespaces, for both
predicates and operators. See the files `src/prolog/lib/*.pl` for predicates and operators. See the files
[`src/prolog/lib/*.pl`](src/prolog/lib) for
examples. examples.
At the time of this writing, several control and list processing At the time of this writing, many predicates reside in their own
operators and predicates are hidden in their own modules that have not modules that need to be imported before they can be used.
been exported to the toplevel. To export them, write The modules that ship with Scryer&nbsp;Prolog are also called
*library*&nbsp;modules or *libraries*, and include:
* [`lists`](src/prolog/lib/lists.pl)
providing `length/2`, `member/2`, `select/3`, `append/[2,3]`,
`foldl/[4,5]`, `maplist/[2-9]`, `same_length/2`, `transpose/2` etc.
* [`dcgs`](src/prolog/lib/dcgs.pl)
Definite Clause Grammars (DCGs), a built-in grammar mechanism
that uses the operator `(-->)/2` to define grammar rules,
and the predicates `phrase/[2,3]` to invoke them.
* [`dif`](src/prolog/lib/dif.pl)
The predicate `dif/2` provides declarative disequality:
It is true if and only if its arguments are different, and
delays the test until a sound decision can be made.
* [`reif`](src/prolog/lib/reif.pl)
providing `if_/3`, `tfilter/3` and related predicates
as described in *Indexing&nbsp;dif/2*.
* [`clpz`](src/prolog/lib/clpz.pl)
CLP(): Constraint Logic Programming over Integers,
providing declarative integer arithmetic via `(#=)/2`, `(#\=)/2`,
`(#>=)/2` etc., and various global constraints and
enumeration predicates for solving combinatorial tasks.
* [`pairs`](src/prolog/lib/pairs.pl)
By convention, *pairs* are Prolog terms with
principal&nbsp;functor `(-)/2`, written as `Key-Value`.
This library provides `pairs_keys_values/3`,
`pairs_keys/2`, and other predicates to reason about pairs.
* [`si`](src/prolog/lib/si.pl)
The predicates `atom_si/1`, `integer_si/1`, `atomic_si/1`
and `list_si/1` implement sound type checks. They raise
instantiation errors if no decision can be made.
They are declarative replacements for logically flawed
lower-level type tests. For instance, instead of `integer(X)`,
write `integer_si(X)` to ensure soundness of your programs.
"si" stands for *sufficiently instantiated*, and also for
*sound&nbsp;inference*.
* [`error`](src/prolog/lib/error.pl)
`must_be/2` and `can_be/2` complement the type checks provided
by `library(si)`, and are especially useful for Prolog library
authors.
* [`tabling`](src/prolog/lib/tabling.pl)
The operator `(table)/1` is used in directives that prepare
predicates for tabled execution (SLG&nbsp;resolution).
* [`format`](src/prolog/lib/format.pl)
The nonterminal `format_//2` is used to describe formatted output,
arranging arguments according to a given format&nbsp;string.
The predicate `format/2` is provided for impure output.
* [`assoc`](src/prolog/lib/assoc.pl)
providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc.
to manage elements in AVL&nbsp;trees which ensure
*O*(log(*N*))&nbsp;access.
* [`clpb`](src/prolog/lib/clpb.pl)
CLP(B): Constraint Logic Programming over Boolean variables,
a BDD-based SAT&nbsp;solver provided via the predicates
`sat/1`, `taut/2`, `labeling/1` etc.
To use predicates provided by the `lists` library, write:
``` ```
?- use_module(library(lists)). ?- use_module(library(lists)).

View File

@@ -52,5 +52,9 @@ fn main()
} }
libraries.write_all(b"\n\n m\n }; libraries.write_all(b"\n\n m\n };
}").unwrap(); }\n").unwrap();
libraries.write_all(b"\npub static PROJECT_DIR: &'static str = \"").unwrap();
libraries.write_all(env::var("CARGO_MANIFEST_DIR").unwrap().as_bytes()).unwrap();
libraries.write_all(b"\";\n").unwrap();
} }

View File

@@ -1,5 +1,7 @@
extern crate crossterm;
#[macro_use] #[macro_use]
extern crate downcast; extern crate downcast;
extern crate git_version;
extern crate indexmap; extern crate indexmap;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
@@ -9,15 +11,17 @@ extern crate nix;
extern crate prolog_parser; extern crate prolog_parser;
#[macro_use] #[macro_use]
extern crate ref_thread_local; extern crate ref_thread_local;
extern crate termion;
use git_version::git_version;
use nix::sys::signal; use nix::sys::signal;
mod prolog; mod prolog;
use crate::prolog::machine::*; use crate::prolog::machine::*;
use crate::prolog::machine::streams::*;
use crate::prolog::read::*; use crate::prolog::read::*;
use std::env;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
extern fn handle_sigint(signal: libc::c_int) { extern fn handle_sigint(signal: libc::c_int) {
@@ -31,6 +35,11 @@ fn main() {
let handler = signal::SigHandler::Handler(handle_sigint); let handler = signal::SigHandler::Handler(handle_sigint);
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap(); unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
let mut wam = Machine::new(readline::input_stream()); if env::args().skip(1).any(|a| a == "-v" || a == "--version") {
println!("{:}", git_version!());
return;
}
let mut wam = Machine::new(readline::input_stream(), Stream::stdout());
wam.run_top_level(); wam.run_top_level();
} }

View File

@@ -6,6 +6,7 @@ use crate::prolog::forms::*;
use crate::prolog::instructions::*; use crate::prolog::instructions::*;
use crate::prolog::iterators::*; use crate::prolog::iterators::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
@@ -15,6 +16,7 @@ use crate::prolog::rug::{Assign, Integer, Rational};
use std::cell::Cell; use std::cell::Cell;
use std::cmp::{max, min, Ordering}; use std::cmp::{max, min, Ordering};
use std::convert::TryFrom;
use std::f64; use std::f64;
use std::num::FpCategory; use std::num::FpCategory;
use std::ops::{Add, Div, Mul, Neg, Sub}; use std::ops::{Add, Div, Mul, Neg, Sub};
@@ -262,6 +264,9 @@ impl<'a> ArithmeticEvaluator<'a> {
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> { fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> {
match c { match c {
&Constant::Fixnum(n) => self
.interm
.push(ArithmeticTerm::Number(Number::Fixnum(n))),
&Constant::Integer(ref n) => self &Constant::Integer(ref n) => self
.interm .interm
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))), .push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
@@ -316,18 +321,25 @@ impl<'a> ArithmeticEvaluator<'a> {
} }
// integer division rounding function -- 9.1.3.1. // integer division rounding function -- 9.1.3.1.
pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> { pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
match n { match n {
&Number::Integer(ref n) => RefOrOwned::Borrowed(n), &Number::Integer(_) => {
RefOrOwned::Borrowed(n)
}
&Number::Float(OrderedFloat(f)) => { &Number::Float(OrderedFloat(f)) => {
RefOrOwned::Owned(Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0))) RefOrOwned::Owned(Number::from(
Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0))
))
}
&Number::Fixnum(n) => {
RefOrOwned::Owned(Number::from(n))
} }
&Number::Rational(ref r) => { &Number::Rational(ref r) => {
let r_ref = r.fract_floor_ref(); let r_ref = r.fract_floor_ref();
let (mut fract, mut floor) = (Rational::new(), Integer::new()); let (mut fract, mut floor) = (Rational::new(), Integer::new());
(&mut fract, &mut floor).assign(r_ref); (&mut fract, &mut floor).assign(r_ref);
RefOrOwned::Owned(floor)
RefOrOwned::Owned(Number::from(floor))
} }
} }
} }
@@ -335,6 +347,7 @@ pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> {
// floating point rounding function -- 9.1.4.1. // floating point rounding function -- 9.1.4.1.
pub fn rnd_f(n: &Number) -> f64 { pub fn rnd_f(n: &Number) -> f64 {
match n { match n {
&Number::Fixnum(n) => n as f64,
&Number::Integer(ref n) => n.to_f64(), &Number::Integer(ref n) => n.to_f64(),
&Number::Float(OrderedFloat(f)) => f, &Number::Float(OrderedFloat(f)) => f,
&Number::Rational(ref r) => r.to_f64(), &Number::Rational(ref r) => r.to_f64(),
@@ -370,22 +383,32 @@ where
} }
} }
#[inline]
fn float_fn_to_f(n: isize) -> Result<f64, EvalError> {
classify_float(n as f64, rnd_f)
}
#[inline]
fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> { fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
classify_float(n.to_f64(), rnd_f) classify_float(n.to_f64(), rnd_f)
} }
#[inline]
fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> { fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
classify_float(r.to_f64(), rnd_f) classify_float(r.to_f64(), rnd_f)
} }
#[inline]
fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> { fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?)) Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
} }
#[inline]
fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> { fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?)) Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
} }
#[inline]
fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> { fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
if FpCategory::Zero == f2.classify() { if FpCategory::Zero == f2.classify() {
Err(EvalError::ZeroDivisor) Err(EvalError::ZeroDivisor)
@@ -399,14 +422,35 @@ impl Add<Number> for Number {
fn add(self, rhs: Number) -> Self::Output { fn add(self, rhs: Number) -> Self::Output {
match (self, rhs) { match (self, rhs) {
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 + n2)), // add_i (Number::Fixnum(n1), Number::Fixnum(n2)) => {
Ok(if let Some(result) = n1.checked_add(n2) {
Number::Fixnum(result)
} else {
Number::from(Integer::from(n1) + Integer::from(n2))
})
}
(Number::Fixnum(n1), Number::Integer(n2)) |
(Number::Integer(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Integer::from(n1) + &*n2))
}
(Number::Fixnum(n1), Number::Rational(n2)) |
(Number::Rational(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Rational::from(n1) + &*n2))
}
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) (Number::Integer(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?)) Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
} }
(Number::Integer(n1), Number::Rational(n2)) (Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => { | (Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::Rational(Rational::from(n1) + n2)) Ok(Number::from(Rational::from(&*n1) + &*n2))
} }
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) (Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
@@ -415,7 +459,9 @@ impl Add<Number> for Number {
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
Ok(Number::Float(add_f(f1, f2)?)) Ok(Number::Float(add_f(f1, f2)?))
} }
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 + r2)), (Number::Rational(r1), Number::Rational(r2)) => {
Ok(Number::from(Rational::from(&*r1) + &*r2))
}
} }
} }
} }
@@ -425,9 +471,10 @@ impl Neg for Number {
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
match self { match self {
Number::Integer(n) => Number::Integer(-n), Number::Fixnum(n) => Number::Fixnum(-n),
Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
Number::Rational(r) => Number::Rational(-r), Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
} }
} }
} }
@@ -445,14 +492,35 @@ impl Mul<Number> for Number {
fn mul(self, rhs: Number) -> Self::Output { fn mul(self, rhs: Number) -> Self::Output {
match (self, rhs) { match (self, rhs) {
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 * n2)), // mul_i (Number::Fixnum(n1), Number::Fixnum(n2)) => {
Ok(if let Some(result) = n1.checked_mul(n2) {
Number::Fixnum(result)
} else {
Number::from(Integer::from(n1) * Integer::from(n2))
})
}
(Number::Fixnum(n1), Number::Integer(n2)) |
(Number::Integer(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Integer::from(n1) * &*n2))
}
(Number::Fixnum(n1), Number::Rational(n2)) |
(Number::Rational(n2), Number::Fixnum(n1)) => {
Ok(Number::from(Rational::from(n1) * &*n2))
}
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) (Number::Integer(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?)) Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?))
} }
(Number::Integer(n1), Number::Rational(n2)) (Number::Integer(n1), Number::Rational(n2))
| (Number::Rational(n2), Number::Integer(n1)) => { | (Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::Rational(Rational::from(n1) * n2)) Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2)))
} }
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) (Number::Rational(n1), Number::Float(OrderedFloat(n2)))
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
@@ -461,7 +529,9 @@ impl Mul<Number> for Number {
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
Ok(Number::Float(mul_f(f1, f2)?)) Ok(Number::Float(mul_f(f1, f2)?))
} }
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 * r2)), (Number::Rational(r1), Number::Rational(r2)) => {
Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2)))
}
} }
} }
} }
@@ -471,24 +541,72 @@ impl Div<Number> for Number {
fn div(self, rhs: Number) -> Self::Output { fn div(self, rhs: Number) -> Self::Output {
match (self, rhs) { match (self, rhs) {
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f( (Number::Fixnum(n1), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_fn_to_f(n2)?,
)?))
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_i_to_f(&n2)?,
)?))
}
(Number::Integer(n1), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
float_fn_to_f(n2)?,
)?))
}
(Number::Fixnum(n1), Number::Rational(n2)) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
float_r_to_f(&n2)?,
)?))
}
(Number::Rational(n1), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
float_r_to_f(&n1)?,
float_fn_to_f(n2)?,
)?))
}
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(
float_fn_to_f(n1)?,
n2,
)?))
}
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
Ok(Number::Float(div_f(
n1,
float_fn_to_f(n2)?,
)?))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::Float(div_f(
float_i_to_f(&n1)?, float_i_to_f(&n1)?,
float_i_to_f(&n2)?, float_i_to_f(&n2)?,
)?)), )?))
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => { (Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?)) Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
} }
(Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?)) Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?))
} }
(Number::Integer(n1), Number::Rational(n2)) => Ok(Number::Float(div_f( (Number::Integer(n1), Number::Rational(n2)) => {
Ok(Number::Float(div_f(
float_i_to_f(&n1)?, float_i_to_f(&n1)?,
float_r_to_f(&n2)?, float_r_to_f(&n2)?,
)?)), )?))
(Number::Rational(n2), Number::Integer(n1)) => Ok(Number::Float(div_f( }
(Number::Rational(n2), Number::Integer(n1)) => {
Ok(Number::Float(div_f(
float_r_to_f(&n2)?, float_r_to_f(&n2)?,
float_i_to_f(&n1)?, float_i_to_f(&n1)?,
)?)), )?))
}
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) => { (Number::Rational(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?)) Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?))
} }
@@ -506,25 +624,47 @@ impl Div<Number> for Number {
} }
} }
impl PartialEq for Number {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2),
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2),
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
(&Number::Fixnum(_), &Number::Float(OrderedFloat(_))) => false,
(&Number::Float(OrderedFloat(_)), &Number::Fixnum(_)) => false,
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2),
(&Number::Integer(_), Number::Float(_)) => false,
(&Number::Float(_), &Number::Integer(_)) => false,
(&Number::Integer(_), &Number::Rational(_)) => false,
(&Number::Rational(_), &Number::Integer(_)) => false,
(&Number::Rational(_), Number::Float(_)) => false,
(&Number::Float(_), &Number::Rational(_)) => false,
(&Number::Float(f1), &Number::Float(f2)) => f1.eq(&f2),
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.eq(&r2),
}
}
}
impl Eq for Number {}
impl PartialOrd for Number { impl PartialOrd for Number {
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> { fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
match (self, rhs) { Some(self.cmp(rhs))
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => Some(n1.cmp(n2)),
(&Number::Integer(_), Number::Float(_)) => Some(Ordering::Greater),
(&Number::Float(_), &Number::Integer(_)) => Some(Ordering::Less),
(&Number::Integer(_), &Number::Rational(_)) => Some(Ordering::Greater),
(&Number::Rational(_), &Number::Integer(_)) => Some(Ordering::Less),
(&Number::Rational(_), Number::Float(_)) => Some(Ordering::Greater),
(&Number::Float(_), &Number::Rational(_)) => Some(Ordering::Less),
(&Number::Float(f1), &Number::Float(f2)) => Some(f1.cmp(&f2)),
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => Some(r1.cmp(&r2)),
}
} }
} }
impl Ord for Number { impl Ord for Number {
fn cmp(&self, rhs: &Number) -> Ordering { fn cmp(&self, rhs: &Number) -> Ordering {
match (self, rhs) { match (self, rhs) {
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2),
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2),
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)),
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2),
(Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)),
(&Number::Fixnum(_), &Number::Float(OrderedFloat(_))) => Ordering::Greater,
(&Number::Float(OrderedFloat(_)), &Number::Fixnum(_)) => Ordering::Less,
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2), (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
(&Number::Integer(_), Number::Float(_)) => Ordering::Greater, (&Number::Integer(_), Number::Float(_)) => Ordering::Greater,
(&Number::Float(_), &Number::Integer(_)) => Ordering::Less, (&Number::Float(_), &Number::Integer(_)) => Ordering::Less,
@@ -538,9 +678,81 @@ impl Ord for Number {
} }
} }
impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
type Error = ();
fn try_from((addr, heap): (Addr, &'a Heap)) -> Result<Number, Self::Error> {
match addr {
Addr::CharCode(c) => {
Ok(Number::from(c as isize))
}
Addr::Fixnum(n) => {
Ok(Number::from(n))
}
Addr::Float(n) => {
Ok(Number::Float(n))
}
Addr::Usize(n) => {
if let Ok(n) = isize::try_from(n) {
Ok(Number::from(n))
} else {
Ok(Number::from(Integer::from(n)))
}
}
Addr::Con(h) => {
Number::try_from(&heap[h])
}
_ => {
Err(())
}
}
}
}
impl<'a> TryFrom<&'a HeapCellValue> for Number {
type Error = ();
fn try_from(value: &'a HeapCellValue) -> Result<Number, Self::Error> {
match value {
HeapCellValue::Addr(addr) => {
match addr {
&Addr::CharCode(c) => {
Ok(Number::from(c as isize))
}
&Addr::Fixnum(n) => {
Ok(Number::from(n))
}
&Addr::Float(n) => {
Ok(Number::Float(n))
}
&Addr::Usize(n) => {
if let Ok(n) = isize::try_from(n) {
Ok(Number::from(n))
} else {
Ok(Number::from(Integer::from(n)))
}
}
_ => {
Err(())
}
}
}
HeapCellValue::Integer(n) => {
Ok(Number::Integer(n.clone()))
}
HeapCellValue::Rational(n) => {
Ok(Number::Rational(n.clone()))
}
_ => {
Err(())
}
}
}
}
// Computes n ^ power. Ignores the sign of power. // Computes n ^ power. Ignores the sign of power.
pub fn binary_pow(mut n: Integer, power: Integer) -> Integer { pub fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
let mut power = power.abs(); let mut power = Integer::from(power.abs_ref());
if power == 0 { if power == 0 {
return Integer::from(1); return Integer::from(1);

View File

@@ -75,7 +75,6 @@ pub enum InlinedClauseType {
IsCompound(RegType), IsCompound(RegType),
IsInteger(RegType), IsInteger(RegType),
IsRational(RegType), IsRational(RegType),
IsString(RegType),
IsFloat(RegType), IsFloat(RegType),
IsNonVar(RegType), IsNonVar(RegType),
IsVar(RegType), IsVar(RegType),
@@ -105,7 +104,6 @@ ref_thread_local! {
m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1))); m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1)));
m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1))); m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1)));
m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1))); m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1)));
m.insert(("string", 1), ClauseType::Inlined(InlinedClauseType::IsString(r1)));
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1))); m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1))); m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1))); m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
@@ -117,7 +115,6 @@ ref_thread_local! {
m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual))); m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)));
m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual))); m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)));
m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)); m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm));
m.insert(("cyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::CyclicTerm));
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq)); m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor)); m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor));
m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground)); m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground));
@@ -141,7 +138,6 @@ impl InlinedClauseType {
&InlinedClauseType::IsCompound(..) => "compound", &InlinedClauseType::IsCompound(..) => "compound",
&InlinedClauseType::IsInteger(..) => "integer", &InlinedClauseType::IsInteger(..) => "integer",
&InlinedClauseType::IsRational(..) => "rational", &InlinedClauseType::IsRational(..) => "rational",
&InlinedClauseType::IsString(..) => "string",
&InlinedClauseType::IsFloat(..) => "float", &InlinedClauseType::IsFloat(..) => "float",
&InlinedClauseType::IsNonVar(..) => "nonvar", &InlinedClauseType::IsNonVar(..) => "nonvar",
&InlinedClauseType::IsVar(..) => "var", &InlinedClauseType::IsVar(..) => "var",
@@ -160,11 +156,9 @@ pub enum SystemClauseType {
AtomCodes, AtomCodes,
AtomLength, AtomLength,
BindFromRegister, BindFromRegister,
CallAttributeGoals,
CallContinuation, CallContinuation,
CharCode, CharCode,
CharsToNumber, CharsToNumber,
ClearAttrVarBindings,
ClearAttributeGoals, ClearAttributeGoals,
CloneAttributeGoals, CloneAttributeGoals,
CodesToNumber, CodesToNumber,
@@ -172,6 +166,8 @@ pub enum SystemClauseType {
CheckCutPoint, CheckCutPoint,
CopyToLiftedHeap, CopyToLiftedHeap,
CreatePartialString, CreatePartialString,
CurrentInput,
CurrentOutput,
DeleteAttribute, DeleteAttribute,
DeleteHeadAttribute, DeleteHeadAttribute,
DynamicModuleResolution(usize), DynamicModuleResolution(usize),
@@ -179,7 +175,6 @@ pub enum SystemClauseType {
EnqueueAttributedVar, EnqueueAttributedVar,
ExpandGoal, ExpandGoal,
ExpandTerm, ExpandTerm,
FetchAttributeGoals,
FetchGlobalVar, FetchGlobalVar,
FetchGlobalVarWithOffset, FetchGlobalVarWithOffset,
GetChar, GetChar,
@@ -231,6 +226,8 @@ pub enum SystemClauseType {
RetractClause, RetractClause,
RestoreCutPolicy, RestoreCutPolicy,
SetCutPoint(RegType), SetCutPoint(RegType),
SetInput,
SetOutput,
StoreGlobalVar, StoreGlobalVar,
StoreGlobalVarWithOffset, StoreGlobalVarWithOffset,
InferenceLevel, InferenceLevel,
@@ -243,7 +240,9 @@ pub enum SystemClauseType {
GetDoubleQuotes, GetDoubleQuotes,
InstallNewBlock, InstallNewBlock,
Maybe, Maybe,
QuotedToken,
RawInputReadChar, RawInputReadChar,
ReadTermFromChars,
ResetBlock, ResetBlock,
ReturnFromVerifyAttr, ReturnFromVerifyAttr,
SetBall, SetBall,
@@ -260,6 +259,7 @@ pub enum SystemClauseType {
Variant, Variant,
WAMInstructions, WAMInstructions,
WriteTerm, WriteTerm,
WriteTermToChars,
} }
impl SystemClauseType { impl SystemClauseType {
@@ -274,7 +274,6 @@ impl SystemClauseType {
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"), &SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
&SystemClauseType::AtomLength => clause_name!("$atom_length"), &SystemClauseType::AtomLength => clause_name!("$atom_length"),
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"), &SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"), &SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
&SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharCode => clause_name!("$char_code"),
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
@@ -284,6 +283,8 @@ impl SystemClauseType {
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
&SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"), &SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"),
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"), &SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
&SystemClauseType::CurrentInput => clause_name!("$current_input"),
&SystemClauseType::CurrentOutput => clause_name!("$current_output"),
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => { &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
@@ -295,7 +296,6 @@ impl SystemClauseType {
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => { &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
clause_name!("$use_qualified_module_from_file") clause_name!("$use_qualified_module_from_file")
} }
&SystemClauseType::ClearAttrVarBindings => clause_name!("$clear_attr_var_bindings"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"), &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
@@ -304,7 +304,6 @@ impl SystemClauseType {
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"), &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"), &SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"), &SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
&SystemClauseType::FetchAttributeGoals => clause_name!("$fetch_attribute_goals"),
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"), &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
&SystemClauseType::FetchGlobalVarWithOffset => { &SystemClauseType::FetchGlobalVarWithOffset => {
clause_name!("$fetch_global_var_with_offset") clause_name!("$fetch_global_var_with_offset")
@@ -362,12 +361,17 @@ impl SystemClauseType {
&SystemClauseType::PointsToContinuationResetMarker => { &SystemClauseType::PointsToContinuationResetMarker => {
clause_name!("$points_to_cont_reset_marker") clause_name!("$points_to_cont_reset_marker")
} }
&SystemClauseType::QuotedToken => {
clause_name!("$quoted_token")
}
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"), &SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"), &SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"), &SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"), &SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
&SystemClauseType::SetInput => clause_name!("$set_input"),
&SystemClauseType::SetOutput => clause_name!("$set_output"),
&SystemClauseType::SetSeed => clause_name!("$set_seed"), &SystemClauseType::SetSeed => clause_name!("$set_seed"),
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"), &SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
&SystemClauseType::StoreGlobalVarWithOffset => { &SystemClauseType::StoreGlobalVarWithOffset => {
@@ -385,6 +389,7 @@ impl SystemClauseType {
&SystemClauseType::NextEP => clause_name!("$nextEP"), &SystemClauseType::NextEP => clause_name!("$nextEP"),
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"), &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
&SystemClauseType::ReadTerm => clause_name!("$read_term"), &SystemClauseType::ReadTerm => clause_name!("$read_term"),
&SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"), &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"), &SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
&SystemClauseType::RetractClause => clause_name!("$retract_clause"), &SystemClauseType::RetractClause => clause_name!("$retract_clause"),
@@ -404,6 +409,7 @@ impl SystemClauseType {
&SystemClauseType::Variant => clause_name!("$variant"), &SystemClauseType::Variant => clause_name!("$variant"),
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"), &SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
&SystemClauseType::WriteTerm => clause_name!("$write_term"), &SystemClauseType::WriteTerm => clause_name!("$write_term"),
&SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"),
} }
} }
@@ -420,11 +426,9 @@ impl SystemClauseType {
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack), ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront), ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack), ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation), ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
("$char_code", 2) => Some(SystemClauseType::CharCode), ("$char_code", 2) => Some(SystemClauseType::CharCode),
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings),
("$clear_attribute_goals", 0) => Some(SystemClauseType::ClearAttributeGoals), ("$clear_attribute_goals", 0) => Some(SystemClauseType::ClearAttributeGoals),
("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals), ("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals),
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
@@ -433,6 +437,8 @@ impl SystemClauseType {
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute), ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef), ("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
@@ -446,7 +452,6 @@ impl SystemClauseType {
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString), ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
("$get_char", 1) => Some(SystemClauseType::GetChar), ("$get_char", 1) => Some(SystemClauseType::GetChar),
@@ -487,6 +492,8 @@ impl SystemClauseType {
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter), ("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy), ("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))), ("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
("$set_input", 1) => Some(SystemClauseType::SetInput),
("$set_output", 1) => Some(SystemClauseType::SetOutput),
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel), ("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock), ("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
("$erase_ball", 0) => Some(SystemClauseType::EraseBall), ("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
@@ -498,10 +505,12 @@ impl SystemClauseType {
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock), ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
("$quoted_token", 1) => Some(SystemClauseType::QuotedToken),
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar), ("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
("$nextEP", 3) => Some(SystemClauseType::NextEP), ("$nextEP", 3) => Some(SystemClauseType::NextEP),
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm), ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
("$read_term", 2) => Some(SystemClauseType::ReadTerm), ("$read_term", 2) => Some(SystemClauseType::ReadTerm),
("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker), ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey), ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
@@ -528,8 +537,9 @@ impl SystemClauseType {
("$use_qualified_module_from_file", 2) => ("$use_qualified_module_from_file", 2) =>
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)), Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
("$variant", 2) => Some(SystemClauseType::Variant), ("$variant", 2) => Some(SystemClauseType::Variant),
("$write_term", 5) => Some(SystemClauseType::WriteTerm),
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions), ("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
("$write_term", 6) => Some(SystemClauseType::WriteTerm),
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
_ => None, _ => None,
} }
} }
@@ -541,7 +551,6 @@ pub enum BuiltInClauseType {
Arg, Arg,
Compare, Compare,
CompareTerm(CompareTermQT), CompareTerm(CompareTermQT),
CyclicTerm,
CopyTerm, CopyTerm,
Eq, Eq,
Functor, Functor,
@@ -572,7 +581,6 @@ impl BuiltInClauseType {
&BuiltInClauseType::Arg => clause_name!("arg"), &BuiltInClauseType::Arg => clause_name!("arg"),
&BuiltInClauseType::Compare => clause_name!("compare"), &BuiltInClauseType::Compare => clause_name!("compare"),
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()), &BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
&BuiltInClauseType::CyclicTerm => clause_name!("cyclic_term"),
&BuiltInClauseType::CopyTerm => clause_name!("copy_term"), &BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
&BuiltInClauseType::Eq => clause_name!("=="), &BuiltInClauseType::Eq => clause_name!("=="),
&BuiltInClauseType::Functor => clause_name!("functor"), &BuiltInClauseType::Functor => clause_name!("functor"),
@@ -592,7 +600,6 @@ impl BuiltInClauseType {
&BuiltInClauseType::Arg => 3, &BuiltInClauseType::Arg => 3,
&BuiltInClauseType::Compare => 2, &BuiltInClauseType::Compare => 2,
&BuiltInClauseType::CompareTerm(_) => 2, &BuiltInClauseType::CompareTerm(_) => 2,
&BuiltInClauseType::CyclicTerm => 1,
&BuiltInClauseType::CopyTerm => 2, &BuiltInClauseType::CopyTerm => 2,
&BuiltInClauseType::Eq => 2, &BuiltInClauseType::Eq => 2,
&BuiltInClauseType::Functor => 3, &BuiltInClauseType::Functor => 3,

View File

@@ -11,7 +11,7 @@ use crate::prolog::iterators::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::targets::*; use crate::prolog::targets::*;
use indexmap::IndexMap; use indexmap::{IndexMap, IndexSet};
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
@@ -50,56 +50,45 @@ impl<'a> ConjunctInfo<'a> {
self.has_deep_cut as usize self.has_deep_cut as usize
} }
fn mark_unsafe_vars<Alloc: Allocator<'a>>( fn mark_unsafe_vars(
&self, &self,
mut unsafe_var_marker: UnsafeVarMarker, mut unsafe_var_marker: UnsafeVarMarker,
marker: &Alloc, code: &mut Code,
code: &mut Code
) { ) {
// target the last goal of the rule for handling unsafe variables. if code.is_empty() {
// we use this weird logic to find the last goal.
let right_index = if let Some(Line::Control(_)) = code.last() {
if code.len() >= 2 {
code.len() - 2
} else {
return; return;
} }
} else {
if code.len() >= 1 { let mut code_index = 0;
code.len() - 1
} else { for phase in 0 .. {
return; while let Line::Query(ref query_instr) = &code[code_index] {
if !unsafe_var_marker.mark_safe_vars(query_instr) {
unsafe_var_marker.mark_phase(query_instr, phase);
} }
};
let mut index = right_index; code_index += 1;
}
if let Line::Query(_) = &code[right_index] { if code_index + 1 < code.len() {
while let Line::Query(_) = &code[index] { code_index += 1;
if index == 0 { } else {
break; break;
}
}
code_index = 0;
for phase in 0 .. {
while let Line::Query(ref mut query_instr) = &mut code[code_index] {
unsafe_var_marker.mark_unsafe_vars(query_instr, phase);
code_index += 1;
}
if code_index + 1 < code.len() {
code_index += 1;
} else { } else {
index -= 1; break;
}
}
if let Line::Query(_) = &code[index] {
} else {
index += 1;
}
unsafe_var_marker.record_unsafe_vars(&self.perm_vs, marker);
for line in code.iter() {
if let Line::Query(ref query_instr) = line {
unsafe_var_marker.mark_safe_vars(query_instr);
}
}
for index in index..right_index + 1 {
if let &mut Line::Query(ref mut query_instr) = &mut code[index] {
unsafe_var_marker.mark_unsafe_vars(query_instr);
}
} }
} }
} }
@@ -174,35 +163,44 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
target.push(Target::to_void(1)); target.push(Target::to_void(1));
} }
fn subterm_to_instr<Target>( fn deep_var_instr<Target: CompilationTarget<'a>>(
&mut self,
cell: &'a Cell<VarReg>,
var: &'a Rc<Var>,
term_loc: GenContext,
is_exposed: bool,
target: &mut Vec<Target>,
) {
if is_exposed || self.get_var_count(var.as_ref()) > 1 {
self.marker.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
} else {
Self::add_or_increment_void_instr(target);
}
}
fn subterm_to_instr<Target: CompilationTarget<'a>>(
&mut self, &mut self,
subterm: &'a Term, subterm: &'a Term,
term_loc: GenContext, term_loc: GenContext,
is_exposed: bool, is_exposed: bool,
target: &mut Vec<Target>, target: &mut Vec<Target>,
) where ) {
Target: CompilationTarget<'a>,
{
match subterm { match subterm {
&Term::AnonVar if is_exposed => { &Term::AnonVar if is_exposed => {
self.marker.mark_anon_var(Level::Deep, term_loc, target) self.marker.mark_anon_var(Level::Deep, term_loc, target);
}
&Term::AnonVar => {
Self::add_or_increment_void_instr(target);
} }
&Term::AnonVar => Self::add_or_increment_void_instr(target),
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => { &Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
self.marker self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
.mark_non_var(Level::Deep, term_loc, cell, target);
target.push(Target::clause_arg_to_instr(cell.get())); target.push(Target::clause_arg_to_instr(cell.get()));
} }
&Term::Constant(_, ref constant) => { &Term::Constant(_, ref constant) => {
target.push(Target::constant_subterm(constant.clone())) target.push(Target::constant_subterm(constant.clone()));
} }
&Term::Var(ref cell, ref var) => { &Term::Var(ref cell, ref var) => {
if is_exposed || self.get_var_count(var) > 1 { self.deep_var_instr(cell, var, term_loc, is_exposed, target);
self.marker
.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
} else {
Self::add_or_increment_void_instr(target);
}
} }
}; };
} }
@@ -221,6 +219,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
for term in iter { for term in iter {
match term { match term {
TermRef::AnonVar(lvl @ Level::Shallow) => {
if let GenContext::Head = term_loc {
self.marker.advance_arg();
} else {
self.marker.mark_anon_var(lvl, term_loc, &mut target);
}
}
TermRef::Clause(lvl, cell, ct, terms) => { TermRef::Clause(lvl, cell, ct, terms) => {
self.marker.mark_non_var(lvl, term_loc, cell, &mut target); self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
target.push(Target::to_structure(ct, terms.len(), cell.get())); target.push(Target::to_structure(ct, terms.len(), cell.get()));
@@ -236,15 +241,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
self.subterm_to_instr(head, term_loc, is_exposed, &mut target); self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target); self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
} }
TermRef::Constant(lvl @ Level::Shallow, cell, Constant::String(ref string)) => {
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
target.push(Target::to_pstr(lvl, string.to_string(), cell.get(), false));
}
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => { TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
self.marker.mark_non_var(lvl, term_loc, cell, &mut target); self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
target.push(Target::to_constant(lvl, constant.clone(), cell.get())); target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
} }
TermRef::AnonVar(lvl @ Level::Shallow) => { TermRef::PartialString(lvl, cell, string, tail) => {
if let GenContext::Head = term_loc { self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
self.marker.advance_arg();
if let Some(tail) = tail {
target.push(Target::to_pstr(lvl, string, cell.get(), true));
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
} else { } else {
self.marker.mark_anon_var(lvl, term_loc, &mut target); target.push(Target::to_pstr(lvl, string, cell.get(), false));
} }
} }
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => { TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
@@ -263,14 +275,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
} }
} }
self.marker self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
} }
TermRef::Var(lvl @ Level::Shallow, cell, var) => { TermRef::Var(lvl @ Level::Shallow, cell, var) => {
self.marker self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
.mark_var(var.clone(), lvl, cell, term_loc, &mut target) }
_ => {
} }
_ => {}
}; };
} }
@@ -432,18 +443,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(fail!()); code.push(fail!());
} }
}, },
&InlinedClauseType::IsString(..) => match terms[0].as_ref() {
&Term::Constant(_, Constant::String(..)) => {
code.push(succeed!());
}
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_string!(r));
}
_ => {
code.push(fail!());
}
},
&InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() { &InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() {
&Term::AnonVar => { &Term::AnonVar => {
code.push(fail!()); code.push(fail!());
@@ -457,7 +456,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
} }
}, },
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() { &InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
&Term::Constant(_, Constant::Integer(_)) => { &Term::Constant(_, Constant::Integer(_)) |
&Term::Constant(_, Constant::Fixnum(_)) => {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
@@ -522,7 +522,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))) code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
} }
} }
&Term::Constant(_, ref c @ Constant::Integer(_)) => { &Term::Constant(_, ref c @ Constant::Integer(_)) |
&Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
code.push(Line::Query(put_constant!( code.push(Line::Query(put_constant!(
Level::Shallow, Level::Shallow,
c.clone(), c.clone(),
@@ -684,6 +685,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
head: (_, ref args, ref p1), head: (_, ref args, ref p1),
ref clauses, ref clauses,
} = rule; } = rule;
let mut code = Vec::new(); let mut code = Vec::new();
self.marker.reset_at_head(args); self.marker.reset_at_head(args);
@@ -705,39 +707,31 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let iter = ChunkedIterator::from_rule_body(p1, clauses); let iter = ChunkedIterator::from_rule_body(p1, clauses);
self.compile_seq(iter, &conjunct_info, &mut code, false)?; self.compile_seq(iter, &conjunct_info, &mut code, false)?;
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &self.marker, &mut code); conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1)); Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
Ok(code) Ok(code)
} }
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker { fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
let mut unsafe_vars = IndexMap::new(); let mut safe_vars = IndexSet::new();
for var_status in self.marker.bindings().values() {
unsafe_vars.insert(var_status.as_reg_type(), false);
}
for fact_instr in fact.iter_mut() { for fact_instr in fact.iter_mut() {
match fact_instr { match fact_instr {
&mut FactInstruction::UnifyValue(reg) => { &mut FactInstruction::UnifyValue(r) => {
if let Some(found) = unsafe_vars.get_mut(&reg) { if !safe_vars.contains(&r) {
if !*found { *fact_instr = FactInstruction::UnifyLocalValue(r);
*found = true; safe_vars.insert(r);
*fact_instr = FactInstruction::UnifyLocalValue(reg);
} }
} }
} &mut FactInstruction::UnifyVariable(r) => {
&mut FactInstruction::UnifyVariable(reg) => { safe_vars.insert(r);
if let Some(found) = unsafe_vars.get_mut(&reg) {
*found = true;
}
} }
_ => {} _ => {}
}; }
} }
UnsafeVarMarker { unsafe_vars } UnsafeVarMarker::from_safe_vars(safe_vars)
} }
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code { pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
@@ -802,7 +796,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let iter = ChunkedIterator::from_term_sequence(query); let iter = ChunkedIterator::from_term_sequence(query);
self.compile_seq(iter, &conjunct_info, &mut code, true)?; self.compile_seq(iter, &conjunct_info, &mut code, true)?;
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &self.marker, &mut code); conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code);
if let Some(query_term) = query.last() { if let Some(query_term) = query.last() {
Self::compile_cleanup(&mut code, &conjunct_info, query_term); Self::compile_cleanup(&mut code, &conjunct_info, query_term);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
/* least_time.pl
*
* By Mark Thom, 2020
*
* find_min_time/2 solves a problem sometimes posed in the first round
* of Google interviews: given a time of day in 24 H format, what is the
* lexicographically least permutation of the time that is itself a
* valid time in 24 H format?
*
* Full generality is achieved using the reif library.
*/
:- module(least_time, [find_min_time/2,
write_time_nl/1]).
:- use_module(library(dcgs)).
:- use_module(library(format)).
:- use_module(library(reif)).
permutation([], []).
permutation([X|Xs], Ys) :-
permutation(Xs, Yss),
select(X, Ys, Yss).
valid_time([H1,H2,M1,M2], T) :-
memberd_t(H1, [0,1,2], TH1),
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
memberd_t(M1, [0,1,2,3,4,5], TM1),
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
( H1 =:= 2 ->
( H2 =< 3 ->
T = true
; T = false
)
; T = true
)
; T = false
).
permuted_times(Time, PermutedTimes) :-
setof(P, permutation(Time, P), PermutedTimes0),
tfilter(valid_time, PermutedTimes0, PermutedTimes).
find_min_time(Time, Min) :-
valid_time(Time, true),
permuted_times(Time, PermutedTimes),
find_min_time_(PermutedTimes, Time, Min).
find_min_time_([], Min, Min).
find_min_time_([Time|Times], MinSoFar, Min) :-
( Time @< MinSoFar ->
find_min_time_(Times, Time, Min)
; find_min_time_(Times, MinSoFar, Min)
).
write_time_nl(Time) :-
format("\"~w~w:~w~w\"~n", Time).

View File

@@ -1,6 +1,5 @@
use prolog_parser::ast::*; use prolog_parser::ast::*;
use crate::prolog::allocator::*;
use crate::prolog::forms::*; use crate::prolog::forms::*;
use crate::prolog::instructions::*; use crate::prolog::instructions::*;
use crate::prolog::iterators::*; use crate::prolog::iterators::*;
@@ -250,67 +249,67 @@ impl<'a> VariableFixtures<'a> {
} }
pub struct UnsafeVarMarker { pub struct UnsafeVarMarker {
pub unsafe_vars: IndexMap<RegType, bool>, pub unsafe_vars: IndexMap<RegType, usize>,
pub safe_vars: IndexSet<RegType>,
} }
impl UnsafeVarMarker { impl UnsafeVarMarker {
pub fn new() -> Self { pub fn new() -> Self {
UnsafeVarMarker { UnsafeVarMarker {
unsafe_vars: IndexMap::new(), unsafe_vars: IndexMap::new(),
safe_vars: IndexSet::new()
} }
} }
pub fn record_unsafe_vars<'a, Alloc: Allocator<'a>>( pub fn from_safe_vars(safe_vars: IndexSet<RegType>) -> Self {
&mut self, UnsafeVarMarker {
fixtures: &VariableFixtures, unsafe_vars: IndexMap::new(),
marker: &Alloc safe_vars
) {
for &(_, ref cb) in fixtures.values() {
if let Some(index) = cb.first() {
if !self.unsafe_vars.contains_key(&index.get().norm()) {
self.unsafe_vars.insert(index.get().norm(), false);
}
}
}
for var in fixtures.last_chunk_temp_vars.iter().cloned() {
let r = marker.get(var);
self.unsafe_vars.insert(r, false);
} }
} }
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) { pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
match query_instr { match query_instr {
QueryInstruction::PutVariable(RegType::Temp(r), _) => { &QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(*r)) { | &QueryInstruction::SetVariable(r) => {
*found = true; self.safe_vars.insert(r);
true
}
_ => {
false
} }
} }
QueryInstruction::SetVariable(reg) => {
if let Some(found) = self.unsafe_vars.get_mut(reg) {
*found = true;
} }
pub fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
match query_instr {
&QueryInstruction::PutValue(r @ RegType::Perm(_), _)
| &QueryInstruction::SetValue(r) => {
let p = self.unsafe_vars.entry(r).or_insert(0);
*p = phase;
} }
_ => {} _ => {}
} }
} }
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction) { pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
match query_instr { match query_instr {
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => { &mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) { if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
if !*found { if p == phase {
*found = true;
*query_instr = QueryInstruction::PutUnsafeValue(i, arg); *query_instr = QueryInstruction::PutUnsafeValue(i, arg);
self.safe_vars.insert(RegType::Perm(i));
} else {
self.unsafe_vars.insert(RegType::Perm(i), p);
} }
} }
} }
&mut QueryInstruction::SetValue(reg) => { &mut QueryInstruction::SetValue(r) => {
if let Some(found) = self.unsafe_vars.get_mut(&reg) { if !self.safe_vars.contains(&r) {
if !*found { *query_instr = QueryInstruction::SetLocalValue(r);
*found = true;
*query_instr = QueryInstruction::SetLocalValue(reg); self.safe_vars.insert(r);
} self.unsafe_vars.remove(&r);
} }
} }
_ => {} _ => {}

View File

@@ -12,6 +12,7 @@ use indexmap::IndexMap;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryFrom;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
@@ -376,6 +377,19 @@ pub enum ModuleSource {
File(ClauseName), File(ClauseName),
} }
impl ModuleSource {
pub fn as_functor_stub(&self) -> MachineStub {
match self {
ModuleSource::Library(ref name) => {
functor!("library", [clause_name(name.clone())])
}
ModuleSource::File(ref name) => {
functor!(clause_name(name.clone()))
}
}
}
}
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator. pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
#[derive(Clone)] #[derive(Clone)]
@@ -394,6 +408,7 @@ pub enum Declaration {
MultiFile(MultiFileIndicator), MultiFile(MultiFileIndicator),
NonCountedBacktracking(ClauseName, usize), // name, arity NonCountedBacktracking(ClauseName, usize), // name, arity
Op(OpDecl), Op(OpDecl),
SetPrologFlag(DoubleQuotes),
UseModule(ModuleSource), UseModule(ModuleSource),
UseQualifiedModule(ModuleSource, Vec<ModuleExport>), UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
} }
@@ -572,11 +587,33 @@ pub struct Module {
pub listing_src: ListingSource, pub listing_src: ListingSource,
} }
#[derive(Clone, PartialEq, Eq)] #[derive(Clone)]
pub enum Number { pub enum Number {
Float(OrderedFloat<f64>), Float(OrderedFloat<f64>),
Integer(Integer), Integer(Rc<Integer>),
Rational(Rational), Rational(Rc<Rational>),
Fixnum(isize),
}
impl From<Integer> for Number {
#[inline]
fn from(n: Integer) -> Self {
Number::Integer(Rc::new(n))
}
}
impl From<Rational> for Number {
#[inline]
fn from(n: Rational) -> Self {
Number::Rational(Rc::new(n))
}
}
impl From<isize> for Number {
#[inline]
fn from(n: isize) -> Self {
Number::Fixnum(n)
}
} }
impl Default for Number { impl Default for Number {
@@ -585,48 +622,89 @@ impl Default for Number {
} }
} }
impl Number { impl Into<Constant> for Number {
pub fn to_constant(self) -> Constant { #[inline]
fn into(self) -> Constant {
match self { match self {
Number::Fixnum(n) => Constant::Fixnum(n),
Number::Integer(n) => Constant::Integer(n), Number::Integer(n) => Constant::Integer(n),
Number::Float(f) => Constant::Float(f), Number::Float(f) => Constant::Float(f),
Number::Rational(r) => Constant::Rational(r), Number::Rational(r) => Constant::Rational(r),
} }
} }
}
impl Into<HeapCellValue> for Number {
#[inline]
fn into(self) -> HeapCellValue {
match self {
Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)),
Number::Integer(n) => HeapCellValue::Integer(n),
Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)),
Number::Rational(r) => HeapCellValue::Rational(r),
}
}
}
impl Number {
#[inline]
pub fn to_u32(&self) -> Option<u32> {
match self {
&Number::Fixnum(n) => u32::try_from(n).ok(),
&Number::Integer(ref n) => n.to_u32(),
&Number::Float(_) => None,
&Number::Rational(ref r) =>
if r.denom() == &1 {
r.numer().to_u32()
} else {
None
}
}
}
#[inline] #[inline]
pub fn is_positive(&self) -> bool { pub fn is_positive(&self) -> bool {
match self { match self {
&Number::Integer(ref n) => n > &0, &Number::Fixnum(n) => n > 0,
&Number::Integer(ref n) => &**n > &0,
&Number::Float(OrderedFloat(f)) => f.is_sign_positive(), &Number::Float(OrderedFloat(f)) => f.is_sign_positive(),
&Number::Rational(ref r) => r > &0, &Number::Rational(ref r) => &**r > &0,
} }
} }
#[inline] #[inline]
pub fn is_negative(&self) -> bool { pub fn is_negative(&self) -> bool {
match self { match self {
&Number::Integer(ref n) => n < &0, &Number::Fixnum(n) => n < 0,
&Number::Integer(ref n) => &**n < &0,
&Number::Float(OrderedFloat(f)) => f.is_sign_negative(), &Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
&Number::Rational(ref r) => r < &0, &Number::Rational(ref r) => &**r < &0,
} }
} }
#[inline] #[inline]
pub fn is_zero(&self) -> bool { pub fn is_zero(&self) -> bool {
match self { match self {
&Number::Integer(ref n) => n == &0, &Number::Fixnum(n) => n == 0,
&Number::Integer(ref n) => &**n == &0,
&Number::Float(f) => f == OrderedFloat(0f64), &Number::Float(f) => f == OrderedFloat(0f64),
&Number::Rational(ref r) => r == &0, &Number::Rational(ref r) => &**r == &0,
} }
} }
#[inline] #[inline]
pub fn abs(self) -> Self { pub fn abs(self) -> Self {
match self { match self {
Number::Integer(n) => Number::Integer(n.abs()), Number::Fixnum(n) =>
if let Some(n) = n.checked_abs() {
Number::from(n)
} else {
Number::from(Integer::from(n).abs())
}
Number::Integer(n) => Number::from(Integer::from(n.abs_ref())),
Number::Float(f) => Number::Float(OrderedFloat(f.abs())), Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
Number::Rational(r) => Number::Rational(r.abs()), Number::Rational(r) => Number::from(Rational::from(r.abs_ref())),
} }
} }
} }

View File

@@ -1,5 +1,3 @@
use prolog_parser::ast::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*; use crate::prolog::machine::machine_state::*;
@@ -22,25 +20,33 @@ impl<'a> HCPreOrderIterator<'a> {
} }
} }
#[inline]
pub fn machine_st(&self) -> &MachineState { pub fn machine_st(&self) -> &MachineState {
&self.machine_st &self.machine_st
} }
fn follow_heap(&mut self, h: usize) -> Addr { fn follow_heap(&mut self, h: usize) -> Addr {
match &self.machine_st.heap[h] { match &self.machine_st.heap[h] {
HeapCellValue::NamedStr(arity, _, _) => { &HeapCellValue::NamedStr(arity, _, _) => {
for idx in (1 .. arity + 1).rev() { for idx in (1 .. arity + 1).rev() {
self.state_stack.push(Addr::HeapCell(h + idx)); self.state_stack.push(Addr::HeapCell(h + idx));
} }
Addr::Str(h) Addr::Str(h)
} }
HeapCellValue::Addr(ref a) => { &HeapCellValue::Addr(a) => {
self.follow(a.clone()) self.follow(a)
} }
HeapCellValue::PartialString(_) => { HeapCellValue::PartialString(..) => {
self.follow(Addr::PStrLocation(h, 0)) self.follow(Addr::PStrLocation(h, 0))
} }
HeapCellValue::Atom(..) | HeapCellValue::DBRef(_)
| HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => {
Addr::Con(h)
}
HeapCellValue::Stream(_) => {
Addr::Stream(h)
}
} }
} }
@@ -51,30 +57,6 @@ impl<'a> HCPreOrderIterator<'a> {
let da = self.machine_st.store(self.machine_st.deref(addr)); let da = self.machine_st.store(self.machine_st.deref(addr));
match da { match da {
Addr::Con(Constant::String(n, s)) => {
if !self.machine_st.machine_flags().double_quotes.is_atom() {
if s.len() > n {
if let Some(c) = s[n ..].chars().next() {
let o = c.len_utf8();
self.state_stack.push(Addr::Con(Constant::String(n+o, s.clone())));
if self.machine_st.machine_flags().double_quotes.is_codes() {
self.state_stack.push(Addr::Con(Constant::CharCode(c as u32)));
} else {
self.state_stack.push(Addr::Con(Constant::Char(c)));
}
}
} else {
return Addr::Con(Constant::EmptyList);
}
}
Addr::Con(Constant::String(n, s))
}
Addr::Con(_) | Addr::DBRef(_) => {
da
}
Addr::Lis(a) => { Addr::Lis(a) => {
self.state_stack.push(Addr::HeapCell(a + 1)); self.state_stack.push(Addr::HeapCell(a + 1));
self.state_stack.push(Addr::HeapCell(a)); self.state_stack.push(Addr::HeapCell(a));
@@ -82,19 +64,19 @@ impl<'a> HCPreOrderIterator<'a> {
da da
} }
Addr::PStrLocation(h, n) => { Addr::PStrLocation(h, n) => {
if let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] { if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
let s = pstr.block_as_str(); if let Some(c) = pstr.range_from(n ..).next() {
if !pstr.at_end(n + c.len_utf8()) {
if let Some(c) = s[n ..].chars().next() {
if pstr.len() > n + c.len_utf8() {
self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8())); self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8()));
} else if has_tail {
self.state_stack.push(Addr::HeapCell(h + 1));
} else { } else {
self.state_stack.push(Addr::PStrTail(h, n + c.len_utf8())); self.state_stack.push(Addr::EmptyList);
} }
self.state_stack.push(Addr::Con(Constant::Char(c))); self.state_stack.push(Addr::Char(c));
} else { } else if has_tail {
unreachable!() return self.follow(Addr::HeapCell(h + 1));
} }
} else { } else {
unreachable!() unreachable!()
@@ -102,80 +84,63 @@ impl<'a> HCPreOrderIterator<'a> {
Addr::PStrLocation(h, n) Addr::PStrLocation(h, n)
} }
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::PStrTail(..) => {
da
}
Addr::Str(s) => { Addr::Str(s) => {
self.follow_heap(s) // record terms of structure. self.follow_heap(s) // record terms of structure.
} }
Addr::Con(h) => {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
if !self.machine_st.flags.double_quotes.is_atom() {
return if let Some(c) = pstr.range_from(0 ..).next() {
self.state_stack.push(Addr::PStrLocation(h, c.len_utf8()));
self.state_stack.push(Addr::Char(c));
Addr::PStrLocation(h, 0)
} else if has_tail {
self.follow(Addr::HeapCell(h + 1))
} else {
Addr::EmptyList
};
}
}
Addr::Con(h)
}
da => {
da
}
} }
} }
} }
impl<'a> Iterator for HCPreOrderIterator<'a> { impl<'a> Iterator for HCPreOrderIterator<'a> {
type Item = HeapCellValue; type Item = Addr;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.state_stack.pop().map(|a| match self.follow(a) { self.state_stack.pop().map(|a| self.follow(a))
Addr::HeapCell(h) => {
HeapCellValue::Addr(self.machine_st.heap[h].as_addr(h))
}
Addr::Str(s) => {
match &self.machine_st.heap[s] {
val @ HeapCellValue::NamedStr(..) => {
val.clone()
}
_ => {
unreachable!()
}
}
}
Addr::PStrTail(h, n) => {
match &self.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr) => {
if pstr.len() > n {
HeapCellValue::Addr(Addr::PStrLocation(h, n))
} else {
HeapCellValue::Addr(pstr.tail_addr().clone())
}
}
_ => {
unreachable!()
}
}
}
Addr::StackCell(fr, sc) => {
HeapCellValue::Addr(self.machine_st.stack.index_and_frame(fr)[sc].clone())
}
da => {
HeapCellValue::Addr(da)
}
})
} }
} }
pub trait MutStackHCIterator pub trait MutStackHCIterator
where where Self: Iterator<Item = Addr>
Self: Iterator<Item = HeapCellValue>,
{ {
fn stack(&mut self) -> &mut Vec<Addr>; fn stack(&mut self) -> &mut Vec<Addr>;
} }
pub struct HCPostOrderIterator<HCIter> { pub struct HCPostOrderIterator<'a> {
base_iter: HCIter, base_iter: HCPreOrderIterator<'a>,
parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node. parent_stack: Vec<(usize, Addr)>, // number of children, parent node.
} }
impl<HCIter> Deref for HCPostOrderIterator<HCIter> { impl<'a> Deref for HCPostOrderIterator<'a> {
type Target = HCIter; type Target = HCPreOrderIterator<'a>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.base_iter &self.base_iter
} }
} }
impl<HCIter: Iterator<Item = HeapCellValue>> HCPostOrderIterator<HCIter> { impl<'a> HCPostOrderIterator<'a> {
pub fn new(base_iter: HCIter) -> Self { pub fn new(base_iter: HCPreOrderIterator<'a>) -> Self {
HCPostOrderIterator { HCPostOrderIterator {
base_iter, base_iter,
parent_stack: vec![], parent_stack: vec![],
@@ -183,8 +148,8 @@ impl<HCIter: Iterator<Item = HeapCellValue>> HCPostOrderIterator<HCIter> {
} }
} }
impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HCIter> { impl<'a> Iterator for HCPostOrderIterator<'a> {
type Item = HeapCellValue; type Item = Addr;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
@@ -197,15 +162,30 @@ impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HC
} }
if let Some(item) = self.base_iter.next() { if let Some(item) = self.base_iter.next() {
match item { match self.base_iter.machine_st.heap.index_addr(&item).as_ref() {
HeapCellValue::NamedStr(arity, name, fix) => self &HeapCellValue::NamedStr(arity, ..) => {
.parent_stack self.parent_stack.push((arity, item));
.push((arity, HeapCellValue::NamedStr(arity, name, fix))), }
HeapCellValue::Addr(Addr::Lis(a)) => self &HeapCellValue::Addr(Addr::Lis(a)) => {
.parent_stack self.parent_stack.push((2, Addr::Lis(a)));
.push((2, HeapCellValue::Addr(Addr::Lis(a)))), }
child_node => { &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
return Some(child_node); match &self.machine_st.heap[h] {
&HeapCellValue::PartialString(ref pstr, _) => {
let c = pstr.range_from(n ..).next().unwrap();
let next_n = n + c.len_utf8();
if !pstr.at_end(next_n) {
self.parent_stack.push((2, Addr::PStrLocation(h, next_n)));
}
}
_ => {
unreachable!()
}
}
}
_ => {
return Some(item);
} }
} }
} else { } else {
@@ -215,21 +195,16 @@ impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HC
} }
} }
pub type HCProperPostOrderIterator<'a> = HCPostOrderIterator<HCPreOrderIterator<'a>>;
impl MachineState { impl MachineState {
pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> { pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> {
HCPreOrderIterator::new(self, a) HCPreOrderIterator::new(self, a)
} }
pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCProperPostOrderIterator<'a> { pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> {
HCPostOrderIterator::new(HCPreOrderIterator::new(self, a)) HCPostOrderIterator::new(HCPreOrderIterator::new(self, a))
} }
pub fn acyclic_pre_order_iter<'a>( pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr,) -> HCAcyclicIterator<'a> {
&'a self,
a: Addr,
) -> HCAcyclicIterator<HCPreOrderIterator<'a>> {
HCAcyclicIterator::new(HCPreOrderIterator::new(self, a)) HCAcyclicIterator::new(HCPreOrderIterator::new(self, a))
} }
@@ -237,7 +212,7 @@ impl MachineState {
&'a self, &'a self,
a1: Addr, a1: Addr,
a2: Addr, a2: Addr,
) -> HCZippedAcyclicIterator<HCPreOrderIterator<'a>> { ) -> HCZippedAcyclicIterator<'a> {
HCZippedAcyclicIterator::new( HCZippedAcyclicIterator::new(
HCPreOrderIterator::new(self, a1), HCPreOrderIterator::new(self, a1),
HCPreOrderIterator::new(self, a2), HCPreOrderIterator::new(self, a2),
@@ -251,13 +226,13 @@ impl<'a> MutStackHCIterator for HCPreOrderIterator<'a> {
} }
} }
pub struct HCAcyclicIterator<HCIter> { pub struct HCAcyclicIterator<'a> {
iter: HCIter, iter: HCPreOrderIterator<'a>,
seen: IndexSet<Addr>, seen: IndexSet<Addr>,
} }
impl<HCIter: MutStackHCIterator> HCAcyclicIterator<HCIter> { impl<'a> HCAcyclicIterator<'a> {
pub fn new(iter: HCIter) -> Self { pub fn new(iter: HCPreOrderIterator<'a>) -> Self {
HCAcyclicIterator { HCAcyclicIterator {
iter, iter,
seen: IndexSet::new(), seen: IndexSet::new(),
@@ -265,19 +240,17 @@ impl<HCIter: MutStackHCIterator> HCAcyclicIterator<HCIter> {
} }
} }
impl<HCIter> Deref for HCAcyclicIterator<HCIter> { impl<'a> Deref for HCAcyclicIterator<'a> {
type Target = HCIter; type Target = HCPreOrderIterator<'a>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.iter &self.iter
} }
} }
impl<HCIter> Iterator for HCAcyclicIterator<HCIter> impl<'a> Iterator for HCAcyclicIterator<'a>
where
HCIter: Iterator<Item = HeapCellValue> + MutStackHCIterator,
{ {
type Item = HeapCellValue; type Item = Addr;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(addr) = self.iter.stack().pop() { while let Some(addr) = self.iter.stack().pop() {
@@ -293,15 +266,15 @@ where
} }
} }
pub struct HCZippedAcyclicIterator<HCIter> { pub struct HCZippedAcyclicIterator<'a> {
i1: HCIter, i1: HCPreOrderIterator<'a>,
i2: HCIter, i2: HCPreOrderIterator<'a>,
seen: IndexSet<(Addr, Addr)>, seen: IndexSet<(Addr, Addr)>,
pub first_to_expire: Ordering, pub first_to_expire: Ordering,
} }
impl<HCIter: MutStackHCIterator> HCZippedAcyclicIterator<HCIter> { impl<'a> HCZippedAcyclicIterator<'a> {
pub fn new(i1: HCIter, i2: HCIter) -> Self { pub fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self {
HCZippedAcyclicIterator { HCZippedAcyclicIterator {
i1, i1,
i2, i2,
@@ -311,11 +284,9 @@ impl<HCIter: MutStackHCIterator> HCZippedAcyclicIterator<HCIter> {
} }
} }
impl<HCIter> Iterator for HCZippedAcyclicIterator<HCIter> impl<'a> Iterator for HCZippedAcyclicIterator<'a>
where
HCIter: Iterator<Item = HeapCellValue> + MutStackHCIterator,
{ {
type Item = (HeapCellValue, HeapCellValue); type Item = (Addr, Addr);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) { while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) {
@@ -338,7 +309,9 @@ where
self.first_to_expire = Ordering::Less; self.first_to_expire = Ordering::Less;
None None
} }
_ => None, _ => {
None
}
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,13 @@
use prolog_parser::ast::*; use prolog_parser::ast::*;
use crate::prolog::instructions::*; use crate::prolog::instructions::*;
use crate::prolog::rug::Integer;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::hash::Hash; use std::hash::Hash;
use std::rc::Rc;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum IntIndex { enum IntIndex {
@@ -48,6 +50,41 @@ impl CodeOffsets {
} }
} }
fn intercept_constant(&mut self, constant: &Constant, index: usize) {
match constant {
&Constant::Atom(ref name, _) if name.is_char() => {
let c = name.as_str().chars().next().unwrap();
let code = self.constants
.entry(Constant::Char(c))
.or_insert(vec![]);
code.push(Self::add_index(code.is_empty(), index));
}
&Constant::Fixnum(n) => {
let code = self.constants
.entry(Constant::Integer(Rc::new(Integer::from(n))))
.or_insert(vec![]);
code.push(Self::add_index(code.is_empty(), index));
}
&Constant::Integer(ref n) => {
if let Some(n) = n.to_isize() {
let code = self.constants
.entry(Constant::Fixnum(n))
.or_insert(vec![]);
code.push(Self::add_index(code.is_empty(), index));
}
}
&Constant::String(_) => {
let is_initial_index = self.lists.is_empty();
self.lists.push(Self::add_index(is_initial_index, index));
}
_ => {
}
}
}
pub fn index_term(&mut self, first_arg: &Term, index: usize) { pub fn index_term(&mut self, first_arg: &Term, index: usize) {
match first_arg { match first_arg {
&Term::Clause(_, ref name, ref terms, _) => { &Term::Clause(_, ref name, ref terms, _) => {
@@ -63,18 +100,12 @@ impl CodeOffsets {
let is_initial_index = self.lists.is_empty(); let is_initial_index = self.lists.is_empty();
self.lists.push(Self::add_index(is_initial_index, index)); self.lists.push(Self::add_index(is_initial_index, index));
} }
&Term::Constant(_, Constant::String(n, ref s)) => {
let is_initial_index = self.lists.is_empty();
self.lists.push(Self::add_index(is_initial_index, index));
let constant = Constant::String(n, s.clone());
let code = self.constants.entry(constant).or_insert(Vec::new());
let is_initial_index = code.is_empty();
code.push(Self::add_index(is_initial_index, index));
}
&Term::Constant(_, ref constant) => { &Term::Constant(_, ref constant) => {
let code = self.constants.entry(constant.clone()).or_insert(Vec::new()); self.intercept_constant(constant, index);
let code = self.constants
.entry(constant.clone())
.or_insert(vec![]);
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
code.push(Self::add_index(is_initial_index, index)); code.push(Self::add_index(is_initial_index, index));
@@ -227,12 +258,11 @@ impl CodeOffsets {
fn switch_on_lst_offset_from( fn switch_on_lst_offset_from(
lst_loc: IntIndex, lst_loc: IntIndex,
prelude_len: usize, prelude_len: usize,
lst_offset: usize,
) -> usize { ) -> usize {
match lst_loc { match lst_loc {
IntIndex::External(o) => o + prelude_len + 1, IntIndex::External(o) => o + prelude_len + 1,
IntIndex::Fail => 0, IntIndex::Fail => 0,
IntIndex::Internal(_) => prelude_len - lst_offset + 1, IntIndex::Internal(_) => 1, // this internal is always 0.
} }
} }
@@ -245,8 +275,6 @@ impl CodeOffsets {
let mut prelude = VecDeque::new(); let mut prelude = VecDeque::new();
let lst_loc = Self::switch_on_list(self.lists, &mut prelude); let lst_loc = Self::switch_on_list(self.lists, &mut prelude);
let lst_offset = prelude.len();
let str_loc = Self::switch_on_structure(self.structures, &mut prelude); let str_loc = Self::switch_on_structure(self.structures, &mut prelude);
let con_loc = Self::switch_on_constant(self.constants, &mut prelude); let con_loc = Self::switch_on_constant(self.constants, &mut prelude);
@@ -254,18 +282,19 @@ impl CodeOffsets {
for (index, line) in prelude.iter_mut().enumerate() { for (index, line) in prelude.iter_mut().enumerate() {
match line { match line {
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) &mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) |
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) |
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => { &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
*i += prelude_length - index *i += prelude_length - index;
}
_ => {
} }
_ => {}
} }
} }
let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc); let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc);
let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len()); let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len());
let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len(), lst_offset); let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len());
let switch_instr = let switch_instr =
IndexingInstruction::SwitchOnTerm(prelude.len() + 1, con_loc, lst_loc, str_loc); IndexingInstruction::SwitchOnTerm(prelude.len() + 1, con_loc, lst_loc, str_loc);

View File

@@ -2,28 +2,29 @@ use prolog_parser::ast::*;
use crate::prolog::clause_types::*; use crate::prolog::clause_types::*;
use crate::prolog::forms::*; use crate::prolog::forms::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::MachineStub; use crate::prolog::machine::machine_errors::MachineStub;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::rug::Integer; use crate::prolog::rug::Integer;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::rc::Rc;
fn reg_type_into_functor(r: RegType) -> MachineStub { fn reg_type_into_functor(r: RegType) -> MachineStub {
match r { match r {
RegType::Temp(r) => functor!("x", 1, [heap_integer!(Integer::from(r))]), RegType::Temp(r) => functor!("x", [integer(r)]),
RegType::Perm(r) => functor!("y", 1, [heap_integer!(Integer::from(r))]), RegType::Perm(r) => functor!("y", [integer(r)]),
} }
} }
impl Level { impl Level {
fn into_functor(self) -> MachineStub { fn into_functor(self) -> MachineStub {
match self { match self {
Level::Root => functor!("level", 1, [heap_atom!("root")]), Level::Root => functor!("level", [atom("root")]),
Level::Shallow => functor!("level", 1, [heap_atom!("shallow")]), Level::Shallow => functor!("level", [atom("shallow")]),
Level::Deep => functor!("level", 1, [heap_atom!("deep")]), Level::Deep => functor!("level", [atom("deep")]),
} }
} }
} }
@@ -31,11 +32,15 @@ impl Level {
impl ArithmeticTerm { impl ArithmeticTerm {
fn into_functor(&self) -> MachineStub { fn into_functor(&self) -> MachineStub {
match self { match self {
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r), &ArithmeticTerm::Reg(r) => {
&ArithmeticTerm::Interm(i) => { reg_type_into_functor(r)
functor!("intermediate", 1, [heap_integer!(Integer::from(i))]) }
&ArithmeticTerm::Interm(i) => {
functor!("intermediate", [integer(i)])
}
&ArithmeticTerm::Number(ref n) => {
vec![n.clone().into()]
} }
&ArithmeticTerm::Number(ref n) => vec![heap_con!(n.clone().to_constant())],
} }
} }
} }
@@ -52,18 +57,20 @@ impl ChoiceInstruction {
pub fn to_functor(&self) -> MachineStub { pub fn to_functor(&self) -> MachineStub {
match self { match self {
&ChoiceInstruction::TryMeElse(offset) => { &ChoiceInstruction::TryMeElse(offset) => {
functor!("try_me_else", 1, [heap_integer!(Integer::from(offset))]) functor!("try_me_else", [integer(offset)])
} }
&ChoiceInstruction::RetryMeElse(offset) => { &ChoiceInstruction::RetryMeElse(offset) => {
functor!("retry_me_else", 1, [heap_integer!(Integer::from(offset))]) functor!("retry_me_else", [integer(offset)])
}
&ChoiceInstruction::TrustMe => {
functor!("trust_me")
}
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
functor!("default_retry_me_else", [integer(offset)])
}
&ChoiceInstruction::DefaultTrustMe => {
functor!("default_trust_me")
} }
&ChoiceInstruction::TrustMe => vec![heap_atom!("trust_me")],
&ChoiceInstruction::DefaultRetryMeElse(offset) => functor!(
"default_retry_me_else",
1,
[heap_integer!(Integer::from(offset))]
),
&ChoiceInstruction::DefaultTrustMe => vec![heap_atom!("default_trust_me")],
} }
} }
} }
@@ -79,21 +86,20 @@ impl CutInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub { pub fn to_functor(&self, h: usize) -> MachineStub {
match self { match self {
&CutInstruction::Cut(r) => { &CutInstruction::Cut(r) => {
let mut stub = functor!("cut", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r)); functor!("cut", [aux(h, 0)], [rt_stub])
stub
} }
&CutInstruction::GetLevel(r) => { &CutInstruction::GetLevel(r) => {
let mut stub = functor!("get_level", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r)); functor!("get_level", [aux(h, 0)], [rt_stub])
stub
} }
&CutInstruction::GetLevelAndUnify(r) => { &CutInstruction::GetLevelAndUnify(r) => {
let mut stub = functor!("get_level_and_unify", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r)); functor!("get_level_and_unify", [aux(h, 0)], [rt_stub])
stub }
&CutInstruction::NeckCut => {
functor!("neck_cut")
} }
&CutInstruction::NeckCut => vec![heap_atom!("neck_cut")],
} }
} }
} }
@@ -122,13 +128,13 @@ impl IndexedChoiceInstruction {
pub fn to_functor(&self) -> MachineStub { pub fn to_functor(&self) -> MachineStub {
match self { match self {
&IndexedChoiceInstruction::Try(offset) => { &IndexedChoiceInstruction::Try(offset) => {
functor!("try", 1, [heap_integer!(Integer::from(offset))]) functor!("try", [integer(offset)])
} }
&IndexedChoiceInstruction::Trust(offset) => { &IndexedChoiceInstruction::Trust(offset) => {
functor!("trust", 1, [heap_integer!(Integer::from(offset))]) functor!("trust", [integer(offset)])
} }
&IndexedChoiceInstruction::Retry(offset) => { &IndexedChoiceInstruction::Retry(offset) => {
functor!("retry", 1, [heap_integer!(Integer::from(offset))]) functor!("retry", [integer(offset)])
} }
} }
} }
@@ -220,14 +226,11 @@ fn arith_instr_unary_functor(
) -> MachineStub { ) -> MachineStub {
let at_stub = at.into_functor(); let at_stub = at.into_functor();
let mut stub = functor!( functor!(
name, name,
2, [aux(h, 0), integer(t)],
[heap_cell!(h + 4), heap_integer!(Integer::from(t))] [at_stub]
); )
stub.extend(at_stub.into_iter());
stub
} }
fn arith_instr_bin_functor( fn arith_instr_bin_functor(
@@ -240,20 +243,11 @@ fn arith_instr_bin_functor(
let at_1_stub = at_1.into_functor(); let at_1_stub = at_1.into_functor();
let at_2_stub = at_2.into_functor(); let at_2_stub = at_2.into_functor();
let mut stub = functor!( functor!(
name, name,
3, [aux(h, 0), aux(h, 1), integer(t)],
[ [at_1_stub, at_2_stub]
heap_cell!(h + 4), )
heap_cell!(h + 4 + at_1_stub.len()),
heap_integer!(Integer::from(t))
]
);
stub.extend(at_1_stub.into_iter());
stub.extend(at_2_stub.into_iter());
stub
} }
impl ArithmeticInstruction { impl ArithmeticInstruction {
@@ -319,17 +313,39 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => { &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, "gcd", at_1, at_2, t) arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
} }
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t), &ArithmeticInstruction::Sign(ref at, t) => {
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t), arith_instr_unary_functor(h, "sign", at, t)
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t), }
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t), &ArithmeticInstruction::Cos(ref at, t) => {
&ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t), arith_instr_unary_functor(h, "cos", at, t)
&ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t), }
&ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t), &ArithmeticInstruction::Sin(ref at, t) => {
&ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t), arith_instr_unary_functor(h, "sin", at, t)
&ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t), }
&ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t), &ArithmeticInstruction::Tan(ref at, t) => {
&ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t), arith_instr_unary_functor(h, "tan", at, t)
}
&ArithmeticInstruction::Log(ref at, t) => {
arith_instr_unary_functor(h, "log", at, t)
}
&ArithmeticInstruction::Exp(ref at, t) => {
arith_instr_unary_functor(h, "exp", at, t)
}
&ArithmeticInstruction::ACos(ref at, t) => {
arith_instr_unary_functor(h, "acos", at, t)
}
&ArithmeticInstruction::ASin(ref at, t) => {
arith_instr_unary_functor(h, "asin", at, t)
}
&ArithmeticInstruction::ATan(ref at, t) => {
arith_instr_unary_functor(h, "atan", at, t)
}
&ArithmeticInstruction::Sqrt(ref at, t) => {
arith_instr_unary_functor(h, "sqrt", at, t)
}
&ArithmeticInstruction::Abs(ref at, t) => {
arith_instr_unary_functor(h, "abs", at, t)
}
&ArithmeticInstruction::Float(ref at, t) => { &ArithmeticInstruction::Float(ref at, t) => {
arith_instr_unary_functor(h, "float", at, t) arith_instr_unary_functor(h, "float", at, t)
} }
@@ -345,8 +361,12 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::Floor(ref at, t) => { &ArithmeticInstruction::Floor(ref at, t) => {
arith_instr_unary_functor(h, "floor", at, t) arith_instr_unary_functor(h, "floor", at, t)
} }
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t), &ArithmeticInstruction::Neg(ref at, t) => {
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t), arith_instr_unary_functor(h, "-", at, t)
}
&ArithmeticInstruction::Plus(ref at, t) => {
arith_instr_unary_functor(h, "+", at, t)
}
&ArithmeticInstruction::BitwiseComplement(ref at, t) => { &ArithmeticInstruction::BitwiseComplement(ref at, t) => {
arith_instr_unary_functor(h, "\\", at, t) arith_instr_unary_functor(h, "\\", at, t)
} }
@@ -378,29 +398,23 @@ impl ControlInstruction {
pub fn to_functor(&self) -> MachineStub { pub fn to_functor(&self) -> MachineStub {
match self { match self {
&ControlInstruction::Allocate(num_frames) => { &ControlInstruction::Allocate(num_frames) => {
functor!("allocate", 1, [heap_integer!(Integer::from(num_frames))]) functor!("allocate", [integer(num_frames)])
}
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => {
functor!("call", [clause_name(ct.name()), integer(arity)])
}
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => {
functor!("execute", [clause_name(ct.name()), integer(arity)])
}
&ControlInstruction::Deallocate => {
functor!("deallocate")
} }
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => functor!(
"call",
2,
[
heap_con!(Constant::Atom(ct.name(), None)),
heap_integer!(Integer::from(arity))
]
),
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => functor!(
"execute",
2,
[
heap_con!(Constant::Atom(ct.name(), None)),
heap_integer!(Integer::from(arity))
]
),
&ControlInstruction::Deallocate => vec![heap_atom!("deallocate")],
&ControlInstruction::JmpBy(_, offset, ..) => { &ControlInstruction::JmpBy(_, offset, ..) => {
functor!("jmp_by", 1, [heap_integer!(Integer::from(offset))]) functor!("jmp_by", [integer(offset)])
}
&ControlInstruction::Proceed => {
functor!("proceed")
} }
&ControlInstruction::Proceed => vec![heap_atom!("proceed")],
} }
} }
} }
@@ -420,26 +434,27 @@ impl From<IndexingInstruction> for Line {
impl IndexingInstruction { impl IndexingInstruction {
pub fn to_functor(&self) -> MachineStub { pub fn to_functor(&self) -> MachineStub {
match self { match self {
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => functor!( &IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => {
functor!(
"switch_on_term", "switch_on_term",
4, [integer(vars),
[ integer(constants),
heap_integer!(Integer::from(vars)), integer(lists),
heap_integer!(Integer::from(constants)), integer(structures)]
heap_integer!(Integer::from(lists)), )
heap_integer!(Integer::from(structures)) }
] &IndexingInstruction::SwitchOnConstant(constants, _) => {
), functor!(
&IndexingInstruction::SwitchOnConstant(constants, _) => functor!(
"switch_on_constant", "switch_on_constant",
1, [integer(constants)]
[heap_integer!(Integer::from(constants))] )
), }
&IndexingInstruction::SwitchOnStructure(structures, _) => functor!( &IndexingInstruction::SwitchOnStructure(structures, _) => {
functor!(
"switch_on_structure", "switch_on_structure",
1, [integer(structures)]
[heap_integer!(Integer::from(structures))] )
), }
} }
} }
} }
@@ -448,6 +463,7 @@ impl IndexingInstruction {
pub enum FactInstruction { pub enum FactInstruction {
GetConstant(Level, Constant, RegType), GetConstant(Level, Constant, RegType),
GetList(Level, RegType), GetList(Level, RegType),
GetPartialString(Level, String, RegType, bool),
GetStructure(ClauseType, usize, RegType), GetStructure(ClauseType, usize, RegType),
GetValue(RegType, usize), GetValue(RegType, usize),
GetVariable(RegType, usize), GetVariable(RegType, usize),
@@ -461,86 +477,95 @@ pub enum FactInstruction {
impl FactInstruction { impl FactInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub { pub fn to_functor(&self, h: usize) -> MachineStub {
match self { match self {
&FactInstruction::GetConstant(lvl, ref constant, r) => { &FactInstruction::GetConstant(lvl, ref c, r) => {
let mut stub = functor!( let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"get_constant", "get_constant",
3, [aux(h, 0), constant(h, c), aux(h, 1)],
[ [lvl_stub, rt_stub]
heap_str!(h + 4), )
heap_con!(constant.clone()),
heap_str!(h + 6)
]
);
stub.append(&mut lvl.into_functor());
stub.append(&mut reg_type_into_functor(r));
stub
} }
&FactInstruction::GetList(lvl, r) => { &FactInstruction::GetList(lvl, r) => {
let mut stub = functor!("get_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]); let lvl_stub = lvl.into_functor();
stub.append(&mut lvl.into_functor()); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub functor!(
"get_list",
[aux(h, 0), aux(h, 1)],
[lvl_stub, rt_stub]
)
}
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"get_partial_string",
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
[lvl_stub, rt_stub]
)
} }
&FactInstruction::GetStructure(ref ct, arity, r) => { &FactInstruction::GetStructure(ref ct, arity, r) => {
let mut stub = functor!( let rt_stub = reg_type_into_functor(r);
"get_structure",
3,
[
heap_con!(Constant::Atom(ct.name(), None)),
heap_integer!(Integer::from(arity)),
heap_str!(h + 4)
]
);
stub.append(&mut reg_type_into_functor(r));
stub functor!(
"get_structure",
[clause_name(ct.name()), integer(arity), aux(h, 0)],
[rt_stub]
)
} }
&FactInstruction::GetValue(r, arg) => { &FactInstruction::GetValue(r, arg) => {
let mut stub = functor!( let rt_stub = reg_type_into_functor(r);
"get_value",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
stub.append(&mut reg_type_into_functor(r));
stub functor!(
"get_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&FactInstruction::GetVariable(r, arg) => { &FactInstruction::GetVariable(r, arg) => {
let mut stub = functor!( let rt_stub = reg_type_into_functor(r);
"get_variable",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
stub.append(&mut reg_type_into_functor(r));
stub functor!(
"get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&FactInstruction::UnifyConstant(ref constant) => { &FactInstruction::UnifyConstant(ref c) => {
functor!("unify_constant", 1, [heap_con!(constant.clone())]) functor!("unify_constant", [constant(h, c)], [])
} }
&FactInstruction::UnifyLocalValue(r) => { &FactInstruction::UnifyLocalValue(r) => {
let mut stub = functor!("unify_local_value", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub functor!(
"unify_local_value",
[aux(h, 0)],
[rt_stub]
)
} }
&FactInstruction::UnifyVariable(r) => { &FactInstruction::UnifyVariable(r) => {
let mut stub = functor!("unify_variable", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub functor!(
"unify_variable",
[aux(h, 0)],
[rt_stub]
)
} }
&FactInstruction::UnifyValue(r) => { &FactInstruction::UnifyValue(r) => {
let mut stub = functor!("unify_value", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub functor!(
"unify_value",
[aux(h, 0)],
[rt_stub]
)
} }
&FactInstruction::UnifyVoid(vars) => { &FactInstruction::UnifyVoid(vars) => {
functor!("unify_void", 1, [heap_integer!(Integer::from(vars))]) functor!("unify_void", [integer(vars)])
} }
} }
} }
@@ -551,6 +576,7 @@ pub enum QueryInstruction {
GetVariable(RegType, usize), GetVariable(RegType, usize),
PutConstant(Level, Constant, RegType), PutConstant(Level, Constant, RegType),
PutList(Level, RegType), PutList(Level, RegType),
PutPartialString(Level, String, RegType, bool),
PutStructure(ClauseType, usize, RegType), PutStructure(ClauseType, usize, RegType),
PutUnsafeValue(usize, usize), PutUnsafeValue(usize, usize),
PutValue(RegType, usize), PutValue(RegType, usize),
@@ -567,103 +593,106 @@ impl QueryInstruction {
match self { match self {
&QueryInstruction::PutUnsafeValue(norm, arg) => functor!( &QueryInstruction::PutUnsafeValue(norm, arg) => functor!(
"put_unsafe_value", "put_unsafe_value",
2, [integer(norm), integer(arg)]
[
heap_integer!(Integer::from(norm)),
heap_integer!(Integer::from(arg))
]
), ),
&QueryInstruction::PutConstant(lvl, ref constant, r) => { &QueryInstruction::PutConstant(lvl, ref c, r) => {
let mut stub = functor!( let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"put_constant", "put_constant",
3, [aux(h, 0), constant(h, c), aux(h, 1)],
[ [lvl_stub, rt_stub]
heap_str!(h + 4), )
heap_con!(constant.clone()),
heap_str!(h + 6)
]
);
stub.append(&mut lvl.into_functor());
stub.append(&mut reg_type_into_functor(r));
stub
} }
&QueryInstruction::PutList(lvl, r) => { &QueryInstruction::PutList(lvl, r) => {
let mut stub = functor!("put_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]); let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
stub.append(&mut lvl.into_functor()); functor!(
stub.append(&mut reg_type_into_functor(r)); "put_list",
[aux(h, 0), aux(h, 1)],
[lvl_stub, rt_stub]
)
}
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
stub functor!(
"put_partial_string",
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
[lvl_stub, rt_stub]
)
} }
&QueryInstruction::PutStructure(ref ct, arity, r) => { &QueryInstruction::PutStructure(ref ct, arity, r) => {
let mut stub = functor!( let rt_stub = reg_type_into_functor(r);
"put_structure",
3,
[
heap_con!(Constant::Atom(ct.name(), None)),
heap_integer!(Integer::from(arity)),
heap_str!(h + 4)
]
);
stub.append(&mut reg_type_into_functor(r)); functor!(
stub "put_structure",
[clause_name(ct.name()), integer(arity), aux(h, 0)],
[rt_stub]
)
} }
&QueryInstruction::PutValue(r, arg) => { &QueryInstruction::PutValue(r, arg) => {
let mut stub = functor!( let rt_stub = reg_type_into_functor(r);
"put_value",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
stub.append(&mut reg_type_into_functor(r)); functor!(
stub "put_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&QueryInstruction::GetVariable(r, arg) => { &QueryInstruction::GetVariable(r, arg) => {
let mut stub = functor!( let rt_stub = reg_type_into_functor(r);
"get_variable",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
stub.append(&mut reg_type_into_functor(r)); functor!(
stub "get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&QueryInstruction::PutVariable(r, arg) => { &QueryInstruction::PutVariable(r, arg) => {
let mut stub = functor!( let rt_stub = reg_type_into_functor(r);
"put_variable",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
stub.append(&mut reg_type_into_functor(r)); functor!(
stub "put_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
} }
&QueryInstruction::SetConstant(ref constant) => { &QueryInstruction::SetConstant(ref c) => {
functor!("set_constant", 1, [heap_con!(constant.clone())]) functor!("set_constant", [constant(h, c)], [])
} }
&QueryInstruction::SetLocalValue(r) => { &QueryInstruction::SetLocalValue(r) => {
let mut stub = functor!("set_local_value", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r)); functor!(
stub "set_local_value",
[aux(h, 0)],
[rt_stub]
)
} }
&QueryInstruction::SetVariable(r) => { &QueryInstruction::SetVariable(r) => {
let mut stub = functor!("set_variable", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r)); functor!(
stub "set_variable",
[aux(h, 0)],
[rt_stub]
)
} }
&QueryInstruction::SetValue(r) => { &QueryInstruction::SetValue(r) => {
let mut stub = functor!("set_value", 1, [heap_str!(h + 2)]); let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r)); functor!(
stub "set_value",
[aux(h, 0)],
[rt_stub]
)
} }
&QueryInstruction::SetVoid(vars) => { &QueryInstruction::SetVoid(vars) => {
functor!("set_void", 1, [heap_integer!(Integer::from(vars))]) functor!("set_void", [integer(vars)])
} }
} }
} }

View File

@@ -16,6 +16,7 @@ pub enum TermRef<'a> {
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term), Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Constant(Level, &'a Cell<RegType>, &'a Constant), Constant(Level, &'a Cell<RegType>, &'a Constant),
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>), Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
Var(Level, &'a Cell<VarReg>, Rc<Var>), Var(Level, &'a Cell<VarReg>, Rc<Var>),
} }
@@ -27,6 +28,7 @@ impl<'a> TermRef<'a> {
| TermRef::Constant(lvl, ..) | TermRef::Constant(lvl, ..)
| TermRef::Var(lvl, ..) | TermRef::Var(lvl, ..)
| TermRef::Clause(lvl, ..) => lvl, | TermRef::Clause(lvl, ..) => lvl,
| TermRef::PartialString(lvl, ..) => lvl,
} }
} }
} }
@@ -43,13 +45,63 @@ pub enum TermIterState<'a> {
), ),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
Var(Level, &'a Cell<VarReg>, Rc<Var>), Var(Level, &'a Cell<VarReg>, Rc<Var>),
} }
fn is_partial_string<'a>(
head: &'a Term,
mut tail: &'a Term,
) -> Option<(String, Option<&'a Term>)>
{
let mut string =
match head {
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
atom.as_str().chars().next().unwrap().to_string()
}
&Term::Constant(_, Constant::Char(c)) => {
c.to_string()
}
_ => {
return None;
}
};
while let Term::Cons(_, ref head, ref succ) = tail {
match head.as_ref() {
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
string.push(atom.as_str().chars().next().unwrap());
}
&Term::Constant(_, Constant::Char(c)) => {
string.push(c);
}
_ => {
return None;
}
};
tail = succ.as_ref();
}
match tail {
Term::AnonVar | Term::Var(..) => {
return Some((string, Some(tail)));
}
Term::Constant(_, Constant::EmptyList) => {
return Some((string, None));
}
_ => {
return None;
}
}
}
impl<'a> TermIterState<'a> { impl<'a> TermIterState<'a> {
pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> { pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
match term { match term {
&Term::AnonVar => TermIterState::AnonVar(lvl), &Term::AnonVar => {
TermIterState::AnonVar(lvl)
}
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => { &Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
let ct = if let Some(spec) = spec { let ct = if let Some(spec) = spec {
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default()) ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
@@ -62,8 +114,12 @@ impl<'a> TermIterState<'a> {
&Term::Cons(ref cell, ref head, ref tail) => { &Term::Cons(ref cell, ref head, ref tail) => {
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
} }
&Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant), &Term::Constant(ref cell, ref constant) => {
&Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()), TermIterState::Constant(lvl, cell, constant)
}
&Term::Var(ref cell, ref var) => {
TermIterState::Var(lvl, cell, var.clone())
}
} }
} }
} }
@@ -169,7 +225,9 @@ impl<'a> Iterator for QueryIterator<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(iter_state) = self.state_stack.pop() { while let Some(iter_state) = self.state_stack.pop() {
match iter_state { match iter_state {
TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)), TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl));
}
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => { TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
if child_num == child_terms.len() { if child_num == child_terms.len() {
match ct { match ct {
@@ -182,7 +240,9 @@ impl<'a> Iterator for QueryIterator<'a> {
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)), lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
} }
} }
_ => return None, _ => {
return None;
}
}; };
} else { } else {
self.state_stack.push(TermIterState::Clause( self.state_stack.push(TermIterState::Clause(
@@ -192,23 +252,41 @@ impl<'a> Iterator for QueryIterator<'a> {
ct, ct,
child_terms, child_terms,
)); ));
self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref()); self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
} }
} }
TermIterState::InitialCons(lvl, cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head, tail) => {
self.state_stack if let Some((string, tail)) = is_partial_string(head, tail) {
.push(TermIterState::FinalCons(lvl, cell, head, tail)); self.state_stack.push(TermIterState::PartialString(
lvl,
cell,
string,
tail,
));
if let Some(tail) = tail {
self.push_subterm(lvl.child_level(), tail);
}
} else {
self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
self.push_subterm(lvl.child_level(), tail); self.push_subterm(lvl.child_level(), tail);
self.push_subterm(lvl.child_level(), head); self.push_subterm(lvl.child_level(), head);
} }
}
TermIterState::PartialString(lvl, cell, string, tail) => {
return Some(TermRef::PartialString(lvl, cell, string, tail));
}
TermIterState::FinalCons(lvl, cell, head, tail) => { TermIterState::FinalCons(lvl, cell, head, tail) => {
return Some(TermRef::Cons(lvl, cell, head, tail)) return Some(TermRef::Cons(lvl, cell, head, tail));
} }
TermIterState::Constant(lvl, cell, constant) => { TermIterState::Constant(lvl, cell, constant) => {
return Some(TermRef::Constant(lvl, cell, constant)) return Some(TermRef::Constant(lvl, cell, constant));
}
TermIterState::Var(lvl, cell, var) => {
return Some(TermRef::Var(lvl, cell, var));
} }
TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)),
}; };
} }
@@ -223,8 +301,7 @@ pub struct FactIterator<'a> {
impl<'a> FactIterator<'a> { impl<'a> FactIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) { fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_queue self.state_queue.push_back(TermIterState::subterm_to_state(lvl, term));
.push_back(TermIterState::subterm_to_state(lvl, term));
} }
pub fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self { pub fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
@@ -241,7 +318,9 @@ impl<'a> FactIterator<'a> {
fn new(term: &'a Term, iterable_root: bool) -> Self { fn new(term: &'a Term, iterable_root: bool) -> Self {
let states = match term { let states = match term {
&Term::AnonVar => vec![TermIterState::AnonVar(Level::Root)], &Term::AnonVar => {
vec![TermIterState::AnonVar(Level::Root)]
}
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => { &Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone()); let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone());
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)] vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
@@ -273,7 +352,9 @@ impl<'a> Iterator for FactIterator<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(state) = self.state_queue.pop_front() { while let Some(state) = self.state_queue.pop_front() {
match state { match state {
TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)), TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl));
}
TermIterState::Clause(lvl, _, cell, ct, child_terms) => { TermIterState::Clause(lvl, _, cell, ct, child_terms) => {
for child_term in child_terms { for child_term in child_terms {
self.push_subterm(lvl.child_level(), child_term); self.push_subterm(lvl.child_level(), child_term);
@@ -285,16 +366,27 @@ impl<'a> Iterator for FactIterator<'a> {
}; };
} }
TermIterState::InitialCons(lvl, cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head, tail) => {
if let Some((string, tail)) = is_partial_string(head, tail) {
if let Some(tail) = tail {
self.push_subterm(Level::Deep, tail);
}
return Some(TermRef::PartialString(lvl, cell, string, tail));
} else {
self.push_subterm(Level::Deep, head); self.push_subterm(Level::Deep, head);
self.push_subterm(Level::Deep, tail); self.push_subterm(Level::Deep, tail);
return Some(TermRef::Cons(lvl, cell, head, tail)); return Some(TermRef::Cons(lvl, cell, head, tail));
} }
}
TermIterState::Constant(lvl, cell, constant) => { TermIterState::Constant(lvl, cell, constant) => {
return Some(TermRef::Constant(lvl, cell, constant)) return Some(TermRef::Constant(lvl, cell, constant))
} }
TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)), TermIterState::Var(lvl, cell, var) => {
_ => {} return Some(TermRef::Var(lvl, cell, var));
}
_ => {
}
} }
} }

View File

@@ -158,4 +158,3 @@ call_residue_vars(Goal, Vars) :-
'$get_attr_var_queue_delim'(B), '$get_attr_var_queue_delim'(B),
call(Goal), call(Goal),
'$get_attr_var_queue_beyond'(B, Vars). '$get_attr_var_queue_beyond'(B, Vars).

View File

@@ -6,15 +6,10 @@
:- use_module(library(error)). :- use_module(library(error)).
between(Lower, Upper, X) :- between(Lower, Upper, X) :-
( Upper == inf ->
must_be(integer, Lower), must_be(integer, Lower),
can_be(integer, X),
enumerate_nats(Lower, X)
; must_be(integer, Lower),
must_be(integer, Upper), must_be(integer, Upper),
can_be(integer, X), can_be(integer, X),
between_(Lower, Upper, X) between_(Lower, Upper, X).
).
between_(Lower, Upper, Lower) :- between_(Lower, Upper, Lower) :-
Lower =< Upper. Lower =< Upper.

View File

@@ -44,15 +44,16 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
abolish/1, asserta/1, assertz/1, atom_chars/2, abolish/1, asserta/1, assertz/1, atom_chars/2,
atom_codes/2, atom_concat/3, atom_length/2, atom_codes/2, atom_concat/3, atom_length/2,
bagof/3, catch/3, char_code/2, clause/2, bagof/3, catch/3, char_code/2, clause/2,
current_op/3, current_predicate/1, current_input/1, current_output/1, current_op/3,
current_prolog_flag/2, expand_goal/2, current_predicate/1, current_prolog_flag/2,
expand_term/2, fail/0, false/0, findall/3, expand_goal/2, expand_term/2, fail/0, false/0,
findall/4, get_char/1, halt/0, max_arity/1, findall/3, findall/4, get_char/1, halt/0,
number_chars/2, number_codes/2, once/1, op/3, max_arity/1, number_chars/2, number_codes/2,
read_term/2, repeat/0, retract/1, once/1, op/3, read_term/2, repeat/0, retract/1,
set_prolog_flag/2, setof/3, sub_atom/5, set_prolog_flag/2, set_input/1, set_output/1,
subsumes_term/2, term_variables/2, throw/1, setof/3, sub_atom/5, subsumes_term/2,
true/0, unify_with_occurs_check/2, write/1, term_variables/2, throw/1, true/0,
unify_with_occurs_check/2, write/1,
write_canonical/1, write_term/2, writeq/1]). write_canonical/1, write_term/2, writeq/1]).
@@ -261,8 +262,11 @@ univ_errors(Term, List, N) :-
Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)), Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)),
'$call_with_default_policy'(univ_worker(Term, List, N)). '$call_with_default_policy'(univ_worker(Term, List, N)).
:- non_counted_backtracking univ_worker/3. :- non_counted_backtracking univ_worker/3.
univ_worker(Term, List, _) :- atomic(Term), !, '$call_with_default_policy'(List = [Term]).
univ_worker(Term, List, _) :-
atomic(Term), !, '$call_with_default_policy'(List = [Term]).
univ_worker(Term, [Name|Args], N) :- univ_worker(Term, [Name|Args], N) :-
var(Term), !, var(Term), !,
'$call_with_default_policy'(Arity is N-1), '$call_with_default_policy'(Arity is N-1),
@@ -273,7 +277,9 @@ univ_worker(Term, List, _) :-
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)), '$call_with_default_policy'(get_args(Args, Term, 1, Arity)),
'$call_with_default_policy'(List = [Name|Args]). '$call_with_default_policy'(List = [Name|Args]).
:- non_counted_backtracking get_args/4. :- non_counted_backtracking get_args/4.
get_args(Args, _, _, 0) :- get_args(Args, _, _, 0) :-
!, '$call_with_default_policy'(Args = []). !, '$call_with_default_policy'(Args = []).
get_args([Arg], Func, N, N) :- get_args([Arg], Func, N, N) :-
@@ -289,6 +295,7 @@ is_write_option(Functor) :-
( Arg == true -> true ( Arg == true -> true
; Arg == false -> true ; Arg == false -> true
; Name == variable_names -> must_be_var_names_list(Arg) ; Name == variable_names -> must_be_var_names_list(Arg)
; Name == max_depth -> integer(Arg), Arg >= 0
; var(Arg) -> throw(error(instantiation_error, write_term/2)) ; var(Arg) -> throw(error(instantiation_error, write_term/2))
; throw(error(domain_error(write_option, Functor), write_term/2)) ; throw(error(domain_error(write_option, Functor), write_term/2))
), % 8.14.2.3 e) ), % 8.14.2.3 e)
@@ -296,6 +303,7 @@ is_write_option(Functor) :-
; Name == quoted -> true ; Name == quoted -> true
; Name == numbervars -> true ; Name == numbervars -> true
; Name == variable_names -> true ; Name == variable_names -> true
; Name == max_depth -> true
; throw(error(domain_error(write_option, Functor), write_term/2)) ; throw(error(domain_error(write_option, Functor), write_term/2))
). % 8.14.2.3 e) ). % 8.14.2.3 e)
@@ -338,7 +346,8 @@ write_term(Term, Options) :-
inst_member_or(Options, numbervars(NumberVars), numbervars(false)), inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
inst_member_or(Options, quoted(Quoted), quoted(false)), inst_member_or(Options, quoted(Quoted), quoted(false)),
inst_member_or(Options, variable_names(VarNames), variable_names([])), inst_member_or(Options, variable_names(VarNames), variable_names([])),
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames). inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth).
write(Term) :- write_term(Term, [numbervars(true)]). write(Term) :- write_term(Term, [numbervars(true)]).
@@ -448,7 +457,7 @@ set_difference([], _, []) :- !.
set_difference(Xs, [], Xs). set_difference(Xs, [], Xs).
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :- group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
non_iso:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0). iso_ext:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
group_by_variant(Pairs, _, [], Pairs). group_by_variant(Pairs, _, [], Pairs).
group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :- group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
@@ -456,7 +465,10 @@ group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
group_by_variants(Pairs0, Solutions). group_by_variants(Pairs0, Solutions).
group_by_variants([], []). group_by_variants([], []).
iterate_variants([V-Solution|GroupSolutions], V, Solution). iterate_variants([V-Solution|GroupSolutions], V, Solution) :-
( GroupSolutions == [] -> !
; true
).
iterate_variants([_|GroupSolutions], Ws, Solution) :- iterate_variants([_|GroupSolutions], Ws, Solution) :-
iterate_variants(GroupSolutions, Ws, Solution). iterate_variants(GroupSolutions, Ws, Solution).
@@ -472,7 +484,9 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
( nonvar(Goal), Goal = _ ^ _ -> ( nonvar(Goal), Goal = _ ^ _ ->
rightmost_power(Goal, Goal1, ExistentialVars0), rightmost_power(Goal, Goal1, ExistentialVars0),
term_variables(ExistentialVars0, ExistentialVars), term_variables(ExistentialVars0, ExistentialVars),
set_difference(Witnesses0, ExistentialVars, Witnesses), sort(Witnesses0, Witnesses1),
sort(ExistentialVars, ExistentialVars1),
set_difference(Witnesses1, ExistentialVars1, Witnesses),
findall(Witnesses-Template, Goal1, PairedSolutions) findall(Witnesses-Template, Goal1, PairedSolutions)
; Witnesses = Witnesses0, ; Witnesses = Witnesses0,
findall(Witnesses-Template, Goal, PairedSolutions) findall(Witnesses-Template, Goal, PairedSolutions)
@@ -491,7 +505,10 @@ bagof(Template, Goal, Solution) :-
iterate_variants(GroupedSolutions, Witnesses, Solution). iterate_variants(GroupedSolutions, Witnesses, Solution).
iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :- iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
sort(Solution0, Solution). sort(Solution0, Solution),
( GroupSolutions == [] -> !
; true
).
iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :- iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :-
iterate_variants_and_sort(GroupSolutions, Ws, Solution). iterate_variants_and_sort(GroupSolutions, Ws, Solution).
@@ -1006,3 +1023,19 @@ subsumes_term(General, Specific) :-
). ).
unify_with_occurs_check(X, Y) :- '$unify_with_occurs_check'(X, Y). unify_with_occurs_check(X, Y) :- '$unify_with_occurs_check'(X, Y).
current_input(S) :- '$current_input'(S).
current_output(S) :- '$current_output'(S).
set_input(S) :-
( var(S) ->
throw(error(instantiation_error, set_input/1))
; '$set_input'(S)
).
set_output(S) :-
( var(S) ->
throw(error(instantiation_error, set_output/1))
; '$set_output'(S)
).

39
src/prolog/lib/charsio.pl Normal file
View File

@@ -0,0 +1,39 @@
:- module(charsio, [read_term_from_chars/2,
write_term_to_chars/3]).
:- use_module(library(iso_ext)).
read_term_from_chars(Chars, Term) :-
( var(Chars) ->
throw(error(instantiation_error, read_term_from_chars/2))
; nonvar(Term) ->
throw(error(uninstantiation_error(Term), read_term_from_chars/2))
; '$skip_max_list'(_, -1, Chars, Chars0),
Chars0 == [],
partial_string(Chars) ->
true
;
throw(error(type_error(complete_string, Chars), read_term_from_chars/2))
),
'$read_term_from_chars'(Chars, Term).
write_term_to_chars(_, Options, _) :-
var(Options), throw(error(instantiation_error, write_term_to_chars/3)).
write_term_to_chars(Term, Options, Chars) :-
'$skip_max_list'(_, -1, Options, Options0),
( var(Options0) ->
throw(error(instantiation_error, write_term_to_chars/3))
; nonvar(Chars) ->
throw(error(uninstantiation_error(Chars), write_term_to_chars/3))
; Options0 == [] ->
true
;
throw(error(type_error(list, Options), write_term_to_chars/3))
),
builtins:inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
builtins:inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
builtins:inst_member_or(Options, quoted(Quoted), quoted(false)),
builtins:inst_member_or(Options, variable_names(VarNames), variable_names([])),
builtins:inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
'$write_term_to_chars'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth, Chars).

View File

@@ -30,7 +30,8 @@
:- use_module(library(between)). :- use_module(library(between)).
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
:- use_module(library(pairs)).
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- use_module(library(error), []). :- use_module(library(error), []).
@@ -106,65 +107,10 @@ type_error(Expectation, Term) :-
type_error(Expectation, Term, Goal-Arg) :- type_error(Expectation, Term, Goal-Arg) :-
throw(error(type_error(Expectation, Term), type_error(Goal, Arg, Expectation, Term))). throw(error(type_error(Expectation, Term), type_error(Goal, Arg, Expectation, Term))).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
foldl/4
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
foldl(Goal_3, Ls, A0, A) :-
foldl_(Ls, Goal_3, A0, A).
foldl_([], _, A, A).
foldl_([L|Ls], G_3, A0, A) :-
call(G_3, L, A0, A1),
foldl_(Ls, G_3, A1, A).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
foldl/5
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
foldl(Goal_4, Xs, Ys, A0, A) :-
foldl_(Xs, Ys, Goal_4, A0, A).
foldl_([], [], _, A, A).
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
call(G_4, X, Y, A0, A1),
foldl_(Xs, Ys, G_4, A1, A).
partition(Pred, Ls0, As, Bs) :- partition(Pred, Ls0, As, Bs) :-
include(Pred, Ls0, As), include(Pred, Ls0, As),
exclude(Pred, Ls0, Bs). exclude(Pred, Ls0, Bs).
sum_list(Ls, S) :-
foldl(sum_, Ls, 0, S).
sum_(L, S0, S) :- S is S0 + L.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Pairs.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
pairs_keys_values([], [], []).
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
pairs_keys_values(ABs, As, Bs).
pairs_keys(Ps, Ks) :- pairs_keys_values(Ps, Ks, _).
pairs_values(Ps, Vs) :- pairs_keys_values(Ps, _, Vs).
map_list_to_pairs(Pred, Ls, Ps) :-
map_list_to_pairs2(Ls, Pred, Ps).
map_list_to_pairs2([], _, []).
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
call(Pred, H, K),
map_list_to_pairs2(T0, Pred, T).
goal_expansion(get_attr(Var, Module, Value), (var(Var),get_atts(Var, Access))) :- goal_expansion(get_attr(Var, Module, Value), (var(Var),get_atts(Var, Access))) :-
Access =.. [Module,Value]. Access =.. [Module,Value].
@@ -728,10 +674,6 @@ existential(V, BDD, Node) :-
Counter network for card(Is,Fs). Counter network for card(Is,Fs).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
same_length([], []).
same_length([_|As], [_|Bs]) :-
same_length(As, Bs).
counter_network(Cs, Fs, Node) :- counter_network(Cs, Fs, Node) :-
same_length([_|Fs], Indicators), same_length([_|Fs], Indicators),
fill_indicators(Indicators, 0, Cs), fill_indicators(Indicators, 0, Cs),

7625
src/prolog/lib/clpz.pl Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
:- module(cont, [reset/3, shift/1]). :- module(cont, [reset/3, shift/1]).
reset(Goal, Ball, Cont) :- reset(Goal, Ball, Cont) :-
@@ -7,14 +6,14 @@ reset(Goal, Ball, Cont) :-
'$bind_from_register'(Cont, 3), '$bind_from_register'(Cont, 3),
'$bind_from_register'(Ball, 4). '$bind_from_register'(Ball, 4).
shift(Term) :- shift(Ball) :-
'$nextEP'(first, E, P), '$nextEP'(first, E, P),
get_chunks(E, P, L), get_chunks(E, P, L),
( L == [] -> ( L == [] ->
Cont = none Cont = none
; Cont = cont(call_continuation(L)) ; Cont = cont(call_continuation(L))
), ),
'$write_cont_and_term'(_, _, Cont, Term), '$write_cont_and_term'(_, _, Cont, Ball),
'$unwind_environments'. '$unwind_environments'.
get_chunks(E, P, L) :- get_chunks(E, P, L) :-

View File

@@ -1,7 +1,9 @@
% :- op(1105, xfy, ('|')). :- module(dcgs, [op(1200, xfx, -->),
op(1105, xfy, '|'),
:- module(dcgs, [op(1200, xfx, -->), phrase/2, phrase/3]). phrase/2,
phrase/3]).
:- use_module(library(error)).
:- use_module(library(lists), [append/3]). :- use_module(library(lists), [append/3]).
user:term_expansion(Term0, Term) :- user:term_expansion(Term0, Term) :-
@@ -31,8 +33,8 @@ phrase_((A -> B ; C), S0, S) :-
). ).
phrase_((A ; B), S0, S) :- phrase_((A ; B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ). ( phrase(A, S0, S) ; phrase(B, S0, S) ).
%% phrase_((A | B), S0, S) :- phrase_((A | B), S0, S) :-
%% ( phrase(A, S0, S) ; phrase(B, S0, S) ). ( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_({G}, S0, S) :- phrase_({G}, S0, S) :-
( call(G), S0 = S ). ( call(G), S0 = S ).
phrase_(call(G), S0, S) :- phrase_(call(G), S0, S) :-
@@ -95,7 +97,7 @@ dcg_constr([]). % 7.14.1
dcg_constr([_|_]). % 7.14.2 - terminal sequence dcg_constr([_|_]). % 7.14.2 - terminal sequence
dcg_constr(( _, _ )). % 7.14.3 - concatenation dcg_constr(( _, _ )). % 7.14.3 - concatenation
dcg_constr(( _ ; _ )). % 7.14.4 - alternative dcg_constr(( _ ; _ )). % 7.14.4 - alternative
%% dcg_constr(( _'|'_ )). % 7.14.6 - alternative dcg_constr(( _'|'_ )). % 7.14.6 - alternative
dcg_constr({_}). % 7.14.7 dcg_constr({_}). % 7.14.7
dcg_constr(call(_)). % 7.14.8 dcg_constr(call(_)). % 7.14.8
dcg_constr(phrase(_)). % 7.14.9 dcg_constr(phrase(_)). % 7.14.9
@@ -107,6 +109,7 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
% the construct to be expanded. % the construct to be expanded.
dcg_cbody([], S0, S, S0 = S). dcg_cbody([], S0, S, S0 = S).
dcg_cbody([T|Ts], S0, S, Goal) :- dcg_cbody([T|Ts], S0, S, Goal) :-
must_be(list, [T|Ts]),
dcg_terminals([T|Ts], S0, S, Goal). dcg_terminals([T|Ts], S0, S, Goal).
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :- dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
dcg_body(GRFirst, S0, S1, First), dcg_body(GRFirst, S0, S1, First),
@@ -119,9 +122,9 @@ dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
subsumes_term(( _GRIf -> _GRThen ), GRCond), subsumes_term(( _GRIf -> _GRThen ), GRCond),
dcg_cbody(GRCond, S0, S, Cond), dcg_cbody(GRCond, S0, S, Cond),
dcg_body(GRElse, S0, S, Else). dcg_body(GRElse, S0, S, Else).
%% dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :- dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
%% dcg_body(GREither, S0, S, Either), dcg_body(GREither, S0, S, Either),
%% dcg_body(GROr, S0, S, Or). dcg_body(GROr, S0, S, Or).
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )). dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)). dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)). dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).

481
src/prolog/lib/format.pl Normal file
View File

@@ -0,0 +1,481 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written March 2020 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
This library provides the nonterminal format_//2 to describe
formatted strings. format/2 is provided for impure output.
Usage:
======
phrase(format_(FormatString, Arguments), Ls)
format_//2 describes a list of characters Ls that are formatted
according to FormatString. FormatString is a string (i.e.,
a list of characters) that specifies the layout of Ls.
The characters in FormatString are used literally, except
for the following tokens with special meaning:
~w use the next available argument from Arguments here
~q use the next argument here, formatted as by writeq/1
~a use the next argument here, which must be an atom
~s use the next argument here, which must be a string
~d use the next argument here, which must be an integer
~f use the next argument here, a floating point number
~Nf where N is an integer: format the float argument
using N digits after the decimal point
~Nd like ~d, placing the last N digits after a decimal point;
if N is 0 or omitted, no decimal point is used.
~ND like ~Nd, separating digits to the left of the decimal point
in groups of three, using the character "," (comma)
~N| where N is an integer: place a tab stop at text column N
~N+ where N is an integer: place a tab stop N characters
after the previous tab stop (or start of line)
~t distribute spaces evenly between the two closest tab stops
~`Ct like ~t, use character C instead of spaces to fill the space
~n newline
~Nn N newlines
~i ignore the next argument
~~ the literal ~
Instead of ~N, you can write ~* to use the next argument from Arguments
as the numeric argument.
The predicate format/2 is like format_//2, except that it outputs
the text on the terminal instead of describing it declaratively.
If at all possible, format_//2 should be used, to stress pure parts
that enable easy testing etc. If necessary, you can emit the list Ls
with maplist(write, Ls).
The entire library only works if the Prolog flag double_quotes
is set to chars, the default value in Scryer Prolog. This should
also stay that way, to encourage a sensible environment.
Example:
?- phrase(format_("~s~n~`.t~w!~12|", ["hello",there]), Cs).
%@ Cs = [h,e,l,l,o,'\n','.','.','.','.','.','.',t,h,e,r,e,!]
%@ ; false.
I place this code in the public domain. Use it in any way you want.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(format, [format_//2,
format/2,
portray_clause/1
]).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(error)).
:- use_module(library(charsio)).
format_(Fs, Args) -->
{ must_be(list, Fs),
must_be(list, Args),
phrase(cells(Fs,Args,0,[]), Cells) },
format_cells(Cells).
format_cells([]) --> [].
format_cells([Cell|Cells]) -->
format_cell(Cell),
format_cells(Cells).
format_cell(newline) --> "\n".
format_cell(cell(From,To,Es)) -->
% distribute the space between the glue elements
{ phrase(elements_gluevars(Es, 0, Length), Vs),
( Vs = [] -> true
; Space is To - From - Length,
( Space =< 0 -> maplist(=(0), Vs)
; length(Vs, NumGlue),
Distr is Space // NumGlue,
Delta is Space - Distr*NumGlue,
( Delta =:= 0 ->
maplist(=(Distr), Vs)
; BigGlue is Distr + Delta,
reverse(Vs, [BigGlue|Rest]),
maplist(=(Distr), Rest)
)
)
) },
format_elements(Es).
format_elements([]) --> [].
format_elements([E|Es]) -->
format_element(E),
format_elements(Es).
format_element(chars(Cs)) --> list(Cs).
format_element(glue(Fill,Num)) -->
{ length(Ls, Num),
maplist(=(Fill), Ls) },
list(Ls).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
elements_gluevars([], N, N) --> [].
elements_gluevars([E|Es], N0, N) -->
element_gluevar(E, N0, N1),
elements_gluevars(Es, N1, N).
element_gluevar(chars(Cs), N0, N) -->
{ length(Cs, L),
N is N0 + L }.
element_gluevar(glue(_,V), N, N) --> [V].
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Our key datastructure is a list of cells and newlines.
A cell has the shape from_to(From,To,Elements), where
From and To denote the positions of surrounding tab stops.
Elements is a list of elements that occur in a cell,
namely terms of the form chars(Cs) and glue(Char, Var).
"glue" elements (TeX terminology) are evenly stretched
to fill the remaining whitespace in the cell. For each
glue element, the character Char is used for filling,
and Var is a free variable that is used when the
available space is distributed.
newline is used if ~n occurs in a format string.
It is is used because a newline character does not
consume whitespace in the sense of format strings.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
cells([], Args, Tab, Es) -->
( { Args == [] } -> cell(Tab, Tab, Es)
; { domain_error(no_remaining_arguments, Args) }
).
cells([~,~|Fs], Args, Tab, Es) --> !,
cells(Fs, Args, Tab, [chars("~")|Es]).
cells([~,w|Fs], [Arg|Args], Tab, Es) --> !,
{ write_term_to_chars(Arg, [], Chars) },
cells(Fs, Args, Tab, [chars(Chars)|Es]).
cells([~,q|Fs], [Arg|Args], Tab, Es) --> !,
{ write_term_to_chars(Arg, [quoted(true)], Chars) },
cells(Fs, Args, Tab, [chars(Chars)|Es]).
cells([~,a|Fs], [Arg|Args], Tab, Es) --> !,
{ atom_chars(Arg, Chars) },
cells(Fs, Args, Tab, [chars(Chars)|Es]).
cells([~|Fs0], Args0, Tab, Es) -->
{ numeric_argument(Fs0, Num, [d|Fs], Args0, [Arg|Args]) },
!,
{ number_chars(Arg, Cs0) },
( { Num =:= 0 } -> { Cs = Cs0 }
; { length(Cs0, L),
( L =< Num ->
Delta is Num - L,
length(Zs, Delta),
maplist(=('0'), Zs),
phrase(("0.",list(Zs),list(Cs0)), Cs)
; BeforeComma is L - Num,
length(Bs, BeforeComma),
append(Bs, Ds, Cs0),
phrase((list(Bs),".",list(Ds)), Cs)
) }
),
cells(Fs, Args, Tab, [chars(Cs)|Es]).
cells([~|Fs0], Args0, Tab, Es) -->
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
!,
{ number_chars(Num, NCs),
phrase(("~",list(NCs),"d"), FStr),
phrase(format_(FStr, [Arg]), Cs0),
phrase(upto_what(Bs0, .), Cs0, Ds),
reverse(Bs0, Bs1),
phrase(groups_of_three(Bs1), Bs2),
reverse(Bs2, Bs),
append(Bs, Ds, Cs) },
cells(Fs, Args, Tab, [chars(Cs)|Es]).
cells([~,i|Fs], [_|Args], Tab, Es) --> !,
cells(Fs, Args, Tab, Es).
cells([~,n|Fs], Args, Tab, Es) --> !,
cell(Tab, Tab, Es),
n_newlines(1),
cells(Fs, Args, 0, []).
cells([~|Fs0], Args0, Tab, Es) -->
{ numeric_argument(Fs0, Num, [n|Fs], Args0, Args) },
!,
cell(Tab, Tab, Es),
n_newlines(Num),
cells(Fs, Args, 0, []).
cells([~,s|Fs], [Arg|Args], Tab, Es) --> !,
cells(Fs, Args, Tab, [chars(Arg)|Es]).
cells([~,f|Fs], [Arg|Args], Tab, Es) --> !,
{ number_chars(Arg, Chars) },
cells(Fs, Args, Tab, [chars(Chars)|Es]).
cells([~|Fs0], Args0, Tab, Es) -->
{ numeric_argument(Fs0, Num, [f|Fs], Args0, [Arg|Args]) },
!,
{ number_chars(Arg, Cs0),
phrase(upto_what(Bs, .), Cs0, Cs),
( Num =:= 0 -> Chars = Bs
; ( Cs = ['.'|Rest] ->
length(Rest, L),
( Num < L ->
length(Ds, Num),
append(Ds, _, Rest)
; Num =:= L ->
Ds = Rest
; Num > L,
Delta is Num - L,
% we should look into the float with
% greater accuracy here, and use the
% actual digits instead of 0.
length(Zs, Delta),
maplist(=('0'), Zs),
append(Rest, Zs, Ds)
)
; length(Ds, Num),
maplist(=('0'), Ds)
),
append(Bs, ['.'|Ds], Chars)
) },
cells(Fs, Args, Tab, [chars(Chars)|Es]).
cells([~,'`',Char,t|Fs], Args, Tab, Es) --> !,
cells(Fs, Args, Tab, [glue(Char,_)|Es]).
cells([~,t|Fs], Args, Tab, Es) --> !,
cells(Fs, Args, Tab, [glue(' ',_)|Es]).
cells([~|Fs0], Args0, Tab, Es) -->
{ numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) },
!,
cell(Tab, Num, Es),
cells(Fs, Args, Num, []).
cells([~|Fs0], Args0, Tab0, Es) -->
{ numeric_argument(Fs0, Num, [+|Fs], Args0, Args) },
!,
{ Tab is Tab0 + Num },
cell(Tab0, Tab, Es),
cells(Fs, Args, Tab, []).
cells([~,C|_], _, _, _) -->
{ atom_chars(A, [~,C]),
domain_error(format_string, A) }.
cells(Fs0, Args, Tab, Es) -->
{ phrase(upto_what(Fs1, ~), Fs0, Fs),
Fs1 = [_|_] },
cells(Fs, Args, Tab, [chars(Fs1)|Es]).
domain_error(Type, Term) :-
throw(error(domain_error(Type, Term), _)).
n_newlines(0) --> !.
n_newlines(1) --> !, [newline].
n_newlines(N0) --> { N0 > 1, N is N0 - 1 }, [newline], n_newlines(N).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(upto_what(Cs, ~), "abc~test", Rest).
Cs = [a,b,c], Rest = [~,t,e,s,t].
?- phrase(upto_what(Cs, ~), "abc", Rest).
Cs = [a,b,c], Rest = [].
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
upto_what([], W), [W] --> [W], !.
upto_what([C|Cs], W) --> [C], !, upto_what(Cs, W).
upto_what([], _) --> [].
groups_of_three([A,B,C,D|Rs]) --> !, [A,B,C], ",", groups_of_three([D|Rs]).
groups_of_three(Ls) --> list(Ls).
cell(From, To, Es0) -->
( { Es0 == [] } -> []
; { reverse(Es0, Es) },
[cell(From,To,Es)]
).
%?- numeric_argument("2f", Num, ['f'|Fs], Args0, Args).
%?- numeric_argument("100b", Num, Rs, Args0, Args).
numeric_argument(Ds, Num, Rest, Args0, Args) :-
( Ds = [*|Rest] ->
Args0 = [Num|Args]
; numeric_argument_(Ds, [], Ns, Rest),
foldl(pow10, Ns, 0-0, Num-_),
Args0 = Args
).
numeric_argument_([D|Ds], Ns0, Ns, Rest) :-
( member(D, "0123456789") ->
number_chars(N, [D]),
numeric_argument_(Ds, [N|Ns0], Ns, Rest)
; Ns = Ns0,
Rest = [D|Ds]
).
pow10(D, N0-Pow0, N-Pow) :-
N is N0 + D*10^Pow0,
Pow is Pow0 + 1.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Impure I/O, implemented as a small wrapper over format_//2.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
format(Fs, Args) :-
phrase(format_(Fs, Args), Cs),
maplist(write, Cs).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(cells("hello", [], 0, []), Cs).
?- phrase(cells("hello~10|", [], 0, []), Cs).
?- phrase(cells("~ta~t~10|", [], 0, []), Cs).
?- phrase(format_("~`at~50|", []), Ls).
?- phrase(cells("~`at~50|", [], 0, []), Cs),
phrase(format_cells(Cs), Ls).
?- phrase(cells("~ta~t~tb~tc~21|", [], 0, []), Cs).
Cs = [cell(0,21,[glue(' ',_38),chars([a]),glue(' ',_62),glue(' ',_67),chars([b]),glue(' ',_91),chars([c])])].
?- phrase(cells("~ta~t~4|", [], 0, []), Cs).
Cs = [cell(0,4,[glue(' ',_38),chars([a]),glue(' ',_62)])].
?- phrase(format_cell(cell(0,1,[glue(a,_94)])), Ls).
?- phrase(format_cell(cell(0,50,[chars("hello")])), Ls).
?- phrase(format_("~`at~50|~n", []), Ls).
?- phrase(format_("hello~n~tthere~6|", []), Ls).
?- format("~ta~t~4|", []).
a true
; false.
?- format("~ta~tb~tc~10|", []).
a b ctrue
; false.
?- format("~tabc~3|", []).
?- format("~ta~t~4|", []).
?- format("~ta~t~tb~tc~20|", []).
a b ctrue
; false.
?- format("~2f~n", [3]).
3.00
true
?- format("~20f", [0.1]).
0.10000000000000000000true % this should use higher accuracy!
; false.
?- X is atan(2), format("~7f~n", [X]).
1.1071487
X = 1.1071487177940906
?- format("~`at~50|~n", []).
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
true
?- format("~t~N", []).
?- format("~q", [.]).
'.'true
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
We also provide a rudimentary version of portray_clause/1.
In the eventual library organization, portray_clause/1
and related predicates (such as listing/1) may be placed
in their own dedicated library.
portray_clause/1 is useful for printing solutions in such a way
that they can be read back with read/1.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
portray_clause(Term) :-
phrase(portray_clause_(Term), Ls),
maplist(write, Ls).
portray_clause_(Term) -->
portray_(Term), ".\n".
literal(Lit) --> format_("~q", [Lit]).
portray_(Var) --> { var(Var) }, !, literal(Var).
portray_((Head :- Body)) --> !,
literal(Head), " :-\n",
body_(Body, 0, 8).
portray_((Head --> Body)) --> !,
literal(Head), " -->\n",
body_(Body, 0, 8).
portray_(Any) --> literal(Any).
body_(Var, C, I) --> { var(Var) }, !,
indent_to(C, I),
literal(Var).
body_((A,B), C, I) --> !,
body_(A, C, I), ",\n",
body_(B, 0, I).
body_((A ; Else), C, I) --> % ( If -> Then ; Else )
{ nonvar(A), A = (If -> Then) },
!,
indent_to(C, I),
"( ",
{ C1 is I + 3 },
body_(If, C1, C1), " ->\n",
body_(Then, 0, C1), "\n",
else_branch(Else, C1, I).
body_((A;B), C, I) --> !,
indent_to(C, I),
"( ",
{ C1 is I + 3 },
body_(A, C1, C1), "\n",
else_branch(B, C1, I).
body_(Goal, C, I) -->
indent_to(C, I), literal(Goal).
else_branch(Else, C, I) -->
indent_to(0, I),
";", " ", % (see #336)
body_(Else, C, C), "\n",
indent_to(0, I),
")".
indent_to(CurrentColumn, Indent) -->
{ Delta is Indent - CurrentColumn },
format_("~t~*|", [Delta]).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- portray_clause(a), nl.
a.
?- nl, portray_clause((a :- b)), nl.
a :-
b.
?- nl, portray_clause((a :- b, c, d)), nl.
a :-
b,
c,
d.
?- nl, portray_clause([a,b,c,d]), nl.
"abcd".
?- nl, portray_clause(X).
?- nl, portray_clause((f(X) :- X)).
?- nl, portray_clause((h :- ( a -> b; c))).
?- nl, portray_clause((h :- ( (a -> x ; y) -> b; c))).
?- nl, portray_clause((h(X) :- ( (a(X) ; y(A,B)) -> b; c))).
?- nl, portray_clause((h :- (a,d;b,c) ; (b,e;d))).
?- nl, portray_clause((a :- b ; c ; d)).
?- nl, portray_clause((h :- L = '.')).
?- nl, portray_clause(-->(a, (b, {t}, d))).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

View File

@@ -3,7 +3,7 @@
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
:- use_module(library(si)). :- use_module(library(si)).
gensym_key(Base, BaseKey) :- gensym_key(Base, BaseKey) :-

View File

@@ -1,9 +1,9 @@
%% for builtins that are not part of the ISO standard. %% for builtins that are not part of the ISO standard.
%% must be loaded at the REPL with %% must be loaded at the REPL with
%% ?- use_module(library(non_iso)). %% ?- use_module(library(iso_ext)).
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2, :- module(iso_ext, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
call_with_inference_limit/3, forall/2, maybe/0, call_with_inference_limit/3, forall/2, maybe/0,
partial_string/1, partial_string/3, partial_string/1, partial_string/3,
partial_string_tail/2, set_random/1, partial_string_tail/2, set_random/1,
@@ -157,13 +157,15 @@ set_random(Seed) :-
; throw(error(instantiation_error, set_random/1)) ; throw(error(instantiation_error, set_random/1))
). ).
partial_string(String, L, L0) :- partial_string(String, L, L0) :-
( String == [] -> throw(error(type_error(list, []), partial_string/3)) ( String == [] ->
L = L0
; catch(atom_chars(Atom, String), ; catch(atom_chars(Atom, String),
error(E, _), error(E, _),
throw(error(E, partial_string/3))) throw(error(E, partial_string/3))),
), '$create_partial_string'(Atom, L, L0)
'$create_partial_string'(Atom, L, L0). ).
partial_string(String) :- partial_string(String) :-
'$is_partial_string'(String). '$is_partial_string'(String).

View File

@@ -1,8 +1,8 @@
:- module(lists, [member/2, select/3, append/3, foldl/4, foldl/5, :- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
memberchk/2, reverse/2, length/2, maplist/2, memberchk/2, reverse/2, length/2, maplist/2,
maplist/3, maplist/4, maplist/5, maplist/6, maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, maplist/7, maplist/8, maplist/9, same_length/2,
sumlist/2]). sum_list/2, transpose/2]).
:- use_module(library(error)). :- use_module(library(error)).
@@ -44,6 +44,12 @@ select(X, [X|Xs], Xs).
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys). select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
append([], []).
append([L0|Ls0], Ls) :-
append(L0, Rest, Ls),
append(Ls0, Rest).
append([], R, R). append([], R, R).
append([X|L], R, [X|S]) :- append(L, R, S). append([X|L], R, [X|S]) :- append(L, R, S).
@@ -102,14 +108,10 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s, E8s). maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s, E8s).
sumlist_([], S, S). sum_list(Ls, S) :-
sumlist_([N|Ns], S, S0) :- foldl(sum_, Ls, 0, S).
S1 is S0 + N,
sumlist_(Ns, S, S1).
sumlist(Ns, S) :- sum_(L, S0, S) :- S is S0 + L.
must_be(list, Ns),
sumlist_(Ns, S, 0).
@@ -134,3 +136,16 @@ foldl_([], [], _, A, A).
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :- foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
call(G_4, X, Y, A0, A1), call(G_4, X, Y, A0, A1),
foldl_(Xs, Ys, G_4, A1, A). foldl_(Xs, Ys, G_4, A1, A).
transpose(Ls, Ts) :-
lists_transpose(Ls, Ts).
lists_transpose([], []).
lists_transpose([L|Ls], Ts) :-
maplist(same_length(L), Ls),
foldl(transpose_, L, Ts, [L|Ls], _).
transpose_(_, Fs, Lists0, Lists) :-
maplist(list_first_rest, Lists0, Fs, Lists).
list_first_rest([L|Ls], L, Ls).

21
src/prolog/lib/pairs.pl Normal file
View File

@@ -0,0 +1,21 @@
:- module(pairs, [pairs_keys_values/3,
pairs_keys/2,
pairs_values/2,
map_list_to_pairs/3]).
pairs_keys_values([], [], []).
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
pairs_keys_values(ABs, As, Bs).
pairs_keys(Ps, Ks) :- pairs_keys_values(Ps, Ks, _).
pairs_values(Ps, Vs) :- pairs_keys_values(Ps, _, Vs).
map_list_to_pairs(Pred, Ls, Ps) :-
map_list_to_pairs2(Ls, Pred, Ps).
map_list_to_pairs2([], _, []).
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
call(Pred, H, K),
map_list_to_pairs2(T0, Pred, T).

View File

@@ -18,7 +18,7 @@
:- use_module(library(cont)). :- use_module(library(cont)).
:- use_module(library(lists)). :- use_module(library(lists)).
%:- use_module(library(debug)). %:- use_module(library(debug)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
%% :- meta_predicate %% :- meta_predicate
%% start_tabling(+, 0). %% start_tabling(+, 0).

View File

@@ -208,4 +208,3 @@ dll_get_reverse_contents_(List, Contents) :-
dll_get_pointer_to_previous(List, Prev), dll_get_pointer_to_previous(List, Prev),
dll_get_reverse_contents_(Prev, Rest) dll_get_reverse_contents_(Prev, Rest)
). ).

View File

@@ -9,7 +9,7 @@
]). ]).
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
:- attribute table_global_worklist/1. :- attribute table_global_worklist/1.

View File

@@ -57,7 +57,7 @@
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(gensym)). :- use_module(library(gensym)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
:- attribute table_status/1, newly_created_table_identifiers/1. :- attribute table_status/1, newly_created_table_identifiers/1.

View File

@@ -44,7 +44,7 @@
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
:- use_module(library(terms)). :- use_module(library(terms)).
:- use_module(trie). :- use_module(trie).

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
driver(Vars, Values) :- driver(Vars, Values) :-
iterate(Vars, Values, ListOfListsOfGoalLists), iterate(Vars, Values, ListOfListsOfGoalLists),
'$clear_attr_var_bindings',
!, !,
call_goals(ListOfListsOfGoalLists), call_goals(ListOfListsOfGoalLists),
'$return_from_verify_attr'. '$return_from_verify_attr'.
@@ -17,13 +16,6 @@ gather_modules([Attr|Attrs], [Module|Modules]) :-
'$module_of'(Module, Attr), % write the owning module of Attr to Module. '$module_of'(Module, Attr), % write the owning module of Attr to Module.
gather_modules(Attrs, Modules). gather_modules(Attrs, Modules).
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
catch(Module:verify_attributes(Var, Value, Goals),
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
Goals = []),
verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([], _, _, []).
call_verify_attributes(Attrs, _, _, []) :- call_verify_attributes(Attrs, _, _, []) :-
var(Attrs), !. var(Attrs), !.
call_verify_attributes([], _, _, []). call_verify_attributes([], _, _, []).
@@ -32,6 +24,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
sort(Modules0, Modules), sort(Modules0, Modules),
verify_attrs(Modules, Var, Value, ListOfGoalLists). verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
catch(Module:verify_attributes(Var, Value, Goals),
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
Goals = []),
verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([], _, _, []).
call_goals([ListOfGoalLists | ListsCubed]) :- call_goals([ListOfGoalLists | ListsCubed]) :-
call_goals_0(ListOfGoalLists), call_goals_0(ListOfGoalLists),
call_goals(ListsCubed). call_goals(ListsCubed).

View File

@@ -1,5 +1,6 @@
use crate::prolog::machine::*; use crate::prolog::machine::*;
use std::cmp::Ordering;
use std::vec::IntoIter; use std::vec::IntoIter;
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl"); pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
@@ -18,7 +19,8 @@ pub(super) struct AttrVarInitializer {
} }
impl AttrVarInitializer { impl AttrVarInitializer {
pub(super) fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self { pub(super)
fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
AttrVarInitializer { AttrVarInitializer {
attribute_goals: vec![], attribute_goals: vec![],
attr_var_queue: vec![], attr_var_queue: vec![],
@@ -31,21 +33,24 @@ impl AttrVarInitializer {
} }
#[inline] #[inline]
pub(super) fn reset(&mut self) { pub(super)
fn reset(&mut self) {
self.attribute_goals.clear(); self.attribute_goals.clear();
self.attr_var_queue.clear(); self.attr_var_queue.clear();
self.bindings.clear(); self.bindings.clear();
} }
#[inline] #[inline]
pub(super) fn backtrack(&mut self, queue_b: usize, bindings_b: usize) { pub(super)
fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
self.attr_var_queue.truncate(queue_b); self.attr_var_queue.truncate(queue_b);
self.bindings.truncate(bindings_b); self.bindings.truncate(bindings_b);
} }
} }
impl MachineState { impl MachineState {
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) { pub(super)
fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
if self.attr_var_init.bindings.is_empty() { if self.attr_var_init.bindings.is_empty() {
self.attr_var_init.instigating_p = self.p.local(); self.attr_var_init.instigating_p = self.p.local();
@@ -66,18 +71,17 @@ impl MachineState {
.attr_var_init .attr_var_init
.bindings .bindings
.iter() .iter()
.map(|(ref h, _)| Addr::AttrVar(*h)); .map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
let iter = self let iter = self
.attr_var_init .attr_var_init
.bindings .bindings
.iter() .drain(0 ..)
.map(|(_, ref addr)| addr.clone()); .map(|(_, addr)| HeapCellValue::Addr(addr));
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
(var_list_addr, value_list_addr) (var_list_addr, value_list_addr)
} }
@@ -92,7 +96,8 @@ impl MachineState {
self[temp_v!(2)] = value_list_addr; self[temp_v!(2)] = value_list_addr;
} }
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> { pub(super)
fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..] let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
.iter() .iter()
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) { .filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
@@ -101,13 +106,16 @@ impl MachineState {
}) })
.collect(); .collect();
attr_vars.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); attr_vars.sort_unstable_by(|a1, a2| {
self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
});
self.term_dedup(&mut attr_vars); self.term_dedup(&mut attr_vars);
attr_vars.into_iter() attr_vars.into_iter()
} }
pub(super) fn verify_attr_interrupt(&mut self, p: usize) { pub(super)
fn verify_attr_interrupt(&mut self, p: usize) {
self.allocate(self.num_of_args + 2); self.allocate(self.num_of_args + 2);
let e = self.e; let e = self.e;
@@ -118,9 +126,9 @@ impl MachineState {
} }
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
Addr::Con(Constant::CutPoint(self.b0)); Addr::CutPoint(self.b0);
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
Addr::Con(Constant::Usize(self.num_of_args)); Addr::Usize(self.num_of_args);
self.verify_attributes(); self.verify_attributes();

View File

@@ -21,7 +21,6 @@ use ref_thread_local::RefThreadLocal;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::File; use std::fs::File;
use std::io::Read;
use std::mem; use std::mem;
use std::path::PathBuf; use std::path::PathBuf;
@@ -60,9 +59,9 @@ fn fix_filename(
Ok(path) Ok(path)
} }
fn load_module<R: Read>( fn load_module(
wam: &mut Machine, wam: &mut Machine,
stream: ParsingStream<R>, stream: Stream,
suppress_warnings: bool, suppress_warnings: bool,
listing_src: &ListingSource, listing_src: &ListingSource,
) -> Result<ClauseName, SessionError> { ) -> Result<ClauseName, SessionError> {
@@ -78,7 +77,11 @@ fn load_module<R: Read>(
listing_src.clone(), listing_src.clone(),
); );
let results = compiler.gather_items(wam, stream, &mut indices); let results = compiler.gather_items(
wam,
&mut parsing_stream(stream),
&mut indices,
);
let module_name = if let Some(ref module) = &compiler.module { let module_name = if let Some(ref module) = &compiler.module {
module.module_decl.name.clone() module.module_decl.name.clone()
@@ -114,14 +117,14 @@ fn load_module_from_file(
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?; let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl); let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
let file_handle = File::open(&path_buf).or_else(|_| { let file_handle = Stream::from(File::open(&path_buf).or_else(|_| {
Err(SessionError::InvalidFileName(filename.clone())) Err(SessionError::InvalidFileName(filename.clone()))
})?; })?);
path_buf.pop(); path_buf.pop();
let listing_src = ListingSource::from_file_and_path(filename, path_buf); let listing_src = ListingSource::from_file_and_path(filename, path_buf);
load_module(wam, parsing_stream(file_handle), suppress_warnings, &listing_src) load_module(wam, file_handle, suppress_warnings, &listing_src)
} }
pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>); pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
@@ -320,10 +323,11 @@ fn setup_module_expansions(wam: &mut Machine, module: &Module) {
); );
} }
pub(super) fn compile_into_module<R: Read>( pub(super)
fn compile_into_module(
wam: &mut Machine, wam: &mut Machine,
module_name: ClauseName, module_name: ClauseName,
src: ParsingStream<R>, src: Stream,
name: ClauseName, name: ClauseName,
) -> EvalSession { ) -> EvalSession {
let mut indices = default_index_store!(wam.atom_tbl_of(&name)); let mut indices = default_index_store!(wam.atom_tbl_of(&name));
@@ -333,7 +337,11 @@ pub(super) fn compile_into_module<R: Read>(
indices.op_dir = module.op_dir.clone(); indices.op_dir = module.op_dir.clone();
indices.atom_tbl = module.atom_tbl.clone(); indices.atom_tbl = module.atom_tbl.clone();
let mut compiler = ListingCompiler::new(&wam.code_repo, true, module.listing_src.clone()); let mut compiler = ListingCompiler::new(
&wam.code_repo,
true,
module.listing_src.clone(),
);
match compile_into_module_impl(wam, &mut compiler, module, src, indices) { match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
Ok(()) => EvalSession::EntrySuccess, Ok(()) => EvalSession::EntrySuccess,
@@ -348,11 +356,11 @@ pub(super) fn compile_into_module<R: Read>(
} }
} }
fn compile_into_module_impl<R: Read>( fn compile_into_module_impl(
wam: &mut Machine, wam: &mut Machine,
compiler: &mut ListingCompiler, compiler: &mut ListingCompiler,
module: Module, module: Module,
src: ParsingStream<R>, src: Stream,
mut indices: IndexStore, mut indices: IndexStore,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
setup_module_expansions(wam, &module); setup_module_expansions(wam, &module);
@@ -363,7 +371,11 @@ fn compile_into_module_impl<R: Read>(
wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?; wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?; wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
let mut results = compiler.gather_items(wam, src, &mut indices)?; let mut results = compiler.gather_items(
wam,
&mut parsing_stream(src),
&mut indices,
)?;
compiler.adapt_in_situ_code( compiler.adapt_in_situ_code(
results.worker_results, results.worker_results,
@@ -392,7 +404,6 @@ fn compile_into_module_impl<R: Read>(
); );
wam.code_repo.code.extend(results.in_situ_code.into_iter()); wam.code_repo.code.extend(results.in_situ_code.into_iter());
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map); clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
Ok(compiler.drop_expansions(&mut wam.code_repo)) Ok(compiler.drop_expansions(&mut wam.code_repo))
@@ -548,8 +559,8 @@ fn add_module(
term_dir: TermDir, term_dir: TermDir,
) { ) {
module.code_dir.extend(indices.code_dir); module.code_dir.extend(indices.code_dir);
module.op_dir.extend(indices.op_dir.into_iter()); module.op_dir.extend(indices.op_dir);
module.term_dir.extend(term_dir.into_iter()); module.term_dir.extend(term_dir);
wam.add_in_situ_module_dir(indices.module_dir); wam.add_in_situ_module_dir(indices.module_dir);
wam.add_module(module); wam.add_module(module);
@@ -568,7 +579,7 @@ fn add_non_module_code(
clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?; clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
add_toplevel(wam, indices, term_dir); add_toplevel(wam, indices, term_dir);
wam.code_repo.code.extend(code.into_iter()); wam.code_repo.code.extend(code);
clause_code_generator.add_clause_code(wam, dynamic_clause_map); clause_code_generator.add_clause_code(wam, dynamic_clause_map);
Ok(()) Ok(())
@@ -591,12 +602,18 @@ fn load_library(
load_module( load_module(
wam, wam,
parsing_stream(code.as_bytes()), Stream::from(*code),
suppress_warnings, suppress_warnings,
&listing_src, &listing_src,
) )
} }
None => Err(SessionError::ModuleNotFound) None => {
let err = ExistenceError::SourceSink(ModuleSource::Library(
name.clone()
));
Err(SessionError::ExistenceError(err))
}
} }
} }
@@ -682,7 +699,11 @@ impl ListingCompiler {
Ok(wam_indices.insert_module(submodule)) Ok(wam_indices.insert_module(submodule))
} else { } else {
Err(SessionError::ModuleNotFound) let err = ExistenceError::SourceSink(ModuleSource::File(
module_name,
));
Err(SessionError::ExistenceError(err))
} }
} }
@@ -716,7 +737,11 @@ impl ListingCompiler {
Ok(wam_indices.insert_module(submodule)) Ok(wam_indices.insert_module(submodule))
} else { } else {
Err(SessionError::ModuleNotFound) let err = ExistenceError::SourceSink(ModuleSource::File(
module_name
));
Err(SessionError::ExistenceError(err))
} }
} }
@@ -968,6 +993,10 @@ impl ListingCompiler {
Declaration::Op(op_decl) => { Declaration::Op(op_decl) => {
self.submit_op(wam, indices, &op_decl) self.submit_op(wam, indices, &op_decl)
} }
Declaration::SetPrologFlag(dbl_quotes) => {
wam.machine_st.flags.double_quotes = dbl_quotes;
Ok(())
}
Declaration::UseModule(ModuleSource::Library(name)) => { Declaration::UseModule(ModuleSource::Library(name)) => {
let name = if !wam.indices.modules.contains_key(&name) { let name = if !wam.indices.modules.contains_key(&name) {
load_library(wam, name, true)? load_library(wam, name, true)?
@@ -1018,10 +1047,10 @@ impl ListingCompiler {
} }
} }
fn setup_multifile_decl<R: Read>( fn setup_multifile_decl(
&self, &self,
indicator: MultiFileIndicator, indicator: MultiFileIndicator,
worker: &mut TopLevelBatchWorker<R>, worker: &mut TopLevelBatchWorker,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
match indicator { match indicator {
MultiFileIndicator::LocalScoped(name, arity) => { MultiFileIndicator::LocalScoped(name, arity) => {
@@ -1042,7 +1071,11 @@ impl ListingCompiler {
insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs); insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
} }
None => { None => {
return Err(SessionError::ModuleNotFound); let err = ExistenceError::SourceSink(ModuleSource::File(
module_name,
));
return Err(SessionError::ExistenceError(err));
} }
} }
} }
@@ -1051,10 +1084,10 @@ impl ListingCompiler {
Ok(()) Ok(())
} }
fn process_and_commit_decl<R: Read>( fn process_and_commit_decl(
&mut self, &mut self,
decl: Declaration, decl: Declaration,
worker: &mut TopLevelBatchWorker<R>, worker: &mut TopLevelBatchWorker,
indices: &mut IndexStore, indices: &mut IndexStore,
flags: MachineFlags, flags: MachineFlags,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
@@ -1101,15 +1134,15 @@ impl ListingCompiler {
result result
} }
pub(crate) fn gather_items<R: Read>( pub(crate) fn gather_items(
&mut self, &mut self,
wam: &mut Machine, wam: &mut Machine,
mut src: ParsingStream<R>, src: &mut ParsingStream<Stream>,
indices: &mut IndexStore, indices: &mut IndexStore,
) -> Result<GatherResult, SessionError> { ) -> Result<GatherResult, SessionError> {
let flags = wam.machine_flags(); let flags = wam.machine_flags();
let atom_tbl = indices.atom_tbl.clone(); let atom_tbl = indices.atom_tbl.clone();
let mut worker = TopLevelBatchWorker::new(&mut src, atom_tbl.clone(), flags, wam); let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags, wam);
let mut toplevel_results = vec![]; let mut toplevel_results = vec![];
let mut toplevel_indices = default_index_store!(atom_tbl.clone()); let mut toplevel_indices = default_index_store!(atom_tbl.clone());
@@ -1302,28 +1335,32 @@ fn compile_work_impl(
Ok(()) Ok(())
} }
fn compile_work<R: Read>( fn compile_work(
compiler: &mut ListingCompiler, compiler: &mut ListingCompiler,
wam: &mut Machine, wam: &mut Machine,
src: ParsingStream<R>, src: Stream,
mut indices: IndexStore, mut indices: IndexStore,
) -> EvalSession { ) -> EvalSession {
let src = &mut parsing_stream(src);
let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices)); let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
try_eval_session!(compile_work_impl(compiler, wam, indices, results)); try_eval_session!(compile_work_impl(compiler, wam, indices, results));
EvalSession::EntrySuccess EvalSession::EntrySuccess
} }
/* This is a truncated version of compile_user_module, used for /* This is a truncated version of compile_user_module, used for
compiling code composing special forms, ie. the code that calls compiling code composing special forms, ie. the code that calls
M:verify_attributes on attributed variables. */ M:verify_attributes on attributed variables. */
pub fn compile_special_form<R: Read>( pub fn compile_special_form(
wam: &mut Machine, wam: &mut Machine,
src: ParsingStream<R>, src: Stream,
listing_src: ListingSource, listing_src: ListingSource,
) -> Result<usize, SessionError> { ) -> Result<usize, SessionError> {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
setup_indices(wam, clause_name!("builtins"), &mut indices)?; setup_indices(wam, clause_name!("builtins"), &mut indices)?;
let src = &mut parsing_stream(src);
let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src); let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src);
let mut results = compiler.gather_items(wam, src, &mut indices)?; let mut results = compiler.gather_items(wam, src, &mut indices)?;
@@ -1348,9 +1385,9 @@ pub fn compile_special_form<R: Read>(
} }
#[inline] #[inline]
pub fn compile_listing<R: Read>( pub fn compile_listing(
wam: &mut Machine, wam: &mut Machine,
src: ParsingStream<R>, src: Stream,
indices: IndexStore, indices: IndexStore,
suppress_warnings: bool, suppress_warnings: bool,
listing_src: ListingSource, listing_src: ListingSource,
@@ -1373,20 +1410,24 @@ pub(super) fn setup_indices(
module: ClauseName, module: ClauseName,
indices: &mut IndexStore, indices: &mut IndexStore,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
if let Some(module) = wam.indices.take_module(module) { if let Some(module) = wam.indices.take_module(module.clone()) {
let flags = wam.machine_flags(); let flags = wam.machine_flags();
let result = indices.use_module(&mut wam.code_repo, flags, &module); let result = indices.use_module(&mut wam.code_repo, flags, &module);
wam.indices.insert_module(module); wam.indices.insert_module(module);
result result
} else { } else {
Err(SessionError::ModuleNotFound) let err = ExistenceError::SourceSink(ModuleSource::Library(
module
));
Err(SessionError::ExistenceError(err))
} }
} }
pub fn compile_user_module<R: Read>( pub fn compile_user_module(
wam: &mut Machine, wam: &mut Machine,
src: ParsingStream<R>, src: Stream,
suppress_warnings: bool, suppress_warnings: bool,
listing_src: ListingSource, listing_src: ListingSource,
) -> EvalSession { ) -> EvalSession {

View File

@@ -1,6 +1,8 @@
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::stack::*; use crate::prolog::machine::stack::*;
use crate::prolog::machine::streams::*;
use std::mem;
use std::ops::IndexMut; use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>; type Trail = Vec<(Ref, HeapCellValue)>;
@@ -11,12 +13,13 @@ pub enum AttrVarPolicy {
StripAttributes StripAttributes
} }
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> { pub(crate)
fn threshold(&self) -> usize; trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
fn push(&mut self, val: HeapCellValue);
fn store(&self, val: Addr) -> Addr;
fn deref(&self, val: Addr) -> Addr; fn deref(&self, val: Addr) -> Addr;
fn push(&mut self, val: HeapCellValue);
fn stack(&mut self) -> &mut Stack; fn stack(&mut self) -> &mut Stack;
fn store(&self, val: Addr) -> Addr;
fn threshold(&self) -> usize;
} }
pub(crate) pub(crate)
@@ -30,13 +33,13 @@ struct CopyTermState<T: CopierTarget> {
scan: usize, scan: usize,
old_h: usize, old_h: usize,
target: T, target: T,
attr_var_policy: AttrVarPolicy attr_var_policy: AttrVarPolicy,
} }
impl<T: CopierTarget> CopyTermState<T> { impl<T: CopierTarget> CopyTermState<T> {
fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self { fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self {
CopyTermState { CopyTermState {
trail: vec![], trail: Trail::new(),
scan: 0, scan: 0,
old_h: target.threshold(), old_h: target.threshold(),
target, target,
@@ -50,152 +53,99 @@ impl<T: CopierTarget> CopyTermState<T> {
&mut self.target[scan] &mut self.target[scan]
} }
fn copied_list(&mut self, addr: usize) -> bool { fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
match &self.target[addr] { let trail_item = mem::replace(
HeapCellValue::Addr(Addr::Lis(addr)) | HeapCellValue::Addr(Addr::HeapCell(addr)) => { &mut self.target[addr],
if *addr >= self.old_h { HeapCellValue::Addr(Addr::Lis(threshold)),
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(*addr)); );
self.scan += 1;
return true;
}
}
_ => {}
};
false self.trail.push((
} Ref::HeapCell(addr),
trail_item,
fn copied_partial_string(&mut self, addr: usize) -> bool { ));
if let HeapCellValue::PartialString(ref pstr) = &self.target[addr] {
if let Addr::PStrLocation(h, n) = pstr.tail_addr() {
if *h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(*h, *n));
self.scan += 1;
return true;
}
}
}
false
} }
fn copy_list(&mut self, addr: usize) { fn copy_list(&mut self, addr: usize) {
if self.copied_list(addr) { for offset in 0 .. 2 {
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
self.scan += 1;
return; return;
} }
}
}
let threshold = self.target.threshold(); let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
let ra = self.target[addr].as_addr(threshold); for i in 0 .. 2 {
let rd = self.target.store(self.target.deref(ra.clone())); let hcv = self.target[addr + i].context_free_clone();
self.target.push(HeapCellValue::Addr(ra.clone()));
let hcv = HeapCellValue::Addr(self.target[addr + 1].as_addr(addr + 1));
self.target.push(hcv); self.target.push(hcv);
match rd.clone() {
Addr::AttrVar(h) | Addr::HeapCell(h) | Addr::PStrTail(h, _)
if h >= self.old_h => {
self.target[threshold] = HeapCellValue::Addr(rd)
} }
var @ Addr::AttrVar(_)
| var @ Addr::HeapCell(..)
| var @ Addr::StackCell(..)
| var @ Addr::PStrTail(..) => {
if ra == rd {
self.reinstantiate_var(var, threshold);
if let AttrVarPolicy::StripAttributes = self.attr_var_policy { let cdr = self.target.store(self.target.deref(Addr::HeapCell(addr + 1)));
self.trail.push((Ref::HeapCell(addr), HeapCellValue::Addr(ra)));
self.target[addr] = HeapCellValue::Addr(Addr::HeapCell(threshold)); if !cdr.is_ref() {
} self.trail_list_cell(addr + 1, threshold);
} else { } else {
self.target[threshold] = HeapCellValue::Addr(ra); let car = self.target.store(self.target.deref(Addr::HeapCell(addr)));
}
}
_ => {
self.trail.push((
Ref::HeapCell(addr),
HeapCellValue::Addr(self.target[addr].as_addr(addr)),
));
self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold)) if !car.is_ref() {
self.trail_list_cell(addr, threshold);
}
} }
};
self.scan += 1; self.scan += 1;
} }
fn copy_partial_string(&mut self, addr: usize, n: usize) { fn copy_partial_string(&mut self, addr: usize, n: usize) {
let threshold = self.target.threshold(); if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n));
self.scan += 1;
let tail_addr =
match &self.target[addr] {
HeapCellValue::PartialString(ref pstr) => {
self.trail.push((
Ref::PStrTail(addr, 0),
HeapCellValue::Addr(pstr.tail.clone()),
));
self.target.store(self.target.deref(pstr.tail.clone()))
}
_ => {
unreachable!()
}
};
let pstr =
match &mut self.target[addr] {
HeapCellValue::PartialString(ref mut pstr) => {
let mut new_pstr = pstr.clone_from_offset(n);
if let Addr::PStrTail(h, n) = &tail_addr {
new_pstr.tail = if *h == addr {
Addr::PStrTail(threshold, *n)
} else {
Addr::HeapCell(threshold + 1)
};
} else {
new_pstr.tail = Addr::HeapCell(threshold + 1);
}
pstr.tail = Addr::PStrLocation(threshold, 0);
new_pstr
}
_ => {
unreachable!()
}
};
match tail_addr {
Addr::PStrTail(h, _) if h == addr => {
self.target.push(HeapCellValue::PartialString(pstr));
}
addr => {
self.target.push(HeapCellValue::PartialString(pstr));
self.target.push(HeapCellValue::Addr(addr));
}
}
}
fn copy_partial_string_from(&mut self, addr: usize, n: usize) {
if self.copied_partial_string(addr) {
return; return;
} }
}
let threshold = self.target.threshold(); let threshold = self.target.threshold();
self.target[self.scan] = *self.value_at_scan() =
HeapCellValue::Addr(Addr::PStrLocation(threshold, n)); HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
self.scan += 1; self.scan += 1;
self.copy_partial_string(addr, n); let (pstr, has_tail) =
match &self.target[addr] {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
(pstr.clone_from_offset(n), has_tail)
}
_ => {
unreachable!()
}
};
self.target.push(HeapCellValue::PartialString(pstr, has_tail));
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
let trail_item = mem::replace(
&mut self.target[addr],
replacement,
);
self.trail.push((
Ref::HeapCell(addr),
trail_item,
));
if has_tail {
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
self.target.push(HeapCellValue::Addr(tail_addr));
}
} }
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) { fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
@@ -203,6 +153,7 @@ impl<T: CopierTarget> CopyTermState<T> {
Addr::HeapCell(h) => { Addr::HeapCell(h) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier)); self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.trail.push(( self.trail.push((
Ref::HeapCell(h), Ref::HeapCell(h),
HeapCellValue::Addr(Addr::HeapCell(h)), HeapCellValue::Addr(Addr::HeapCell(h)),
@@ -211,27 +162,12 @@ impl<T: CopierTarget> CopyTermState<T> {
Addr::StackCell(fr, sc) => { Addr::StackCell(fr, sc) => {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier); self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
self.trail.push(( self.trail.push((
Ref::StackCell(fr, sc), Ref::StackCell(fr, sc),
HeapCellValue::Addr(Addr::StackCell(fr, sc)), HeapCellValue::Addr(Addr::StackCell(fr, sc)),
)); ));
} }
Addr::PStrTail(h, n) => {
match &mut self.target[h] {
HeapCellValue::PartialString(ref mut pstr) => {
pstr.tail = Addr::PStrTail(frontier, n);
}
_ => {
unreachable!()
}
}
self.target[frontier] = HeapCellValue::Addr(Addr::PStrTail(frontier, n));
self.trail.push((
Ref::PStrTail(h, n),
HeapCellValue::Addr(Addr::PStrTail(h, n))
));
}
Addr::AttrVar(h) => { Addr::AttrVar(h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy { let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.threshold() self.target.threshold()
@@ -241,6 +177,7 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold)); self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
self.trail.push(( self.trail.push((
Ref::AttrVar(h), Ref::AttrVar(h),
HeapCellValue::Addr(Addr::AttrVar(h)), HeapCellValue::Addr(Addr::AttrVar(h)),
@@ -249,18 +186,20 @@ impl<T: CopierTarget> CopyTermState<T> {
if let AttrVarPolicy::DeepCopy = self.attr_var_policy { if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold))); self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
let list_val = self.target[h + 1].clone(); let list_val = self.target[h + 1].context_free_clone();
self.target.push(list_val); self.target.push(list_val);
} }
} }
_ => unreachable!() _ => {
unreachable!()
}
} }
} }
fn copy_var(&mut self, addr: Addr) { fn copy_var(&mut self, addr: Addr) {
let rd = self.target.store(self.target.deref(addr.clone())); let rd = self.target.store(self.target.deref(addr));
match rd.clone() { match rd {
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
*self.value_at_scan() = HeapCellValue::Addr(rd); *self.value_at_scan() = HeapCellValue::Addr(rd);
self.scan += 1; self.scan += 1;
@@ -275,30 +214,54 @@ impl<T: CopierTarget> CopyTermState<T> {
} }
} }
fn copy_stream(&mut self, addr: usize) {
let threshold = self.target.threshold();
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Stream(threshold)),
);
self.trail.push((
Ref::HeapCell(addr),
trail_item,
));
self.target.push(HeapCellValue::Stream(Stream::null_stream()));
self.scan += 1;
}
fn copy_structure(&mut self, addr: usize) { fn copy_structure(&mut self, addr: usize) {
match self.target[addr].clone() { match self.target[addr].context_free_clone() {
HeapCellValue::NamedStr(arity, name, fixity) => { HeapCellValue::NamedStr(arity, name, fixity) => {
let threshold = self.target.threshold(); let threshold = self.target.threshold();
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold)); *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
self.target[addr] = HeapCellValue::Addr(Addr::Str(threshold));
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Str(threshold)),
);
self.trail.push(( self.trail.push((
Ref::HeapCell(addr), Ref::HeapCell(addr),
HeapCellValue::NamedStr(arity, name.clone(), fixity.clone()), trail_item,
)); ));
self.target.push(HeapCellValue::NamedStr(arity, name, fixity)); self.target.push(HeapCellValue::NamedStr(arity, name, fixity));
for i in 0..arity { for i in 0..arity {
let hcv = self.target[addr + 1 + i].clone(); let hcv = self.target[addr + 1 + i].context_free_clone();
self.target.push(hcv); self.target.push(hcv);
} }
} }
HeapCellValue::Addr(Addr::Str(addr)) => { HeapCellValue::Addr(Addr::Str(addr)) => {
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr)) *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
} }
_ => {} _ => {
unreachable!()
}
} }
self.scan += 1; self.scan += 1;
@@ -310,32 +273,43 @@ impl<T: CopierTarget> CopyTermState<T> {
while self.scan < self.target.threshold() { while self.scan < self.target.threshold() {
match self.value_at_scan() { match self.value_at_scan() {
HeapCellValue::NamedStr(..) => { &mut HeapCellValue::Addr(addr) => {
match addr {
Addr::Con(h) => {
let addr = self.target[h].as_addr(h);
if addr == Addr::Con(h) {
*self.value_at_scan() = self.target[h].context_free_clone();
} else {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
Addr::Lis(h) if h >= self.old_h => {
self.scan += 1; self.scan += 1;
} }
HeapCellValue::Addr(ref addr) => { Addr::Lis(h) => {
match addr.clone() { self.copy_list(h);
Addr::Lis(addr) => {
self.copy_list(addr);
} }
addr @ Addr::AttrVar(_) addr @ Addr::AttrVar(_) |
| addr @ Addr::HeapCell(_) addr @ Addr::HeapCell(_) |
| addr @ Addr::StackCell(..) addr @ Addr::StackCell(..) => {
| addr @ Addr::PStrTail(..) => {
self.copy_var(addr); self.copy_var(addr);
} }
Addr::Str(addr) => { Addr::Str(addr) => {
self.copy_structure(addr); self.copy_structure(addr);
} }
Addr::PStrLocation(addr, n) => { Addr::PStrLocation(addr, n) => {
self.copy_partial_string_from(addr, n); self.copy_partial_string(addr, n);
} }
Addr::Con(_) | Addr::DBRef(_) => { Addr::Stream(h) => {
self.copy_stream(h);
}
_ => {
self.scan += 1; self.scan += 1;
} }
} }
} }
HeapCellValue::PartialString(_) => { _ => {
self.scan += 1; self.scan += 1;
} }
} }
@@ -349,10 +323,6 @@ impl<T: CopierTarget> CopyTermState<T> {
match r { match r {
Ref::AttrVar(h) | Ref::HeapCell(h) => Ref::AttrVar(h) | Ref::HeapCell(h) =>
self.target[h] = value, self.target[h] = value,
Ref::PStrTail(h, _) =>
if let HeapCellValue::PartialString(ref mut pstr) = &mut self.target[h] {
pstr.tail = value.as_addr(0);
},
Ref::StackCell(fr, sc) => Ref::StackCell(fr, sc) =>
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0), self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0),
} }

View File

@@ -1,11 +1,12 @@
use prolog_parser::ast::*; use prolog_parser::ast::*;
use crate::prolog::heap_print::*; use crate::prolog::heap_print::*;
use crate::prolog::machine::*;
use crate::prolog::machine::compile::*; use crate::prolog::machine::compile::*;
use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::*; use crate::prolog::machine::streams::*;
use std::io::Read; use std::convert::TryFrom;
impl Machine { impl Machine {
pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> { pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
@@ -15,9 +16,9 @@ impl Machine {
} }
} }
fn compile_into_machine<R: Read>( fn compile_into_machine(
&mut self, &mut self,
src: ParsingStream<R>, src: Stream,
name: ClauseName, name: ClauseName,
arity: usize, arity: usize,
) -> EvalSession { ) -> EvalSession {
@@ -42,13 +43,35 @@ impl Machine {
let arity = self.machine_st[arity].clone(); let arity = self.machine_st[arity].clone();
let name = match self.machine_st.store(self.machine_st.deref(name)) { let name = match self.machine_st.store(self.machine_st.deref(name)) {
Addr::Con(Constant::Atom(name, _)) => name, Addr::Con(h) =>
if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] {
name.clone()
} else {
unreachable!()
},
_ => unreachable!(), _ => unreachable!(),
}; };
let arity = match self.machine_st.store(self.machine_st.deref(arity)) { let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
Addr::Con(Constant::Integer(arity)) => arity.to_usize().unwrap(), Addr::Con(h) => {
_ => unreachable!(), match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
}
Addr::Usize(n) => {
n
}
_ => {
unreachable!()
}
}; };
(name, arity) (name, arity)
@@ -102,7 +125,9 @@ impl Machine {
let module_addr = self.machine_st[module].clone(); let module_addr = self.machine_st[module].clone();
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) { let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get_mut(&module) { Addr::Con(h) =>
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
match self.indices.modules.get_mut(module) {
Some(ref mut module) => { Some(ref mut module) => {
module.code_dir.remove(&(name.clone(), arity)); module.code_dir.remove(&(name.clone(), arity));
module.module_decl.name.clone() module.module_decl.name.clone()
@@ -111,6 +136,9 @@ impl Machine {
self.machine_st.fail = true; self.machine_st.fail = true;
return; return;
} }
}
} else {
unreachable!()
}, },
_ => unreachable!(), _ => unreachable!(),
}; };
@@ -130,7 +158,12 @@ impl Machine {
) { ) {
let machine_st = mem::replace(&mut self.machine_st, MachineState::new()); let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
let result = self.compile_into_machine(parsing_stream(pred_str.as_bytes()), name, arity); let result = self.compile_into_machine(
Stream::from(pred_str),
name,
arity,
);
self.machine_st = machine_st; self.machine_st = machine_st;
if let EvalSession::Error(err) = result { if let EvalSession::Error(err) = result {
@@ -158,20 +191,33 @@ impl Machine {
place.push_to_queue(&mut addrs, added_clause); place.push_to_queue(&mut addrs, added_clause);
self.print_new_dynamic_clause(addrs, name.clone(), arity) self.print_new_dynamic_clause(addrs, name.clone(), arity)
} }
Err(err) => return self.machine_st.throw_exception(err), Err(err) => {
return self.machine_st.throw_exception(err);
}
}; };
self.handle_eval_result_from_dynamic_compile(pred_str, name, arity, place.predicate_name()); self.handle_eval_result_from_dynamic_compile(
pred_str,
name,
arity,
place.predicate_name(),
);
} }
fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool { fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) { let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get(&module) { Addr::Con(h) =>
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
match self.indices.modules.get(module) {
Some(ref module) => module.atom_tbl.clone(), Some(ref module) => module.atom_tbl.clone(),
None => { None => {
self.machine_st.fail = true; self.machine_st.fail = true;
return false; return false;
} }
}
} else {
self.machine_st.fail = true;
return false;
}, },
_ => unreachable!(), _ => unreachable!(),
}; };
@@ -200,7 +246,18 @@ impl Machine {
fn retract_from_dynamic_predicate_in_module(&mut self) { fn retract_from_dynamic_predicate_in_module(&mut self) {
let index = self.machine_st[temp_v!(3)].clone(); let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) { let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), Addr::Con(h) =>
match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
_ => unreachable!(), _ => unreachable!(),
}; };
@@ -220,7 +277,9 @@ impl Machine {
self.print_new_dynamic_clause(addrs, name.clone(), arity) self.print_new_dynamic_clause(addrs, name.clone(), arity)
} }
Err(err) => return self.machine_st.throw_exception(err), Err(err) => {
return self.machine_st.throw_exception(err);
}
}; };
self.handle_eval_result_from_dynamic_compile( self.handle_eval_result_from_dynamic_compile(
@@ -235,8 +294,22 @@ impl Machine {
fn retract_from_dynamic_predicate(&mut self) { fn retract_from_dynamic_predicate(&mut self) {
let index = self.machine_st[temp_v!(3)].clone(); let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) { let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), Addr::Con(h) => {
_ => unreachable!(), match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
}
_ => {
unreachable!()
}
}; };
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2)); let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
@@ -253,7 +326,9 @@ impl Machine {
self.print_new_dynamic_clause(addrs, name.clone(), arity) self.print_new_dynamic_clause(addrs, name.clone(), arity)
} }
Err(err) => return self.machine_st.throw_exception(err), Err(err) => {
return self.machine_st.throw_exception(err);
}
}; };
self.handle_eval_result_from_dynamic_compile( self.handle_eval_result_from_dynamic_compile(

View File

@@ -1,11 +1,12 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::prolog_parser::ast::*; use crate::prolog_parser::ast::Constant;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::partial_string::*; use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::*; use crate::prolog::machine::raw_block::*;
use std::convert::TryFrom;
use std::mem; use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::ptr; use std::ptr;
@@ -39,12 +40,12 @@ impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
} }
pub(crate) pub(crate)
struct HeapIntoIterator<T: RawBlockTraits> { struct HeapIntoIter<T: RawBlockTraits> {
offset: usize, offset: usize,
buf: RawBlock<T>, buf: RawBlock<T>,
} }
impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> { impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
fn drop(&mut self) { fn drop(&mut self) {
let mut heap = let mut heap =
HeapTemplate { buf: self.buf.take(), _marker: PhantomData }; HeapTemplate { buf: self.buf.take(), _marker: PhantomData };
@@ -54,7 +55,7 @@ impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> {
} }
} }
impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> { impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
type Item = HeapCellValue; type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@@ -72,19 +73,19 @@ impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> {
} }
pub(crate) pub(crate)
struct HeapIterator<'a, T: RawBlockTraits> { struct HeapIter<'a, T: RawBlockTraits> {
offset: usize, offset: usize,
buf: &'a RawBlock<T>, buf: &'a RawBlock<T>,
} }
impl<'a, T: RawBlockTraits> HeapIterator<'a, T> { impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
pub(crate) pub(crate)
fn new(buf: &'a RawBlock<T>, offset: usize) -> Self { fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
HeapIterator { buf, offset } HeapIter { buf, offset }
} }
} }
impl<'a, T: RawBlockTraits> Iterator for HeapIterator<'a, T> { impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
type Item = &'a HeapCellValue; type Item = &'a HeapCellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@@ -101,20 +102,28 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIterator<'a, T> {
} }
} }
#[allow(dead_code)]
pub(crate) pub(crate)
struct HeapIteratorMut<'a, T: RawBlockTraits> { fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
for (index, term) in heap.enumerate() {
println!("{} : {}", h + index, term);
}
}
pub(crate)
struct HeapIterMut<'a, T: RawBlockTraits> {
offset: usize, offset: usize,
buf: &'a mut RawBlock<T>, buf: &'a mut RawBlock<T>,
} }
impl<'a, T: RawBlockTraits> HeapIteratorMut<'a, T> { impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
pub(crate) pub(crate)
fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self { fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
HeapIteratorMut { buf, offset } HeapIterMut { buf, offset }
} }
} }
impl<'a, T: RawBlockTraits> Iterator for HeapIteratorMut<'a, T> { impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
type Item = &'a mut HeapCellValue; type Item = &'a mut HeapCellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@@ -140,17 +149,183 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline] #[inline]
pub(crate) pub(crate)
fn push(&mut self, val: HeapCellValue) { fn clone(&self, h: usize) -> HeapCellValue {
unsafe { match &self[h] {
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>()); &HeapCellValue::Addr(addr) => {
ptr::write(self.buf.top as *mut _, val); HeapCellValue::Addr(addr)
self.buf.top = new_top; }
&HeapCellValue::Atom(ref name, ref op) => {
HeapCellValue::Atom(name.clone(), op.clone())
}
&HeapCellValue::DBRef(ref db_ref) => {
HeapCellValue::DBRef(db_ref.clone())
}
&HeapCellValue::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&HeapCellValue::PartialString(..) => {
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Addr(Addr::Stream(h))
}
} }
} }
#[inline] #[inline]
pub(crate) pub(crate)
fn allocate_pstr(&mut self, mut src: &str) -> Option<Addr> { fn put_complete_string(&mut self, s: &str) -> Addr {
let addr = self.allocate_pstr(s);
self.pop();
let h = self.h();
match &mut self[h - 1] {
&mut HeapCellValue::PartialString(_, ref mut has_tail) => {
*has_tail = false;
}
_ => {
unreachable!()
}
}
addr
}
#[inline]
pub(crate)
fn put_constant(&mut self, c: Constant) -> Addr {
match c {
Constant::Atom(name, op) => {
Addr::Con(self.push(HeapCellValue::Atom(name, op)))
}
Constant::Char(c) => {
Addr::Char(c)
}
Constant::CharCode(c) => {
Addr::CharCode(c)
}
Constant::EmptyList => {
Addr::EmptyList
}
Constant::Fixnum(n) => {
Addr::Fixnum(n)
}
Constant::Integer(n) => {
Addr::Con(self.push(HeapCellValue::Integer(n)))
}
Constant::Rational(r) => {
Addr::Con(self.push(HeapCellValue::Rational(r)))
}
Constant::Float(f) => {
Addr::Float(f)
}
Constant::String(s) => {
if s.is_empty() {
Addr::EmptyList
} else {
self.put_complete_string(&s)
}
}
Constant::Usize(n) => {
Addr::Usize(n)
}
}
}
#[inline]
pub(crate)
fn pop(&mut self) {
let h = self.h();
if h > 0 {
self.truncate(h - 1);
}
}
#[inline]
pub(crate)
fn push(&mut self, val: HeapCellValue) -> usize {
let h = self.h();
unsafe {
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
ptr::write(self.buf.top as *mut _, val);
self.buf.top = new_top;
}
h
}
#[inline]
pub(crate)
fn atom_at(&self, h: usize) -> bool {
if let HeapCellValue::Atom(..) = &self[h] {
true
} else {
false
}
}
#[inline]
pub(crate)
fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
match non_heap_value {
HeapCellValue::Addr(addr) => {
addr
}
val @ HeapCellValue::Atom(..)
| val @ HeapCellValue::Integer(_)
| val @ HeapCellValue::DBRef(_)
| val @ HeapCellValue::Rational(_) => {
Addr::Con(self.push(val))
}
val @ HeapCellValue::NamedStr(..) => {
Addr::Str(self.push(val))
}
val @ HeapCellValue::Stream(..) => {
Addr::Stream(self.push(val))
}
HeapCellValue::PartialString(pstr, has_tail) => {
let h = self.push(HeapCellValue::PartialString(pstr, has_tail));
if has_tail {
self.push(HeapCellValue::Addr(Addr::EmptyList));
}
Addr::Con(h)
}
}
}
#[inline]
pub(crate)
fn allocate_pstr(&mut self, src: &str) -> Addr {
self.write_pstr(src)
.unwrap_or_else(|| {
let h = self.h();
self.push(HeapCellValue::PartialString(
PartialString::empty(),
true,
));
self.push(HeapCellValue::Addr(
Addr::HeapCell(h + 1)
));
Addr::PStrLocation(h, 0)
})
}
#[inline]
fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
let orig_h = self.h(); let orig_h = self.h();
loop { loop {
@@ -158,17 +333,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
return if orig_h == self.h() { return if orig_h == self.h() {
None None
} else { } else {
let prev_h = self.h() - 1; let tail_h = self.h() - 1;
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
match &mut self[prev_h] {
HeapCellValue::PartialString(ref mut pstr) => {
let s = pstr.block_as_str();
pstr.tail = Addr::PStrTail(prev_h, s.len());
}
_ => {
unreachable!()
}
}
Some(Addr::PStrLocation(orig_h, 0)) Some(Addr::PStrLocation(orig_h, 0))
}; };
@@ -176,8 +342,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
let h = self.h(); let h = self.h();
let (mut pstr, rest_src) = let (pstr, rest_src) =
match PartialString::new(src, h) { match PartialString::new(src) {
Some(tuple) => { Some(tuple) => {
tuple tuple
} }
@@ -188,44 +354,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
} else if orig_h == h { } else if orig_h == h {
return None; return None;
} else { } else {
let prev_h = h - 1; self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
match &mut self[prev_h] {
HeapCellValue::PartialString(ref mut pstr) => {
let s = pstr.block_as_str();
pstr.tail = Addr::PStrTail(prev_h, s.len());
}
_ => {
unreachable!()
}
}
return Some(Addr::PStrLocation(orig_h, 0)); return Some(Addr::PStrLocation(orig_h, 0));
} }
} }
}; };
let new_top = unsafe { self.push(HeapCellValue::PartialString(pstr, true));
self.buf.new_block(mem::size_of::<HeapCellValue>())
};
if rest_src != "" { if rest_src != "" {
pstr.tail = Addr::PStrLocation(h+1, 0); self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
src = rest_src; src = rest_src;
} else { } else {
pstr.tail = Addr::PStrTail(h, src.len()); self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
}
unsafe{
ptr::write(
self.buf.top as *mut _,
HeapCellValue::PartialString(pstr),
);
}
self.buf.top = new_top;
if rest_src == "" {
return Some(Addr::PStrLocation(orig_h, 0)); return Some(Addr::PStrLocation(orig_h, 0));
} }
} }
@@ -279,35 +420,39 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
} }
pub(crate) pub(crate)
fn to_list<Iter: Iterator<Item = Addr>>(&mut self, values: Iter) -> usize { fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
where Iter: Iterator<Item = SrcT>,
SrcT: Into<HeapCellValue>
{
let head_addr = self.h(); let head_addr = self.h();
let mut h = head_addr;
for value in values { for value in values.map(|v| v.into()) {
let h = self.h();
self.push(HeapCellValue::Addr(Addr::Lis(h + 1))); self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.push(HeapCellValue::Addr(value)); self.push(value);
h += 2;
} }
self.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList))); self.push(HeapCellValue::Addr(Addr::EmptyList));
head_addr head_addr
} }
/* Create an iterator starting from the passed offset. */ /* Create an iterator starting from the passed offset. */
pub(crate) pub(crate)
fn iter_from<'a>(&'a self, offset: usize) -> HeapIterator<'a, T> { fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
HeapIterator::new(&self.buf, offset * mem::size_of::<HeapCellValue>()) HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
} }
pub(crate) pub(crate)
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIteratorMut<'a, T> { fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
HeapIteratorMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>()) HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
} }
pub(crate) pub(crate)
fn into_iter(mut self) -> HeapIntoIterator<T> { fn into_iter(mut self) -> HeapIntoIter<T> {
HeapIntoIterator { buf: self.buf.take(), offset: 0 } HeapIntoIter { buf: self.buf.take(), offset: 0 }
} }
pub(crate) pub(crate)
@@ -320,8 +465,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
pub(crate) pub(crate)
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> { fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> { let extract_integer = |s: usize| -> Option<usize> {
match self[s].as_addr(s) { match &self[s] {
Addr::Con(Constant::Integer(n)) => n.to_usize(), &HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
&HeapCellValue::Integer(ref n) => n.to_usize(),
_ => None _ => None
} }
}; };
@@ -361,6 +507,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
_ => None _ => None
} }
} }
#[inline]
pub
fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
match addr {
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) => {
RefOrOwned::Borrowed(&self[h])
}
addr => {
RefOrOwned::Owned(HeapCellValue::Addr(*addr))
}
}
}
} }
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> { impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {

View File

@@ -1,6 +1,7 @@
use prolog_parser::ast::*; use prolog_parser::ast::*;
use crate::prolog::forms::PredicateKey; use crate::prolog::forms::{ModuleSource, Number, PredicateKey};
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*; use crate::prolog::machine::machine_state::*;
use crate::prolog::rug::Integer; use crate::prolog::rug::Integer;
@@ -21,34 +22,103 @@ pub(super) struct MachineError {
from: ErrorProvenance, from: ErrorProvenance,
} }
impl MachineError { pub(super)
pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { trait TypeError {
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None))); fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
functor!(
"/",
2,
[name, heap_integer!(Integer::from(arity))],
SharedOpDesc::new(400, YFX)
)
} }
pub(super) fn evaluation_error(eval_error: EvalError) -> Self { impl TypeError for Addr {
let stub = functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())]); fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), addr(self)]
);
MachineError { MachineError {
stub, stub,
location: None, location: None,
from: ErrorProvenance::Received, from: ErrorProvenance::Received
}
} }
} }
pub(super) fn type_error(valid_type: ValidType, culprit: Addr) -> Self { impl TypeError for MachineStub {
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError {
let stub = functor!( let stub = functor!(
"type_error", "type_error",
2, [atom(valid_type.as_str()), aux(h, 0)],
[ [self]
heap_atom!(valid_type.as_str()), );
HeapCellValue::Addr(culprit)
] MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed
}
}
}
impl TypeError for Number {
fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), number(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
}
}
}
pub(super)
trait PermissionError {
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError;
}
impl PermissionError for Addr {
fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError {
let stub = functor!(
"permission_error",
[atom(perm.as_str()), atom(index_str), addr(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
}
}
}
impl PermissionError for MachineStub {
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError {
let stub = functor!(
"permission_error",
[atom(perm.as_str()), atom(index_str), aux(h, 0)],
[self]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed
}
}
}
pub(super)
trait DomainError {
fn domain_error(self, error: DomainErrorType) -> MachineError;
}
impl DomainError for Addr {
fn domain_error(self, error: DomainErrorType) -> MachineError {
let stub = functor!(
"domain_error",
[atom(error.as_str()), addr(self)]
); );
MachineError { MachineError {
@@ -57,55 +127,74 @@ impl MachineError {
from: ErrorProvenance::Received, from: ErrorProvenance::Received,
} }
} }
}
pub(super) fn module_resolution_error( impl DomainError for Number {
fn domain_error(self, error: DomainErrorType) -> MachineError {
let stub = functor!(
"domain_error",
[atom(error.as_str()), number(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
impl MachineError {
pub(super)
fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
functor!(
"/",
SharedOpDesc::new(400, YFX),
[clause_name(name), integer(arity)]
)
}
pub(super)
fn evaluation_error(eval_error: EvalError) -> Self {
let stub = functor!("evaluation_error", [atom(eval_error.as_str())]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super)
fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
culprit.type_error(h, valid_type)
}
pub(super)
fn module_resolution_error(
h: usize, h: usize,
mod_name: ClauseName, mod_name: ClauseName,
name: ClauseName, name: ClauseName,
arity: usize, arity: usize,
) -> Self { ) -> Self {
let mod_name = HeapCellValue::Addr(Addr::Con(Constant::Atom(mod_name, None))); let res_stub = functor!(
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
let mut stub = functor!(
"evaluation_error",
1,
[HeapCellValue::Addr(Addr::HeapCell(h + 2))]
);
stub.append(&mut functor!(
"/",
2,
[
HeapCellValue::Addr(Addr::HeapCell(h + 2 + 3)),
heap_integer!(Integer::from(arity))
],
SharedOpDesc::new(400, YFX)
));
stub.append(&mut functor!(
":", ":",
2, SharedOpDesc::new(600, XFY),
[mod_name, name], [clause_name(mod_name), clause_name(name)]
SharedOpDesc::new(600, XFY) );
));
let ind_stub = functor!(
MachineError { "/",
stub, SharedOpDesc::new(400, YFX),
location: None, [aux(h + 2, 0), integer(arity)],
from: ErrorProvenance::Constructed, [res_stub]
} );
}
let stub = functor!(
pub(super) fn existence_error(h: usize, err: ExistenceError) -> Self { "evaluation_error",
match err { [aux(h, 0)],
ExistenceError::Procedure(name, arity) => { [ind_stub]
let mut stub = functor!(
"existence_error",
2,
[heap_atom!("procedure"), heap_str!(3 + h)]
); );
stub.append(&mut Self::functor_stub(name, arity));
MachineError { MachineError {
stub, stub,
@@ -113,57 +202,34 @@ impl MachineError {
from: ErrorProvenance::Constructed, from: ErrorProvenance::Constructed,
} }
} }
ExistenceError::Module(name) => {
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
let stub = functor!("existence_error", 2, [heap_atom!("module"), name]);
MachineError { pub(super)
stub, fn existence_error(h: usize, err: ExistenceError) -> Self {
location: None,
from: ErrorProvenance::Constructed,
}
}
}
}
pub(super) fn session_error(h: usize, err: SessionError) -> Self {
match err { match err {
SessionError::ParserError(err) => Self::syntax_error(h, err), ExistenceError::Module(name) => {
SessionError::CannotOverwriteBuiltIn(pred_str) let stub = functor!(
| SessionError::CannotOverwriteImport(pred_str) => { "existence_error",
Self::permission_error(PermissionError::Modify, "private_procedure", pred_str) [atom("source_sink"), clause_name(name)]
} );
SessionError::InvalidFileName(filename) => {
Self::existence_error(h, ExistenceError::Module(filename))
}
SessionError::ModuleDoesNotContainExport(..) => Self::permission_error(
PermissionError::Access,
"private_procedure",
clause_name!("module_does_not_contain_claimed_export"),
),
SessionError::ModuleNotFound => Self::permission_error(
PermissionError::Access,
"private_procedure",
clause_name!("module_does_not_exist"),
),
SessionError::OpIsInfixAndPostFix(op) => {
Self::permission_error(PermissionError::Create, "operator", op)
}
_ => unreachable!(),
}
}
pub(super) fn permission_error( MachineError {
err: PermissionError, stub,
index_str: &'static str, location: None,
pred_str: ClauseName, from: ErrorProvenance::Received,
) -> Self { }
let pred_str = HeapCellValue::Addr(Addr::Con(Constant::Atom(pred_str, None))); }
ExistenceError::Procedure(name, arity) => {
let culprit = functor!(
"/",
SharedOpDesc::new(400, YFX),
[clause_name(name), integer(arity)]
);
let err = vec![heap_atom!(err.as_str()), heap_atom!(index_str), pred_str]; let stub = functor!(
let mut stub = functor!("permission_error", 3); "existence_error",
[atom("procedure"), aux(h, 0)],
stub.extend(err.into_iter()); [culprit]
);
MachineError { MachineError {
stub, stub,
@@ -171,46 +237,168 @@ impl MachineError {
from: ErrorProvenance::Constructed, from: ErrorProvenance::Constructed,
} }
} }
ExistenceError::SourceSink(source) => {
let source_stub = source.as_functor_stub();
let stub = functor!(
"existence_error",
[atom("source_sink"), aux(h, 0)],
[source_stub]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
ExistenceError::Stream(culprit) => {
let stub = functor!(
"existence_error",
[atom("stream"), addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
}
pub(super)
fn permission_error<T: PermissionError>(
h: usize,
err: Permission,
index_str: &'static str,
culprit: T,
) -> Self {
culprit.permission_error(
h,
index_str,
err,
)
}
fn arithmetic_error(h: usize, err: ArithmeticError) -> Self { fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
match err { match err {
ArithmeticError::UninstantiatedVar => Self::instantiation_error(), ArithmeticError::UninstantiatedVar => {
Self::instantiation_error()
}
ArithmeticError::NonEvaluableFunctor(name, arity) => { ArithmeticError::NonEvaluableFunctor(name, arity) => {
let name = HeapCellValue::Addr(Addr::Con(name));
let culprit = functor!( let culprit = functor!(
"/", "/",
2, SharedOpDesc::new(400, YFX),
[name, heap_integer!(Integer::from(arity))], [constant(h, &name), integer(arity)]
SharedOpDesc::new(400, YFX)
); );
let mut stub = Self::type_error(ValidType::Evaluable, Addr::HeapCell(3 + h)).stub; Self::type_error(h, ValidType::Evaluable, culprit)
stub.extend(culprit.into_iter()); }
}
}
#[inline]
pub(super)
fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
culprit.domain_error(error)
}
pub(super)
fn instantiation_error() -> Self {
let stub = functor!("instantiation_error");
MachineError { MachineError {
stub, stub,
location: None, location: None,
from: ErrorProvenance::Constructed, from: ErrorProvenance::Received,
} }
} }
pub(super)
fn uninstantiation_error(culprit: Addr) -> Self {
let stub = functor!(
"uninstantiation_error",
[addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super)
fn session_error(h: usize, err: SessionError) -> Self {
match err {
SessionError::CannotOverwriteBuiltIn(pred_str) |
SessionError::CannotOverwriteImport(pred_str) => {
Self::permission_error(
h,
Permission::Modify,
"private_procedure",
functor!(clause_name(pred_str)),
)
}
SessionError::ExistenceError(err) => {
Self::existence_error(h, err)
}
SessionError::InvalidFileName(filename) => {
Self::existence_error(h, ExistenceError::Module(filename))
}
SessionError::ModuleDoesNotContainExport(..) => {
Self::permission_error(
h,
Permission::Access,
"private_procedure",
functor!("module_does_not_contain_claimed_export"),
)
}
SessionError::NamelessEntry => {
Self::permission_error(
h,
Permission::Create,
"static_procedure",
functor!("nameless_procedure")
)
}
SessionError::OpIsInfixAndPostFix(op) => {
Self::permission_error(
h,
Permission::Create,
"operator",
functor!(clause_name(op)),
)
}
SessionError::ParserError(err) => {
Self::syntax_error(h, err)
}
SessionError::QueryCannotBeDefinedAsFact => {
Self::permission_error(
h,
Permission::Create,
"static_procedure",
functor!("query_cannot_be_defined_as_fact")
)
}
} }
} }
pub(super) fn syntax_error(h: usize, err: ParserError) -> Self { pub(super)
fn syntax_error(h: usize, err: ParserError) -> Self {
if let ParserError::Arithmetic(err) = err { if let ParserError::Arithmetic(err) = err {
return Self::arithmetic_error(h, err); return Self::arithmetic_error(h, err);
} }
let location = err.line_and_col_num(); let location = err.line_and_col_num();
let err = vec![heap_atom!(err.as_str())]; let stub = functor!(err.as_str());
let mut stub = if err.len() == 1 { let stub = functor!(
functor!("syntax_error", 1) "syntax_error",
} else { [aux(h, 0)],
functor!("syntax_error", 1, [heap_str!(h + 2)]) [stub]
}; );
stub.extend(err.into_iter());
MachineError { MachineError {
stub, stub,
@@ -219,30 +407,10 @@ impl MachineError {
} }
} }
pub(super) fn domain_error(error: DomainError, culprit: Addr) -> Self { pub(super)
let stub = functor!( fn representation_error(flag: RepFlag) -> Self {
"domain_error", let stub = functor!("representation_error", [atom(flag.as_str())]);
2,
[heap_atom!(error.as_str()), HeapCellValue::Addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super) fn instantiation_error() -> Self {
let stub = functor!("instantiation_error");
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super) fn representation_error(flag: RepFlag) -> Self {
let stub = functor!("representation_error", 1, [heap_atom!(flag.as_str())]);
MachineError { MachineError {
stub, stub,
location: None, location: None,
@@ -268,18 +436,22 @@ impl MachineError {
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum PermissionError { pub enum Permission {
Access, Access,
Create, Create,
InputStream,
Modify, Modify,
OutputStream,
} }
impl PermissionError { impl Permission {
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
PermissionError::Access => "access", Permission::Access => "access",
PermissionError::Create => "create", Permission::Create => "create",
PermissionError::Modify => "modify", Permission::InputStream => "input",
Permission::Modify => "modify",
Permission::OutputStream => "output",
} }
} }
} }
@@ -331,14 +503,18 @@ impl ValidType {
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum DomainError { pub enum DomainErrorType {
NotLessThanZero, NotLessThanZero,
Stream,
StreamOrAlias,
} }
impl DomainError { impl DomainErrorType {
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
DomainError::NotLessThanZero => "not_less_than_zero", DomainErrorType::NotLessThanZero => "not_less_than_zero",
DomainErrorType::Stream => "stream",
DomainErrorType::StreamOrAlias => "stream_or_alias",
} }
} }
} }
@@ -388,21 +564,20 @@ impl EvalError {
} }
// used by '$skip_max_list'. // used by '$skip_max_list'.
#[derive(Clone, Copy)]
pub(super) enum CycleSearchResult { pub(super) enum CycleSearchResult {
EmptyList, EmptyList,
NotList, NotList,
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length. ProperList(usize), // the list length.
CompleteString(usize, Rc<String>), // the string length (in bytes), the string.
UntouchedString(usize, Rc<String>), // the cut off, past which is the untouched string.
PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string. PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
PStrTail(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
UntouchedList(usize), // the address of an uniterated Addr::Lis(address). UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
} }
impl MachineState { impl MachineState {
// see 8.4.3 of Draft Technical Corrigendum 2. // see 8.4.3 of Draft Technical Corrigendum 2.
pub(super) fn check_sort_errors(&self) -> CallResult { pub(super)
fn check_sort_errors(&self) -> CallResult {
let stub = MachineError::functor_stub(clause_name!("sort"), 2); let stub = MachineError::functor_stub(clause_name!("sort"), 2);
let list = self.store(self.deref(self[temp_v!(1)].clone())); let list = self.store(self.deref(self[temp_v!(1)].clone()));
let sorted = self.store(self.deref(self[temp_v!(2)].clone())); let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
@@ -412,14 +587,14 @@ impl MachineState {
return Err(self.error_form(MachineError::instantiation_error(), stub)) return Err(self.error_form(MachineError::instantiation_error(), stub))
} }
CycleSearchResult::NotList => { CycleSearchResult::NotList => {
return Err(self.error_form(MachineError::type_error(ValidType::List, list), stub)) return Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
} }
_ => {} _ => {}
}; };
match self.detect_cycles(sorted.clone()) { match self.detect_cycles(sorted.clone()) {
CycleSearchResult::NotList if !sorted.is_ref() => { CycleSearchResult::NotList if !sorted.is_ref() => {
Err(self.error_form(MachineError::type_error(ValidType::List, sorted), stub)) Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub))
} }
_ => Ok(()), _ => Ok(()),
} }
@@ -430,7 +605,7 @@ impl MachineState {
match self.detect_cycles(list.clone()) { match self.detect_cycles(list.clone()) {
CycleSearchResult::NotList if !list.is_ref() => { CycleSearchResult::NotList if !list.is_ref() => {
Err(self.error_form(MachineError::type_error(ValidType::List, list), stub)) Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
} }
_ => { _ => {
let mut addr = list; let mut addr = list;
@@ -439,18 +614,23 @@ impl MachineState {
let mut new_l = l; let mut new_l = l;
loop { loop {
match self.heap[new_l].clone() { match self.heap.clone(new_l) {
HeapCellValue::Addr(Addr::Str(l)) => new_l = l, HeapCellValue::Addr(Addr::Str(l)) => {
HeapCellValue::NamedStr(2, ref name, Some(_)) new_l = l;
if name.as_str() == "-" => }
{ HeapCellValue::NamedStr(2, ref name, Some(_))
break if name.as_str() == "-" => {
break;
}
HeapCellValue::Addr(Addr::HeapCell(_)) => {
break;
}
HeapCellValue::Addr(Addr::StackCell(..)) => {
break;
} }
HeapCellValue::Addr(Addr::HeapCell(_)) => break,
HeapCellValue::Addr(Addr::StackCell(..)) => break,
_ => { _ => {
return Err(self.error_form( return Err(self.error_form(
MachineError::type_error(ValidType::Pair, Addr::HeapCell(l)), MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)),
stub, stub,
)) ))
} }
@@ -466,8 +646,10 @@ impl MachineState {
} }
// see 8.4.4 of Draft Technical Corrigendum 2. // see 8.4.4 of Draft Technical Corrigendum 2.
pub(super) fn check_keysort_errors(&self) -> CallResult { pub(super)
fn check_keysort_errors(&self) -> CallResult {
let stub = MachineError::functor_stub(clause_name!("keysort"), 2); let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
let pairs = self.store(self.deref(self[temp_v!(1)].clone())); let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
let sorted = self.store(self.deref(self[temp_v!(2)].clone())); let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
@@ -476,7 +658,7 @@ impl MachineState {
Err(self.error_form(MachineError::instantiation_error(), stub)) Err(self.error_form(MachineError::instantiation_error(), stub))
} }
CycleSearchResult::NotList => { CycleSearchResult::NotList => {
Err(self.error_form(MachineError::type_error(ValidType::List, pairs), stub)) Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub))
} }
_ => Ok(()), _ => Ok(()),
}?; }?;
@@ -484,7 +666,8 @@ impl MachineState {
self.check_for_list_pairs(sorted) self.check_for_list_pairs(sorted)
} }
pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub { pub(super)
fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
let location = err.location; let location = err.location;
let err_len = err.len(); let err_len = err.len();
@@ -500,21 +683,17 @@ impl MachineState {
if let Some((line_num, _)) = location { if let Some((line_num, _)) = location {
let colon_op_desc = Some(SharedOpDesc::new(600, XFY)); let colon_op_desc = Some(SharedOpDesc::new(600, XFY));
stub.extend( stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc));
vec![ stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)));
HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc), stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num))));
HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)),
heap_integer!(Integer::from(line_num)),
]
.into_iter(),
);
} }
stub.extend(src.into_iter()); stub.extend(src.into_iter());
stub stub
} }
pub(super) fn throw_exception(&mut self, err: MachineStub) { pub(super)
fn throw_exception(&mut self, err: MachineStub) {
let h = self.heap.h(); let h = self.heap.h();
self.ball.boundary = 0; self.ball.boundary = 0;
@@ -532,16 +711,19 @@ impl MachineState {
pub enum ExistenceError { pub enum ExistenceError {
Module(ClauseName), Module(ClauseName),
Procedure(ClauseName, usize), Procedure(ClauseName, usize),
SourceSink(ModuleSource),
Stream(Addr),
} }
pub enum SessionError { pub enum SessionError {
CannotOverwriteBuiltIn(ClauseName), CannotOverwriteBuiltIn(ClauseName),
CannotOverwriteImport(ClauseName), CannotOverwriteImport(ClauseName),
ExistenceError(ExistenceError),
InvalidFileName(ClauseName), InvalidFileName(ClauseName),
ModuleDoesNotContainExport(ClauseName, PredicateKey), ModuleDoesNotContainExport(ClauseName, PredicateKey),
ModuleNotFound,
NamelessEntry, NamelessEntry,
OpIsInfixAndPostFix(ClauseName), OpIsInfixAndPostFix(ClauseName),
QueryCannotBeDefinedAsFact,
ParserError(ParserError), ParserError(ParserError),
} }
@@ -566,4 +748,5 @@ impl From<ParserError> for EvalSession {
fn from(err: ParserError) -> Self { fn from(err: ParserError) -> Self {
EvalSession::from(SessionError::ParserError(err)) EvalSession::from(SessionError::ParserError(err))
} }
} }

View File

@@ -7,16 +7,20 @@ use crate::prolog::forms::*;
use crate::prolog::machine::code_repo::CodeRepo; use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::Ball; use crate::prolog::machine::Ball;
use crate::prolog::machine::heap::*; use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::partial_string::*; use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::RawBlockTraits; use crate::prolog::machine::raw_block::RawBlockTraits;
use crate::prolog::machine::streams::Stream;
use crate::prolog::instructions::*; use crate::prolog::instructions::*;
use crate::prolog::rug::Integer; use crate::prolog::ordered_float::OrderedFloat;
use crate::prolog::rug::{Integer, Rational};
use indexmap::IndexMap; use indexmap::IndexMap;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::{BTreeMap, VecDeque}; use std::collections::{BTreeMap, VecDeque};
use std::convert::TryFrom;
use std::mem; use std::mem;
use std::ops::{Add, AddAssign, Sub, SubAssign}; use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::rc::Rc; use std::rc::Rc;
@@ -38,25 +42,40 @@ pub enum DBRef {
), ),
} }
#[derive(Clone, PartialEq, Eq, Hash)] // 7.2
pub enum Addr { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
AttrVar(usize), pub enum TermOrderCategory {
Con(Constant), Variable,
DBRef(DBRef), FloatingPoint,
Lis(usize), Integer,
HeapCell(usize), Atom,
StackCell(usize, usize), Compound,
Str(usize),
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
PStrTail(usize, usize), // location of pstr in heap, offset into string in bytes.
} }
#[derive(Clone, Copy, Hash, Eq, PartialEq)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Addr {
AttrVar(usize),
Char(char),
CharCode(u32),
Con(usize),
CutPoint(usize),
EmptyList,
Fixnum(isize),
Float(OrderedFloat<f64>),
Lis(usize),
HeapCell(usize),
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
StackCell(usize, usize),
Str(usize),
Stream(usize),
Usize(usize),
}
#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
pub enum Ref { pub enum Ref {
AttrVar(usize), AttrVar(usize),
HeapCell(usize), HeapCell(usize),
StackCell(usize, usize), StackCell(usize, usize),
PStrTail(usize, usize),
} }
impl Ref { impl Ref {
@@ -65,7 +84,28 @@ impl Ref {
Ref::AttrVar(h) => Addr::AttrVar(h), Ref::AttrVar(h) => Addr::AttrVar(h),
Ref::HeapCell(h) => Addr::HeapCell(h), Ref::HeapCell(h) => Addr::HeapCell(h),
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc), Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
Ref::PStrTail(h, n) => Addr::PStrTail(h, n), }
}
}
impl Ord for Ref {
fn cmp(&self, other: &Ref) -> Ordering {
match (self, other) {
(Ref::AttrVar(h1), Ref::AttrVar(h2))
| (Ref::HeapCell(h1), Ref::HeapCell(h2))
| (Ref::HeapCell(h1), Ref::AttrVar(h2))
| (Ref::AttrVar(h1), Ref::HeapCell(h2)) => {
h1.cmp(&h2)
}
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => {
fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2))
}
(Ref::StackCell(..), _) => {
Ordering::Greater
}
(_, Ref::StackCell(..)) => {
Ordering::Less
}
} }
} }
} }
@@ -82,7 +122,7 @@ impl PartialOrd<Ref> for Addr {
match self { match self {
&Addr::StackCell(fr, sc) => { &Addr::StackCell(fr, sc) => {
match *r { match *r {
Ref::AttrVar(_) | Ref::HeapCell(_) | Ref::PStrTail(..) => { Ref::AttrVar(_) | Ref::HeapCell(_) => {
Some(Ordering::Greater) Some(Ordering::Greater)
} }
Ref::StackCell(fr1, sc1) => { Ref::StackCell(fr1, sc1) => {
@@ -104,22 +144,6 @@ impl PartialOrd<Ref> for Addr {
Ref::AttrVar(h1) | Ref::HeapCell(h1) => { Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
h.partial_cmp(h1) h.partial_cmp(h1)
} }
Ref::PStrTail(h1, _) => {
h.partial_cmp(h1)
}
}
}
&Addr::PStrTail(h, n) => {
match r {
Ref::StackCell(..) => {
Some(Ordering::Less)
}
Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
h.partial_cmp(h1)
}
Ref::PStrTail(h1, n1) => {
Some(h.cmp(h1).then_with(|| n.cmp(n1)))
}
} }
} }
_ => { _ => {
@@ -130,9 +154,24 @@ impl PartialOrd<Ref> for Addr {
} }
impl Addr { impl Addr {
#[inline]
pub fn is_heap_bound(&self) -> bool {
match self {
Addr::Char(_) | Addr::CharCode(_) | Addr::EmptyList |
Addr::CutPoint(_) | Addr::Usize(_) | Addr::Fixnum(_) |
Addr::Float(_) => {
false
}
_ => {
true
}
}
}
#[inline]
pub fn is_ref(&self) -> bool { pub fn is_ref(&self) -> bool {
match self { match self {
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) | Addr::PStrTail(..) => { Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => {
true true
} }
_ => { _ => {
@@ -141,16 +180,115 @@ impl Addr {
} }
} }
#[inline]
pub fn as_var(&self) -> Option<Ref> { pub fn as_var(&self) -> Option<Ref> {
match self { match self {
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)), &Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)), &Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)), &Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
&Addr::PStrTail(h, n) => Some(Ref::PStrTail(h, n)),
_ => None, _ => None,
} }
} }
pub(super)
fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
match Number::try_from((*self, heap)) {
Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => {
Some(TermOrderCategory::Integer)
}
Ok(Number::Float(_)) => {
Some(TermOrderCategory::FloatingPoint)
}
_ => {
match self {
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
Some(TermOrderCategory::Variable)
}
Addr::Float(_) => {
Some(TermOrderCategory::FloatingPoint)
}
&Addr::Con(h) => {
match &heap[h] {
HeapCellValue::Atom(..) => {
Some(TermOrderCategory::Atom)
}
HeapCellValue::DBRef(_) => {
None
}
_ => {
unreachable!()
}
}
}
Addr::Char(_) | Addr::EmptyList => {
Some(TermOrderCategory::Atom)
}
Addr::CharCode(_) | Addr::Fixnum(_) | Addr::Usize(_) => {
Some(TermOrderCategory::Integer)
}
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
Some(TermOrderCategory::Compound)
}
Addr::CutPoint(_) | Addr::Stream(_) => {
None
}
}
}
}
}
pub fn as_constant(&self, machine_st: &MachineState) -> Option<Constant> {
match self {
&Addr::Char(c) => {
Some(Constant::Char(c))
}
&Addr::CharCode(c) => {
Some(Constant::CharCode(c))
}
&Addr::Con(h) => {
match &machine_st.heap[h] {
&HeapCellValue::Atom(ref name, ref op) => {
Some(Constant::Atom(name.clone(), op.clone()))
}
&HeapCellValue::Integer(ref n) => {
Some(Constant::Integer(n.clone()))
}
&HeapCellValue::Rational(ref n) => {
Some(Constant::Rational(n.clone()))
}
_ => {
None
}
}
}
&Addr::EmptyList => {
Some(Constant::EmptyList)
}
&Addr::Fixnum(n) => {
Some(Constant::Fixnum(n))
}
&Addr::Float(f) => {
Some(Constant::Float(f))
}
&Addr::PStrLocation(h, n) => {
let mut heap_pstr_iter =
machine_st.heap_pstr_iter(Addr::PStrLocation(h, n));
let buf = heap_pstr_iter.to_string();
let end_addr = heap_pstr_iter.focus();
if end_addr == Addr::EmptyList {
Some(Constant::String(Rc::new(buf)))
} else {
None
}
}
_ => {
None
}
}
}
pub fn is_protected(&self, e: usize) -> bool { pub fn is_protected(&self, e: usize) -> bool {
match self { match self {
&Addr::StackCell(addr, _) if addr >= e => false, &Addr::StackCell(addr, _) if addr >= e => false,
@@ -164,12 +302,13 @@ impl Add<usize> for Addr {
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self { match self {
Addr::Stream(h) => Addr::Stream(h + rhs),
Addr::Con(h) => Addr::Con(h + rhs),
Addr::Lis(a) => Addr::Lis(a + rhs), Addr::Lis(a) => Addr::Lis(a + rhs),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs), Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs), Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
Addr::Str(s) => Addr::Str(s + rhs), Addr::Str(s) => Addr::Str(s + rhs),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n), Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs, n),
_ => self, _ => self,
} }
} }
@@ -181,11 +320,12 @@ impl Sub<i64> for Addr {
fn sub(self, rhs: i64) -> Self::Output { fn sub(self, rhs: i64) -> Self::Output {
if rhs < 0 { if rhs < 0 {
match self { match self {
Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize),
Addr::Con(h) => Addr::Con(h + rhs.abs() as usize),
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize), Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize), Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize), Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize), Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs.abs() as usize, n),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n), Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
_ => self, _ => self,
} }
@@ -200,11 +340,12 @@ impl Sub<usize> for Addr {
fn sub(self, rhs: usize) -> Self::Output { fn sub(self, rhs: usize) -> Self::Output {
match self { match self {
Addr::Stream(h) => Addr::Stream(h - rhs),
Addr::Con(h) => Addr::Con(h - rhs),
Addr::Lis(a) => Addr::Lis(a - rhs), Addr::Lis(a) => Addr::Lis(a - rhs),
Addr::AttrVar(h) => Addr::AttrVar(h - rhs), Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
Addr::HeapCell(h) => Addr::HeapCell(h - rhs), Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
Addr::Str(s) => Addr::Str(s - rhs), Addr::Str(s) => Addr::Str(s - rhs),
Addr::PStrTail(h, n) => Addr::PStrTail(h - rhs, n),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n), Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
_ => self, _ => self,
} }
@@ -230,29 +371,78 @@ impl From<Ref> for TrailRef {
} }
} }
#[derive(Clone, PartialEq)]
pub enum HeapCellValue { pub enum HeapCellValue {
Addr(Addr), Addr(Addr),
Atom(ClauseName, Option<SharedOpDesc>),
DBRef(DBRef),
Integer(Rc<Integer>),
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one. NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
PartialString(PartialString), Rational(Rc<Rational>),
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
Stream(Stream),
} }
impl HeapCellValue { impl HeapCellValue {
#[inline]
pub fn as_addr(&self, focus: usize) -> Addr { pub fn as_addr(&self, focus: usize) -> Addr {
match self { match self {
HeapCellValue::Addr(ref a) => { HeapCellValue::Addr(ref a) => {
a.clone() *a
}
HeapCellValue::Atom(..) | HeapCellValue::DBRef(..) | HeapCellValue::Integer(..) |
HeapCellValue::Rational(..) => {
Addr::Con(focus)
} }
HeapCellValue::NamedStr(_, _, _) => { HeapCellValue::NamedStr(_, _, _) => {
Addr::Str(focus) Addr::Str(focus)
} }
HeapCellValue::PartialString(_) => { HeapCellValue::PartialString(..) => {
Addr::PStrLocation(focus, 0) Addr::PStrLocation(focus, 0)
} }
HeapCellValue::Stream(_) => {
Addr::Stream(focus)
} }
} }
} }
#[inline]
pub fn context_free_clone(&self) -> HeapCellValue {
match self {
&HeapCellValue::Addr(addr) => {
HeapCellValue::Addr(addr)
}
&HeapCellValue::Atom(ref name, ref op) => {
HeapCellValue::Atom(name.clone(), op.clone())
}
&HeapCellValue::DBRef(ref db_ref) => {
HeapCellValue::DBRef(db_ref.clone())
}
&HeapCellValue::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
}
&HeapCellValue::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&HeapCellValue::PartialString(ref pstr, has_tail) => {
HeapCellValue::PartialString(pstr.clone(), has_tail)
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Stream(Stream::null_stream())
}
}
}
}
impl From<Addr> for HeapCellValue {
#[inline]
fn from(value: Addr) -> HeapCellValue {
HeapCellValue::Addr(value)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub enum IndexPtr { pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
@@ -428,37 +618,31 @@ impl LocalCodePtr {
LocalCodePtr::DirEntry(p) => { LocalCodePtr::DirEntry(p) => {
heap.append(functor!( heap.append(functor!(
"dir_entry", "dir_entry",
1, [integer(*p)]
[heap_integer!(Integer::from(*p))]
)); ));
} }
LocalCodePtr::InSituDirEntry(p) => { LocalCodePtr::InSituDirEntry(p) => {
heap.append(functor!( heap.append(functor!(
"in_situ_dir_entry", "in_situ_dir_entry",
1, [integer(*p)]
[heap_integer!(Integer::from(*p))]
)); ));
} }
LocalCodePtr::TopLevel(chunk_num, offset) => { LocalCodePtr::TopLevel(chunk_num, offset) => {
heap.append(functor!( heap.append(functor!(
"top_level", "top_level",
2, [integer(*chunk_num), integer(*offset)]
[heap_integer!(Integer::from(*chunk_num)),
heap_integer!(Integer::from(*offset))]
)); ));
} }
LocalCodePtr::UserGoalExpansion(p) => { LocalCodePtr::UserGoalExpansion(p) => {
heap.append(functor!( heap.append(functor!(
"user_goal_expansion", "user_goal_expansion",
1, [integer(*p)]
[heap_integer!(Integer::from(*p))]
)); ));
} }
LocalCodePtr::UserTermExpansion(p) => { LocalCodePtr::UserTermExpansion(p) => {
heap.append(functor!( heap.append(functor!(
"user_term_expansion", "user_term_expansion",
1, [integer(*p)]
[heap_integer!(Integer::from(*p))]
)); ));
} }
} }
@@ -470,8 +654,12 @@ impl LocalCodePtr {
impl PartialOrd<CodePtr> for CodePtr { impl PartialOrd<CodePtr> for CodePtr {
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> { fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
match (self, other) { match (self, other) {
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => l1.partial_cmp(l2), (&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => {
_ => Some(Ordering::Greater), l1.partial_cmp(l2)
}
_ => {
Some(Ordering::Greater)
}
} }
} }
} }
@@ -486,8 +674,12 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
| (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => { | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
p1.partial_cmp(p2) p1.partial_cmp(p2)
} }
(_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less), (_, &LocalCodePtr::TopLevel(_, _)) => {
_ => Some(Ordering::Greater), Some(Ordering::Less)
}
_ => {
Some(Ordering::Greater)
}
} }
} }
} }
@@ -613,17 +805,19 @@ impl ModuleStub {
} }
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>; pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
pub struct IndexStore { pub struct IndexStore {
pub(super) atom_tbl: TabledData<Atom>, pub(super) atom_tbl: TabledData<Atom>,
pub(super) code_dir: CodeDir, pub(super) code_dir: CodeDir,
pub(super) module_dir: ModuleDir,
pub(super) dynamic_code_dir: DynamicCodeDir, pub(super) dynamic_code_dir: DynamicCodeDir,
pub(super) global_variables: GlobalVarDir, pub(super) global_variables: GlobalVarDir,
pub(super) in_situ_code_dir: InSituCodeDir, pub(super) in_situ_code_dir: InSituCodeDir,
pub(super) in_situ_module_dir: ModuleStubDir, pub(super) in_situ_module_dir: ModuleStubDir,
pub(super) module_dir: ModuleDir,
pub(super) modules: ModuleDir, pub(super) modules: ModuleDir,
pub(super) op_dir: OpDir, pub(super) op_dir: OpDir,
pub(super) stream_aliases: StreamAliasDir,
} }
impl IndexStore { impl IndexStore {
@@ -710,6 +904,7 @@ impl IndexStore {
in_situ_module_dir: ModuleStubDir::new(), in_situ_module_dir: ModuleStubDir::new(),
op_dir: default_op_dir(), op_dir: default_op_dir(),
modules: ModuleDir::new(), modules: ModuleDir::new(),
stream_aliases: StreamAliasDir::new(),
} }
} }
@@ -740,13 +935,13 @@ impl IndexStore {
let r_w_h = clause_name!("run_cleaners_with_handling"); let r_w_h = clause_name!("run_cleaners_with_handling");
let r_wo_h = clause_name!("run_cleaners_without_handling"); let r_wo_h = clause_name!("run_cleaners_without_handling");
let non_iso = clause_name!("non_iso"); let iso_ext = clause_name!("iso_ext");
let r_w_h = self let r_w_h = self
.get_internal(r_w_h, 0, non_iso.clone()) .get_internal(r_w_h, 0, iso_ext.clone())
.and_then(|item| item.local()); .and_then(|item| item.local());
let r_wo_h = self let r_wo_h = self
.get_internal(r_wo_h, 1, non_iso) .get_internal(r_wo_h, 1, iso_ext)
.and_then(|item| item.local()); .and_then(|item| item.local());
if let Some(r_w_h) = r_w_h { if let Some(r_w_h) = r_w_h {

View File

@@ -1,7 +1,9 @@
use prolog_parser::ast::*; use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*; use crate::prolog::clause_types::*;
use crate::prolog::forms::*; use crate::prolog::forms::*;
use crate::prolog::heap_print::*;
use crate::prolog::machine::attributed_variables::*; use crate::prolog::machine::attributed_variables::*;
use crate::prolog::machine::copier::*; use crate::prolog::machine::copier::*;
use crate::prolog::machine::heap::*; use crate::prolog::machine::heap::*;
@@ -9,16 +11,191 @@ use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::modules::*; use crate::prolog::machine::modules::*;
use crate::prolog::machine::stack::*; use crate::prolog::machine::stack::*;
use crate::prolog::read::PrologStream; use crate::prolog::machine::streams::*;
use crate::prolog::read::readline;
use crate::prolog::rug::Integer; use crate::prolog::rug::Integer;
use downcast::Any; use downcast::Any;
use indexmap::{IndexMap, IndexSet};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::io::{stdout, Write}; use std::convert::TryFrom;
use std::io::Write;
use std::mem; use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
pub(crate) struct HeapPStrIter<'a> {
focus: Addr,
machine_st: &'a MachineState,
seen: IndexSet<Addr>,
}
impl<'a> HeapPStrIter<'a> {
#[inline]
fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
HeapPStrIter {
focus,
machine_st,
seen: IndexSet::new(),
}
}
#[inline]
pub(crate)
fn focus(&'a self) -> Addr {
self.machine_st.store(self.machine_st.deref(self.focus))
}
#[inline]
pub(crate)
fn to_string(&mut self) -> String {
let mut buf = String::new();
while let Some(iteratee) = self.next() {
match iteratee {
PStrIteratee::Char(c) => {
buf.push(c);
}
PStrIteratee::PStrSegment(h, n) => {
match &self.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
buf += pstr.as_str_from(n);
}
_ => {
unreachable!()
}
}
}
}
}
buf
}
}
#[derive(Clone, Copy)]
pub(crate) enum PStrIteratee {
Char(char),
PStrSegment(usize, usize),
}
impl<'a> Iterator for HeapPStrIter<'a> {
type Item = PStrIteratee;
fn next(&mut self) -> Option<Self::Item> {
let addr = self.machine_st.store(self.machine_st.deref(self.focus));
if !self.seen.contains(&addr) {
self.seen.insert(addr);
} else {
return None;
}
match addr {
Addr::PStrLocation(h, n) => {
if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
self.focus = if has_tail {
Addr::HeapCell(h + 1)
} else {
Addr::EmptyList
};
return Some(PStrIteratee::PStrSegment(h, n));
} else {
unreachable!()
}
}
Addr::Lis(l) => {
let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
let opt_c = match addr {
Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
if atom.is_char() {
Some(atom.as_str().chars().next().unwrap())
} else {
None
}
} else {
unreachable!()
}
}
Addr::Char(c) => {
Some(c)
}
_ => {
None
}
};
if let Some(c) = opt_c {
self.focus = Addr::HeapCell(l + 1);
return Some(PStrIteratee::Char(c));
} else {
return None;
}
}
Addr::EmptyList => {
self.focus = Addr::EmptyList;
return None;
}
_ => {
return None;
}
}
}
}
#[inline]
pub(super)
fn compare_pstr_to_string<'a>(
heap_pstr_iter: &mut HeapPStrIter<'a>,
s: &String,
) -> Option<usize> {
let mut s_offset = 0;
while let Some(iteratee) = heap_pstr_iter.next() {
match iteratee {
PStrIteratee::Char(c1) => {
if let Some(c2) = s[s_offset ..].chars().next() {
if c1 != c2 {
return None;
} else {
s_offset += c1.len_utf8();
}
} else {
return None;
}
}
PStrIteratee::PStrSegment(h, n) => {
match heap_pstr_iter.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
let t = pstr.as_str_from(n);
if s[s_offset ..].starts_with(t) {
s_offset += t.len();
} else if t.starts_with(&s[s_offset ..]) {
heap_pstr_iter.focus =
Addr::PStrLocation(h, n + s[s_offset ..].len());
s_offset += s[s_offset ..].len();
return Some(s_offset);
} else {
return None;
}
}
_ => {
unreachable!()
}
}
}
}
}
Some(s_offset)
}
pub struct Ball { pub struct Ball {
pub(super) boundary: usize, pub(super) boundary: usize,
pub(super) stub: Heap, pub(super) stub: Heap,
@@ -57,13 +234,12 @@ impl Ball {
for heap_value in self.stub.iter_from(0) { for heap_value in self.stub.iter_from(0) {
stub.push(match heap_value { stub.push(match heap_value {
HeapCellValue::Addr(ref addr) => HeapCellValue::Addr(addr.clone() - diff), &HeapCellValue::Addr(addr) => {
HeapCellValue::PartialString(ref pstr) => { HeapCellValue::Addr(addr - diff)
let mut new_pstr = pstr.clone(); }
new_pstr.tail = pstr.tail.clone() - diff; heap_value => {
HeapCellValue::PartialString(new_pstr) heap_value.context_free_clone()
} }
heap_value => heap_value.clone(),
}); });
} }
@@ -185,14 +361,18 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
let index = h - self.heap_boundary; let index = h - self.heap_boundary;
self.stub[index].as_addr(h) self.stub[index].as_addr(h)
} }
Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(), Addr::StackCell(fr, sc) => {
addr => addr, self.stack.index_and_frame(fr)[sc]
}
addr => {
addr
}
} }
} }
fn deref(&self, mut addr: Addr) -> Addr { fn deref(&self, mut addr: Addr) -> Addr {
loop { loop {
let value = self.store(addr.clone()); let value = self.store(addr);
if value.is_ref() && value != addr { if value.is_ref() && value != addr {
addr = value; addr = value;
@@ -225,9 +405,12 @@ impl Index<RegType> for MachineState {
impl IndexMut<RegType> for MachineState { impl IndexMut<RegType> for MachineState {
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output { fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
match reg { match reg {
RegType::Temp(temp) => &mut self.registers[temp], RegType::Temp(temp) => {
&mut self.registers[temp]
}
RegType::Perm(perm) => { RegType::Perm(perm) => {
let e = self.e; let e = self.e;
&mut self.stack.index_and_frame_mut(e)[perm] &mut self.stack.index_and_frame_mut(e)[perm]
} }
} }
@@ -242,8 +425,49 @@ pub(super) enum MachineMode {
Write, Write,
} }
#[derive(Clone)]
pub(super) enum HeapPtr {
HeapCell(usize),
PStrChar(usize, usize),
PStrLocation(usize, usize),
}
impl HeapPtr {
#[inline]
pub(super)
fn read(&self, heap: &Heap) -> Addr {
match self {
&HeapPtr::HeapCell(h) => {
Addr::HeapCell(h)
}
&HeapPtr::PStrChar(h, n) => {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &heap[h] {
if let Some(c) = pstr.range_from(n ..).next() {
Addr::Char(c)
} else if has_tail {
Addr::HeapCell(h + 1)
} else {
Addr::EmptyList
}
} else {
unreachable!()
}
}
&HeapPtr::PStrLocation(h, n) => {
Addr::PStrLocation(h, n)
}
}
}
}
impl Default for HeapPtr {
fn default() -> Self {
HeapPtr::HeapCell(0)
}
}
pub struct MachineState { pub struct MachineState {
pub(super) s: usize, pub(super) s: HeapPtr,
pub(super) p: CodePtr, pub(super) p: CodePtr,
pub(super) b: usize, pub(super) b: usize,
pub(super) b0: usize, pub(super) b0: usize,
@@ -270,37 +494,208 @@ pub struct MachineState {
} }
impl MachineState { impl MachineState {
pub(crate)
fn read_term(
&mut self,
current_input_stream: &mut Stream,
indices: &mut IndexStore,
) -> CallResult {
match self.read(
&mut parsing_stream(current_input_stream.clone()),
indices.atom_tbl.clone(),
&indices.op_dir,
) {
Ok(term_write_result) => {
let a1 = self[temp_v!(1)];
self.unify(Addr::HeapCell(term_write_result.heap_loc), a1);
if self.fail {
return Ok(());
}
let mut list_of_var_eqs = vec![];
for (var, binding) in term_write_result.var_dict.into_iter().rev() {
let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
let h = self.heap.h();
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
self.heap.push(HeapCellValue::Atom(var_atom, None));
self.heap.push(HeapCellValue::Addr(binding));
list_of_var_eqs.push(Addr::Str(h));
}
let a2 = self[temp_v!(2)];
let list_offset =
Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
Ok(self.unify(list_offset, a2))
}
Err(err) => {
if let ParserError::UnexpectedEOF = err {
std::process::exit(0);
}
// reset the input stream after an input failure.
*current_input_stream = readline::input_stream();
let h = self.heap.h();
let syntax_error = MachineError::syntax_error(h, err);
let stub = MachineError::functor_stub(clause_name!("read_term"), 2);
Err(self.error_form(syntax_error, stub))
}
}
}
pub(crate)
fn write_term<'a>(
&'a self,
op_dir: &'a OpDir,
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub>
{
let ignore_ops = self.store(self.deref(self[temp_v!(2)]));
let numbervars = self.store(self.deref(self[temp_v!(3)]));
let quoted = self.store(self.deref(self[temp_v!(4)]));
let max_depth = self.store(self.deref(self[temp_v!(6)]));
let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new());
if let &Addr::Con(h) = &ignore_ops {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.ignore_ops = name.as_str() == "true";
} else {
unreachable!()
}
}
if let &Addr::Con(h) = &numbervars {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.numbervars = name.as_str() == "true";
} else {
unreachable!()
}
}
if let &Addr::Con(h) = &quoted {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.quoted = name.as_str() == "true";
} else {
unreachable!()
}
}
match Number::try_from((max_depth, &self.heap)) {
Ok(Number::Fixnum(n)) => {
if let Ok(n) = usize::try_from(n) {
printer.max_depth = n;
} else {
return Ok(None);
}
}
Ok(Number::Integer(n)) => {
if let Some(n) = n.to_usize() {
printer.max_depth = n;
} else {
return Ok(None);
}
}
_ => {
unreachable!();
}
}
let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
match self.try_from_list(temp_v!(5), stub) {
Ok(addrs) => {
let mut var_names: IndexMap<Addr, String> = IndexMap::new();
for addr in addrs {
match addr {
Addr::Str(s) => match &self.heap[s] {
&HeapCellValue::NamedStr(2, ref name, _)
if name.as_str() == "=" =>
{
let atom = self.heap[s + 1].as_addr(s + 1);
let var = self.heap[s + 2].as_addr(s + 2);
let atom = match self.store(self.deref(atom)) {
Addr::Con(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
atom.to_string()
} else {
unreachable!()
}
}
Addr::Char(c) => c.to_string(),
_ => unreachable!(),
};
let var = self.store(self.deref(var));
if var_names.contains_key(&var) {
continue;
}
var_names.insert(var, atom);
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}
printer.var_names = var_names;
}
Err(err) => {
return Err(err);
}
}
Ok(Some(printer))
}
#[inline]
pub(crate)
fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> {
HeapPStrIter::new(self, focus)
}
pub(super) pub(super)
fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError> { fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError> {
let mut chars = String::new(); let mut chars = String::new();
let mut iter = addrs.iter(); let mut iter = addrs.iter();
while let Some(addr) = iter.next() { while let Some(addr) = iter.next() {
match addr { let addr = self.store(self.deref(*addr));
&Addr::Con(Constant::String(n, ref s))
if self.flags.double_quotes.is_chars() => {
if s.len() < n {
chars += &s[n ..];
}
if iter.next().is_some() { match addr {
return Err(MachineError::type_error(ValidType::Character, addr.clone())); Addr::Char(c) => {
}
}
&Addr::Con(Constant::Char(c)) => {
chars.push(c); chars.push(c);
continue;
} }
&Addr::Con(Constant::Atom(ref name, _)) Addr::Con(h) => {
if name.as_str().len() == 1 => { if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
if name.is_char() {
chars += name.as_str(); chars += name.as_str();
continue;
}
}
} }
_ => { _ => {
}
};
let h = self.heap.h();
return Err( return Err(
MachineError::type_error(ValidType::Character, addr.clone()) MachineError::type_error(h, ValidType::Character, addr)
); );
} }
}
}
Ok(chars) Ok(chars)
} }
@@ -384,15 +779,15 @@ impl MachineState {
} }
} }
fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<usize> fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<LocalCodePtr>
{ {
match indices.in_situ_code_dir.get(&(name.clone(), arity)) { match indices.in_situ_code_dir.get(&(name.clone(), arity)) {
Some(p) => Some(*p), Some(p) => Some(LocalCodePtr::InSituDirEntry(*p)),
None => None =>
match indices.code_dir.get(&(name, arity)) { match indices.code_dir.get(&(name, arity)) {
Some(ref idx) => { Some(ref idx) => {
if let IndexPtr::Index(p) = idx.0.borrow().0 { if let IndexPtr::Index(p) = idx.0.borrow().0 {
Some(p) Some(LocalCodePtr::DirEntry(p))
} else { } else {
None None
} }
@@ -411,12 +806,12 @@ fn try_in_situ(
) -> CallResult { ) -> CallResult {
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) { if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
if last_call { if last_call {
machine_st.execute_at_index(arity, LocalCodePtr::DirEntry(p)); machine_st.execute_at_index(arity, p);
} else { } else {
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(p)); machine_st.call_at_index(arity, p);
} }
machine_st.p = in_situ_dir_entry!(p); machine_st.p = CodePtr::Local(p);
Ok(()) Ok(())
} else { } else {
let stub = MachineError::functor_stub(name.clone(), arity); let stub = MachineError::functor_stub(name.clone(), arity);
@@ -435,7 +830,7 @@ pub(crate) trait CallPolicy: Any {
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone(); machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
} }
machine_st.num_of_args = n; machine_st.num_of_args = n;
@@ -474,7 +869,7 @@ pub(crate) trait CallPolicy: Any {
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone(); machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
} }
machine_st.num_of_args = n; machine_st.num_of_args = n;
@@ -510,7 +905,7 @@ pub(crate) trait CallPolicy: Any {
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone(); machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
} }
machine_st.num_of_args = n; machine_st.num_of_args = n;
@@ -536,8 +931,8 @@ pub(crate) trait CallPolicy: Any {
attr_var_init_bindings_b, attr_var_init_bindings_b,
); );
machine_st.stack.truncate(machine_st.b);
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
machine_st.stack.truncate(b);
machine_st.hb = machine_st.heap.h(); machine_st.hb = machine_st.heap.h();
machine_st.p += offset; machine_st.p += offset;
@@ -550,7 +945,7 @@ pub(crate) trait CallPolicy: Any {
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells; let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone(); machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
} }
machine_st.num_of_args = n; machine_st.num_of_args = n;
@@ -576,8 +971,8 @@ pub(crate) trait CallPolicy: Any {
attr_var_init_bindings_b, attr_var_init_bindings_b,
); );
machine_st.stack.truncate(machine_st.b);
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
machine_st.stack.truncate(b);
machine_st.hb = machine_st.heap.h(); machine_st.hb = machine_st.heap.h();
machine_st.p += 1; machine_st.p += 1;
@@ -667,11 +1062,12 @@ pub(crate) trait CallPolicy: Any {
machine_st: &mut MachineState, machine_st: &mut MachineState,
ct: &BuiltInClauseType, ct: &BuiltInClauseType,
indices: &mut IndexStore, indices: &mut IndexStore,
parsing_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
match ct { match ct {
&BuiltInClauseType::AcyclicTerm => { &BuiltInClauseType::AcyclicTerm => {
let addr = machine_st[temp_v!(1)].clone(); let addr = machine_st[temp_v!(1)];
machine_st.fail = machine_st.is_cyclic_term(addr); machine_st.fail = machine_st.is_cyclic_term(addr);
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
@@ -680,48 +1076,50 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::Compare => { &BuiltInClauseType::Compare => {
let a1 = machine_st[temp_v!(1)].clone(); let a1 = machine_st[temp_v!(1)];
let a2 = machine_st[temp_v!(2)].clone(); let a2 = machine_st[temp_v!(2)];
let a3 = machine_st[temp_v!(3)].clone(); let a3 = machine_st[temp_v!(3)];
let c = match machine_st.compare_term_test(&a2, &a3) { let atom = match machine_st.compare_term_test(&a2, &a3) {
Ordering::Greater => { Some(Ordering::Greater) => {
let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir);
Addr::Con(Constant::Atom(clause_name!(">"), spec)) HeapCellValue::Atom(clause_name!(">"), spec)
} }
Ordering::Equal => { Some(Ordering::Equal) => {
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
Addr::Con(Constant::Atom(clause_name!("="), spec)) HeapCellValue::Atom(clause_name!("="), spec)
} }
Ordering::Less => { None | Some(Ordering::Less) => {
let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir);
Addr::Con(Constant::Atom(clause_name!("<"), spec)) HeapCellValue::Atom(clause_name!("<"), spec)
} }
}; };
machine_st.unify(a1, c); let h = machine_st.heap.h();
machine_st.heap.push(atom);
machine_st.unify(a1, Addr::Con(h));
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::CompareTerm(qt) => { &BuiltInClauseType::CompareTerm(qt) => {
machine_st.compare_term(qt); machine_st.compare_term(qt);
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::CyclicTerm => {
let addr = machine_st[temp_v!(1)].clone();
machine_st.fail = !machine_st.is_cyclic_term(addr);
return_from_clause!(machine_st.last_call, machine_st)
}
&BuiltInClauseType::Nl => { &BuiltInClauseType::Nl => {
let mut stdout = stdout(); write!(current_output_stream, "\n").unwrap();
current_output_stream.flush().unwrap();
write!(stdout, "\n").unwrap();
stdout.flush().unwrap();
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::Read => { &BuiltInClauseType::Read => {
match machine_st.read(parsing_stream, indices.atom_tbl.clone(), &indices.op_dir) { match machine_st.read(
&mut parsing_stream(current_input_stream.clone()),
indices.atom_tbl.clone(),
&indices.op_dir,
) {
Ok(offset) => { Ok(offset) => {
let addr = machine_st[temp_v!(1)].clone(); let addr = machine_st[temp_v!(1)];
machine_st.unify(addr, Addr::HeapCell(offset.heap_loc)); machine_st.unify(addr, Addr::HeapCell(offset.heap_loc));
} }
Err(e) => { Err(e) => {
@@ -741,8 +1139,8 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::Eq => { &BuiltInClauseType::Eq => {
let a1 = machine_st[temp_v!(1)].clone(); let a1 = machine_st[temp_v!(1)];
let a2 = machine_st[temp_v!(2)].clone(); let a2 = machine_st[temp_v!(2)];
machine_st.fail = machine_st.eq_test(a1, a2); machine_st.fail = machine_st.eq_test(a1, a2);
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
@@ -756,10 +1154,11 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::NotEq => { &BuiltInClauseType::NotEq => {
let a1 = machine_st[temp_v!(1)].clone(); let a1 = machine_st[temp_v!(1)];
let a2 = machine_st[temp_v!(2)].clone(); let a2 = machine_st[temp_v!(2)];
machine_st.fail = if let Ordering::Equal = machine_st.compare_term_test(&a1, &a2) { machine_st.fail =
if let Some(Ordering::Equal) = machine_st.compare_term_test(&a1, &a2) {
true true
} else { } else {
false false
@@ -773,12 +1172,15 @@ pub(crate) trait CallPolicy: Any {
let stub = MachineError::functor_stub(clause_name!("sort"), 2); let stub = MachineError::functor_stub(clause_name!("sort"), 2);
let mut list = machine_st.try_from_list(temp_v!(1), stub)?; let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2)); list.sort_unstable_by(|a1, a2| {
machine_st.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
});
machine_st.term_dedup(&mut list); machine_st.term_dedup(&mut list);
let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter())); let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter()));
let r2 = machine_st[temp_v!(2)].clone(); let r2 = machine_st[temp_v!(2)];
machine_st.unify(r2, heap_addr); machine_st.unify(r2, heap_addr);
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
@@ -795,21 +1197,25 @@ pub(crate) trait CallPolicy: Any {
key_pairs.push((key, val.clone())); key_pairs.push((key, val.clone()));
} }
key_pairs.sort_by(|a1, a2| machine_st.compare_term_test(&a1.0, &a2.0)); key_pairs.sort_by(|a1, a2| {
machine_st.compare_term_test(&a1.0, &a2.0).unwrap_or(Ordering::Less)
});
let key_pairs = key_pairs.into_iter().map(|kp| kp.1); let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs)); let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs));
let r2 = machine_st[temp_v!(2)].clone(); let r2 = machine_st[temp_v!(2)];
machine_st.unify(r2, heap_addr); machine_st.unify(r2, heap_addr);
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::Is(r, ref at) => { &BuiltInClauseType::Is(r, ref at) => {
let a1 = machine_st[r].clone(); let a1 = machine_st[r];
let a2 = machine_st.get_number(at)?; let n2 = machine_st.get_number(at)?;
let n2 = machine_st.heap.put_constant(n2.into());
machine_st.unify(a1, n2);
machine_st.unify(a1, Addr::Con(a2.to_constant()));
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
} }
@@ -842,13 +1248,20 @@ pub(crate) trait CallPolicy: Any {
machine_st: &mut MachineState, machine_st: &mut MachineState,
arity: usize, arity: usize,
indices: &mut IndexStore, indices: &mut IndexStore,
parsing_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
if let Some((name, arity)) = machine_st.setup_call_n(arity) { if let Some((name, arity)) = machine_st.setup_call_n(arity) {
match ClauseType::from(name.clone(), arity, None) { match ClauseType::from(name.clone(), arity, None) {
ClauseType::BuiltIn(built_in) => { ClauseType::BuiltIn(built_in) => {
machine_st.setup_built_in_call(built_in.clone()); machine_st.setup_built_in_call(built_in.clone());
self.call_builtin(machine_st, &built_in, indices, parsing_stream)?; self.call_builtin(
machine_st,
&built_in,
indices,
current_input_stream,
current_output_stream,
)?;
} }
ClauseType::CallN => { ClauseType::CallN => {
machine_st.handle_internal_call_n(arity); machine_st.handle_internal_call_n(arity);
@@ -876,11 +1289,13 @@ pub(crate) trait CallPolicy: Any {
} }
} }
ClauseType::Hook(_) | ClauseType::System(_) => { ClauseType::Hook(_) | ClauseType::System(_) => {
let name = Addr::Con(Constant::Atom(name, None)); let name = functor!(clause_name(name));
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
return Err(machine_st return Err(machine_st.error_form(
.error_form(MachineError::type_error(ValidType::Callable, name), stub)); MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name),
stub,
));
} }
}; };
} }
@@ -928,10 +1343,17 @@ impl CallPolicy for CWILCallPolicy {
machine_st: &mut MachineState, machine_st: &mut MachineState,
ct: &BuiltInClauseType, ct: &BuiltInClauseType,
indices: &mut IndexStore, indices: &mut IndexStore,
parsing_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
self.prev_policy self.prev_policy.call_builtin(
.call_builtin(machine_st, ct, indices, parsing_stream)?; machine_st,
ct,
indices,
current_input_stream,
current_output_stream
)?;
self.increment(machine_st) self.increment(machine_st)
} }
@@ -940,10 +1362,17 @@ impl CallPolicy for CWILCallPolicy {
machine_st: &mut MachineState, machine_st: &mut MachineState,
arity: usize, arity: usize,
indices: &mut IndexStore, indices: &mut IndexStore,
parsing_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
self.prev_policy self.prev_policy.call_n(
.call_n(machine_st, arity, indices, parsing_stream)?; machine_st,
arity,
indices,
current_input_stream,
current_output_stream,
)?;
self.increment(machine_st) self.increment(machine_st)
} }
} }
@@ -962,7 +1391,8 @@ pub(crate) struct CWILCallPolicy {
} }
impl CWILCallPolicy { impl CWILCallPolicy {
pub(crate) fn new_in_place(policy: &mut Box<dyn CallPolicy>) { pub(crate)
fn new_in_place(policy: &mut Box<dyn CallPolicy>) {
let mut prev_policy: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {}); let mut prev_policy: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
mem::swap(&mut prev_policy, policy); mem::swap(&mut prev_policy, policy);
@@ -972,6 +1402,7 @@ impl CWILCallPolicy {
limits: vec![], limits: vec![],
inference_limit_exceeded: false, inference_limit_exceeded: false,
}; };
*policy = Box::new(new_policy); *policy = Box::new(new_policy);
} }
@@ -983,10 +1414,10 @@ impl CWILCallPolicy {
if let Some(&(ref limit, bp)) = self.limits.last() { if let Some(&(ref limit, bp)) = self.limits.last() {
if self.count == *limit { if self.count == *limit {
self.inference_limit_exceeded = true; self.inference_limit_exceeded = true;
return Err(functor!( return Err(functor!(
"inference_limit_exceeded", "inference_limit_exceeded",
1, [addr(Addr::Usize(bp))]
[HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))]
)); ));
} else { } else {
self.count += 1; self.count += 1;
@@ -996,7 +1427,8 @@ impl CWILCallPolicy {
Ok(()) Ok(())
} }
pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { pub(crate)
fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer {
limit += &self.count; limit += &self.count;
match self.limits.last().cloned() { match self.limits.last().cloned() {
@@ -1007,7 +1439,8 @@ impl CWILCallPolicy {
&self.count &self.count
} }
pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { pub(crate)
fn remove_limit(&mut self, b: usize) -> &Integer {
if let Some((_, bp)) = self.limits.last().cloned() { if let Some((_, bp)) = self.limits.last().cloned() {
if bp == b { if bp == b {
self.limits.pop(); self.limits.pop();
@@ -1017,11 +1450,13 @@ impl CWILCallPolicy {
&self.count &self.count
} }
pub(crate) fn is_empty(&self) -> bool { pub(crate)
fn is_empty(&self) -> bool {
self.limits.is_empty() self.limits.is_empty()
} }
pub(crate) fn into_inner(&mut self) -> Box<dyn CallPolicy> { pub(crate)
fn into_inner(&mut self) -> Box<dyn CallPolicy> {
let mut new_inner: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {}); let mut new_inner: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
mem::swap(&mut self.prev_policy, &mut new_inner); mem::swap(&mut self.prev_policy, &mut new_inner);
new_inner new_inner
@@ -1030,16 +1465,16 @@ impl CWILCallPolicy {
pub(crate) trait CutPolicy: Any { pub(crate) trait CutPolicy: Any {
// returns true iff we fail or cut redirected the MachineState's p itself // returns true iff we fail or cut redirected the MachineState's p itself
fn cut(&mut self, _: &mut MachineState, _: RegType) -> bool; fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool;
} }
downcast!(dyn CutPolicy); downcast!(dyn CutPolicy);
fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool { fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool {
let b = machine_st.b; let b = machine_st.b;
match addr { match addr {
Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => { &Addr::CutPoint(b0) | &Addr::Usize(b0) => {
if b > b0 { if b > b0 {
machine_st.b = b0; machine_st.b = b0;
machine_st.tidy_trail(); machine_st.tidy_trail();
@@ -1057,14 +1492,14 @@ fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
pub(crate) struct DefaultCutPolicy {} pub(crate) struct DefaultCutPolicy {}
pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) { pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) {
let addr = machine_st.store(machine_st.deref(machine_st[r].clone())); let addr = machine_st.store(machine_st.deref(machine_st[r]));
cut_body(machine_st, addr); cut_body(machine_st, &addr);
} }
impl CutPolicy for DefaultCutPolicy { impl CutPolicy for DefaultCutPolicy {
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
let addr = machine_st[r].clone(); let addr = machine_st[r];
cut_body(machine_st, addr) cut_body(machine_st, &addr)
} }
} }
@@ -1102,7 +1537,7 @@ impl SCCCutPolicy {
let (idx, arity) = if machine_st.block < prev_block { let (idx, arity) = if machine_st.block < prev_block {
(dir_entry!(self.r_c_w_h), 0) (dir_entry!(self.r_c_w_h), 0)
} else { } else {
machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff)); machine_st[temp_v!(1)] = Addr::Usize(b_cutoff);
(dir_entry!(self.r_c_wo_h), 1) (dir_entry!(self.r_c_wo_h), 1)
}; };
@@ -1124,8 +1559,8 @@ impl CutPolicy for SCCCutPolicy {
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
let b = machine_st.b; let b = machine_st.b;
match machine_st[r].clone() { match machine_st[r] {
Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => { Addr::Usize(b0) | Addr::CutPoint(b0) => {
if b > b0 { if b > b0 {
machine_st.b = b0; machine_st.b = b0;
machine_st.tidy_trail(); machine_st.tidy_trail();

File diff suppressed because it is too large Load Diff

View File

@@ -19,12 +19,15 @@ pub mod machine_errors;
pub mod machine_indices; pub mod machine_indices;
pub(super) mod machine_state; pub(super) mod machine_state;
pub mod modules; pub mod modules;
mod partial_string; pub mod partial_string;
mod raw_block; mod raw_block;
mod stack; mod stack;
pub(crate) mod streams;
pub(super) mod term_expansion; pub(super) mod term_expansion;
pub mod toplevel; pub mod toplevel;
#[macro_use]
mod arithmetic_ops;
#[macro_use] #[macro_use]
mod machine_state_impl; mod machine_state_impl;
mod system_calls; mod system_calls;
@@ -36,14 +39,14 @@ use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*; use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::modules::*; use crate::prolog::machine::modules::*;
use crate::prolog::machine::streams::*;
use crate::prolog::machine::toplevel::*; use crate::prolog::machine::toplevel::*;
use crate::prolog::read::PrologStream;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fs::File; use std::fs::File;
use std::io::Read;
use std::mem; use std::mem;
use std::ops::Index; use std::ops::Index;
use std::path::PathBuf; use std::path::PathBuf;
@@ -76,7 +79,8 @@ pub struct Machine {
pub(super) indices: IndexStore, pub(super) indices: IndexStore,
pub(super) code_repo: CodeRepo, pub(super) code_repo: CodeRepo,
pub(super) toplevel_idx: usize, pub(super) toplevel_idx: usize,
pub(super) prolog_stream: ParsingStream<Box<dyn Read>>, pub(super) current_input_stream: Stream,
pub(super) current_output_stream: Stream,
} }
impl Index<LocalCodePtr> for CodeRepo { impl Index<LocalCodePtr> for CodeRepo {
@@ -149,8 +153,16 @@ impl SubModuleUser for IndexStore {
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) { fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) { if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) {
if !code_idx.is_undefined() { if !code_idx.is_undefined() {
match (name.as_str(), arity) {
("term_expansion", 2) => {
}
("goal_expansion", 2) => {
}
_ => {
println!("Warning: overwriting {}/{}", &name, arity); println!("Warning: overwriting {}/{}", &name, arity);
} }
}
}
let (p, module_name) = idx.0.borrow().clone(); let (p, module_name) = idx.0.borrow().clone();
set_code_index!(code_idx, p, module_name); set_code_index!(code_idx, p, module_name);
@@ -193,7 +205,11 @@ impl SubModuleUser for IndexStore {
#[inline] #[inline]
fn current_dir() -> std::path::PathBuf { fn current_dir() -> std::path::PathBuf {
let mut path_buf = std::path::PathBuf::from(file!()); let mut path_buf = std::path::PathBuf::from(PROJECT_DIR);
// file!() always produces a path relative to PROJECT_DIR.
path_buf = path_buf.join(std::path::PathBuf::from(file!()));
path_buf.pop(); path_buf.pop();
path_buf path_buf
} }
@@ -212,7 +228,11 @@ impl Machine {
current_dir.clone(), current_dir.clone(),
); );
match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes()), verify_attrs_src) match compile_special_form(
self,
Stream::from(VERIFY_ATTRS),
verify_attrs_src,
)
{ {
Ok(p) => { Ok(p) => {
self.machine_st.attr_var_init.verify_attrs_loc = p; self.machine_st.attr_var_init.verify_attrs_loc = p;
@@ -226,7 +246,11 @@ impl Machine {
current_dir, current_dir,
); );
match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src) match compile_special_form(
self,
Stream::from(PROJECT_ATTRS),
project_attrs_src,
)
{ {
Ok(p) => { Ok(p) => {
self.machine_st.attr_var_init.project_attrs_loc = p; self.machine_st.attr_var_init.project_attrs_loc = p;
@@ -250,7 +274,7 @@ impl Machine {
compile_user_module( compile_user_module(
self, self,
parsing_stream(TOPLEVEL.as_bytes()), Stream::from(TOPLEVEL),
true, true,
top_lvl_src, top_lvl_src,
); );
@@ -264,7 +288,11 @@ impl Machine {
Ok(self.indices.insert_module(module)) Ok(self.indices.insert_module(module))
} else { } else {
Err(SessionError::ModuleNotFound) let err = ExistenceError::SourceSink(ModuleSource::File(
clause_name!("$toplevel"),
));
Err(SessionError::ExistenceError(err))
} }
} }
@@ -278,7 +306,7 @@ impl Machine {
if path.is_file() { if path.is_file() {
let file_src = match File::open(&path) { let file_src = match File::open(&path) {
Ok(file_handle) => parsing_stream(file_handle), Ok(file_handle) => Stream::from(file_handle),
Err(_) => return, Err(_) => return,
}; };
@@ -293,7 +321,7 @@ impl Machine {
#[cfg(test)] #[cfg(test)]
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.prolog_stream = readline::input_stream(); self.current_input_stream = readline::input_stream();
self.policies.cut_policy = Box::new(DefaultCutPolicy {}); self.policies.cut_policy = Box::new(DefaultCutPolicy {});
self.machine_st.reset(); self.machine_st.reset();
} }
@@ -319,8 +347,8 @@ impl Machine {
// the first of these is the path to the scryer-prolog executable, so skip // the first of these is the path to the scryer-prolog executable, so skip
// it. // it.
for filename in env::args().skip(1) { for filename in env::args().skip(1) {
let atom = atom!(filename, self.indices.atom_tbl); let atom = clause_name!(filename, self.indices.atom_tbl);
filename_atoms.push(Addr::Con(atom)); filename_atoms.push(HeapCellValue::Atom(atom, None));
} }
let list_addr = let list_addr =
@@ -332,7 +360,7 @@ impl Machine {
self.run_query(); self.run_query();
} }
pub fn new(prolog_stream: PrologStream) -> Self pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self
{ {
let mut wam = Machine { let mut wam = Machine {
machine_st: MachineState::new(), machine_st: MachineState::new(),
@@ -341,7 +369,8 @@ impl Machine {
indices: IndexStore::new(), indices: IndexStore::new(),
code_repo: CodeRepo::new(), code_repo: CodeRepo::new(),
toplevel_idx: 0, toplevel_idx: 0,
prolog_stream, current_input_stream,
current_output_stream,
}; };
let atom_tbl = wam.indices.atom_tbl.clone(); let atom_tbl = wam.indices.atom_tbl.clone();
@@ -354,7 +383,7 @@ impl Machine {
compile_listing( compile_listing(
&mut wam, &mut wam,
parsing_stream(BUILTINS.as_bytes()), Stream::from(BUILTINS),
default_index_store!(atom_tbl.clone()), default_index_store!(atom_tbl.clone()),
true, true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
@@ -365,25 +394,36 @@ impl Machine {
wam.compile_special_forms(); wam.compile_special_forms();
compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true, compile_user_module(&mut wam,
Stream::from(ERROR),
true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
clause_name!("error"), clause_name!("error"),
lib_path.clone(), lib_path.clone(),
) )
); );
compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true,
compile_user_module(&mut wam,
Stream::from(LISTS),
true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
clause_name!("lists"), clause_name!("lists"),
lib_path.clone(), lib_path.clone(),
), ),
); );
compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()), true,
compile_user_module(&mut wam,
Stream::from(ISO_EXT),
true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
clause_name!("non_iso"), clause_name!("iso_ext"),
lib_path.clone(), lib_path.clone(),
) )
); );
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
compile_user_module(&mut wam,
Stream::from(SI),
true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
clause_name!("si"), clause_name!("si"),
lib_path.clone(), lib_path.clone(),
@@ -514,15 +554,17 @@ impl Machine {
HeapCellValue::NamedStr(arity, ref name, _) HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 2 && name.as_str() == "/" => { if *arity == 2 && name.as_str() == "/" => {
let name = match &self.machine_st.heap[s+1] { let name = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) => &HeapCellValue::Atom(ref name, _) =>
name.clone(), name.clone(),
_ => _ =>
unreachable!() unreachable!()
}; };
let arity = match &self.machine_st.heap[s+2] { let arity = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) => &HeapCellValue::Integer(ref arity) =>
arity.to_usize().unwrap(), arity.to_usize().unwrap(),
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
usize::try_from(n).unwrap(),
_ => _ =>
unreachable!() unreachable!()
}; };
@@ -532,22 +574,24 @@ impl Machine {
HeapCellValue::NamedStr(arity, ref name, _) HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 3 && name.as_str() == "op" => { if *arity == 3 && name.as_str() == "op" => {
let name = match &self.machine_st.heap[s+3] { let name = match &self.machine_st.heap[s+3] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) => &HeapCellValue::Atom(ref name, _) =>
name.clone(), name.clone(),
_ => _ =>
unreachable!() unreachable!()
}; };
let spec = match &self.machine_st.heap[s+2] { let spec = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) => &HeapCellValue::Atom(ref name, _) =>
name.clone(), name.clone(),
_ => _ =>
unreachable!() unreachable!()
}; };
let prec = match &self.machine_st.heap[s+1] { let prec = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) => &HeapCellValue::Integer(ref arity) =>
arity.to_usize().unwrap(), arity.to_usize().unwrap(),
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
usize::try_from(n).unwrap(),
_ => _ =>
unreachable!() unreachable!()
}; };
@@ -577,9 +621,13 @@ impl Machine {
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
let module_spec = self.machine_st[temp_v!(1)].clone(); let module_spec = self.machine_st[temp_v!(1)].clone();
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) { let name = {
Addr::Con(Constant::Atom(name, _)) => name, let addr = self.machine_st.store(self.machine_st.deref(module_spec));
_ => unreachable!()
match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => name.clone(),
_ => unreachable!(),
}
}; };
let load_result = match to_src(name) { let load_result = match to_src(name) {
@@ -620,9 +668,13 @@ impl Machine {
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
let module_spec = self.machine_st[temp_v!(1)].clone(); let module_spec = self.machine_st[temp_v!(1)].clone();
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) { let name = {
Addr::Con(Constant::Atom(name, _)) => name, let addr = self.machine_st.store(self.machine_st.deref(module_spec));
_ => unreachable!()
match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => name.clone(),
_ => unreachable!(),
}
}; };
let exports = match self.extract_module_export_list() { let exports = match self.extract_module_export_list() {
@@ -699,7 +751,7 @@ impl Machine {
snapshot.e = self.machine_st.e; snapshot.e = self.machine_st.e;
snapshot.b = self.machine_st.b; snapshot.b = self.machine_st.b;
snapshot.b0 = self.machine_st.b0; snapshot.b0 = self.machine_st.b0;
snapshot.s = self.machine_st.s; snapshot.s = self.machine_st.s.clone();
snapshot.tr = self.machine_st.tr; snapshot.tr = self.machine_st.tr;
snapshot.num_of_args = self.machine_st.num_of_args; snapshot.num_of_args = self.machine_st.num_of_args;
@@ -751,12 +803,16 @@ impl Machine {
&mut self.indices, &mut self.indices,
&mut self.policies, &mut self.policies,
&mut self.code_repo, &mut self.code_repo,
&mut self.prolog_stream, &mut self.current_input_stream,
&mut self.current_output_stream,
); );
match self.machine_st.p { match self.machine_st.p {
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {} CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {
CodePtr::REPL(code_ptr, p) => self.handle_toplevel_command(code_ptr, p), }
CodePtr::REPL(code_ptr, p) => {
self.handle_toplevel_command(code_ptr, p)
}
CodePtr::DynamicTransaction(trans_type, p) => { CodePtr::DynamicTransaction(trans_type, p) => {
// self.code_repo.cached_query is about to be overwritten by the term expander, // self.code_repo.cached_query is about to be overwritten by the term expander,
// so hold onto it locally and restore it after the compiler has finished. // so hold onto it locally and restore it after the compiler has finished.
@@ -784,29 +840,37 @@ impl MachineState {
indices: &mut IndexStore, indices: &mut IndexStore,
policies: &mut MachinePolicies, policies: &mut MachinePolicies,
code_repo: &CodeRepo, code_repo: &CodeRepo,
prolog_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) { ) {
match instr { match instr {
&Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr), &Line::Arithmetic(ref arith_instr) => {
self.execute_arith_instr(arith_instr)
}
&Line::Choice(ref choice_instr) => { &Line::Choice(ref choice_instr) => {
self.execute_choice_instr(choice_instr, &mut policies.call_policy) self.execute_choice_instr(choice_instr, &mut policies.call_policy)
} }
&Line::Cut(ref cut_instr) => { &Line::Cut(ref cut_instr) => {
self.execute_cut_instr(cut_instr, &mut policies.cut_policy) self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
} }
&Line::Control(ref control_instr) => self.execute_ctrl_instr( &Line::Control(ref control_instr) => {
self.execute_ctrl_instr(
indices, indices,
code_repo, code_repo,
&mut policies.call_policy, &mut policies.call_policy,
&mut policies.cut_policy, &mut policies.cut_policy,
prolog_stream, current_input_stream,
current_output_stream,
control_instr, control_instr,
), )
}
&Line::Fact(ref fact_instr) => { &Line::Fact(ref fact_instr) => {
self.execute_fact_instr(&fact_instr); self.execute_fact_instr(&fact_instr);
self.p += 1; self.p += 1;
} }
&Line::Indexing(ref indexing_instr) => self.execute_indexing_instr(&indexing_instr), &Line::Indexing(ref indexing_instr) => {
self.execute_indexing_instr(&indexing_instr)
}
&Line::IndexedChoice(ref choice_instr) => { &Line::IndexedChoice(ref choice_instr) => {
self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy) self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
} }
@@ -822,14 +886,22 @@ impl MachineState {
indices: &mut IndexStore, indices: &mut IndexStore,
policies: &mut MachinePolicies, policies: &mut MachinePolicies,
code_repo: &CodeRepo, code_repo: &CodeRepo,
prolog_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) { ) {
let instr = match code_repo.lookup_instr(self.last_call, &self.p) { let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
Some(instr) => instr, Some(instr) => instr,
None => return, None => return,
}; };
self.dispatch_instr(instr.as_ref(), indices, policies, code_repo, prolog_stream); self.dispatch_instr(
instr.as_ref(),
indices,
policies,
code_repo,
current_input_stream,
current_output_stream,
);
} }
fn backtrack(&mut self) { fn backtrack(&mut self) {
@@ -880,7 +952,8 @@ impl MachineState {
indices: &mut IndexStore, indices: &mut IndexStore,
policies: &mut MachinePolicies, policies: &mut MachinePolicies,
code_repo: &mut CodeRepo, code_repo: &mut CodeRepo,
prolog_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> bool { ) -> bool {
loop { loop {
let instr = match code_repo.lookup_instr(self.last_call, &self.p) { let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
@@ -896,7 +969,14 @@ impl MachineState {
None => return false, None => return false,
}; };
self.dispatch_instr(instr.as_ref(), indices, policies, code_repo, prolog_stream); self.dispatch_instr(
instr.as_ref(),
indices,
policies,
code_repo,
current_input_stream,
current_output_stream,
);
if self.fail { if self.fail {
self.backtrack(); self.backtrack();
@@ -920,10 +1000,17 @@ impl MachineState {
indices: &mut IndexStore, indices: &mut IndexStore,
policies: &mut MachinePolicies, policies: &mut MachinePolicies,
code_repo: &mut CodeRepo, code_repo: &mut CodeRepo,
prolog_stream: &mut PrologStream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) { ) {
loop { loop {
self.execute_instr(indices, policies, code_repo, prolog_stream); self.execute_instr(
indices,
policies,
code_repo,
current_input_stream,
current_output_stream,
);
if self.fail { if self.fail {
self.backtrack(); self.backtrack();
@@ -939,7 +1026,13 @@ impl MachineState {
if !instigating_instr.as_ref().is_head_instr() { if !instigating_instr.as_ref().is_head_instr() {
let cp = self.p.local(); let cp = self.p.local();
self.run_verify_attr_interrupt(cp); self.run_verify_attr_interrupt(cp);
} else if !self.verify_attr_stepper(indices, policies, code_repo, prolog_stream) { } else if !self.verify_attr_stepper(
indices,
policies,
code_repo,
current_input_stream,
current_output_stream,
) {
if self.fail { if self.fail {
break; break;
} }

View File

@@ -1,28 +1,28 @@
use crate::prolog::machine::machine_indices::*; use core::marker::PhantomData;
use crate::prolog::machine::raw_block::*;
use std::alloc;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::ops::RangeFrom;
use std::slice; use std::slice;
use std::str; use std::str;
pub(crate) struct PartialStringTraits {}
impl RawBlockTraits for PartialStringTraits {
#[inline]
fn init_size() -> usize {
0
}
#[inline]
fn align() -> usize {
mem::align_of::<char>()
}
}
pub struct PartialString { pub struct PartialString {
pub(super) buf: RawBlock<PartialStringTraits>, buf: *const u8,
pub(super) tail: Addr, len: usize,
_marker: PhantomData<[u8]>,
}
impl Drop for PartialString {
fn drop(&mut self) {
unsafe {
let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::<u8>());
alloc::dealloc(self.buf as *mut u8, layout);
self.buf = ptr::null();
self.len = 0;
}
}
} }
impl Clone for PartialString { impl Clone for PartialString {
@@ -32,17 +32,10 @@ impl Clone for PartialString {
} }
} }
impl PartialEq for PartialString { fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
#[inline]
fn eq(&self, other: &Self) -> bool {
self as *const _ == other as *const _
}
}
fn scan_for_terminator(src: &str) -> usize {
let mut terminator_idx = 0; let mut terminator_idx = 0;
for c in src.chars() { for c in iter {
if c == '\u{0}' { if c == '\u{0}' {
break; break;
} }
@@ -53,12 +46,61 @@ fn scan_for_terminator(src: &str) -> usize {
terminator_idx terminator_idx
} }
pub struct PStrIter {
buf: *const u8,
}
impl PStrIter {
#[inline]
fn from(buf: *const u8, idx: usize) -> Self {
PStrIter {
buf: (buf as usize + idx) as *const _
}
}
}
impl Iterator for PStrIter {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let mut byte_count = 0;
for n in 0 .. mem::size_of::<char>() {
let b = ptr::read((self.buf as usize + n) as *const u8);
if b == 0u8 {
break;
} else {
byte_count += 1;
}
}
if byte_count == 0 {
return None;
}
let slice = slice::from_raw_parts(self.buf, byte_count);
let s = str::from_utf8(slice).unwrap();
if let Some(c) = s.chars().next() {
self.buf = self.buf.offset(c.len_utf8() as isize);
Some(c)
} else {
None
}
}
}
}
impl PartialString { impl PartialString {
#[inline]
pub(super) pub(super)
fn new(src: &str, h: usize) -> Option<(Self, &str)> { fn new(src: &str) -> Option<(Self, &str)> {
let pstr = PartialString { let pstr = PartialString {
buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()), buf: ptr::null_mut(),
tail: Addr::PStrTail(h, 0), len: 0,
_marker: PhantomData,
}; };
unsafe { unsafe {
@@ -66,22 +108,51 @@ impl PartialString {
} }
} }
#[inline]
pub(super)
fn empty() -> Self {
let mut pstr = PartialString {
buf: ptr::null(),
len: 0,
_marker: PhantomData,
};
unsafe {
let layout = alloc::Layout::from_size_align_unchecked(
'\u{0}'.len_utf8(),
mem::align_of::<u8>(),
);
pstr.buf = alloc::alloc(layout) as *const _;
pstr.len = '\u{0}'.len_utf8();
pstr.write_terminator_at(0);
}
pstr
}
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> { unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
let terminator_idx = scan_for_terminator(src); let terminator_idx = scan_for_terminator(src.chars());
if terminator_idx == 0 { if terminator_idx == 0 {
return None; return None;
} }
let new_top = self.buf.new_block(terminator_idx + '\u{0}'.len_utf8()); let layout = alloc::Layout::from_size_align_unchecked(
terminator_idx + '\u{0}'.len_utf8(),
mem::align_of::<u8>(),
);
self.buf = alloc::alloc(layout) as *const _;
self.len = terminator_idx + '\u{0}'.len_utf8();
ptr::copy( ptr::copy(
src.as_ptr(), src.as_ptr(),
self.buf.top as *mut _, self.buf as *mut _,
terminator_idx, terminator_idx,
); );
self.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
self.write_terminator_at(terminator_idx); self.write_terminator_at(terminator_idx);
Some(if terminator_idx != src.len() { Some(if terminator_idx != src.len() {
@@ -91,30 +162,38 @@ impl PartialString {
}) })
} }
/* Ordinarily cloning of heap cell values is done in copy_term,
* so we rely on it to set the tail correctly. here it's set to PStrTail(0, 0),
* because we don't know its heap location. */
pub(super) pub(super)
fn clone_from_offset(&self, n: usize) -> Self { fn clone_from_offset(&self, n: usize) -> Self {
let len =
if self.len - '\u{0}'.len_utf8() > n {
self.len - n - '\u{0}'.len_utf8()
} else {
0
};
let mut pstr = PartialString { let mut pstr = PartialString {
buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()), buf: ptr::null_mut(),
tail: Addr::PStrTail(0, 0), len: len + '\u{0}'.len_utf8(),
_marker: PhantomData,
}; };
unsafe { unsafe {
let len = if self.len() > n { self.len() - n } else { 0 }; let layout = alloc::Layout::from_size_align_unchecked(
let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8()); len + '\u{0}'.len_utf8(),
mem::align_of::<u8>(),
);
pstr.buf = alloc::alloc(layout);
if len > 0 { if len > 0 {
ptr::copy( ptr::copy(
(self.buf.base as usize + n) as *mut u8, (self.buf as usize + n) as *const u8,
pstr.buf.base as *mut _, pstr.buf as *mut _,
len, len,
); );
} }
pstr.write_terminator_at(len); pstr.write_terminator_at(len);
pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
} }
pstr pstr
@@ -125,37 +204,35 @@ impl PartialString {
fn write_terminator_at(&mut self, index: usize) { fn write_terminator_at(&mut self, index: usize) {
unsafe { unsafe {
ptr::write( ptr::write(
(self.buf.base as usize + index) as *mut u8, (self.buf as usize + index) as *mut u8,
0u8, 0u8,
); );
} }
} }
#[inline] #[inline]
pub(crate) pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
fn block_as_str(&self) -> &str { PStrIter::from(self.buf, index.start)
}
#[inline]
pub fn at_end(&self, end_n: usize) -> bool {
unsafe { unsafe {
let slice = slice::from_raw_parts(self.buf.base, self.len()); ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
str::from_utf8(slice).unwrap()
} }
} }
#[inline] #[inline]
pub(crate) pub fn as_str_from(&self, n: usize) -> &str {
fn tail_addr(&self) -> &Addr { unsafe {
&self.tail let slice = slice::from_raw_parts(
} self.buf,
self.len - '\u{0}'.len_utf8(),
);
#[inline] let s = str::from_utf8(slice).unwrap();
pub fn len(&self) -> usize {
self.buf.top as usize - self.buf.base as usize
}
#[inline] &s[n ..]
pub fn truncate(&mut self, len: usize) {
if (len + self.buf.base as usize) < self.buf.top as usize {
self.buf.top = (len + self.buf.base as usize) as *const _;
self.write_terminator_at(len);
} }
} }
} }

View File

@@ -36,20 +36,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
block block
} }
pub(crate)
fn with_capacity(cap: usize) -> Self {
let mut block = RawBlock { size: 0,
base: ptr::null(),
top: ptr::null(),
_marker: PhantomData };
unsafe {
block.init_at_size(cap);
}
block
}
unsafe fn init_at_size(&mut self, cap: usize) { unsafe fn init_at_size(&mut self, cap: usize) {
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align()); let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
@@ -86,7 +72,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
mem::replace(self, Self::empty_block()) mem::replace(self, Self::empty_block())
} }
#[inline] #[inline]
fn free_space(&self) -> usize { fn free_space(&self) -> usize {
debug_assert!(self.top >= self.base, debug_assert!(self.top >= self.base,

View File

@@ -49,7 +49,6 @@ impl Drop for Stack {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct FramePrelude { pub struct FramePrelude {
is_or_frame: u8,
pub num_cells: usize, pub num_cells: usize,
} }
@@ -62,7 +61,6 @@ pub struct AndFramePrelude {
pub struct AndFrame { pub struct AndFrame {
pub prelude: AndFramePrelude, pub prelude: AndFramePrelude,
_marker: PhantomData<Addr>,
} }
impl AndFrame { impl AndFrame {
@@ -101,24 +99,6 @@ impl IndexMut<usize> for AndFrame {
} }
} }
impl Drop for AndFrame {
fn drop(&mut self) {
let prelude_offset = prelude_size::<AndFramePrelude>();
unsafe {
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset;
for idx in 0 .. self.prelude.univ_prelude.num_cells {
let index_offset = idx * mem::size_of::<Addr>();
let ptr = (ptr + index_offset) as *mut Addr;
ptr::drop_in_place(ptr);
}
}
}
}
pub struct OrFramePrelude { pub struct OrFramePrelude {
pub univ_prelude: FramePrelude, pub univ_prelude: FramePrelude,
pub e: usize, pub e: usize,
@@ -135,7 +115,6 @@ pub struct OrFramePrelude {
pub struct OrFrame { pub struct OrFrame {
pub prelude: OrFramePrelude, pub prelude: OrFramePrelude,
_marker: PhantomData<Addr>
} }
impl Index<usize> for OrFrame { impl Index<usize> for OrFrame {
@@ -170,24 +149,6 @@ impl IndexMut<usize> for OrFrame {
} }
} }
impl Drop for OrFrame {
fn drop(&mut self) {
let prelude_offset = prelude_size::<OrFramePrelude>();
unsafe {
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset;
for idx in 0 .. self.prelude.univ_prelude.num_cells {
let index_offset = idx * mem::size_of::<Addr>();
let ptr = (ptr + index_offset) as *mut Addr;
ptr::drop_in_place(ptr);
}
}
}
}
impl OrFrame { impl OrFrame {
pub fn size_of(num_cells: usize) -> usize { pub fn size_of(num_cells: usize) -> usize {
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>() prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
@@ -211,8 +172,6 @@ impl Stack {
} }
let and_frame = &mut *(self.buf.top as *mut AndFrame); let and_frame = &mut *(self.buf.top as *mut AndFrame);
and_frame.prelude.univ_prelude.is_or_frame = 0;
and_frame.prelude.univ_prelude.num_cells = num_cells; and_frame.prelude.univ_prelude.num_cells = num_cells;
let e = self.buf.top as usize - self.buf.base as usize; let e = self.buf.top as usize - self.buf.base as usize;
@@ -234,8 +193,6 @@ impl Stack {
} }
let or_frame = &mut *(self.buf.top as *mut OrFrame); let or_frame = &mut *(self.buf.top as *mut OrFrame);
or_frame.prelude.univ_prelude.is_or_frame = 1;
or_frame.prelude.univ_prelude.num_cells = num_cells; or_frame.prelude.univ_prelude.num_cells = num_cells;
let b = self.buf.top as usize - self.buf.base as usize; let b = self.buf.top as usize - self.buf.base as usize;
@@ -281,6 +238,7 @@ impl Stack {
Stack { buf: self.buf.take(), _marker: PhantomData } Stack { buf: self.buf.take(), _marker: PhantomData }
} }
#[inline]
pub fn truncate(&mut self, b: usize) { pub fn truncate(&mut self, b: usize) {
if b == 0 { if b == 0 {
self.inner_truncate(mem::align_of::<Addr>()); self.inner_truncate(mem::align_of::<Addr>());
@@ -289,42 +247,14 @@ impl Stack {
} }
} }
#[inline]
fn inner_truncate(&mut self, b: usize) { fn inner_truncate(&mut self, b: usize) {
let mut b = b + self.buf.base as usize; let base = b + self.buf.base as usize;
let base = b;
unsafe {
while b as *const _ < self.buf.top {
let univ_prelude = ptr::read(b as *const FramePrelude);
let offset = if univ_prelude.is_or_frame == 0 {
let frame_ptr = b as *mut AndFrame;
let frame = &mut *frame_ptr;
let size_of_frame = AndFrame::size_of(frame.prelude.univ_prelude.num_cells);
ptr::drop_in_place(frame_ptr);
b + size_of_frame
} else {
debug_assert!(univ_prelude.is_or_frame == 1);
let frame_ptr = b as *mut OrFrame;
let frame = &mut *frame_ptr;
let size_of_frame = OrFrame::size_of(frame.prelude.univ_prelude.num_cells);
ptr::drop_in_place(frame_ptr);
b + size_of_frame
};
b = offset;
}
if base < self.buf.top as usize { if base < self.buf.top as usize {
self.buf.top = base as *const _; self.buf.top = base as *const _;
} }
} }
}
pub fn drop_in_place(&mut self) { pub fn drop_in_place(&mut self) {
self.truncate(mem::align_of::<Addr>()); self.truncate(mem::align_of::<Addr>());

View File

@@ -0,0 +1,356 @@
use crate::prolog_parser::ast::*;
use crate::prolog::read::readline::*;
use std::cell::RefCell;
use std::error::Error;
use std::fmt;
use std::fs::File;
use std::io::{stdin, stdout, Cursor, ErrorKind, Read, Write};
use std::hash::{Hash, Hasher};
use std::net::TcpStream;
use std::rc::Rc;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum StreamType {
Binary,
Text,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum EOFAction {
EOFCode,
Error,
Reset,
}
/* all these streams are closed automatically when the instance is
* dropped. */
pub enum StreamInstance {
Bytes(Cursor<Vec<u8>>),
DynReadSource(Box<dyn Read>),
File(File),
Null,
ReadlineStream(ReadlineStream),
Stdin,
Stdout,
TcpStream(TcpStream),
}
#[derive(Clone)]
struct WrappedStreamInstance(Rc<RefCell<StreamInstance>>);
impl WrappedStreamInstance {
#[inline]
fn new(stream_inst: StreamInstance) -> Self {
WrappedStreamInstance(Rc::new(RefCell::new(stream_inst)))
}
}
impl PartialEq for WrappedStreamInstance {
#[inline]
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
impl Eq for WrappedStreamInstance {}
impl Hash for WrappedStreamInstance {
fn hash<H: Hasher>(&self, state: &mut H) {
let rc = &self.0;
let ptr = Rc::into_raw(rc.clone());
state.write_usize(ptr as usize);
unsafe {
// necessary to avoid memory leak.
let _ = Rc::from_raw(ptr);
};
}
}
#[derive(Debug)]
enum StreamError {
ReadFromOutputStream,
WriteToInputStream,
FlushToInputStream,
}
impl fmt::Display for StreamError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StreamError::ReadFromOutputStream => {
write!(f, "attempted to read from a write-only stream")
}
StreamError::WriteToInputStream => {
write!(f, "attempted to write to a read-only stream")
}
StreamError::FlushToInputStream => {
write!(f, "attempted to flush a read-only stream")
}
}
}
}
impl Error for StreamError {}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct StreamOptions {
pub stream_type: StreamType,
pub reposition: bool,
pub alias: Option<ClauseName>,
pub eof_action: EOFAction,
}
impl Default for StreamOptions {
#[inline]
fn default() -> Self {
StreamOptions {
stream_type: StreamType::Text,
reposition: false,
alias: None,
eof_action: EOFAction::EOFCode,
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Stream {
pub options: StreamOptions,
stream_inst: WrappedStreamInstance,
}
impl From<String> for Stream {
fn from(string: String) -> Self {
Stream {
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::Bytes(Cursor::new(string.into_bytes()))
)
}
}
}
impl From<ReadlineStream> for Stream {
fn from(rl_stream: ReadlineStream) -> Self {
Stream {
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::ReadlineStream(rl_stream)
),
}
}
}
impl From<&'static str> for Stream {
fn from(src: &'static str) -> Stream {
Stream {
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::DynReadSource(Box::new(src.as_bytes()))
),
}
}
}
impl From<File> for Stream {
fn from(file: File) -> Stream {
Stream {
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::File(file)
),
}
}
}
impl Stream {
#[inline]
pub(crate)
fn as_ptr(&self) -> *const RefCell<StreamInstance> {
let rc = self.stream_inst.0.clone();
let ptr = Rc::into_raw(rc);
unsafe {
// must be done to avoid memory leak.
let _ = Rc::from_raw(ptr);
}
ptr
}
#[inline]
pub(crate)
fn stdout() -> Self {
Stream {
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::Stdout
),
}
}
#[inline]
pub(crate)
fn stdin() -> Self {
Stream {
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::Stdin
),
}
}
#[inline]
pub(crate)
fn null_stream() -> Self {
Stream {
options: StreamOptions::default(), // TODO: null_options?
stream_inst: WrappedStreamInstance::new(
StreamInstance::Null
),
}
}
#[inline]
pub(crate)
fn is_stdout(&self) -> bool {
match *self.stream_inst.0.borrow() {
StreamInstance::Stdout => {
true
}
_ => {
false
}
}
}
#[inline]
pub(crate)
fn is_stdin(&self) -> bool {
match *self.stream_inst.0.borrow() {
StreamInstance::Stdin | StreamInstance::ReadlineStream(_) => {
true
}
_ => {
false
}
}
}
#[inline]
pub(crate)
fn is_input_stream(&self) -> bool {
match *self.stream_inst.0.borrow() {
StreamInstance::Stdin
| StreamInstance::TcpStream(_)
| StreamInstance::Bytes(_)
| StreamInstance::ReadlineStream(_)
| StreamInstance::DynReadSource(_)
| StreamInstance::File(_) => {
true
}
_ => {
false
}
}
}
#[inline]
pub(crate)
fn is_output_stream(&self) -> bool {
match *self.stream_inst.0.borrow() {
StreamInstance::Stdout
| StreamInstance::TcpStream(_)
| StreamInstance::Bytes(_)
| StreamInstance::File(_) => {
true
}
_ => {
false
}
}
}
}
impl Read for Stream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match *self.stream_inst.0.borrow_mut() {
StreamInstance::File(ref mut file) => {
file.read(buf)
}
StreamInstance::TcpStream(ref mut tcp_stream) => {
tcp_stream.read(buf)
}
StreamInstance::ReadlineStream(ref mut rl_stream) => {
rl_stream.read(buf)
}
StreamInstance::DynReadSource(ref mut src) => {
src.read(buf)
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.read(buf)
}
StreamInstance::Stdin => {
stdin().read(buf)
}
StreamInstance::Stdout | StreamInstance::Null => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
))
}
}
}
}
impl Write for Stream {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match *self.stream_inst.0.borrow_mut() {
StreamInstance::File(ref mut file) => {
file.write(buf)
}
StreamInstance::TcpStream(ref mut tcp_stream) => {
tcp_stream.write(buf)
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.write(buf)
}
StreamInstance::Stdout => {
stdout().write(buf)
}
_ => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::WriteToInputStream,
))
}
}
}
fn flush(&mut self) -> std::io::Result<()> {
match *self.stream_inst.0.borrow_mut() {
StreamInstance::File(ref mut file) => {
file.flush()
}
StreamInstance::TcpStream(ref mut tcp_stream) => {
tcp_stream.flush()
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.flush()
}
StreamInstance::Stdout => {
stdout().flush()
}
_ => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::FlushToInputStream,
))
}
}
}
}
//TODO: write a Seek instance.

File diff suppressed because it is too large Load Diff

View File

@@ -8,35 +8,9 @@ use crate::prolog::rug::Integer;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::Read;
use std::iter::Rev; use std::iter::Rev;
use std::vec::IntoIter; use std::vec::IntoIter;
fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> {
if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term {
if name.as_str() == s && subterms.len() == 2 {
let snd = *subterms.pop().unwrap();
let fst = *subterms.pop().unwrap();
return Some((fst, snd));
}
}
None
}
pub fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term> {
let mut terms = vec![];
while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
terms.push(fst);
term = snd;
}
terms.push(term);
terms
}
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
where where
I: DoubleEndedIterator<Item = Term>, I: DoubleEndedIterator<Item = Term>,
@@ -53,7 +27,11 @@ where
term term
} }
fn extract_from_list(head: Box<Term>, tail: Box<Term>) -> Result<Rev<IntoIter<Term>>, ParserError> { fn extract_from_list(
head: Box<Term>,
tail: Box<Term>,
) -> Result<Rev<IntoIter<Term>>, ParserError>
{
let mut terms = vec![*head]; let mut terms = vec![*head];
let mut tail = *tail; let mut tail = *tail;
@@ -69,10 +47,10 @@ fn extract_from_list(head: Box<Term>, tail: Box<Term>) -> Result<Rev<IntoIter<Te
} }
} }
pub struct TermStream<'a, R: Read> { pub struct TermStream<'a> {
stack: Vec<Term>, stack: Vec<Term>,
pub(crate) wam: &'a mut Machine, pub(crate) wam: &'a mut Machine,
parser: Parser<'a, R>, parser: Parser<'a, Stream>,
pub(crate) flags: MachineFlags, pub(crate) flags: MachineFlags,
term_expansion_lens: (usize, usize), term_expansion_lens: (usize, usize),
goal_expansion_lens: (usize, usize), goal_expansion_lens: (usize, usize),
@@ -100,7 +78,7 @@ impl ExpansionAdditionResult {
} }
} }
impl<'a, R: Read> Drop for TermStream<'a, R> { impl<'a> Drop for TermStream<'a> {
fn drop(&mut self) { fn drop(&mut self) {
self.wam.indices.in_situ_code_dir.clear(); self.wam.indices.in_situ_code_dir.clear();
self.wam.indices.in_situ_module_dir.clear(); self.wam.indices.in_situ_module_dir.clear();
@@ -110,9 +88,9 @@ impl<'a, R: Read> Drop for TermStream<'a, R> {
} }
} }
impl<'a, R: Read> TermStream<'a, R> { impl<'a> TermStream<'a> {
pub fn new( pub fn new(
src: &'a mut ParsingStream<R>, src: &'a mut ParsingStream<Stream>,
atom_tbl: TabledData<Atom>, atom_tbl: TabledData<Atom>,
flags: MachineFlags, flags: MachineFlags,
wam: &'a mut Machine, wam: &'a mut Machine,
@@ -326,7 +304,8 @@ impl<'a, R: Read> TermStream<'a, R> {
} }
impl MachineState { impl MachineState {
pub(super) fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter { pub(super)
fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
let output = PrinterOutputter::new(); let output = PrinterOutputter::new();
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output); let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
let mut max_var_length = 0; let mut max_var_length = 0;
@@ -337,12 +316,16 @@ impl MachineState {
printer.quoted = true; printer.quoted = true;
printer.numbervars = true; printer.numbervars = true;
// the purpose of the offset is to avoid clashes with variable names that might
// occur after the addresses in the expanded term are substituted with the variable // the purpose of the offset is to avoid clashes with variable
// names in the pre-expansion term. This formula ensures that all generated "numbervars"- // names that might occur after the addresses in the expanded
// style variable names will be longer than the keys of the var_dict, and therefore // term are substituted with the variable names in the
// not equal to any of them. // pre-expansion term. This formula ensures that all generated
// "numbervars"- style variable names will be longer than the
// keys of the var_dict, and therefore not equal to any of
// them.
printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26; printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
printer.print_strings_as_strs = true;
printer.drop_toplevel_spec(); printer.drop_toplevel_spec();
printer.see_all_locs(); printer.see_all_locs();
@@ -354,8 +337,8 @@ impl MachineState {
} }
// reset the machine, but keep the heap contents as they were. // reset the machine, but keep the heap contents as they were.
// this prevents clashes between underscored variable names // this prevents clashes between underscored variable names in the
// in the same query. // same query.
fn reset_with_heap_preservation(&mut self) { fn reset_with_heap_preservation(&mut self) {
let heap = self.heap.take(); let heap = self.heap.take();
self.reset(); self.reset();
@@ -379,13 +362,16 @@ impl MachineState {
wam.code_repo.cached_query = code; wam.code_repo.cached_query = code;
self.cp = LocalCodePtr::TopLevel(0, 0); self.cp = LocalCodePtr::TopLevel(0, 0);
self.at_end_of_expansion = false; self.at_end_of_expansion = false;
self.flags.double_quotes = DoubleQuotes::Chars;
self.query_stepper( self.query_stepper(
&mut wam.indices, &mut wam.indices,
&mut wam.policies, &mut wam.policies,
&mut wam.code_repo, &mut wam.code_repo,
&mut readline::input_stream(), &mut readline::input_stream(),
&mut Stream::stdout(),
); );
if self.fail || self.at_end_of_expansion { if self.fail || self.at_end_of_expansion {
@@ -398,6 +384,7 @@ impl MachineState {
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir); let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
self.reset_with_heap_preservation(); self.reset_with_heap_preservation();
Some(output.result()) Some(output.result())
} }
} }

View File

@@ -13,7 +13,7 @@ use indexmap::{IndexMap, IndexSet};
use std::borrow::BorrowMut; use std::borrow::BorrowMut;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::Read; use std::convert::TryFrom;
use std::mem; use std::mem;
use std::ops::DerefMut; use std::ops::DerefMut;
use std::rc::Rc; use std::rc::Rc;
@@ -30,15 +30,15 @@ fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, O
} }
} }
struct CompositeIndices<'a, 'b, 'c, R: Read> { struct CompositeIndices<'a, 'b, 'c> {
term_stream: &'b mut TermStream<'a, R>, term_stream: &'b mut TermStream<'a>,
index_src: IndexSource<'c, IndexStore>, index_src: IndexSource<'c, IndexStore>,
static_code_dir: Option<IndexSource<'c, CodeDir>> static_code_dir: Option<IndexSource<'c, CodeDir>>
} }
impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> { impl<'a, 'b, 'c> CompositeIndices<'a, 'b, 'c> {
fn new( fn new(
term_stream: &'b mut TermStream<'a, R>, term_stream: &'b mut TermStream<'a>,
index_src: IndexSource<'c, IndexStore>, index_src: IndexSource<'c, IndexStore>,
static_code_dir: Option<IndexSource<'c, CodeDir>>, static_code_dir: Option<IndexSource<'c, CodeDir>>,
) -> Self { ) -> Self {
@@ -212,8 +212,8 @@ fn setup_op_decl(
}; };
let prec = match *terms.pop().unwrap() { let prec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Integer(bi)) => match bi.to_usize() { Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
Some(n) if n <= 1200 => n, Ok(n) if n <= 1200 => n,
_ => return Err(ParserError::InconsistentEntry), _ => return Err(ParserError::InconsistentEntry),
}, },
_ => return Err(ParserError::InconsistentEntry), _ => return Err(ParserError::InconsistentEntry),
@@ -225,16 +225,21 @@ fn setup_op_decl(
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError> fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError>
{ {
match term { match term {
Term::Clause(_, ref name, ref mut terms, Some(_)) Term::Clause(_, ref slash, ref mut terms, Some(_))
if name.as_str() == "/" && terms.len() == 2 => if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
{ {
let arity = *terms.pop().unwrap(); let arity = *terms.pop().unwrap();
let name = *terms.pop().unwrap(); let name = *terms.pop().unwrap();
let arity = arity let arity = arity
.to_constant() .to_constant()
.and_then(|c| c.to_integer()) .and_then(|c| {
.and_then(|n| n.to_usize()) match c {
Constant::Integer(n) => n.to_usize(),
Constant::Fixnum(n) => usize::try_from(n).ok(),
_ => None
}
})
.ok_or(ParserError::InvalidModuleExport)?; .ok_or(ParserError::InvalidModuleExport)?;
let name = name let name = name
@@ -242,7 +247,11 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserErro
.and_then(|c| c.to_atom()) .and_then(|c| c.to_atom())
.ok_or(ParserError::InvalidModuleExport)?; .ok_or(ParserError::InvalidModuleExport)?;
if slash.as_str() == "/" {
Ok((name, arity)) Ok((name, arity))
} else {
Ok((name, arity + 2))
}
} }
_ => Err(ParserError::InvalidModuleExport), _ => Err(ParserError::InvalidModuleExport),
} }
@@ -339,6 +348,32 @@ fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, Pars
} }
} }
fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, ParserError> {
let dbl_quotes = *terms.pop().unwrap();
match terms[0].as_ref() {
Term::Constant(_, Constant::Atom(ref name, _))
if name.as_str() == "double_quotes" => {
match dbl_quotes {
Term::Constant(_, Constant::Atom(name, _)) => {
match name.as_str() {
"atom" => Ok(DoubleQuotes::Atom),
"chars" => Ok(DoubleQuotes::Chars),
"codes" => Ok(DoubleQuotes::Codes),
_ => Err(ParserError::InvalidDoubleQuotesDecl),
}
}
_ => {
Err(ParserError::InvalidDoubleQuotesDecl)
}
}
},
_ => {
Err(ParserError::InvalidDoubleQuotesDecl)
}
}
}
type UseModuleExport = (ModuleSource, Vec<ModuleExport>); type UseModuleExport = (ModuleSource, Vec<ModuleExport>);
fn setup_qualified_import( fn setup_qualified_import(
@@ -551,8 +586,8 @@ fn draw_from_term_dir_impl(
} }
} }
fn draw_from_term_dir<R: Read>( fn draw_from_term_dir(
indices: &CompositeIndices<R>, indices: &CompositeIndices,
intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>, intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
top_level_term_dirs: &mut TermDirQuantum, top_level_term_dirs: &mut TermDirQuantum,
key: &PredicateKey, key: &PredicateKey,
@@ -589,8 +624,8 @@ fn draw_from_term_dir<R: Read>(
); );
} }
fn setup_declaration<'a, 'b, 'c, R: Read>( fn setup_declaration<'a, 'b, 'c>(
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
flags: MachineFlags, flags: MachineFlags,
mut terms: Vec<Box<Term>>, mut terms: Vec<Box<Term>>,
line_num: usize, line_num: usize,
@@ -620,18 +655,23 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
Ok(Declaration::NonCountedBacktracking(name, arity)) Ok(Declaration::NonCountedBacktracking(name, arity))
} }
("set_prolog_flag", 2) => {
Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?))
}
("multifile", 1) => { ("multifile", 1) => {
let mut term = *terms.pop().unwrap(); let mut term = *terms.pop().unwrap();
match setup_predicate_indicator(&mut term) { match setup_predicate_indicator(&mut term) {
Ok((name, arity)) => Ok((name, arity)) => {
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))), Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity)))
_ => }
_ => {
setup_scoped_predicate_indicator(&mut term) setup_scoped_predicate_indicator(&mut term)
.map(|key| { .map(|key| {
Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key)) Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
}) })
} }
}
} }
("use_module", 1) => { ("use_module", 1) => {
Ok(Declaration::UseModule(setup_use_module_decl(terms)?)) Ok(Declaration::UseModule(setup_use_module_decl(terms)?))
@@ -644,7 +684,9 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
Err(ParserError::InconsistentEntry) Err(ParserError::InconsistentEntry)
} }
}, },
_ => Err(ParserError::InconsistentEntry), _ => {
Err(ParserError::InconsistentEntry)
}
} }
} }
@@ -767,9 +809,9 @@ impl RelationWorker {
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym)) self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
} }
fn to_query_term<'a, 'b, 'c, R: Read>( fn to_query_term<'a, 'b, 'c>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term, term: Term,
) -> Result<QueryTerm, ParserError> { ) -> Result<QueryTerm, ParserError> {
match term { match term {
@@ -843,9 +885,9 @@ impl RelationWorker {
} }
} }
fn pre_query_term<'a, 'b, 'c, R: Read>( fn pre_query_term<'a, 'b, 'c>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term, term: Term,
) -> Result<QueryTerm, ParserError> { ) -> Result<QueryTerm, ParserError> {
match term { match term {
@@ -864,9 +906,9 @@ impl RelationWorker {
} }
} }
fn setup_query<'a, 'b, 'c, R: Read>( fn setup_query<'a, 'b, 'c>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
terms: Vec<Box<Term>>, terms: Vec<Box<Term>>,
blocks_cuts: bool, blocks_cuts: bool,
) -> Result<Vec<QueryTerm>, ParserError> { ) -> Result<Vec<QueryTerm>, ParserError> {
@@ -917,10 +959,10 @@ impl RelationWorker {
Ok(query_terms) Ok(query_terms)
} }
fn setup_hook<'a, 'b, 'c, R: Read>( fn setup_hook<'a, 'b, 'c>(
&mut self, &mut self,
hook: CompileTimeHook, hook: CompileTimeHook,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term, term: Term,
) -> Result<CompileTimeHookCompileInfo, ParserError> { ) -> Result<CompileTimeHookCompileInfo, ParserError> {
match flatten_hook(term) { match flatten_hook(term) {
@@ -941,9 +983,9 @@ impl RelationWorker {
} }
} }
fn setup_rule<'a, 'b, 'c, R: Read>( fn setup_rule<'a, 'b, 'c>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
mut terms: Vec<Box<Term>>, mut terms: Vec<Box<Term>>,
blocks_cuts: bool, blocks_cuts: bool,
assume_dyn: bool, assume_dyn: bool,
@@ -974,9 +1016,9 @@ impl RelationWorker {
} }
} }
fn try_term_to_query<'a, 'b, 'c, R: Read>( fn try_term_to_query<'a, 'b, 'c>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
terms: Vec<Box<Term>>, terms: Vec<Box<Term>>,
blocks_cuts: bool, blocks_cuts: bool,
) -> Result<TopLevel, ParserError> { ) -> Result<TopLevel, ParserError> {
@@ -987,10 +1029,10 @@ impl RelationWorker {
)?)) )?))
} }
fn compact_module_scoped_head<'a, 'b, 'c, R: Read>( fn compact_module_scoped_head<'a, 'b, 'c>(
&self, &self,
term: &mut Term, term: &mut Term,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
) { ) {
let inner_term = match term { let inner_term = match term {
Term::Clause(_, ref name, ref mut inner_terms, _) Term::Clause(_, ref name, ref mut inner_terms, _)
@@ -1015,9 +1057,9 @@ impl RelationWorker {
*term = inner_term; *term = inner_term;
} }
fn try_term_to_tl<'a, 'b, 'c, R: Read>( fn try_term_to_tl<'a, 'b, 'c>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term, term: Term,
blocks_cuts: bool, blocks_cuts: bool,
) -> Result<TopLevel, ParserError> { ) -> Result<TopLevel, ParserError> {
@@ -1051,19 +1093,20 @@ impl RelationWorker {
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)) Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
} }
} }
term => term => {
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)), Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
}
} }
} }
fn try_terms_to_tls<'a, 'b, 'c, I, R>( fn try_terms_to_tls<'a, 'b, 'c, I>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
terms: I, terms: I,
blocks_cuts: bool, blocks_cuts: bool,
) -> Result<VecDeque<TopLevel>, ParserError> ) -> Result<VecDeque<TopLevel>, ParserError>
where where
I: IntoIterator<Item = Term>, R: Read I: IntoIterator<Item = Term>
{ {
let mut results = VecDeque::new(); let mut results = VecDeque::new();
@@ -1074,9 +1117,9 @@ impl RelationWorker {
Ok(results) Ok(results)
} }
fn parse_queue<'a, 'b, 'c, R: Read>( fn parse_queue<'a, 'b, 'c>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c>,
) -> Result<VecDeque<TopLevel>, ParserError> { ) -> Result<VecDeque<TopLevel>, ParserError> {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
@@ -1090,8 +1133,7 @@ impl RelationWorker {
fn absorb(&mut self, other: RelationWorker) { fn absorb(&mut self, other: RelationWorker) {
self.queue.extend(other.queue.into_iter()); self.queue.extend(other.queue.into_iter());
self.dynamic_clauses self.dynamic_clauses.extend(other.dynamic_clauses.into_iter());
.extend(other.dynamic_clauses.into_iter());
} }
} }
@@ -1099,8 +1141,8 @@ pub type DynamicClause = Vec<(Term, Term)>;
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>; pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
pub struct TopLevelBatchWorker<'a, R: Read> { pub struct TopLevelBatchWorker<'a> {
pub(crate) term_stream: TermStream<'a, R>, pub(crate) term_stream: TermStream<'a>,
rel_worker: RelationWorker, rel_worker: RelationWorker,
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>, pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
pub(crate) dynamic_clause_map: DynamicClauseMap, pub(crate) dynamic_clause_map: DynamicClauseMap,
@@ -1110,14 +1152,14 @@ pub struct TopLevelBatchWorker<'a, R: Read> {
pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>, pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
} }
impl<'a, R: Read> TopLevelBatchWorker<'a, R> { impl<'a> TopLevelBatchWorker<'a> {
pub fn new( pub fn new(
inner: &'a mut ParsingStream<R>, stream: &'a mut ParsingStream<Stream>,
atom_tbl: TabledData<Atom>, atom_tbl: TabledData<Atom>,
flags: MachineFlags, flags: MachineFlags,
wam: &'a mut Machine, wam: &'a mut Machine,
) -> Self { ) -> Self {
let term_stream = TermStream::new(inner, atom_tbl, flags, wam); let term_stream = TermStream::new(stream, atom_tbl, flags, wam);
let line_num = term_stream.line_num(); let line_num = term_stream.line_num();
let col_num = term_stream.col_num(); let col_num = term_stream.col_num();
@@ -1248,7 +1290,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
TopLevel::Declaration(decl) => TopLevel::Declaration(decl) =>
return Ok(Some(decl)), return Ok(Some(decl)),
TopLevel::Query(_) => TopLevel::Query(_) =>
return Err(SessionError::NamelessEntry), return Err(SessionError::QueryCannotBeDefinedAsFact),
} }
} }

View File

@@ -4,52 +4,183 @@ macro_rules! interm {
}; };
} }
macro_rules! heap_str { /* A simple macro to count the arguments in a variadic list
($s:expr) => { * of token trees.
HeapCellValue::Addr(Addr::Str($s)) */
}; macro_rules! count_tt {
} () => { 0 };
($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 };
macro_rules! heap_integer { ($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
($i:expr) => {
HeapCellValue::Addr(Addr::Con(Constant::Integer($i)))
};
}
macro_rules! heap_cell {
($i:expr) => {
HeapCellValue::Addr(Addr::HeapCell($i))
};
}
macro_rules! heap_con {
($i:expr) => {
HeapCellValue::Addr(Addr::Con($i))
};
}
macro_rules! heap_atom {
($name:expr) => {
HeapCellValue::Addr(Addr::Con(atom!($name)))
};
($name:expr, $tbl:expr) => {
HeapCellValue::Addr(Addr::Con(atom!($name, $tbl)))
};
} }
macro_rules! functor { macro_rules! functor {
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
{
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let arity = count_tt!($($dt) +);
let aux_lens = [$($aux.len()),*];
let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
$(
result.extend($aux.into_iter());
)*
result.extend(addendum.into_iter());
result
}
});
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let arity = count_tt!($($dt) +);
let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter());
result
}
});
($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
{
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let arity = count_tt!($($dt) +);
let aux_lens = [$($aux.len()),*];
let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
$(
result.extend($aux.into_iter());
)*
result.extend(addendum.into_iter());
result
}
});
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{
let arity = count_tt!($($dt) +);
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]
}
});
($name:expr, $fixity:expr) => (
vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ]
);
(clause_name($name:expr)) => (
vec![ HeapCellValue::Atom($name, None) ]
);
($name:expr) => ( ($name:expr) => (
vec![ heap_atom!($name) ] vec![ HeapCellValue::Atom(clause_name!($name), None) ]
); );
($name:expr, $len:expr) => ( }
vec![ HeapCellValue::NamedStr($len, clause_name!($name), None) ]
macro_rules! functor_term {
(aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
HeapCellValue::Addr(Addr::HeapCell($arity + 1))
});
(aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let len: usize = $aux_lens[0 .. $e].iter().sum();
HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len))
});
(aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1))
});
(aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let len: usize = $aux_lens[0 .. $e].iter().sum();
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len))
});
(addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Addr($e)
); );
($name:expr, $len:expr, [$($args:expr),*]) => ( (constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
vec![ HeapCellValue::NamedStr($len, clause_name!($name), None), $($args),* ] from_constant!($e, $h, $arity, $aux_lens, $addendum)
); );
($name:expr, $len:expr, [$($args:expr),*], $fix: expr) => ( (constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
vec![ HeapCellValue::NamedStr($len, clause_name!($name), Some($fix)), $($args),* ] from_constant!($e, 0, $arity, $aux_lens, $addendum)
); );
(number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
$e.into()
);
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
HeapCellValue::Integer(Rc::new(Integer::from($e)))
);
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
HeapCellValue::Atom($e, None)
);
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
HeapCellValue::Atom(clause_name!($e), None)
);
(string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $h;
$addendum.put_complete_string(&$e);
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
});
(boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
if $e {
functor_term!(atom("true"), $arity, $aux_lens, $addendum)
} else {
functor_term!(atom("false"), $arity, $aux_lens, $addendum)
}
});
($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => (
$e
);
}
macro_rules! from_constant {
($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({
match $e {
&Constant::Atom(ref name, ref op) => {
HeapCellValue::Atom(name.clone(), op.clone())
}
&Constant::Char(c) => {
HeapCellValue::Addr(Addr::Char(c))
}
&Constant::CharCode(c) => {
HeapCellValue::Addr(Addr::CharCode(c))
}
&Constant::Fixnum(n) => {
HeapCellValue::Addr(Addr::Fixnum(n))
}
&Constant::Integer(ref n) => {
HeapCellValue::Integer(n.clone())
}
&Constant::Rational(ref r) => {
HeapCellValue::Rational(r.clone())
}
&Constant::Float(f) => {
HeapCellValue::Addr(Addr::Float(f))
}
&Constant::String(ref s) => {
let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $over_h;
$addendum.put_complete_string(&s);
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
}
&Constant::Usize(u) => {
HeapCellValue::Addr(Addr::Usize(u))
}
&Constant::EmptyList => {
HeapCellValue::Addr(Addr::EmptyList)
}
}
})
} }
macro_rules! is_atom { macro_rules! is_atom {
@@ -94,12 +225,6 @@ macro_rules! is_nonvar {
}; };
} }
macro_rules! is_string {
($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsString($r)), 1, 0)
};
}
macro_rules! is_var { macro_rules! is_var {
($r:expr) => { ($r:expr) => {
call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0) call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
@@ -211,12 +336,6 @@ macro_rules! dir_entry {
}; };
} }
macro_rules! in_situ_dir_entry {
($idx:expr) => {
CodePtr::Local(LocalCodePtr::InSituDirEntry($idx))
};
}
macro_rules! set_code_index { macro_rules! set_code_index {
($idx:expr, $ip:expr, $mod_name:expr) => {{ ($idx:expr, $ip:expr, $mod_name:expr) => {{
let mut idx = $idx.0.borrow_mut(); let mut idx = $idx.0.borrow_mut();
@@ -238,6 +357,7 @@ macro_rules! index_store {
in_situ_module_dir: ModuleStubDir::new(), in_situ_module_dir: ModuleStubDir::new(),
op_dir: $op_dir, op_dir: $op_dir,
modules: $modules, modules: $modules,
stream_aliases: StreamAliasDir::new(),
} }
}; };
} }

View File

@@ -6,27 +6,16 @@ use crate::prolog::forms::*;
use crate::prolog::iterators::*; use crate::prolog::iterators::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::MachineState; use crate::prolog::machine::machine_state::MachineState;
use crate::prolog::machine::streams::Stream;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::Read;
type SubtermDeque = VecDeque<(usize, usize)>; type SubtermDeque = VecDeque<(usize, usize)>;
impl<'a> TermRef<'a> { pub type PrologStream = ParsingStream<Stream>;
fn as_addr(&self, h: usize) -> Addr {
match self {
&TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h),
&TermRef::Cons(..) => Addr::HeapCell(h),
&TermRef::Constant(_, _, c) => Addr::Con(c.clone()),
&TermRef::Clause(..) => Addr::Str(h),
}
}
}
pub type PrologStream = ParsingStream<Box<dyn Read>>;
pub mod readline { pub mod readline {
use prolog_parser::ast::*; use crate::prolog::machine::streams::Stream;
use crate::prolog::rustyline::error::ReadlineError; use crate::prolog::rustyline::error::ReadlineError;
use crate::prolog::rustyline::{Cmd, Editor, KeyPress}; use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
use std::io::{Cursor, Read}; use std::io::{Cursor, Read};
@@ -52,10 +41,10 @@ pub mod readline {
} }
impl ReadlineStream { impl ReadlineStream {
fn input_stream(pending_input: String) -> Self { pub fn input_stream(pending_input: String) -> Stream {
let mut rl = Editor::<()>::new(); let mut rl = Editor::<()>::new();
rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string())); rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
ReadlineStream { rl, pending_input: Cursor::new(pending_input) } Stream::from(ReadlineStream { rl, pending_input: Cursor::new(pending_input) })
} }
fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
@@ -93,15 +82,14 @@ pub mod readline {
result => { result => {
result result
} }
} }
} }
} }
#[inline] #[inline]
pub fn input_stream() -> crate::PrologStream { pub fn input_stream() -> Stream {
let reader: Box<dyn Read> = Box::new(ReadlineStream::input_stream(String::from(""))); let input_stream = ReadlineStream::input_stream(String::from(""));
parsing_stream(reader) Stream::from(input_stream)
} }
} }
@@ -119,24 +107,17 @@ impl MachineState {
} }
} }
fn push_stub_addr(machine_st: &mut MachineState) { #[inline]
let h = machine_st.heap.h(); pub(crate)
machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
let term_writer = TermWriter::new(machine_st);
term_writer.write_term_to_heap(term)
} }
fn modify_head_of_queue( struct TermWriter<'a> {
machine_st: &mut MachineState, machine_st: &'a mut MachineState,
queue: &mut SubtermDeque, queue: SubtermDeque,
term: TermRef, var_dict: HeapVarDict,
h: usize,
) {
if let Some((arity, site_h)) = queue.pop_front() {
machine_st.heap[site_h] = HeapCellValue::Addr(term.as_addr(h));
if arity > 1 {
queue.push_front((arity - 1, site_h + 1));
}
}
} }
pub struct TermWriteResult { pub struct TermWriteResult {
@@ -144,76 +125,135 @@ pub struct TermWriteResult {
pub(crate) var_dict: HeapVarDict, pub(crate) var_dict: HeapVarDict,
} }
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult { impl<'a> TermWriter<'a> {
let heap_loc = machine_st.heap.h(); #[inline]
fn new(machine_st: &'a mut MachineState) -> Self {
TermWriter {
machine_st,
queue: SubtermDeque::new(),
var_dict: HeapVarDict::new(),
}
}
let mut queue = SubtermDeque::new(); #[inline]
let mut var_dict = HeapVarDict::new(); fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
if let Some((arity, site_h)) = self.queue.pop_front() {
self.machine_st.heap[site_h] =
HeapCellValue::Addr(self.term_as_addr(term, h));
if arity > 1 {
self.queue.push_front((arity - 1, site_h + 1));
}
}
}
#[inline]
fn push_stub_addr(&mut self) {
let h = self.machine_st.heap.h();
self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
}
fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
match term {
&TermRef::AnonVar(_) | &TermRef::Var(..) => {
Addr::HeapCell(h)
}
&TermRef::Cons(..) => {
Addr::HeapCell(h)
}
&TermRef::Constant(_, _, c) => {
self.machine_st.heap.put_constant(c.clone())
}
&TermRef::Clause(..) => {
Addr::Str(h)
}
&TermRef::PartialString(..) => {
Addr::PStrLocation(h, 0)
}
}
}
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
let heap_loc = self.machine_st.heap.h();
for term in breadth_first_iter(term, true) { for term in breadth_first_iter(term, true) {
let h = machine_st.heap.h(); let h = self.machine_st.heap.h();
match &term { match &term {
&TermRef::Cons(lvl, ..) => { &TermRef::Cons(lvl, ..) => {
queue.push_back((2, h + 1)); self.queue.push_back((2, h + 1));
machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1))); self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
push_stub_addr(machine_st); self.push_stub_addr();
push_stub_addr(machine_st); self.push_stub_addr();
if let Level::Root = lvl { if let Level::Root = lvl {
continue; continue;
} }
} }
&TermRef::Clause(lvl, _, ref ct, subterms) => { &TermRef::Clause(lvl, _, ref ct, subterms) => {
queue.push_back((subterms.len(), h + 1)); self.queue.push_back((subterms.len(), h + 1));
let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec()); let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
machine_st.heap.push(named); self.machine_st.heap.push(named);
for _ in 0..subterms.len() { for _ in 0..subterms.len() {
push_stub_addr(machine_st); self.push_stub_addr();
} }
if let Level::Root = lvl { if let Level::Root = lvl {
continue; continue;
} }
} }
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => { &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) |
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h)))
}
&TermRef::Var(Level::Root, ..) => { &TermRef::Var(Level::Root, ..) => {
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))) let addr = self.term_as_addr(&term, h);
self.machine_st.heap.push(HeapCellValue::Addr(addr));
} }
&TermRef::AnonVar(_) => { &TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
if arity > 1 { if arity > 1 {
queue.push_front((arity - 1, site_h + 1)); self.queue.push_front((arity - 1, site_h + 1));
} }
} }
continue; continue;
} }
&TermRef::PartialString(lvl, _, ref pstr, tail) => {
if tail.is_some() {
self.machine_st.heap.allocate_pstr(&pstr);
} else {
self.machine_st.heap.put_complete_string(&pstr);
}
if let Level::Root = lvl {
} else if tail.is_some() {
let h = self.machine_st.heap.h();
self.queue.push_back((1, h - 1));
}
}
&TermRef::Var(_, _, ref var) => { &TermRef::Var(_, _, ref var) => {
if let Some((arity, site_h)) = queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
if let Some(addr) = var_dict.get(var).cloned() { if let Some(addr) = self.var_dict.get(var).cloned() {
machine_st.heap[site_h] = HeapCellValue::Addr(addr); self.machine_st.heap[site_h] = HeapCellValue::Addr(addr);
} else { } else {
var_dict.insert(var.clone(), Addr::HeapCell(site_h)); self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
} }
if arity > 1 { if arity > 1 {
queue.push_front((arity - 1, site_h + 1)); self.queue.push_front((arity - 1, site_h + 1));
} }
} }
continue; continue;
} }
_ => {} _ => {
}
}; };
modify_head_of_queue(machine_st, &mut queue, term, h); self.modify_head_of_queue(&term, h);
} }
TermWriteResult { heap_loc, var_dict } TermWriteResult { heap_loc, var_dict: self.var_dict }
}
} }

View File

@@ -17,6 +17,8 @@ pub trait CompilationTarget<'a> {
fn to_void(_: usize) -> Self; fn to_void(_: usize) -> Self;
fn is_void_instr(&self) -> bool; fn is_void_instr(&self) -> bool;
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self;
fn incr_void_instr(&mut self); fn incr_void_instr(&mut self);
fn constant_subterm(_: Constant) -> Self; fn constant_subterm(_: Constant) -> Self;
@@ -62,6 +64,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
} }
} }
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
FactInstruction::GetPartialString(lvl, string, r, has_tail)
}
fn incr_void_instr(&mut self) { fn incr_void_instr(&mut self) {
match self { match self {
&mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1, &mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
@@ -117,6 +123,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
QueryInstruction::PutList(lvl, reg) QueryInstruction::PutList(lvl, reg)
} }
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
QueryInstruction::PutPartialString(lvl, string, r, has_tail)
}
fn to_void(subterms: usize) -> Self { fn to_void(subterms: usize) -> Self {
QueryInstruction::SetVoid(subterms) QueryInstruction::SetVoid(subterms)
} }

View File

@@ -24,26 +24,30 @@
% make '$compile_batch', a system routine, callable. % make '$compile_batch', a system routine, callable.
'$$compile_batch' :- '$compile_batch'. '$$compile_batch' :- '$compile_batch'.
'$instruction_match'([Item], []) :- '$instruction_match'(Term, VarList) :-
( atom(Item) -> !, ( var(Term) ->
throw(error(instantiation_error, repl/0))
;
Term = [Item] -> !,
( atom(Item) ->
( Item == user -> ( Item == user ->
catch('$$compile_batch', E, '$print_exception_with_check'(E)) catch('$$compile_batch', E, '$print_exception_with_check'(E))
; consult(Item) ; consult(Item)
) )
; !, ;
catch(throw(error(type_error(atom, Item), repl/0)), catch(throw(error(type_error(atom, Item), repl/0)),
E, E,
'$print_exception_with_check'(E)) '$print_exception_with_check'(E))
)
;
'$submit_query_and_print_results'(Term, VarList)
). ).
'$instruction_match'(Term, VarList) :-
'$submit_query_and_print_results'(Term, VarList),
!.
'$submit_query_and_print_results'(Term0, VarList) :- '$submit_query_and_print_results'(Term0, VarList) :-
( expand_goals(Term0, Term) -> true ( expand_goals(Term0, Term) -> true
; Term0 = Term ; Term0 = Term
), ),
( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), ( '$get_b_value'(B), write(' '), call(Term), '$write_eqs_and_read_input'(B, VarList),
! !
% clear attribute goal lists, which may be populated by % clear attribute goal lists, which may be populated by
% copy_term/3 prior to failure. % copy_term/3 prior to failure.
@@ -57,34 +61,78 @@
_, _,
false), false),
( EqPrec < FPrec -> true ( EqPrec < FPrec -> true
; '$quoted_token'(F) -> true
; EqPrec == FPrec, ; EqPrec == FPrec,
memberchk(EqSpec, [fx,xfx,yfx]) memberchk(EqSpec, [fx,xfx,yfx])
). ).
'$write_goal'(G, VarList) :- '$fabricate_var_name'(VarName, N) :-
char_code('A', AC),
LN is N mod 26 + AC,
char_code(LC, LN),
NN is N // 26,
( NN =:= 0 ->
atom_chars(VarName, ['_', LC])
; number_chars(NN, NNChars),
atom_chars(VarName, ['_', LC | NNChars])
).
'$var_list_contains_name'([VarName = _ | VarList], VarName0) :-
( VarName == VarName0 -> true
; '$var_list_contains_name'(VarList, VarName0)
).
'$var_list_contains_variable'([_ = Var | VarList], Var0) :-
( Var == Var0 -> true
; '$var_list_contains_variable'(VarList, Var0)
).
'$make_new_var_name'(V, VarName, N, N1, VarList) :-
'$fabricate_var_name'(VarName0, N),
( '$var_list_contains_name'(VarList, VarName0) ->
N0 is N + 1,
'$make_new_var_name'(V, VarName, N0, N1, VarList)
; VarName = VarName0,
N1 is N + 1
).
'$extend_var_list'(Value, VarList, NewVarList) :-
term_variables(Value, Vars),
'$extend_var_list_'(Vars, 0, VarList, NewVarList).
'$extend_var_list_'([], N, VarList, VarList).
'$extend_var_list_'([V|Vs], N, VarList, NewVarList) :-
( '$var_list_contains_variable'(VarList, V) ->
'$extend_var_list_'(Vs, N, VarList, NewVarList)
; '$make_new_var_name'(V, VarName, N, N1, VarList),
NewVarList = [VarName = V | NewVarList0],
'$extend_var_list_'(Vs, N1, VarList, NewVarList0)
).
'$write_goal'(G, VarList, MaxDepth) :-
( G = (Var = Value) -> ( G = (Var = Value) ->
write(Var), write(Var),
write(' = '), write(' = '),
( '$needs_bracketing'(Value, (=)) -> ( '$needs_bracketing'(Value, (=)) ->
write('('), write('('),
write_term(Value, [quoted(true), variable_names(VarList)]), write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
write(')') write(')')
; write_term(Value, [quoted(true), variable_names(VarList)]) ; write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)])
) )
; G == [] -> ; G == [] ->
write('true') write('true')
; write_term(G, [quoted(true), variable_names(VarList)]) ; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth)])
). ).
'$write_last_goal'(G, VarList) :- '$write_last_goal'(G, VarList, MaxDepth) :-
( G = (Var = Value) -> ( G = (Var = Value) ->
write(Var), write(Var),
write(' = '), write(' = '),
( '$needs_bracketing'(Value, (=)) -> ( '$needs_bracketing'(Value, (=)) ->
write('('), write('('),
write_term(Value, [quoted(true), variable_names(VarList)]), write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
write(')') write(')')
; write_term(Value, [quoted(true), variable_names(VarList)]), ; write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
( '$trailing_period_is_ambiguous'(Value) -> ( '$trailing_period_is_ambiguous'(Value) ->
write(' ') write(' ')
; true ; true
@@ -92,16 +140,16 @@
) )
; G == [] -> ; G == [] ->
write('true') write('true')
; write_term(G, [quoted(true), variable_names(VarList)]) ; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth)])
). ).
'$write_eq'((G1, G2), VarList) :- '$write_eq'((G1, G2), VarList, MaxDepth) :-
!, !,
'$write_goal'(G1, VarList), '$write_goal'(G1, VarList, MaxDepth),
write(', '), write(', '),
'$write_eq'(G2, VarList). '$write_eq'(G2, VarList, MaxDepth).
'$write_eq'(G, VarList) :- '$write_eq'(G, VarList, MaxDepth) :-
'$write_last_goal'(G, VarList). '$write_last_goal'(G, VarList, MaxDepth).
'$graphic_token_char'(C) :- '$graphic_token_char'(C) :-
memberchk(C, ['#', '$', '&', '*', '+', '-', '.', ('/'), ':', memberchk(C, ['#', '$', '&', '*', '+', '-', '.', ('/'), ':',
@@ -118,27 +166,52 @@
'$graphic_token_char'(Char). '$graphic_token_char'(Char).
'$write_eqs_and_read_input'(B, VarList) :- '$write_eqs_and_read_input'(B, VarList) :-
sort(VarList, SortedVarList), '$extend_var_list'(VarList, VarList, NewVarList),
sort(NewVarList, SortedVarList),
'$get_b_value'(B0), '$get_b_value'(B0),
'$gather_goals'(SortedVarList, VarList, Goals), '$gather_goals'(SortedVarList, SortedVarList, Goals),
( B0 == B -> ( B0 == B ->
( Goals == [] -> ( Goals == [] ->
write('true.'), nl write('true.'), nl
; thread_goals(Goals, ThreadedGoals, (',')), ; thread_goals(Goals, ThreadedGoals, (',')),
'$write_eq'(ThreadedGoals, VarList), '$write_eq'(ThreadedGoals, NewVarList, 20),
write('.'), write('.'),
nl nl
) )
; thread_goals(Goals, ThreadedGoals, (',')), ; thread_goals(Goals, ThreadedGoals, (',')),
'$write_eq'(ThreadedGoals, VarList), '$write_eq'(ThreadedGoals, NewVarList, 20),
'$raw_input_read_char'(C), '$read_input'(ThreadedGoals, NewVarList)
( C == (';'), !,
write(' ;'), nl, false
; C == ('.'), !,
write(' ...'), nl
)
). ).
'$read_input'(ThreadedGoals, NewVarList) :-
'$raw_input_read_char'(C),
( C == w ->
nl,
write(' '),
'$write_eq'(ThreadedGoals, NewVarList, 0),
'$read_input'(ThreadedGoals, NewVarList)
; C == p ->
nl,
write(' '),
'$write_eq'(ThreadedGoals, NewVarList, 20),
'$read_input'(ThreadedGoals, NewVarList)
; C == (';') ->
nl, write('; '), false
; C == h ->
'$help_message',
'$read_input'(ThreadedGoals, NewVarList)
; C == '.',
nl, write('; ...'), nl
).
'$help_message' :-
nl, nl,
write('SPACE, "n" or ";": next solution, if any\n'),
write('".": stop enumeration\n'),
write('"h": display this help message\n'),
write('"w": write terms without depth limit\n'),
write('"p": print terms with depth limit\n\n').
'$gather_query_vars'([_ = Var | Vars], QueryVars) :- '$gather_query_vars'([_ = Var | Vars], QueryVars) :-
( var(Var) -> ( var(Var) ->
QueryVars = [Var | QueryVars1], QueryVars = [Var | QueryVars1],
@@ -153,10 +226,8 @@
). ).
'$gather_goals'([], VarList, Goals) :- '$gather_goals'([], VarList, Goals) :-
'$get_attr_var_queue_beyond'(0, AttrVars),
'$gather_query_vars'(VarList, QueryVars), '$gather_query_vars'(VarList, QueryVars),
'$call_attribute_goals'(QueryVars, AttrVars), copy_term(QueryVars, QueryVars, Goals).
'$fetch_attribute_goals'(Goals).
'$gather_goals'([Var = Value | Pairs], VarList, Goals) :- '$gather_goals'([Var = Value | Pairs], VarList, Goals) :-
( ( nonvar(Value) ( ( nonvar(Value)
; '$is_a_different_variable'(Pairs, Value) ; '$is_a_different_variable'(Pairs, Value)
@@ -167,7 +238,7 @@
). ).
'$print_exception'(E) :- '$print_exception'(E) :-
write_term('caught: ', [quoted(false)]), write_term('caught: ', [quoted(false), max_depth(20)]),
writeq(E), writeq(E),
nl. nl.

View File

@@ -58,7 +58,13 @@ impl fmt::Display for FactInstruction {
&FactInstruction::GetConstant(lvl, ref constant, ref r) => { &FactInstruction::GetConstant(lvl, ref constant, ref r) => {
write!(f, "get_constant {}, {}{}", constant, lvl, r.reg_num()) write!(f, "get_constant {}, {}{}", constant, lvl, r.reg_num())
} }
&FactInstruction::GetList(lvl, ref r) => write!(f, "get_list {}{}", lvl, r.reg_num()), &FactInstruction::GetList(lvl, ref r) => {
write!(f, "get_list {}{}", lvl, r.reg_num())
}
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
write!(f, "get_partial_string({}, {}, {}, {})",
lvl, s, r, has_tail)
}
&FactInstruction::GetStructure(ref ct, ref arity, ref r) => { &FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
write!(f, "get_structure {}/{}, {}", ct.name(), arity, r) write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
} }
@@ -86,7 +92,13 @@ impl fmt::Display for QueryInstruction {
&QueryInstruction::PutConstant(lvl, ref constant, ref r) => { &QueryInstruction::PutConstant(lvl, ref constant, ref r) => {
write!(f, "put_constant {}, {}{}", constant, lvl, r.reg_num()) write!(f, "put_constant {}, {}{}", constant, lvl, r.reg_num())
} }
&QueryInstruction::PutList(lvl, ref r) => write!(f, "put_list {}{}", lvl, r.reg_num()), &QueryInstruction::PutList(lvl, ref r) => {
write!(f, "put_list {}{}", lvl, r.reg_num())
}
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
write!(f, "put_partial_string({}, {}, {}, {})",
lvl, s, r, has_tail)
}
&QueryInstruction::PutStructure(ref ct, ref arity, ref r) => { &QueryInstruction::PutStructure(ref ct, ref arity, ref r) => {
write!(f, "put_structure {}/{}, {}", ct.name(), arity, r) write!(f, "put_structure {}/{}, {}", ct.name(), arity, r)
} }
@@ -143,6 +155,10 @@ impl fmt::Display for HeapCellValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&HeapCellValue::Addr(ref addr) => write!(f, "{}", addr), &HeapCellValue::Addr(ref addr) => write!(f, "{}", addr),
&HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
&HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref),
&HeapCellValue::Integer(ref n) => write!(f, "{}", n),
&HeapCellValue::Rational(ref n) => write!(f, "{}", n),
&HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!( &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
f, f,
"{}/{} (op, priority: {}, spec: {})", "{}/{} (op, priority: {}, spec: {})",
@@ -154,8 +170,16 @@ impl fmt::Display for HeapCellValue {
&HeapCellValue::NamedStr(arity, ref name, None) => { &HeapCellValue::NamedStr(arity, ref name, None) => {
write!(f, "{}/{}", name.as_str(), arity) write!(f, "{}/{}", name.as_str(), arity)
} }
&HeapCellValue::PartialString(ref pstr) => { &HeapCellValue::PartialString(ref pstr, has_tail) => {
write!(f, "pstr ( buf: {}, tail: {} )", pstr.block_as_str(), pstr.tail_addr()) write!(
f,
"pstr ( buf: \"{}\", has_tail({}) )",
pstr.as_str_from(0),
has_tail,
)
}
&HeapCellValue::Stream(ref stream) => {
write!(f, "$stream({})", stream.as_ptr() as usize)
} }
} }
} }
@@ -175,15 +199,21 @@ impl fmt::Display for DBRef {
impl fmt::Display for Addr { impl fmt::Display for Addr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&Addr::Char(c) => write!(f, "Addr::Char({})", c),
&Addr::CharCode(c) => write!(f, "Addr::CharCode({})", c),
&Addr::EmptyList => write!(f, "Addr::EmptyList"),
&Addr::Fixnum(n) => write!(f, "Addr::Fixnum({})", n),
&Addr::Float(fl) => write!(f, "Addr::Float({})", fl),
&Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
&Addr::Con(ref c) => write!(f, "Addr::Con({})", c), &Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
&Addr::DBRef(ref db_ref) => write!(f, "Addr::DBRef({})", db_ref),
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l), &Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
&Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h), &Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h), &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc), &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
&Addr::Str(s) => write!(f, "Addr::Str({})", s), &Addr::Str(s) => write!(f, "Addr::Str({})", s),
&Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n), &Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n),
&Addr::PStrTail(h, n) => write!(f, "Addr::PStrTail({}, {})", h, n), &Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream),
&Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp),
} }
} }
} }
@@ -259,14 +289,18 @@ 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::ExistenceError(ref err) => {
write!(f, "{}", err)
}
&SessionError::CannotOverwriteBuiltIn(ref msg) => {
write!(f, "cannot overwrite {}", msg)
}
&SessionError::CannotOverwriteImport(ref msg) => { &SessionError::CannotOverwriteImport(ref msg) => {
write!(f, "cannot overwrite import {}", msg) write!(f, "cannot overwrite import {}", msg)
} }
&SessionError::InvalidFileName(ref filename) => { &SessionError::InvalidFileName(ref filename) => {
write!(f, "filename {} is invalid", filename) write!(f, "filename {} is invalid", filename)
} }
&SessionError::ModuleNotFound => write!(f, "module not found."),
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => { &SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
write!( write!(
f, f,
@@ -282,7 +316,44 @@ impl fmt::Display for SessionError {
&SessionError::NamelessEntry => { &SessionError::NamelessEntry => {
write!(f, "the predicate head is not an atom or clause.") 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::QueryCannotBeDefinedAsFact => {
write!(f, "queries cannot be defined as facts.")
}
}
}
}
impl fmt::Display for ExistenceError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ExistenceError::Module(ref module_name) => {
write!(f, "the module {} does not exist", module_name)
}
&ExistenceError::Procedure(ref name, arity) => {
write!(f, "the procedure {}/{} does not exist", name, arity)
}
&ExistenceError::SourceSink(ref module_source) => {
write!(f, "the source/sink {} does not exist", module_source)
}
&ExistenceError::Stream(ref addr) => {
write!(f, "the stream at {} does not exist", addr)
}
}
}
}
impl fmt::Display for ModuleSource {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ModuleSource::File(ref file) => {
write!(f, "at the file {}", file)
}
&ModuleSource::Library(ref library) => {
write!(f, "at library({})", library)
}
} }
} }
} }
@@ -305,6 +376,7 @@ impl fmt::Display for Line {
impl fmt::Display for Number { impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&Number::Fixnum(n) => write!(f, "{}", n),
&Number::Float(fl) => write!(f, "{}", fl), &Number::Float(fl) => write!(f, "{}", fl),
&Number::Integer(ref bi) => write!(f, "{}", bi), &Number::Integer(ref bi) => write!(f, "{}", bi),
&Number::Rational(ref r) => write!(f, "{}", r), &Number::Rational(ref r) => write!(f, "{}", r),

View File

@@ -1,7 +1,7 @@
:- module(tests_on_builtins, []). :- module(tests_on_builtins, []).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
test_queries_on_builtins :- test_queries_on_builtins :-
\+ atom(_), \+ atom(_),

View File

@@ -1,7 +1,7 @@
:- module(tests_on_call_with_inference_limit, []). :- module(tests_on_call_with_inference_limit, []).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
:- dynamic(f/1). :- dynamic(f/1).
:- dynamic(g/1). :- dynamic(g/1).

View File

@@ -62,4 +62,3 @@ cleanup :- abolish(p/3),
abolish(h/1). abolish(h/1).
:- initialization(test_queries_on_rules). :- initialization(test_queries_on_rules).

View File

@@ -1,6 +1,6 @@
:- module(test_on_setup_call_cleanup, []). :- module(test_on_setup_call_cleanup, []).
:- use_module(library(non_iso)). :- use_module(library(iso_ext)).
test_queries_on_setup_call_cleanup :- test_queries_on_setup_call_cleanup :-
\+ setup_call_cleanup(false, _, _), \+ setup_call_cleanup(false, _, _),