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.
# 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]]
name = "arrayref"
version = "0.3.5"
@@ -24,7 +29,7 @@ version = "0.3.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -48,7 +53,7 @@ dependencies = [
[[package]]
name = "bitflags"
version = "1.1.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -73,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.7"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -81,7 +86,7 @@ name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
@@ -94,16 +99,39 @@ name = "crossbeam-utils"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
]
[[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]]
name = "dirs"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
]
@@ -112,7 +140,7 @@ name = "dirs-sys"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
"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)",
@@ -148,6 +176,40 @@ name = "fuchsia-cprng"
version = "0.1.1"
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]]
name = "gmp-mpfr-sys"
version = "1.1.14"
@@ -162,6 +224,23 @@ name = "indexmap"
version = "1.1.0"
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]]
name = "lazy_static"
version = "1.4.0"
@@ -172,7 +251,7 @@ name = "lexical"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
]
@@ -181,7 +260,7 @@ name = "lexical-core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
"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)",
@@ -192,12 +271,20 @@ name = "libc"
version = "0.2.62"
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]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
@@ -210,14 +297,53 @@ name = "memchr"
version = "2.2.1"
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]]
name = "nix"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
"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)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -227,9 +353,9 @@ name = "nix"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
"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)",
"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)",
]
[[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]]
name = "proc-macro2"
version = "0.4.30"
@@ -314,9 +467,17 @@ dependencies = [
"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]]
name = "prolog_parser"
version = "0.8.40"
version = "0.8.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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)",
]
[[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]]
name = "rand_core"
version = "0.3.1"
@@ -373,14 +542,6 @@ name = "redox_syscall"
version = "0.1.51"
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]]
name = "redox_users"
version = "0.3.1"
@@ -422,9 +583,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustyline"
version = "5.0.3"
version = "6.0.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)",
"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)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -441,25 +603,55 @@ name = "ryu"
version = "0.2.7"
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]]
name = "scryer-prolog"
version = "0.8.118"
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)",
"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)",
"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)",
"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)",
"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)",
"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)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustyline 6.0.0 (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]]
name = "smallvec"
version = "0.6.13"
@@ -468,6 +660,11 @@ dependencies = [
"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]]
name = "stackvector"
version = "1.0.2"
@@ -491,6 +688,16 @@ dependencies = [
"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]]
name = "synstructure"
version = "0.10.2"
@@ -502,16 +709,6 @@ dependencies = [
"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]]
name = "unicode-segmentation"
version = "1.3.0"
@@ -527,6 +724,11 @@ name = "unicode-xid"
version = "0.1.0"
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]]
name = "unicode_reader"
version = "1.0.0"
@@ -554,6 +756,11 @@ name = "void"
version = "1.0.2"
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]]
name = "winapi"
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)",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
@@ -573,36 +785,58 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
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]
"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 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 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 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 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 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 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 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-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 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 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 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 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 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 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 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.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"
@@ -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.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 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 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 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.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 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_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 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 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 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 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 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 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 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 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-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.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 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 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-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-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"]
[dependencies]
crossterm = "0.16.0"
dirs = "2.0.2"
downcast = "0.10.0"
git-version = "0.3.4"
indexmap = "1.0.2"
lazy_static = "1.4.0"
libc = "0.2.62"
nix = "0.15.0"
num-rug-adapter = { optional = true, version = "0.1.1" }
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"
rug = { version = "1.4.0", optional = true }
rustyline = "5.0.3"
termion = "1.4.0"
rustyline = "6.0.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
control (`setup_call_cleanup/3`, `call_with_inference_limit/3`,
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.~~
- [x] `term_expansion/2` and `goal_expansion/2`.
- [x] Definite Clause Grammars.
@@ -52,11 +52,11 @@ Extend Scryer Prolog to include the following, among other features:
"Delimited Continuations for Prolog").
- [x] Tabling library based on delimited continuations
(documented in "Tabling as a Library with Delimited Control").
- [x] A _redone_ representation of strings as difference list of
chars, using a packed internal representation.
- [ ] clp(B) and clp() as builtin libraries (_in progress_).
- [x] A _redone_ representation of strings as difference lists of
characters, using a packed internal representation.
- [x] clp(B) and clp() as builtin libraries.
- [ ] 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."
- [ ] Mode declarations.
@@ -92,8 +92,14 @@ strings.
First, install the latest stable version of
[Rust](https://www.rust-lang.org/en-US/install.html) using your
preferred method. Then install Scryer Prolog with cargo,
like so:
preferred method. Scryer tends to use features from newer Rust
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
@@ -117,11 +123,6 @@ $> cargo run [--release]
The optional `--release` flag will perform various optimizations,
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
To enter a multi-clause predicate, the directive "[user]" is used.
@@ -155,11 +156,10 @@ Wildcards work as well:
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).
?- member(X, [a, b, c]).
true .
X = a ;
X = b ;
X = c ;
false.
X = a
; X = b
; X = c
; false.
```
and so do conjunctive queries:
```
@@ -169,10 +169,9 @@ f(X) :- g(X).
g(x). g(y). g(z).
h(call(f, X)).
?- h(X), X.
true .
X = call(f, x) ;
X = call(f, y) ;
X = call(f, z).
X = call(f,x)
; X = call(f,y)
; X = call(f,z).
```
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,
```
?- write_canonical(-5 + 3 - (2 * 4) // 8).
-(+(-(5), 3), //(*(2, 4), 8))
?- write_canonical(-5 + 3 - (2 * 4) // 8), nl.
-(+(-5,3),//(*(2,4),8))
true.
```
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
"partial strings." Partial strings imitate difference lists of
characters, but their characters are packed in UTF-8 format, a much
more efficient alternative to how lists of characters are represented
in many other Prologs.
In Scryer Prolog, the default value of the Prolog flag `double_quotes`
is `chars`, which is also the recommended setting. This means that
double-quoted strings are interpreted as lists of *characters*, in the
tradition of Marseille&nbsp;Prolog.
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),
partial_string_tail(X, Tail), Tail == Y.`
Scryer Prolog uses the same efficient encoding for *partial* strings,
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
Scryer has a simple predicate-based module system. It provides a
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.
At the time of this writing, several control and list processing
operators and predicates are hidden in their own modules that have not
been exported to the toplevel. To export them, write
At the time of this writing, many predicates reside in their own
modules that need to be imported before they can be used.
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)).

View File

@@ -52,5 +52,9 @@ fn main()
}
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]
extern crate downcast;
extern crate git_version;
extern crate indexmap;
#[macro_use]
extern crate lazy_static;
@@ -9,15 +11,17 @@ extern crate nix;
extern crate prolog_parser;
#[macro_use]
extern crate ref_thread_local;
extern crate termion;
use git_version::git_version;
use nix::sys::signal;
mod prolog;
use crate::prolog::machine::*;
use crate::prolog::machine::streams::*;
use crate::prolog::read::*;
use std::env;
use std::sync::atomic::Ordering;
extern fn handle_sigint(signal: libc::c_int) {
@@ -31,6 +35,11 @@ fn main() {
let handler = signal::SigHandler::Handler(handle_sigint);
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();
}

View File

@@ -6,6 +6,7 @@ use crate::prolog::forms::*;
use crate::prolog::instructions::*;
use crate::prolog::iterators::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
@@ -15,6 +16,7 @@ use crate::prolog::rug::{Assign, Integer, Rational};
use std::cell::Cell;
use std::cmp::{max, min, Ordering};
use std::convert::TryFrom;
use std::f64;
use std::num::FpCategory;
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> {
match c {
&Constant::Fixnum(n) => self
.interm
.push(ArithmeticTerm::Number(Number::Fixnum(n))),
&Constant::Integer(ref n) => self
.interm
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
@@ -316,18 +321,25 @@ impl<'a> ArithmeticEvaluator<'a> {
}
// 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 {
&Number::Integer(ref n) => RefOrOwned::Borrowed(n),
&Number::Integer(_) => {
RefOrOwned::Borrowed(n)
}
&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) => {
let r_ref = r.fract_floor_ref();
let (mut fract, mut floor) = (Rational::new(), Integer::new());
(&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.
pub fn rnd_f(n: &Number) -> f64 {
match n {
&Number::Fixnum(n) => n as f64,
&Number::Integer(ref n) => n.to_f64(),
&Number::Float(OrderedFloat(f)) => f,
&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> {
classify_float(n.to_f64(), rnd_f)
}
#[inline]
fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
classify_float(r.to_f64(), rnd_f)
}
#[inline]
fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
}
#[inline]
fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
}
#[inline]
fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
if FpCategory::Zero == f2.classify() {
Err(EvalError::ZeroDivisor)
@@ -399,14 +422,35 @@ impl Add<Number> for Number {
fn add(self, rhs: Number) -> Self::Output {
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::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Integer(n1), Number::Rational(n2))
| (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::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
@@ -415,7 +459,9 @@ impl Add<Number> for Number {
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(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 {
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::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 {
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::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Integer(n1), Number::Rational(n2))
| (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::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
@@ -461,7 +529,9 @@ impl Mul<Number> for Number {
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(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 {
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(&n2)?,
)?)),
)?))
}
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
}
(Number::Float(OrderedFloat(n2)), Number::Integer(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_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_i_to_f(&n1)?,
)?)),
)?))
}
(Number::Rational(n1), Number::Float(OrderedFloat(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 {
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
match (self, 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)),
}
Some(self.cmp(rhs))
}
}
impl Ord for Number {
fn cmp(&self, rhs: &Number) -> Ordering {
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(_), Number::Float(_)) => Ordering::Greater,
(&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.
pub fn binary_pow(mut n: Integer, power: Integer) -> Integer {
let mut power = power.abs();
pub fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
let mut power = Integer::from(power.abs_ref());
if power == 0 {
return Integer::from(1);

View File

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

View File

@@ -11,7 +11,7 @@ use crate::prolog::iterators::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::targets::*;
use indexmap::IndexMap;
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::rc::Rc;
@@ -50,56 +50,45 @@ impl<'a> ConjunctInfo<'a> {
self.has_deep_cut as usize
}
fn mark_unsafe_vars<Alloc: Allocator<'a>>(
fn mark_unsafe_vars(
&self,
mut unsafe_var_marker: UnsafeVarMarker,
marker: &Alloc,
code: &mut Code
code: &mut Code,
) {
// target the last goal of the rule for handling unsafe variables.
// 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 {
if code.is_empty() {
return;
}
} else {
if code.len() >= 1 {
code.len() - 1
} else {
return;
let mut code_index = 0;
for phase in 0 .. {
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] {
while let Line::Query(_) = &code[index] {
if index == 0 {
if code_index + 1 < code.len() {
code_index += 1;
} else {
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 {
index -= 1;
}
}
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);
}
break;
}
}
}
@@ -174,35 +163,44 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
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,
subterm: &'a Term,
term_loc: GenContext,
is_exposed: bool,
target: &mut Vec<Target>,
) where
Target: CompilationTarget<'a>,
{
) {
match subterm {
&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, _, _, _) => {
self.marker
.mark_non_var(Level::Deep, term_loc, cell, target);
self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
target.push(Target::clause_arg_to_instr(cell.get()));
}
&Term::Constant(_, ref constant) => {
target.push(Target::constant_subterm(constant.clone()))
target.push(Target::constant_subterm(constant.clone()));
}
&Term::Var(ref cell, ref var) => {
if is_exposed || self.get_var_count(var) > 1 {
self.marker
.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
} else {
Self::add_or_increment_void_instr(target);
}
self.deep_var_instr(cell, var, term_loc, is_exposed, target);
}
};
}
@@ -221,6 +219,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
for term in iter {
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) => {
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
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(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) => {
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
}
TermRef::AnonVar(lvl @ Level::Shallow) => {
if let GenContext::Head = term_loc {
self.marker.advance_arg();
TermRef::PartialString(lvl, cell, string, tail) => {
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
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 {
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() == "!" => {
@@ -263,14 +275,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
self.marker
.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
}
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
self.marker
.mark_var(var.clone(), lvl, cell, term_loc, &mut target)
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
}
_ => {
}
_ => {}
};
}
@@ -432,18 +443,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
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() {
&Term::AnonVar => {
code.push(fail!());
@@ -457,7 +456,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
},
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
&Term::Constant(_, Constant::Integer(_)) => {
&Term::Constant(_, Constant::Integer(_)) |
&Term::Constant(_, Constant::Fixnum(_)) => {
code.push(succeed!());
}
&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))))
}
}
&Term::Constant(_, ref c @ Constant::Integer(_)) => {
&Term::Constant(_, ref c @ Constant::Integer(_)) |
&Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
code.push(Line::Query(put_constant!(
Level::Shallow,
c.clone(),
@@ -684,6 +685,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
head: (_, ref args, ref p1),
ref clauses,
} = rule;
let mut code = Vec::new();
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);
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));
Ok(code)
}
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
let mut unsafe_vars = IndexMap::new();
for var_status in self.marker.bindings().values() {
unsafe_vars.insert(var_status.as_reg_type(), false);
}
let mut safe_vars = IndexSet::new();
for fact_instr in fact.iter_mut() {
match fact_instr {
&mut FactInstruction::UnifyValue(reg) => {
if let Some(found) = unsafe_vars.get_mut(&reg) {
if !*found {
*found = true;
*fact_instr = FactInstruction::UnifyLocalValue(reg);
&mut FactInstruction::UnifyValue(r) => {
if !safe_vars.contains(&r) {
*fact_instr = FactInstruction::UnifyLocalValue(r);
safe_vars.insert(r);
}
}
}
&mut FactInstruction::UnifyVariable(reg) => {
if let Some(found) = unsafe_vars.get_mut(&reg) {
*found = true;
}
&mut FactInstruction::UnifyVariable(r) => {
safe_vars.insert(r);
}
_ => {}
};
}
}
UnsafeVarMarker { unsafe_vars }
UnsafeVarMarker::from_safe_vars(safe_vars)
}
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);
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() {
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 crate::prolog::allocator::*;
use crate::prolog::forms::*;
use crate::prolog::instructions::*;
use crate::prolog::iterators::*;
@@ -250,67 +249,67 @@ impl<'a> VariableFixtures<'a> {
}
pub struct UnsafeVarMarker {
pub unsafe_vars: IndexMap<RegType, bool>,
pub unsafe_vars: IndexMap<RegType, usize>,
pub safe_vars: IndexSet<RegType>,
}
impl UnsafeVarMarker {
pub fn new() -> Self {
UnsafeVarMarker {
unsafe_vars: IndexMap::new(),
safe_vars: IndexSet::new()
}
}
pub fn record_unsafe_vars<'a, Alloc: Allocator<'a>>(
&mut self,
fixtures: &VariableFixtures,
marker: &Alloc
) {
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 from_safe_vars(safe_vars: IndexSet<RegType>) -> Self {
UnsafeVarMarker {
unsafe_vars: IndexMap::new(),
safe_vars
}
}
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) {
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
match query_instr {
QueryInstruction::PutVariable(RegType::Temp(r), _) => {
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(*r)) {
*found = true;
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
| &QueryInstruction::SetVariable(r) => {
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 {
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) {
if !*found {
*found = true;
if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
if p == phase {
*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) => {
if let Some(found) = self.unsafe_vars.get_mut(&reg) {
if !*found {
*found = true;
*query_instr = QueryInstruction::SetLocalValue(reg);
}
&mut QueryInstruction::SetValue(r) => {
if !self.safe_vars.contains(&r) {
*query_instr = QueryInstruction::SetLocalValue(r);
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::collections::VecDeque;
use std::convert::TryFrom;
use std::path::PathBuf;
use std::rc::Rc;
@@ -376,6 +377,19 @@ pub enum ModuleSource {
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.
#[derive(Clone)]
@@ -394,6 +408,7 @@ pub enum Declaration {
MultiFile(MultiFileIndicator),
NonCountedBacktracking(ClauseName, usize), // name, arity
Op(OpDecl),
SetPrologFlag(DoubleQuotes),
UseModule(ModuleSource),
UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
}
@@ -572,11 +587,33 @@ pub struct Module {
pub listing_src: ListingSource,
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone)]
pub enum Number {
Float(OrderedFloat<f64>),
Integer(Integer),
Rational(Rational),
Integer(Rc<Integer>),
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 {
@@ -585,48 +622,89 @@ impl Default for Number {
}
}
impl Number {
pub fn to_constant(self) -> Constant {
impl Into<Constant> for Number {
#[inline]
fn into(self) -> Constant {
match self {
Number::Fixnum(n) => Constant::Fixnum(n),
Number::Integer(n) => Constant::Integer(n),
Number::Float(f) => Constant::Float(f),
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]
pub fn is_positive(&self) -> bool {
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::Rational(ref r) => r > &0,
&Number::Rational(ref r) => &**r > &0,
}
}
#[inline]
pub fn is_negative(&self) -> bool {
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::Rational(ref r) => r < &0,
&Number::Rational(ref r) => &**r < &0,
}
}
#[inline]
pub fn is_zero(&self) -> bool {
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::Rational(ref r) => r == &0,
&Number::Rational(ref r) => &**r == &0,
}
}
#[inline]
pub fn abs(self) -> 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::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_state::*;
@@ -22,25 +20,33 @@ impl<'a> HCPreOrderIterator<'a> {
}
}
#[inline]
pub fn machine_st(&self) -> &MachineState {
&self.machine_st
}
fn follow_heap(&mut self, h: usize) -> Addr {
match &self.machine_st.heap[h] {
HeapCellValue::NamedStr(arity, _, _) => {
for idx in (1..arity + 1).rev() {
&HeapCellValue::NamedStr(arity, _, _) => {
for idx in (1 .. arity + 1).rev() {
self.state_stack.push(Addr::HeapCell(h + idx));
}
Addr::Str(h)
}
HeapCellValue::Addr(ref a) => {
self.follow(a.clone())
&HeapCellValue::Addr(a) => {
self.follow(a)
}
HeapCellValue::PartialString(_) => {
HeapCellValue::PartialString(..) => {
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));
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) => {
self.state_stack.push(Addr::HeapCell(a + 1));
self.state_stack.push(Addr::HeapCell(a));
@@ -82,19 +64,19 @@ impl<'a> HCPreOrderIterator<'a> {
da
}
Addr::PStrLocation(h, n) => {
if let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] {
let s = pstr.block_as_str();
if let Some(c) = s[n ..].chars().next() {
if pstr.len() > n + c.len_utf8() {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
if let Some(c) = pstr.range_from(n ..).next() {
if !pstr.at_end(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 {
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)));
} else {
unreachable!()
self.state_stack.push(Addr::Char(c));
} else if has_tail {
return self.follow(Addr::HeapCell(h + 1));
}
} else {
unreachable!()
@@ -102,80 +84,63 @@ impl<'a> HCPreOrderIterator<'a> {
Addr::PStrLocation(h, n)
}
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::PStrTail(..) => {
da
}
Addr::Str(s) => {
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> {
type Item = HeapCellValue;
type Item = Addr;
fn next(&mut self) -> Option<Self::Item> {
self.state_stack.pop().map(|a| match 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)
}
})
self.state_stack.pop().map(|a| self.follow(a))
}
}
pub trait MutStackHCIterator
where
Self: Iterator<Item = HeapCellValue>,
where Self: Iterator<Item = Addr>
{
fn stack(&mut self) -> &mut Vec<Addr>;
}
pub struct HCPostOrderIterator<HCIter> {
base_iter: HCIter,
parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node.
pub struct HCPostOrderIterator<'a> {
base_iter: HCPreOrderIterator<'a>,
parent_stack: Vec<(usize, Addr)>, // number of children, parent node.
}
impl<HCIter> Deref for HCPostOrderIterator<HCIter> {
type Target = HCIter;
impl<'a> Deref for HCPostOrderIterator<'a> {
type Target = HCPreOrderIterator<'a>;
fn deref(&self) -> &Self::Target {
&self.base_iter
}
}
impl<HCIter: Iterator<Item = HeapCellValue>> HCPostOrderIterator<HCIter> {
pub fn new(base_iter: HCIter) -> Self {
impl<'a> HCPostOrderIterator<'a> {
pub fn new(base_iter: HCPreOrderIterator<'a>) -> Self {
HCPostOrderIterator {
base_iter,
parent_stack: vec![],
@@ -183,8 +148,8 @@ impl<HCIter: Iterator<Item = HeapCellValue>> HCPostOrderIterator<HCIter> {
}
}
impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HCIter> {
type Item = HeapCellValue;
impl<'a> Iterator for HCPostOrderIterator<'a> {
type Item = Addr;
fn next(&mut self) -> Option<Self::Item> {
loop {
@@ -197,15 +162,30 @@ impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HC
}
if let Some(item) = self.base_iter.next() {
match item {
HeapCellValue::NamedStr(arity, name, fix) => self
.parent_stack
.push((arity, HeapCellValue::NamedStr(arity, name, fix))),
HeapCellValue::Addr(Addr::Lis(a)) => self
.parent_stack
.push((2, HeapCellValue::Addr(Addr::Lis(a)))),
child_node => {
return Some(child_node);
match self.base_iter.machine_st.heap.index_addr(&item).as_ref() {
&HeapCellValue::NamedStr(arity, ..) => {
self.parent_stack.push((arity, item));
}
&HeapCellValue::Addr(Addr::Lis(a)) => {
self.parent_stack.push((2, Addr::Lis(a)));
}
&HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
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 {
@@ -215,21 +195,16 @@ impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HC
}
}
pub type HCProperPostOrderIterator<'a> = HCPostOrderIterator<HCPreOrderIterator<'a>>;
impl MachineState {
pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'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))
}
pub fn acyclic_pre_order_iter<'a>(
&'a self,
a: Addr,
) -> HCAcyclicIterator<HCPreOrderIterator<'a>> {
pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr,) -> HCAcyclicIterator<'a> {
HCAcyclicIterator::new(HCPreOrderIterator::new(self, a))
}
@@ -237,7 +212,7 @@ impl MachineState {
&'a self,
a1: Addr,
a2: Addr,
) -> HCZippedAcyclicIterator<HCPreOrderIterator<'a>> {
) -> HCZippedAcyclicIterator<'a> {
HCZippedAcyclicIterator::new(
HCPreOrderIterator::new(self, a1),
HCPreOrderIterator::new(self, a2),
@@ -251,13 +226,13 @@ impl<'a> MutStackHCIterator for HCPreOrderIterator<'a> {
}
}
pub struct HCAcyclicIterator<HCIter> {
iter: HCIter,
pub struct HCAcyclicIterator<'a> {
iter: HCPreOrderIterator<'a>,
seen: IndexSet<Addr>,
}
impl<HCIter: MutStackHCIterator> HCAcyclicIterator<HCIter> {
pub fn new(iter: HCIter) -> Self {
impl<'a> HCAcyclicIterator<'a> {
pub fn new(iter: HCPreOrderIterator<'a>) -> Self {
HCAcyclicIterator {
iter,
seen: IndexSet::new(),
@@ -265,19 +240,17 @@ impl<HCIter: MutStackHCIterator> HCAcyclicIterator<HCIter> {
}
}
impl<HCIter> Deref for HCAcyclicIterator<HCIter> {
type Target = HCIter;
impl<'a> Deref for HCAcyclicIterator<'a> {
type Target = HCPreOrderIterator<'a>;
fn deref(&self) -> &Self::Target {
&self.iter
}
}
impl<HCIter> Iterator for HCAcyclicIterator<HCIter>
where
HCIter: Iterator<Item = HeapCellValue> + MutStackHCIterator,
impl<'a> Iterator for HCAcyclicIterator<'a>
{
type Item = HeapCellValue;
type Item = Addr;
fn next(&mut self) -> Option<Self::Item> {
while let Some(addr) = self.iter.stack().pop() {
@@ -293,15 +266,15 @@ where
}
}
pub struct HCZippedAcyclicIterator<HCIter> {
i1: HCIter,
i2: HCIter,
pub struct HCZippedAcyclicIterator<'a> {
i1: HCPreOrderIterator<'a>,
i2: HCPreOrderIterator<'a>,
seen: IndexSet<(Addr, Addr)>,
pub first_to_expire: Ordering,
}
impl<HCIter: MutStackHCIterator> HCZippedAcyclicIterator<HCIter> {
pub fn new(i1: HCIter, i2: HCIter) -> Self {
impl<'a> HCZippedAcyclicIterator<'a> {
pub fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self {
HCZippedAcyclicIterator {
i1,
i2,
@@ -311,11 +284,9 @@ impl<HCIter: MutStackHCIterator> HCZippedAcyclicIterator<HCIter> {
}
}
impl<HCIter> Iterator for HCZippedAcyclicIterator<HCIter>
where
HCIter: Iterator<Item = HeapCellValue> + MutStackHCIterator,
impl<'a> Iterator for HCZippedAcyclicIterator<'a>
{
type Item = (HeapCellValue, HeapCellValue);
type Item = (Addr, Addr);
fn next(&mut self) -> Option<Self::Item> {
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;
None
}
_ => None,
_ => {
None
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,13 @@
use prolog_parser::ast::*;
use crate::prolog::instructions::*;
use crate::prolog::rug::Integer;
use indexmap::IndexMap;
use std::collections::VecDeque;
use std::hash::Hash;
use std::rc::Rc;
#[derive(Clone, Copy)]
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) {
match first_arg {
&Term::Clause(_, ref name, ref terms, _) => {
@@ -63,18 +100,12 @@ impl CodeOffsets {
let is_initial_index = self.lists.is_empty();
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) => {
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();
code.push(Self::add_index(is_initial_index, index));
@@ -227,12 +258,11 @@ impl CodeOffsets {
fn switch_on_lst_offset_from(
lst_loc: IntIndex,
prelude_len: usize,
lst_offset: usize,
) -> usize {
match lst_loc {
IntIndex::External(o) => o + prelude_len + 1,
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 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 con_loc = Self::switch_on_constant(self.constants, &mut prelude);
@@ -254,18 +282,19 @@ impl CodeOffsets {
for (index, line) in prelude.iter_mut().enumerate() {
match line {
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i))
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i))
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
*i += prelude_length - index
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) |
&mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) |
&mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
*i += prelude_length - index;
}
_ => {
}
_ => {}
}
}
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 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 =
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::forms::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::MachineStub;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::rug::Integer;
use indexmap::IndexMap;
use std::collections::VecDeque;
use std::rc::Rc;
fn reg_type_into_functor(r: RegType) -> MachineStub {
match r {
RegType::Temp(r) => functor!("x", 1, [heap_integer!(Integer::from(r))]),
RegType::Perm(r) => functor!("y", 1, [heap_integer!(Integer::from(r))]),
RegType::Temp(r) => functor!("x", [integer(r)]),
RegType::Perm(r) => functor!("y", [integer(r)]),
}
}
impl Level {
fn into_functor(self) -> MachineStub {
match self {
Level::Root => functor!("level", 1, [heap_atom!("root")]),
Level::Shallow => functor!("level", 1, [heap_atom!("shallow")]),
Level::Deep => functor!("level", 1, [heap_atom!("deep")]),
Level::Root => functor!("level", [atom("root")]),
Level::Shallow => functor!("level", [atom("shallow")]),
Level::Deep => functor!("level", [atom("deep")]),
}
}
}
@@ -31,11 +32,15 @@ impl Level {
impl ArithmeticTerm {
fn into_functor(&self) -> MachineStub {
match self {
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
&ArithmeticTerm::Interm(i) => {
functor!("intermediate", 1, [heap_integer!(Integer::from(i))])
&ArithmeticTerm::Reg(r) => {
reg_type_into_functor(r)
}
&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 {
match self {
&ChoiceInstruction::TryMeElse(offset) => {
functor!("try_me_else", 1, [heap_integer!(Integer::from(offset))])
functor!("try_me_else", [integer(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 {
match self {
&CutInstruction::Cut(r) => {
let mut stub = functor!("cut", 1, [heap_str!(h + 2)]);
stub.append(&mut reg_type_into_functor(r));
stub
let rt_stub = reg_type_into_functor(r);
functor!("cut", [aux(h, 0)], [rt_stub])
}
&CutInstruction::GetLevel(r) => {
let mut stub = functor!("get_level", 1, [heap_str!(h + 2)]);
stub.append(&mut reg_type_into_functor(r));
stub
let rt_stub = reg_type_into_functor(r);
functor!("get_level", [aux(h, 0)], [rt_stub])
}
&CutInstruction::GetLevelAndUnify(r) => {
let mut stub = functor!("get_level_and_unify", 1, [heap_str!(h + 2)]);
stub.append(&mut reg_type_into_functor(r));
stub
let rt_stub = reg_type_into_functor(r);
functor!("get_level_and_unify", [aux(h, 0)], [rt_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 {
match self {
&IndexedChoiceInstruction::Try(offset) => {
functor!("try", 1, [heap_integer!(Integer::from(offset))])
functor!("try", [integer(offset)])
}
&IndexedChoiceInstruction::Trust(offset) => {
functor!("trust", 1, [heap_integer!(Integer::from(offset))])
functor!("trust", [integer(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 {
let at_stub = at.into_functor();
let mut stub = functor!(
functor!(
name,
2,
[heap_cell!(h + 4), heap_integer!(Integer::from(t))]
);
stub.extend(at_stub.into_iter());
stub
[aux(h, 0), integer(t)],
[at_stub]
)
}
fn arith_instr_bin_functor(
@@ -240,20 +243,11 @@ fn arith_instr_bin_functor(
let at_1_stub = at_1.into_functor();
let at_2_stub = at_2.into_functor();
let mut stub = functor!(
functor!(
name,
3,
[
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
[aux(h, 0), aux(h, 1), integer(t)],
[at_1_stub, at_2_stub]
)
}
impl ArithmeticInstruction {
@@ -319,17 +313,39 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::Gcd(ref at_1, ref 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::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", 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::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::Sign(ref at, t) => {
arith_instr_unary_functor(h, "sign", at, t)
}
&ArithmeticInstruction::Cos(ref at, t) => {
arith_instr_unary_functor(h, "cos", 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::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) => {
arith_instr_unary_functor(h, "float", at, t)
}
@@ -345,8 +361,12 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::Floor(ref at, t) => {
arith_instr_unary_functor(h, "floor", at, t)
}
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t),
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t),
&ArithmeticInstruction::Neg(ref 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) => {
arith_instr_unary_functor(h, "\\", at, t)
}
@@ -378,29 +398,23 @@ impl ControlInstruction {
pub fn to_functor(&self) -> MachineStub {
match self {
&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, ..) => {
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 {
pub fn to_functor(&self) -> MachineStub {
match self {
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => functor!(
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => {
functor!(
"switch_on_term",
4,
[
heap_integer!(Integer::from(vars)),
heap_integer!(Integer::from(constants)),
heap_integer!(Integer::from(lists)),
heap_integer!(Integer::from(structures))
]
),
&IndexingInstruction::SwitchOnConstant(constants, _) => functor!(
[integer(vars),
integer(constants),
integer(lists),
integer(structures)]
)
}
&IndexingInstruction::SwitchOnConstant(constants, _) => {
functor!(
"switch_on_constant",
1,
[heap_integer!(Integer::from(constants))]
),
&IndexingInstruction::SwitchOnStructure(structures, _) => functor!(
[integer(constants)]
)
}
&IndexingInstruction::SwitchOnStructure(structures, _) => {
functor!(
"switch_on_structure",
1,
[heap_integer!(Integer::from(structures))]
),
[integer(structures)]
)
}
}
}
}
@@ -448,6 +463,7 @@ impl IndexingInstruction {
pub enum FactInstruction {
GetConstant(Level, Constant, RegType),
GetList(Level, RegType),
GetPartialString(Level, String, RegType, bool),
GetStructure(ClauseType, usize, RegType),
GetValue(RegType, usize),
GetVariable(RegType, usize),
@@ -461,86 +477,95 @@ pub enum FactInstruction {
impl FactInstruction {
pub fn to_functor(&self, h: usize) -> MachineStub {
match self {
&FactInstruction::GetConstant(lvl, ref constant, r) => {
let mut stub = functor!(
&FactInstruction::GetConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"get_constant",
3,
[
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
[aux(h, 0), constant(h, c), aux(h, 1)],
[lvl_stub, rt_stub]
)
}
&FactInstruction::GetList(lvl, r) => {
let mut stub = functor!("get_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]);
stub.append(&mut lvl.into_functor());
stub.append(&mut reg_type_into_functor(r));
let lvl_stub = lvl.into_functor();
let rt_stub = 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) => {
let mut stub = functor!(
"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));
let rt_stub = reg_type_into_functor(r);
stub
functor!(
"get_structure",
[clause_name(ct.name()), integer(arity), aux(h, 0)],
[rt_stub]
)
}
&FactInstruction::GetValue(r, arg) => {
let mut stub = functor!(
"get_value",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
stub.append(&mut reg_type_into_functor(r));
let rt_stub = reg_type_into_functor(r);
stub
functor!(
"get_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
}
&FactInstruction::GetVariable(r, arg) => {
let mut stub = functor!(
"get_variable",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
stub.append(&mut reg_type_into_functor(r));
let rt_stub = reg_type_into_functor(r);
stub
functor!(
"get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
}
&FactInstruction::UnifyConstant(ref constant) => {
functor!("unify_constant", 1, [heap_con!(constant.clone())])
&FactInstruction::UnifyConstant(ref c) => {
functor!("unify_constant", [constant(h, c)], [])
}
&FactInstruction::UnifyLocalValue(r) => {
let mut stub = functor!("unify_local_value", 1, [heap_str!(h + 2)]);
stub.append(&mut reg_type_into_functor(r));
let rt_stub = reg_type_into_functor(r);
stub
functor!(
"unify_local_value",
[aux(h, 0)],
[rt_stub]
)
}
&FactInstruction::UnifyVariable(r) => {
let mut stub = functor!("unify_variable", 1, [heap_str!(h + 2)]);
stub.append(&mut reg_type_into_functor(r));
let rt_stub = reg_type_into_functor(r);
stub
functor!(
"unify_variable",
[aux(h, 0)],
[rt_stub]
)
}
&FactInstruction::UnifyValue(r) => {
let mut stub = functor!("unify_value", 1, [heap_str!(h + 2)]);
stub.append(&mut reg_type_into_functor(r));
let rt_stub = reg_type_into_functor(r);
stub
functor!(
"unify_value",
[aux(h, 0)],
[rt_stub]
)
}
&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),
PutConstant(Level, Constant, RegType),
PutList(Level, RegType),
PutPartialString(Level, String, RegType, bool),
PutStructure(ClauseType, usize, RegType),
PutUnsafeValue(usize, usize),
PutValue(RegType, usize),
@@ -567,103 +593,106 @@ impl QueryInstruction {
match self {
&QueryInstruction::PutUnsafeValue(norm, arg) => functor!(
"put_unsafe_value",
2,
[
heap_integer!(Integer::from(norm)),
heap_integer!(Integer::from(arg))
]
[integer(norm), integer(arg)]
),
&QueryInstruction::PutConstant(lvl, ref constant, r) => {
let mut stub = functor!(
&QueryInstruction::PutConstant(lvl, ref c, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
"put_constant",
3,
[
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
[aux(h, 0), constant(h, c), aux(h, 1)],
[lvl_stub, rt_stub]
)
}
&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());
stub.append(&mut reg_type_into_functor(r));
functor!(
"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) => {
let mut stub = functor!(
"put_structure",
3,
[
heap_con!(Constant::Atom(ct.name(), None)),
heap_integer!(Integer::from(arity)),
heap_str!(h + 4)
]
);
let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub
functor!(
"put_structure",
[clause_name(ct.name()), integer(arity), aux(h, 0)],
[rt_stub]
)
}
&QueryInstruction::PutValue(r, arg) => {
let mut stub = functor!(
"put_value",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub
functor!(
"put_value",
[aux(h, 0), integer(arg)],
[rt_stub]
)
}
&QueryInstruction::GetVariable(r, arg) => {
let mut stub = functor!(
"get_variable",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub
functor!(
"get_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
}
&QueryInstruction::PutVariable(r, arg) => {
let mut stub = functor!(
"put_variable",
2,
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
);
let rt_stub = reg_type_into_functor(r);
stub.append(&mut reg_type_into_functor(r));
stub
functor!(
"put_variable",
[aux(h, 0), integer(arg)],
[rt_stub]
)
}
&QueryInstruction::SetConstant(ref constant) => {
functor!("set_constant", 1, [heap_con!(constant.clone())])
&QueryInstruction::SetConstant(ref c) => {
functor!("set_constant", [constant(h, c)], [])
}
&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));
stub
functor!(
"set_local_value",
[aux(h, 0)],
[rt_stub]
)
}
&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));
stub
functor!(
"set_variable",
[aux(h, 0)],
[rt_stub]
)
}
&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));
stub
functor!(
"set_value",
[aux(h, 0)],
[rt_stub]
)
}
&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),
Constant(Level, &'a Cell<RegType>, &'a Constant),
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>),
}
@@ -27,6 +28,7 @@ impl<'a> TermRef<'a> {
| TermRef::Constant(lvl, ..)
| TermRef::Var(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),
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>),
}
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> {
pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
match term {
&Term::AnonVar => TermIterState::AnonVar(lvl),
&Term::AnonVar => {
TermIterState::AnonVar(lvl)
}
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
let ct = if let Some(spec) = spec {
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
@@ -62,8 +114,12 @@ impl<'a> TermIterState<'a> {
&Term::Cons(ref cell, ref head, ref tail) => {
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
}
&Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant),
&Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()),
&Term::Constant(ref cell, ref constant) => {
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> {
while let Some(iter_state) = self.state_stack.pop() {
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) => {
if child_num == child_terms.len() {
match ct {
@@ -182,7 +240,9 @@ impl<'a> Iterator for QueryIterator<'a> {
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
}
}
_ => return None,
_ => {
return None;
}
};
} else {
self.state_stack.push(TermIterState::Clause(
@@ -192,23 +252,41 @@ impl<'a> Iterator for QueryIterator<'a> {
ct,
child_terms,
));
self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
}
}
TermIterState::InitialCons(lvl, cell, head, tail) => {
self.state_stack
.push(TermIterState::FinalCons(lvl, cell, head, tail));
if let Some((string, tail)) = is_partial_string(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(), head);
}
}
TermIterState::PartialString(lvl, cell, string, tail) => {
return Some(TermRef::PartialString(lvl, cell, string, 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) => {
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> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_queue
.push_back(TermIterState::subterm_to_state(lvl, term));
self.state_queue.push_back(TermIterState::subterm_to_state(lvl, term));
}
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 {
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) => {
let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone());
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> {
while let Some(state) = self.state_queue.pop_front() {
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) => {
for child_term in child_terms {
self.push_subterm(lvl.child_level(), child_term);
@@ -285,16 +366,27 @@ impl<'a> Iterator for FactIterator<'a> {
};
}
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, tail);
return Some(TermRef::Cons(lvl, cell, head, tail));
}
}
TermIterState::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),
call(Goal),
'$get_attr_var_queue_beyond'(B, Vars).

View File

@@ -6,15 +6,10 @@
:- use_module(library(error)).
between(Lower, Upper, X) :-
( Upper == inf ->
must_be(integer, Lower),
can_be(integer, X),
enumerate_nats(Lower, X)
; must_be(integer, Lower),
must_be(integer, Upper),
can_be(integer, X),
between_(Lower, Upper, X)
).
between_(Lower, Upper, X).
between_(Lower, Upper, Lower) :-
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,
atom_codes/2, atom_concat/3, atom_length/2,
bagof/3, catch/3, char_code/2, clause/2,
current_op/3, current_predicate/1,
current_prolog_flag/2, expand_goal/2,
expand_term/2, fail/0, false/0, findall/3,
findall/4, get_char/1, halt/0, max_arity/1,
number_chars/2, number_codes/2, once/1, op/3,
read_term/2, repeat/0, retract/1,
set_prolog_flag/2, setof/3, sub_atom/5,
subsumes_term/2, term_variables/2, throw/1,
true/0, unify_with_occurs_check/2, write/1,
current_input/1, current_output/1, current_op/3,
current_predicate/1, current_prolog_flag/2,
expand_goal/2, expand_term/2, fail/0, false/0,
findall/3, findall/4, get_char/1, halt/0,
max_arity/1, number_chars/2, number_codes/2,
once/1, op/3, read_term/2, repeat/0, retract/1,
set_prolog_flag/2, set_input/1, set_output/1,
setof/3, sub_atom/5, subsumes_term/2,
term_variables/2, throw/1, true/0,
unify_with_occurs_check/2, write/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)),
'$call_with_default_policy'(univ_worker(Term, List, N)).
:- 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) :-
var(Term), !,
'$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'(List = [Name|Args]).
:- non_counted_backtracking get_args/4.
get_args(Args, _, _, 0) :-
!, '$call_with_default_policy'(Args = []).
get_args([Arg], Func, N, N) :-
@@ -289,6 +295,7 @@ is_write_option(Functor) :-
( Arg == true -> true
; Arg == false -> true
; 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))
; throw(error(domain_error(write_option, Functor), write_term/2))
), % 8.14.2.3 e)
@@ -296,6 +303,7 @@ is_write_option(Functor) :-
; Name == quoted -> true
; Name == numbervars -> true
; Name == variable_names -> true
; Name == max_depth -> true
; throw(error(domain_error(write_option, Functor), write_term/2))
). % 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, quoted(Quoted), quoted(false)),
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)]).
@@ -448,7 +457,7 @@ set_difference([], _, []) :- !.
set_difference(Xs, [], Xs).
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_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([], []).
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).
@@ -472,7 +484,9 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
( nonvar(Goal), Goal = _ ^ _ ->
rightmost_power(Goal, Goal1, ExistentialVars0),
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)
; Witnesses = Witnesses0,
findall(Witnesses-Template, Goal, PairedSolutions)
@@ -491,7 +505,10 @@ bagof(Template, Goal, Solution) :-
iterate_variants(GroupedSolutions, Witnesses, 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).
@@ -1006,3 +1023,19 @@ subsumes_term(General, Specific) :-
).
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(atts)).
:- 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(error), []).
@@ -106,65 +107,10 @@ type_error(Expectation, Term) :-
type_error(Expectation, Term, Goal-Arg) :-
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) :-
include(Pred, Ls0, As),
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))) :-
Access =.. [Module,Value].
@@ -728,10 +674,6 @@ existential(V, BDD, Node) :-
Counter network for card(Is,Fs).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
same_length([], []).
same_length([_|As], [_|Bs]) :-
same_length(As, Bs).
counter_network(Cs, Fs, Node) :-
same_length([_|Fs], Indicators),
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]).
reset(Goal, Ball, Cont) :-
@@ -7,14 +6,14 @@ reset(Goal, Ball, Cont) :-
'$bind_from_register'(Cont, 3),
'$bind_from_register'(Ball, 4).
shift(Term) :-
shift(Ball) :-
'$nextEP'(first, E, P),
get_chunks(E, P, L),
( L == [] ->
Cont = none
; Cont = cont(call_continuation(L))
),
'$write_cont_and_term'(_, _, Cont, Term),
'$write_cont_and_term'(_, _, Cont, Ball),
'$unwind_environments'.
get_chunks(E, P, L) :-

View File

@@ -1,7 +1,9 @@
% :- op(1105, xfy, ('|')).
:- module(dcgs, [op(1200, xfx, -->), phrase/2, phrase/3]).
:- module(dcgs, [op(1200, xfx, -->),
op(1105, xfy, '|'),
phrase/2,
phrase/3]).
:- use_module(library(error)).
:- use_module(library(lists), [append/3]).
user:term_expansion(Term0, Term) :-
@@ -31,8 +33,8 @@ phrase_((A -> B ; C), S0, S) :-
).
phrase_((A ; B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
%% phrase_((A | B), S0, S) :-
%% ( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_((A | B), S0, S) :-
( phrase(A, S0, S) ; phrase(B, S0, S) ).
phrase_({G}, S0, S) :-
( 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.3 - concatenation
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(call(_)). % 7.14.8
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.
dcg_cbody([], S0, S, S0 = S).
dcg_cbody([T|Ts], S0, S, Goal) :-
must_be(list, [T|Ts]),
dcg_terminals([T|Ts], S0, S, Goal).
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
dcg_body(GRFirst, S0, S1, First),
@@ -119,9 +122,9 @@ dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
subsumes_term(( _GRIf -> _GRThen ), GRCond),
dcg_cbody(GRCond, S0, S, Cond),
dcg_body(GRElse, S0, S, Else).
%% dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
%% dcg_body(GREither, S0, S, Either),
%% dcg_body(GROr, S0, S, Or).
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
dcg_body(GREither, S0, S, Either),
dcg_body(GROr, S0, S, Or).
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
dcg_cbody(call(Cont), S0, S, call(Cont, 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(lists)).
:- use_module(library(non_iso)).
:- use_module(library(iso_ext)).
:- use_module(library(si)).
gensym_key(Base, BaseKey) :-

View File

@@ -1,9 +1,9 @@
%% for builtins that are not part of the ISO standard.
%% 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,
partial_string/1, partial_string/3,
partial_string_tail/2, set_random/1,
@@ -157,13 +157,15 @@ set_random(Seed) :-
; throw(error(instantiation_error, set_random/1))
).
partial_string(String, L, L0) :-
( String == [] -> throw(error(type_error(list, []), partial_string/3))
( String == [] ->
L = L0
; catch(atom_chars(Atom, String),
error(E, _),
throw(error(E, partial_string/3)))
),
'$create_partial_string'(Atom, L, L0).
throw(error(E, partial_string/3))),
'$create_partial_string'(Atom, L, L0)
).
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,
maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2,
sumlist/2]).
sum_list/2, transpose/2]).
:- use_module(library(error)).
@@ -44,6 +44,12 @@ select(X, [X|Xs], Xs).
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([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).
sumlist_([], S, S).
sumlist_([N|Ns], S, S0) :-
S1 is S0 + N,
sumlist_(Ns, S, S1).
sum_list(Ls, S) :-
foldl(sum_, Ls, 0, S).
sumlist(Ns, S) :-
must_be(list, Ns),
sumlist_(Ns, S, 0).
sum_(L, S0, S) :- S is S0 + L.
@@ -134,3 +136,16 @@ 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).
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(lists)).
%:- use_module(library(debug)).
:- use_module(library(non_iso)).
:- use_module(library(iso_ext)).
%% :- meta_predicate
%% start_tabling(+, 0).

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
driver(Vars, Values) :-
iterate(Vars, Values, ListOfListsOfGoalLists),
'$clear_attr_var_bindings',
!,
call_goals(ListOfListsOfGoalLists),
'$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.
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, _, _, []) :-
var(Attrs), !.
call_verify_attributes([], _, _, []).
@@ -32,6 +24,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
sort(Modules0, Modules),
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_0(ListOfGoalLists),
call_goals(ListsCubed).

View File

@@ -1,5 +1,6 @@
use crate::prolog::machine::*;
use std::cmp::Ordering;
use std::vec::IntoIter;
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
@@ -18,7 +19,8 @@ pub(super) struct 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 {
attribute_goals: vec![],
attr_var_queue: vec![],
@@ -31,21 +33,24 @@ impl AttrVarInitializer {
}
#[inline]
pub(super) fn reset(&mut self) {
pub(super)
fn reset(&mut self) {
self.attribute_goals.clear();
self.attr_var_queue.clear();
self.bindings.clear();
}
#[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.bindings.truncate(bindings_b);
}
}
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() {
self.attr_var_init.instigating_p = self.p.local();
@@ -66,18 +71,17 @@ impl MachineState {
.attr_var_init
.bindings
.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 iter = self
.attr_var_init
.bindings
.iter()
.map(|(_, ref addr)| addr.clone());
.drain(0 ..)
.map(|(_, addr)| HeapCellValue::Addr(addr));
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
(var_list_addr, value_list_addr)
}
@@ -92,7 +96,8 @@ impl MachineState {
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..]
.iter()
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
@@ -101,13 +106,16 @@ impl MachineState {
})
.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);
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);
let e = self.e;
@@ -118,9 +126,9 @@ impl MachineState {
}
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] =
Addr::Con(Constant::Usize(self.num_of_args));
Addr::Usize(self.num_of_args);
self.verify_attributes();

View File

@@ -21,7 +21,6 @@ use ref_thread_local::RefThreadLocal;
use std::cell::Cell;
use std::collections::VecDeque;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::path::PathBuf;
@@ -60,9 +59,9 @@ fn fix_filename(
Ok(path)
}
fn load_module<R: Read>(
fn load_module(
wam: &mut Machine,
stream: ParsingStream<R>,
stream: Stream,
suppress_warnings: bool,
listing_src: &ListingSource,
) -> Result<ClauseName, SessionError> {
@@ -78,7 +77,11 @@ fn load_module<R: Read>(
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 {
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 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()))
})?;
})?);
path_buf.pop();
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>);
@@ -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,
module_name: ClauseName,
src: ParsingStream<R>,
src: Stream,
name: ClauseName,
) -> EvalSession {
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.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) {
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,
compiler: &mut ListingCompiler,
module: Module,
src: ParsingStream<R>,
src: Stream,
mut indices: IndexStore,
) -> Result<(), SessionError> {
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::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(
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());
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
Ok(compiler.drop_expansions(&mut wam.code_repo))
@@ -548,8 +559,8 @@ fn add_module(
term_dir: TermDir,
) {
module.code_dir.extend(indices.code_dir);
module.op_dir.extend(indices.op_dir.into_iter());
module.term_dir.extend(term_dir.into_iter());
module.op_dir.extend(indices.op_dir);
module.term_dir.extend(term_dir);
wam.add_in_situ_module_dir(indices.module_dir);
wam.add_module(module);
@@ -568,7 +579,7 @@ fn add_non_module_code(
clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
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);
Ok(())
@@ -591,12 +602,18 @@ fn load_library(
load_module(
wam,
parsing_stream(code.as_bytes()),
Stream::from(*code),
suppress_warnings,
&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))
} 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))
} 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) => {
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)) => {
let name = if !wam.indices.modules.contains_key(&name) {
load_library(wam, name, true)?
@@ -1018,10 +1047,10 @@ impl ListingCompiler {
}
}
fn setup_multifile_decl<R: Read>(
fn setup_multifile_decl(
&self,
indicator: MultiFileIndicator,
worker: &mut TopLevelBatchWorker<R>,
worker: &mut TopLevelBatchWorker,
) -> Result<(), SessionError> {
match indicator {
MultiFileIndicator::LocalScoped(name, arity) => {
@@ -1042,7 +1071,11 @@ impl ListingCompiler {
insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
}
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(())
}
fn process_and_commit_decl<R: Read>(
fn process_and_commit_decl(
&mut self,
decl: Declaration,
worker: &mut TopLevelBatchWorker<R>,
worker: &mut TopLevelBatchWorker,
indices: &mut IndexStore,
flags: MachineFlags,
) -> Result<(), SessionError> {
@@ -1101,15 +1134,15 @@ impl ListingCompiler {
result
}
pub(crate) fn gather_items<R: Read>(
pub(crate) fn gather_items(
&mut self,
wam: &mut Machine,
mut src: ParsingStream<R>,
src: &mut ParsingStream<Stream>,
indices: &mut IndexStore,
) -> Result<GatherResult, SessionError> {
let flags = wam.machine_flags();
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_indices = default_index_store!(atom_tbl.clone());
@@ -1302,28 +1335,32 @@ fn compile_work_impl(
Ok(())
}
fn compile_work<R: Read>(
fn compile_work(
compiler: &mut ListingCompiler,
wam: &mut Machine,
src: ParsingStream<R>,
src: Stream,
mut indices: IndexStore,
) -> EvalSession {
let src = &mut parsing_stream(src);
let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
try_eval_session!(compile_work_impl(compiler, wam, indices, results));
EvalSession::EntrySuccess
}
/* This is a truncated version of compile_user_module, used for
compiling code composing special forms, ie. the code that calls
M:verify_attributes on attributed variables. */
pub fn compile_special_form<R: Read>(
pub fn compile_special_form(
wam: &mut Machine,
src: ParsingStream<R>,
src: Stream,
listing_src: ListingSource,
) -> Result<usize, SessionError> {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
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 results = compiler.gather_items(wam, src, &mut indices)?;
@@ -1348,9 +1385,9 @@ pub fn compile_special_form<R: Read>(
}
#[inline]
pub fn compile_listing<R: Read>(
pub fn compile_listing(
wam: &mut Machine,
src: ParsingStream<R>,
src: Stream,
indices: IndexStore,
suppress_warnings: bool,
listing_src: ListingSource,
@@ -1373,20 +1410,24 @@ pub(super) fn setup_indices(
module: ClauseName,
indices: &mut IndexStore,
) -> 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 result = indices.use_module(&mut wam.code_repo, flags, &module);
wam.indices.insert_module(module);
result
} 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,
src: ParsingStream<R>,
src: Stream,
suppress_warnings: bool,
listing_src: ListingSource,
) -> EvalSession {

View File

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

View File

@@ -1,11 +1,12 @@
use prolog_parser::ast::*;
use crate::prolog::heap_print::*;
use crate::prolog::machine::*;
use crate::prolog::machine::compile::*;
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 {
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,
src: ParsingStream<R>,
src: Stream,
name: ClauseName,
arity: usize,
) -> EvalSession {
@@ -42,13 +43,35 @@ impl Machine {
let arity = self.machine_st[arity].clone();
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!(),
};
let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
Addr::Con(Constant::Integer(arity)) => arity.to_usize().unwrap(),
_ => unreachable!(),
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!()
}
}
}
Addr::Usize(n) => {
n
}
_ => {
unreachable!()
}
};
(name, arity)
@@ -102,7 +125,9 @@ impl Machine {
let module_addr = self.machine_st[module].clone();
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) => {
module.code_dir.remove(&(name.clone(), arity));
module.module_decl.name.clone()
@@ -111,6 +136,9 @@ impl Machine {
self.machine_st.fail = true;
return;
}
}
} else {
unreachable!()
},
_ => unreachable!(),
};
@@ -130,7 +158,12 @@ impl Machine {
) {
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;
if let EvalSession::Error(err) = result {
@@ -158,20 +191,33 @@ impl Machine {
place.push_to_queue(&mut addrs, added_clause);
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 {
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(),
None => {
self.machine_st.fail = true;
return false;
}
}
} else {
self.machine_st.fail = true;
return false;
},
_ => unreachable!(),
};
@@ -200,7 +246,18 @@ impl Machine {
fn retract_from_dynamic_predicate_in_module(&mut self) {
let index = self.machine_st[temp_v!(3)].clone();
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!(),
};
@@ -220,7 +277,9 @@ impl Machine {
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(
@@ -235,8 +294,22 @@ impl Machine {
fn retract_from_dynamic_predicate(&mut self) {
let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(),
_ => unreachable!(),
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!()
}
};
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)
}
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(

View File

@@ -1,11 +1,12 @@
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::partial_string::*;
use crate::prolog::machine::raw_block::*;
use std::convert::TryFrom;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
@@ -39,12 +40,12 @@ impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
}
pub(crate)
struct HeapIntoIterator<T: RawBlockTraits> {
struct HeapIntoIter<T: RawBlockTraits> {
offset: usize,
buf: RawBlock<T>,
}
impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> {
impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
fn drop(&mut self) {
let mut heap =
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;
fn next(&mut self) -> Option<Self::Item> {
@@ -72,19 +73,19 @@ impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> {
}
pub(crate)
struct HeapIterator<'a, T: RawBlockTraits> {
struct HeapIter<'a, T: RawBlockTraits> {
offset: usize,
buf: &'a RawBlock<T>,
}
impl<'a, T: RawBlockTraits> HeapIterator<'a, T> {
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
pub(crate)
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;
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)
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,
buf: &'a mut RawBlock<T>,
}
impl<'a, T: RawBlockTraits> HeapIteratorMut<'a, T> {
impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
pub(crate)
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;
fn next(&mut self) -> Option<Self::Item> {
@@ -140,17 +149,183 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline]
pub(crate)
fn push(&mut self, val: HeapCellValue) {
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;
fn clone(&self, h: usize) -> HeapCellValue {
match &self[h] {
&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(..) => {
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Addr(Addr::Stream(h))
}
}
}
#[inline]
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();
loop {
@@ -158,17 +333,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
return if orig_h == self.h() {
None
} else {
let prev_h = self.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!()
}
}
let tail_h = self.h() - 1;
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
Some(Addr::PStrLocation(orig_h, 0))
};
@@ -176,8 +342,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
let h = self.h();
let (mut pstr, rest_src) =
match PartialString::new(src, h) {
let (pstr, rest_src) =
match PartialString::new(src) {
Some(tuple) => {
tuple
}
@@ -188,44 +354,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
} else if orig_h == h {
return None;
} else {
let prev_h = 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!()
}
}
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
return Some(Addr::PStrLocation(orig_h, 0));
}
}
};
let new_top = unsafe {
self.buf.new_block(mem::size_of::<HeapCellValue>())
};
self.push(HeapCellValue::PartialString(pstr, true));
if rest_src != "" {
pstr.tail = Addr::PStrLocation(h+1, 0);
self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
src = rest_src;
} else {
pstr.tail = Addr::PStrTail(h, src.len());
}
unsafe{
ptr::write(
self.buf.top as *mut _,
HeapCellValue::PartialString(pstr),
);
}
self.buf.top = new_top;
if rest_src == "" {
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
return Some(Addr::PStrLocation(orig_h, 0));
}
}
@@ -279,35 +420,39 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
}
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 mut h = head_addr;
for value in values {
let h = self.h();
for value in values.map(|v| v.into()) {
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
}
/* Create an iterator starting from the passed offset. */
pub(crate)
fn iter_from<'a>(&'a self, offset: usize) -> HeapIterator<'a, T> {
HeapIterator::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate)
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIteratorMut<'a, T> {
HeapIteratorMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
}
pub(crate)
fn into_iter(mut self) -> HeapIntoIterator<T> {
HeapIntoIterator { buf: self.buf.take(), offset: 0 }
fn into_iter(mut self) -> HeapIntoIter<T> {
HeapIntoIter { buf: self.buf.take(), offset: 0 }
}
pub(crate)
@@ -320,8 +465,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
pub(crate)
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> {
match self[s].as_addr(s) {
Addr::Con(Constant::Integer(n)) => n.to_usize(),
match &self[s] {
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
&HeapCellValue::Integer(ref n) => n.to_usize(),
_ => None
}
};
@@ -361,6 +507,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
_ => 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> {

View File

@@ -1,6 +1,7 @@
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_state::*;
use crate::prolog::rug::Integer;
@@ -21,34 +22,103 @@ pub(super) struct MachineError {
from: ErrorProvenance,
}
impl MachineError {
pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
functor!(
"/",
2,
[name, heap_integer!(Integer::from(arity))],
SharedOpDesc::new(400, YFX)
)
}
pub(super)
trait TypeError {
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
}
impl TypeError for Addr {
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), addr(self)]
);
pub(super) fn evaluation_error(eval_error: EvalError) -> Self {
let stub = functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())]);
MachineError {
stub,
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!(
"type_error",
2,
[
heap_atom!(valid_type.as_str()),
HeapCellValue::Addr(culprit)
]
[atom(valid_type.as_str()), aux(h, 0)],
[self]
);
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 {
@@ -57,55 +127,74 @@ impl MachineError {
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,
mod_name: ClauseName,
name: ClauseName,
arity: usize,
) -> Self {
let mod_name = HeapCellValue::Addr(Addr::Con(Constant::Atom(mod_name, None)));
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!(
let res_stub = functor!(
":",
2,
[mod_name, name],
SharedOpDesc::new(600, XFY)
));
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
pub(super) fn existence_error(h: usize, err: ExistenceError) -> Self {
match err {
ExistenceError::Procedure(name, arity) => {
let mut stub = functor!(
"existence_error",
2,
[heap_atom!("procedure"), heap_str!(3 + h)]
SharedOpDesc::new(600, XFY),
[clause_name(mod_name), clause_name(name)]
);
let ind_stub = functor!(
"/",
SharedOpDesc::new(400, YFX),
[aux(h + 2, 0), integer(arity)],
[res_stub]
);
let stub = functor!(
"evaluation_error",
[aux(h, 0)],
[ind_stub]
);
stub.append(&mut Self::functor_stub(name, arity));
MachineError {
stub,
@@ -113,57 +202,34 @@ impl MachineError {
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 {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
}
}
pub(super) fn session_error(h: usize, err: SessionError) -> Self {
pub(super)
fn existence_error(h: usize, err: ExistenceError) -> Self {
match err {
SessionError::ParserError(err) => Self::syntax_error(h, err),
SessionError::CannotOverwriteBuiltIn(pred_str)
| SessionError::CannotOverwriteImport(pred_str) => {
Self::permission_error(PermissionError::Modify, "private_procedure", pred_str)
}
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!(),
}
}
ExistenceError::Module(name) => {
let stub = functor!(
"existence_error",
[atom("source_sink"), clause_name(name)]
);
pub(super) fn permission_error(
err: PermissionError,
index_str: &'static str,
pred_str: ClauseName,
) -> Self {
let pred_str = HeapCellValue::Addr(Addr::Con(Constant::Atom(pred_str, None)));
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
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 mut stub = functor!("permission_error", 3);
stub.extend(err.into_iter());
let stub = functor!(
"existence_error",
[atom("procedure"), aux(h, 0)],
[culprit]
);
MachineError {
stub,
@@ -171,46 +237,168 @@ impl MachineError {
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 {
match err {
ArithmeticError::UninstantiatedVar => Self::instantiation_error(),
ArithmeticError::UninstantiatedVar => {
Self::instantiation_error()
}
ArithmeticError::NonEvaluableFunctor(name, arity) => {
let name = HeapCellValue::Addr(Addr::Con(name));
let culprit = functor!(
"/",
2,
[name, heap_integer!(Integer::from(arity))],
SharedOpDesc::new(400, YFX)
SharedOpDesc::new(400, YFX),
[constant(h, &name), integer(arity)]
);
let mut stub = Self::type_error(ValidType::Evaluable, Addr::HeapCell(3 + h)).stub;
stub.extend(culprit.into_iter());
Self::type_error(h, ValidType::Evaluable, culprit)
}
}
}
#[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 {
stub,
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 {
return Self::arithmetic_error(h, err);
}
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 {
functor!("syntax_error", 1)
} else {
functor!("syntax_error", 1, [heap_str!(h + 2)])
};
stub.extend(err.into_iter());
let stub = functor!(
"syntax_error",
[aux(h, 0)],
[stub]
);
MachineError {
stub,
@@ -219,30 +407,10 @@ impl MachineError {
}
}
pub(super) fn domain_error(error: DomainError, culprit: Addr) -> Self {
let stub = functor!(
"domain_error",
2,
[heap_atom!(error.as_str()), HeapCellValue::Addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super)
fn representation_error(flag: RepFlag) -> Self {
let stub = functor!("representation_error", [atom(flag.as_str())]);
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 {
stub,
location: None,
@@ -268,18 +436,22 @@ impl MachineError {
}
#[derive(Clone, Copy)]
pub enum PermissionError {
pub enum Permission {
Access,
Create,
InputStream,
Modify,
OutputStream,
}
impl PermissionError {
impl Permission {
pub fn as_str(self) -> &'static str {
match self {
PermissionError::Access => "access",
PermissionError::Create => "create",
PermissionError::Modify => "modify",
Permission::Access => "access",
Permission::Create => "create",
Permission::InputStream => "input",
Permission::Modify => "modify",
Permission::OutputStream => "output",
}
}
}
@@ -331,14 +503,18 @@ impl ValidType {
}
#[derive(Clone, Copy)]
pub enum DomainError {
pub enum DomainErrorType {
NotLessThanZero,
Stream,
StreamOrAlias,
}
impl DomainError {
impl DomainErrorType {
pub fn as_str(self) -> &'static str {
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'.
#[derive(Clone, Copy)]
pub(super) enum CycleSearchResult {
EmptyList,
NotList,
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
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.
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).
}
impl MachineState {
// 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 list = self.store(self.deref(self[temp_v!(1)].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))
}
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()) {
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(()),
}
@@ -430,7 +605,7 @@ impl MachineState {
match self.detect_cycles(list.clone()) {
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;
@@ -439,18 +614,23 @@ impl MachineState {
let mut new_l = l;
loop {
match self.heap[new_l].clone() {
HeapCellValue::Addr(Addr::Str(l)) => new_l = l,
HeapCellValue::NamedStr(2, ref name, Some(_))
if name.as_str() == "-" =>
{
break
match self.heap.clone(new_l) {
HeapCellValue::Addr(Addr::Str(l)) => {
new_l = l;
}
HeapCellValue::NamedStr(2, ref name, Some(_))
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(
MachineError::type_error(ValidType::Pair, Addr::HeapCell(l)),
MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)),
stub,
))
}
@@ -466,8 +646,10 @@ impl MachineState {
}
// 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 pairs = self.store(self.deref(self[temp_v!(1)].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))
}
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(()),
}?;
@@ -484,7 +666,8 @@ impl MachineState {
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 err_len = err.len();
@@ -500,21 +683,17 @@ impl MachineState {
if let Some((line_num, _)) = location {
let colon_op_desc = Some(SharedOpDesc::new(600, XFY));
stub.extend(
vec![
HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc),
HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)),
heap_integer!(Integer::from(line_num)),
]
.into_iter(),
);
stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc));
stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)));
stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num))));
}
stub.extend(src.into_iter());
stub
}
pub(super) fn throw_exception(&mut self, err: MachineStub) {
pub(super)
fn throw_exception(&mut self, err: MachineStub) {
let h = self.heap.h();
self.ball.boundary = 0;
@@ -532,16 +711,19 @@ impl MachineState {
pub enum ExistenceError {
Module(ClauseName),
Procedure(ClauseName, usize),
SourceSink(ModuleSource),
Stream(Addr),
}
pub enum SessionError {
CannotOverwriteBuiltIn(ClauseName),
CannotOverwriteImport(ClauseName),
ExistenceError(ExistenceError),
InvalidFileName(ClauseName),
ModuleDoesNotContainExport(ClauseName, PredicateKey),
ModuleNotFound,
NamelessEntry,
OpIsInfixAndPostFix(ClauseName),
QueryCannotBeDefinedAsFact,
ParserError(ParserError),
}
@@ -566,4 +748,5 @@ impl From<ParserError> for EvalSession {
fn from(err: ParserError) -> Self {
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::Ball;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::RawBlockTraits;
use crate::prolog::machine::streams::Stream;
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 std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::{BTreeMap, VecDeque};
use std::convert::TryFrom;
use std::mem;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::rc::Rc;
@@ -38,25 +42,40 @@ pub enum DBRef {
),
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Addr {
AttrVar(usize),
Con(Constant),
DBRef(DBRef),
Lis(usize),
HeapCell(usize),
StackCell(usize, usize),
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.
// 7.2
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TermOrderCategory {
Variable,
FloatingPoint,
Integer,
Atom,
Compound,
}
#[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 {
AttrVar(usize),
HeapCell(usize),
StackCell(usize, usize),
PStrTail(usize, usize),
}
impl Ref {
@@ -65,7 +84,28 @@ impl Ref {
Ref::AttrVar(h) => Addr::AttrVar(h),
Ref::HeapCell(h) => Addr::HeapCell(h),
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 {
&Addr::StackCell(fr, sc) => {
match *r {
Ref::AttrVar(_) | Ref::HeapCell(_) | Ref::PStrTail(..) => {
Ref::AttrVar(_) | Ref::HeapCell(_) => {
Some(Ordering::Greater)
}
Ref::StackCell(fr1, sc1) => {
@@ -104,22 +144,6 @@ impl PartialOrd<Ref> for Addr {
Ref::AttrVar(h1) | Ref::HeapCell(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 {
#[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 {
match self {
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) | Addr::PStrTail(..) => {
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => {
true
}
_ => {
@@ -141,16 +180,115 @@ impl Addr {
}
}
#[inline]
pub fn as_var(&self) -> Option<Ref> {
match self {
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
&Addr::PStrTail(h, n) => Some(Ref::PStrTail(h, n)),
_ => 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 {
match self {
&Addr::StackCell(addr, _) if addr >= e => false,
@@ -164,12 +302,13 @@ impl Add<usize> for Addr {
fn add(self, rhs: usize) -> Self::Output {
match self {
Addr::Stream(h) => Addr::Stream(h + rhs),
Addr::Con(h) => Addr::Con(h + rhs),
Addr::Lis(a) => Addr::Lis(a + rhs),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
Addr::Str(s) => Addr::Str(s + rhs),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs, n),
_ => self,
}
}
@@ -181,11 +320,12 @@ impl Sub<i64> for Addr {
fn sub(self, rhs: i64) -> Self::Output {
if rhs < 0 {
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::AttrVar(h) => Addr::AttrVar(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::PStrTail(h, n) => Addr::PStrTail(h + rhs.abs() as usize, n),
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
_ => self,
}
@@ -200,11 +340,12 @@ impl Sub<usize> for Addr {
fn sub(self, rhs: usize) -> Self::Output {
match self {
Addr::Stream(h) => Addr::Stream(h - rhs),
Addr::Con(h) => Addr::Con(h - rhs),
Addr::Lis(a) => Addr::Lis(a - rhs),
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
Addr::HeapCell(h) => Addr::HeapCell(h - 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),
_ => self,
}
@@ -230,27 +371,76 @@ impl From<Ref> for TrailRef {
}
}
#[derive(Clone, PartialEq)]
pub enum HeapCellValue {
Addr(Addr),
Atom(ClauseName, Option<SharedOpDesc>),
DBRef(DBRef),
Integer(Rc<Integer>),
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 {
#[inline]
pub fn as_addr(&self, focus: usize) -> Addr {
match self {
HeapCellValue::Addr(ref a) => {
a.clone()
*a
}
HeapCellValue::Atom(..) | HeapCellValue::DBRef(..) | HeapCellValue::Integer(..) |
HeapCellValue::Rational(..) => {
Addr::Con(focus)
}
HeapCellValue::NamedStr(_, _, _) => {
Addr::Str(focus)
}
HeapCellValue::PartialString(_) => {
HeapCellValue::PartialString(..) => {
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)]
@@ -428,37 +618,31 @@ impl LocalCodePtr {
LocalCodePtr::DirEntry(p) => {
heap.append(functor!(
"dir_entry",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
LocalCodePtr::InSituDirEntry(p) => {
heap.append(functor!(
"in_situ_dir_entry",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
LocalCodePtr::TopLevel(chunk_num, offset) => {
heap.append(functor!(
"top_level",
2,
[heap_integer!(Integer::from(*chunk_num)),
heap_integer!(Integer::from(*offset))]
[integer(*chunk_num), integer(*offset)]
));
}
LocalCodePtr::UserGoalExpansion(p) => {
heap.append(functor!(
"user_goal_expansion",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
LocalCodePtr::UserTermExpansion(p) => {
heap.append(functor!(
"user_term_expansion",
1,
[heap_integer!(Integer::from(*p))]
[integer(*p)]
));
}
}
@@ -470,8 +654,12 @@ impl LocalCodePtr {
impl PartialOrd<CodePtr> for CodePtr {
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
match (self, other) {
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => l1.partial_cmp(l2),
_ => Some(Ordering::Greater),
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => {
l1.partial_cmp(l2)
}
_ => {
Some(Ordering::Greater)
}
}
}
}
@@ -486,8 +674,12 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
| (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
p1.partial_cmp(p2)
}
(_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less),
_ => Some(Ordering::Greater),
(_, &LocalCodePtr::TopLevel(_, _)) => {
Some(Ordering::Less)
}
_ => {
Some(Ordering::Greater)
}
}
}
}
@@ -613,17 +805,19 @@ impl ModuleStub {
}
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
pub struct IndexStore {
pub(super) atom_tbl: TabledData<Atom>,
pub(super) code_dir: CodeDir,
pub(super) module_dir: ModuleDir,
pub(super) dynamic_code_dir: DynamicCodeDir,
pub(super) global_variables: GlobalVarDir,
pub(super) in_situ_code_dir: InSituCodeDir,
pub(super) in_situ_module_dir: ModuleStubDir,
pub(super) module_dir: ModuleDir,
pub(super) modules: ModuleDir,
pub(super) op_dir: OpDir,
pub(super) stream_aliases: StreamAliasDir,
}
impl IndexStore {
@@ -710,6 +904,7 @@ impl IndexStore {
in_situ_module_dir: ModuleStubDir::new(),
op_dir: default_op_dir(),
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_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
.get_internal(r_w_h, 0, non_iso.clone())
.get_internal(r_w_h, 0, iso_ext.clone())
.and_then(|item| item.local());
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());
if let Some(r_w_h) = r_w_h {

View File

@@ -1,7 +1,9 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_print::*;
use crate::prolog::machine::attributed_variables::*;
use crate::prolog::machine::copier::*;
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::modules::*;
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 downcast::Any;
use indexmap::{IndexMap, IndexSet};
use std::cmp::Ordering;
use std::io::{stdout, Write};
use std::convert::TryFrom;
use std::io::Write;
use std::mem;
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(super) boundary: usize,
pub(super) stub: Heap,
@@ -57,13 +234,12 @@ impl Ball {
for heap_value in self.stub.iter_from(0) {
stub.push(match heap_value {
HeapCellValue::Addr(ref addr) => HeapCellValue::Addr(addr.clone() - diff),
HeapCellValue::PartialString(ref pstr) => {
let mut new_pstr = pstr.clone();
new_pstr.tail = pstr.tail.clone() - diff;
HeapCellValue::PartialString(new_pstr)
&HeapCellValue::Addr(addr) => {
HeapCellValue::Addr(addr - diff)
}
heap_value => {
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;
self.stub[index].as_addr(h)
}
Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(),
addr => addr,
Addr::StackCell(fr, sc) => {
self.stack.index_and_frame(fr)[sc]
}
addr => {
addr
}
}
}
fn deref(&self, mut addr: Addr) -> Addr {
loop {
let value = self.store(addr.clone());
let value = self.store(addr);
if value.is_ref() && value != addr {
addr = value;
@@ -225,9 +405,12 @@ impl Index<RegType> for MachineState {
impl IndexMut<RegType> for MachineState {
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
match reg {
RegType::Temp(temp) => &mut self.registers[temp],
RegType::Temp(temp) => {
&mut self.registers[temp]
}
RegType::Perm(perm) => {
let e = self.e;
&mut self.stack.index_and_frame_mut(e)[perm]
}
}
@@ -242,8 +425,49 @@ pub(super) enum MachineMode {
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(super) s: usize,
pub(super) s: HeapPtr,
pub(super) p: CodePtr,
pub(super) b: usize,
pub(super) b0: usize,
@@ -270,37 +494,208 @@ pub struct 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)
fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError> {
let mut chars = String::new();
let mut iter = addrs.iter();
while let Some(addr) = iter.next() {
match addr {
&Addr::Con(Constant::String(n, ref s))
if self.flags.double_quotes.is_chars() => {
if s.len() < n {
chars += &s[n ..];
}
let addr = self.store(self.deref(*addr));
if iter.next().is_some() {
return Err(MachineError::type_error(ValidType::Character, addr.clone()));
}
}
&Addr::Con(Constant::Char(c)) => {
match addr {
Addr::Char(c) => {
chars.push(c);
continue;
}
&Addr::Con(Constant::Atom(ref name, _))
if name.as_str().len() == 1 => {
Addr::Con(h) => {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
if name.is_char() {
chars += name.as_str();
continue;
}
}
}
_ => {
}
};
let h = self.heap.h();
return Err(
MachineError::type_error(ValidType::Character, addr.clone())
MachineError::type_error(h, ValidType::Character, addr)
);
}
}
}
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)) {
Some(p) => Some(*p),
Some(p) => Some(LocalCodePtr::InSituDirEntry(*p)),
None =>
match indices.code_dir.get(&(name, arity)) {
Some(ref idx) => {
if let IndexPtr::Index(p) = idx.0.borrow().0 {
Some(p)
Some(LocalCodePtr::DirEntry(p))
} else {
None
}
@@ -411,12 +806,12 @@ fn try_in_situ(
) -> CallResult {
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
if last_call {
machine_st.execute_at_index(arity, LocalCodePtr::DirEntry(p));
machine_st.execute_at_index(arity, p);
} 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(())
} else {
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;
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;
@@ -474,7 +869,7 @@ pub(crate) trait CallPolicy: Any {
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
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;
@@ -510,7 +905,7 @@ pub(crate) trait CallPolicy: Any {
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
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;
@@ -536,8 +931,8 @@ pub(crate) trait CallPolicy: Any {
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.stack.truncate(b);
machine_st.hb = machine_st.heap.h();
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;
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;
@@ -576,8 +971,8 @@ pub(crate) trait CallPolicy: Any {
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.stack.truncate(b);
machine_st.hb = machine_st.heap.h();
machine_st.p += 1;
@@ -667,11 +1062,12 @@ pub(crate) trait CallPolicy: Any {
machine_st: &mut MachineState,
ct: &BuiltInClauseType,
indices: &mut IndexStore,
parsing_stream: &mut PrologStream,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult {
match ct {
&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);
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)
}
&BuiltInClauseType::Compare => {
let a1 = machine_st[temp_v!(1)].clone();
let a2 = machine_st[temp_v!(2)].clone();
let a3 = machine_st[temp_v!(3)].clone();
let a1 = machine_st[temp_v!(1)];
let a2 = machine_st[temp_v!(2)];
let a3 = machine_st[temp_v!(3)];
let c = match machine_st.compare_term_test(&a2, &a3) {
Ordering::Greater => {
let atom = match machine_st.compare_term_test(&a2, &a3) {
Some(Ordering::Greater) => {
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);
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);
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)
}
&BuiltInClauseType::CompareTerm(qt) => {
machine_st.compare_term(qt);
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 => {
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)
}
&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) => {
let addr = machine_st[temp_v!(1)].clone();
let addr = machine_st[temp_v!(1)];
machine_st.unify(addr, Addr::HeapCell(offset.heap_loc));
}
Err(e) => {
@@ -741,8 +1139,8 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st)
}
&BuiltInClauseType::Eq => {
let a1 = machine_st[temp_v!(1)].clone();
let a2 = machine_st[temp_v!(2)].clone();
let a1 = machine_st[temp_v!(1)];
let a2 = machine_st[temp_v!(2)];
machine_st.fail = machine_st.eq_test(a1, a2);
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)
}
&BuiltInClauseType::NotEq => {
let a1 = machine_st[temp_v!(1)].clone();
let a2 = machine_st[temp_v!(2)].clone();
let a1 = machine_st[temp_v!(1)];
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
} else {
false
@@ -773,12 +1172,15 @@ pub(crate) trait CallPolicy: Any {
let stub = MachineError::functor_stub(clause_name!("sort"), 2);
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);
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);
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.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 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);
return_from_clause!(machine_st.last_call, machine_st)
}
&BuiltInClauseType::Is(r, ref at) => {
let a1 = machine_st[r].clone();
let a2 = machine_st.get_number(at)?;
let a1 = machine_st[r];
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)
}
}
@@ -842,13 +1248,20 @@ pub(crate) trait CallPolicy: Any {
machine_st: &mut MachineState,
arity: usize,
indices: &mut IndexStore,
parsing_stream: &mut PrologStream,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult {
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
match ClauseType::from(name.clone(), arity, None) {
ClauseType::BuiltIn(built_in) => {
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 => {
machine_st.handle_internal_call_n(arity);
@@ -876,11 +1289,13 @@ pub(crate) trait CallPolicy: Any {
}
}
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);
return Err(machine_st
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
return Err(machine_st.error_form(
MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name),
stub,
));
}
};
}
@@ -928,10 +1343,17 @@ impl CallPolicy for CWILCallPolicy {
machine_st: &mut MachineState,
ct: &BuiltInClauseType,
indices: &mut IndexStore,
parsing_stream: &mut PrologStream,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult {
self.prev_policy
.call_builtin(machine_st, ct, indices, parsing_stream)?;
self.prev_policy.call_builtin(
machine_st,
ct,
indices,
current_input_stream,
current_output_stream
)?;
self.increment(machine_st)
}
@@ -940,10 +1362,17 @@ impl CallPolicy for CWILCallPolicy {
machine_st: &mut MachineState,
arity: usize,
indices: &mut IndexStore,
parsing_stream: &mut PrologStream,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult {
self.prev_policy
.call_n(machine_st, arity, indices, parsing_stream)?;
self.prev_policy.call_n(
machine_st,
arity,
indices,
current_input_stream,
current_output_stream,
)?;
self.increment(machine_st)
}
}
@@ -962,7 +1391,8 @@ pub(crate) struct 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 {});
mem::swap(&mut prev_policy, policy);
@@ -972,6 +1402,7 @@ impl CWILCallPolicy {
limits: vec![],
inference_limit_exceeded: false,
};
*policy = Box::new(new_policy);
}
@@ -983,10 +1414,10 @@ impl CWILCallPolicy {
if let Some(&(ref limit, bp)) = self.limits.last() {
if self.count == *limit {
self.inference_limit_exceeded = true;
return Err(functor!(
"inference_limit_exceeded",
1,
[HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))]
[addr(Addr::Usize(bp))]
));
} else {
self.count += 1;
@@ -996,7 +1427,8 @@ impl CWILCallPolicy {
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;
match self.limits.last().cloned() {
@@ -1007,7 +1439,8 @@ impl CWILCallPolicy {
&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 bp == b {
self.limits.pop();
@@ -1017,11 +1450,13 @@ impl CWILCallPolicy {
&self.count
}
pub(crate) fn is_empty(&self) -> bool {
pub(crate)
fn is_empty(&self) -> bool {
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 {});
mem::swap(&mut self.prev_policy, &mut new_inner);
new_inner
@@ -1030,16 +1465,16 @@ impl CWILCallPolicy {
pub(crate) trait CutPolicy: Any {
// 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);
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;
match addr {
Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => {
&Addr::CutPoint(b0) | &Addr::Usize(b0) => {
if b > b0 {
machine_st.b = b0;
machine_st.tidy_trail();
@@ -1057,14 +1492,14 @@ fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
pub(crate) struct DefaultCutPolicy {}
pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) {
let addr = machine_st.store(machine_st.deref(machine_st[r].clone()));
cut_body(machine_st, addr);
let addr = machine_st.store(machine_st.deref(machine_st[r]));
cut_body(machine_st, &addr);
}
impl CutPolicy for DefaultCutPolicy {
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
let addr = machine_st[r].clone();
cut_body(machine_st, addr)
let addr = machine_st[r];
cut_body(machine_st, &addr)
}
}
@@ -1102,7 +1537,7 @@ impl SCCCutPolicy {
let (idx, arity) = if machine_st.block < prev_block {
(dir_entry!(self.r_c_w_h), 0)
} 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)
};
@@ -1124,8 +1559,8 @@ impl CutPolicy for SCCCutPolicy {
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
let b = machine_st.b;
match machine_st[r].clone() {
Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => {
match machine_st[r] {
Addr::Usize(b0) | Addr::CutPoint(b0) => {
if b > b0 {
machine_st.b = b0;
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(super) mod machine_state;
pub mod modules;
mod partial_string;
pub mod partial_string;
mod raw_block;
mod stack;
pub(crate) mod streams;
pub(super) mod term_expansion;
pub mod toplevel;
#[macro_use]
mod arithmetic_ops;
#[macro_use]
mod machine_state_impl;
mod system_calls;
@@ -36,14 +39,14 @@ use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::modules::*;
use crate::prolog::machine::streams::*;
use crate::prolog::machine::toplevel::*;
use crate::prolog::read::PrologStream;
use indexmap::IndexMap;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::ops::Index;
use std::path::PathBuf;
@@ -76,7 +79,8 @@ pub struct Machine {
pub(super) indices: IndexStore,
pub(super) code_repo: CodeRepo,
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 {
@@ -149,8 +153,16 @@ impl SubModuleUser for IndexStore {
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 !code_idx.is_undefined() {
match (name.as_str(), arity) {
("term_expansion", 2) => {
}
("goal_expansion", 2) => {
}
_ => {
println!("Warning: overwriting {}/{}", &name, arity);
}
}
}
let (p, module_name) = idx.0.borrow().clone();
set_code_index!(code_idx, p, module_name);
@@ -193,7 +205,11 @@ impl SubModuleUser for IndexStore {
#[inline]
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
}
@@ -212,7 +228,11 @@ impl Machine {
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) => {
self.machine_st.attr_var_init.verify_attrs_loc = p;
@@ -226,7 +246,11 @@ impl Machine {
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) => {
self.machine_st.attr_var_init.project_attrs_loc = p;
@@ -250,7 +274,7 @@ impl Machine {
compile_user_module(
self,
parsing_stream(TOPLEVEL.as_bytes()),
Stream::from(TOPLEVEL),
true,
top_lvl_src,
);
@@ -264,7 +288,11 @@ impl Machine {
Ok(self.indices.insert_module(module))
} 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() {
let file_src = match File::open(&path) {
Ok(file_handle) => parsing_stream(file_handle),
Ok(file_handle) => Stream::from(file_handle),
Err(_) => return,
};
@@ -293,7 +321,7 @@ impl Machine {
#[cfg(test)]
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.machine_st.reset();
}
@@ -319,8 +347,8 @@ impl Machine {
// the first of these is the path to the scryer-prolog executable, so skip
// it.
for filename in env::args().skip(1) {
let atom = atom!(filename, self.indices.atom_tbl);
filename_atoms.push(Addr::Con(atom));
let atom = clause_name!(filename, self.indices.atom_tbl);
filename_atoms.push(HeapCellValue::Atom(atom, None));
}
let list_addr =
@@ -332,7 +360,7 @@ impl Machine {
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 {
machine_st: MachineState::new(),
@@ -341,7 +369,8 @@ impl Machine {
indices: IndexStore::new(),
code_repo: CodeRepo::new(),
toplevel_idx: 0,
prolog_stream,
current_input_stream,
current_output_stream,
};
let atom_tbl = wam.indices.atom_tbl.clone();
@@ -354,7 +383,7 @@ impl Machine {
compile_listing(
&mut wam,
parsing_stream(BUILTINS.as_bytes()),
Stream::from(BUILTINS),
default_index_store!(atom_tbl.clone()),
true,
ListingSource::from_file_and_path(
@@ -365,25 +394,36 @@ impl Machine {
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(
clause_name!("error"),
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(
clause_name!("lists"),
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(
clause_name!("non_iso"),
clause_name!("iso_ext"),
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(
clause_name!("si"),
lib_path.clone(),
@@ -514,15 +554,17 @@ impl Machine {
HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 2 && name.as_str() == "/" => {
let name = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
&HeapCellValue::Atom(ref name, _) =>
name.clone(),
_ =>
unreachable!()
};
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(),
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
usize::try_from(n).unwrap(),
_ =>
unreachable!()
};
@@ -532,22 +574,24 @@ impl Machine {
HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 3 && name.as_str() == "op" => {
let name = match &self.machine_st.heap[s+3] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
&HeapCellValue::Atom(ref name, _) =>
name.clone(),
_ =>
unreachable!()
};
let spec = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
&HeapCellValue::Atom(ref name, _) =>
name.clone(),
_ =>
unreachable!()
};
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(),
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
usize::try_from(n).unwrap(),
_ =>
unreachable!()
};
@@ -577,9 +621,13 @@ impl Machine {
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
let module_spec = self.machine_st[temp_v!(1)].clone();
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
Addr::Con(Constant::Atom(name, _)) => name,
_ => unreachable!()
let name = {
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => name.clone(),
_ => unreachable!(),
}
};
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 module_spec = self.machine_st[temp_v!(1)].clone();
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
Addr::Con(Constant::Atom(name, _)) => name,
_ => unreachable!()
let name = {
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => name.clone(),
_ => unreachable!(),
}
};
let exports = match self.extract_module_export_list() {
@@ -699,7 +751,7 @@ impl Machine {
snapshot.e = self.machine_st.e;
snapshot.b = self.machine_st.b;
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.num_of_args = self.machine_st.num_of_args;
@@ -751,12 +803,16 @@ impl Machine {
&mut self.indices,
&mut self.policies,
&mut self.code_repo,
&mut self.prolog_stream,
&mut self.current_input_stream,
&mut self.current_output_stream,
);
match self.machine_st.p {
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {}
CodePtr::REPL(code_ptr, p) => self.handle_toplevel_command(code_ptr, p),
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {
}
CodePtr::REPL(code_ptr, p) => {
self.handle_toplevel_command(code_ptr, p)
}
CodePtr::DynamicTransaction(trans_type, p) => {
// 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.
@@ -784,29 +840,37 @@ impl MachineState {
indices: &mut IndexStore,
policies: &mut MachinePolicies,
code_repo: &CodeRepo,
prolog_stream: &mut PrologStream,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) {
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) => {
self.execute_choice_instr(choice_instr, &mut policies.call_policy)
}
&Line::Cut(ref cut_instr) => {
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,
code_repo,
&mut policies.call_policy,
&mut policies.cut_policy,
prolog_stream,
current_input_stream,
current_output_stream,
control_instr,
),
)
}
&Line::Fact(ref fact_instr) => {
self.execute_fact_instr(&fact_instr);
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) => {
self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
}
@@ -822,14 +886,22 @@ impl MachineState {
indices: &mut IndexStore,
policies: &mut MachinePolicies,
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) {
Some(instr) => instr,
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) {
@@ -880,7 +952,8 @@ impl MachineState {
indices: &mut IndexStore,
policies: &mut MachinePolicies,
code_repo: &mut CodeRepo,
prolog_stream: &mut PrologStream,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> bool {
loop {
let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
@@ -896,7 +969,14 @@ impl MachineState {
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 {
self.backtrack();
@@ -920,10 +1000,17 @@ impl MachineState {
indices: &mut IndexStore,
policies: &mut MachinePolicies,
code_repo: &mut CodeRepo,
prolog_stream: &mut PrologStream,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) {
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 {
self.backtrack();
@@ -939,7 +1026,13 @@ impl MachineState {
if !instigating_instr.as_ref().is_head_instr() {
let cp = self.p.local();
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 {
break;
}

View File

@@ -1,28 +1,28 @@
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::raw_block::*;
use core::marker::PhantomData;
use std::alloc;
use std::mem;
use std::ptr;
use std::ops::RangeFrom;
use std::slice;
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 {
buf: *const u8,
len: usize,
_marker: PhantomData<[u8]>,
}
pub struct PartialString {
pub(super) buf: RawBlock<PartialStringTraits>,
pub(super) tail: Addr,
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 {
@@ -32,17 +32,10 @@ impl Clone for PartialString {
}
}
impl PartialEq for PartialString {
#[inline]
fn eq(&self, other: &Self) -> bool {
self as *const _ == other as *const _
}
}
fn scan_for_terminator(src: &str) -> usize {
fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
let mut terminator_idx = 0;
for c in src.chars() {
for c in iter {
if c == '\u{0}' {
break;
}
@@ -53,12 +46,61 @@ fn scan_for_terminator(src: &str) -> usize {
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 {
#[inline]
pub(super)
fn new(src: &str, h: usize) -> Option<(Self, &str)> {
fn new(src: &str) -> Option<(Self, &str)> {
let pstr = PartialString {
buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()),
tail: Addr::PStrTail(h, 0),
buf: ptr::null_mut(),
len: 0,
_marker: PhantomData,
};
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)> {
let terminator_idx = scan_for_terminator(src);
let terminator_idx = scan_for_terminator(src.chars());
if terminator_idx == 0 {
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(
src.as_ptr(),
self.buf.top as *mut _,
self.buf as *mut _,
terminator_idx,
);
self.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
self.write_terminator_at(terminator_idx);
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)
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 {
buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()),
tail: Addr::PStrTail(0, 0),
buf: ptr::null_mut(),
len: len + '\u{0}'.len_utf8(),
_marker: PhantomData,
};
unsafe {
let len = if self.len() > n { self.len() - n } else { 0 };
let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8());
let layout = alloc::Layout::from_size_align_unchecked(
len + '\u{0}'.len_utf8(),
mem::align_of::<u8>(),
);
pstr.buf = alloc::alloc(layout);
if len > 0 {
ptr::copy(
(self.buf.base as usize + n) as *mut u8,
pstr.buf.base as *mut _,
(self.buf as usize + n) as *const u8,
pstr.buf as *mut _,
len,
);
}
pstr.write_terminator_at(len);
pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
}
pstr
@@ -125,37 +204,35 @@ impl PartialString {
fn write_terminator_at(&mut self, index: usize) {
unsafe {
ptr::write(
(self.buf.base as usize + index) as *mut u8,
(self.buf as usize + index) as *mut u8,
0u8,
);
}
}
#[inline]
pub(crate)
fn block_as_str(&self) -> &str {
pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
PStrIter::from(self.buf, index.start)
}
#[inline]
pub fn at_end(&self, end_n: usize) -> bool {
unsafe {
let slice = slice::from_raw_parts(self.buf.base, self.len());
str::from_utf8(slice).unwrap()
ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
}
}
#[inline]
pub(crate)
fn tail_addr(&self) -> &Addr {
&self.tail
}
pub fn as_str_from(&self, n: usize) -> &str {
unsafe {
let slice = slice::from_raw_parts(
self.buf,
self.len - '\u{0}'.len_utf8(),
);
#[inline]
pub fn len(&self) -> usize {
self.buf.top as usize - self.buf.base as usize
}
let s = str::from_utf8(slice).unwrap();
#[inline]
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);
&s[n ..]
}
}
}

View File

@@ -36,20 +36,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
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) {
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())
}
#[inline]
fn free_space(&self) -> usize {
debug_assert!(self.top >= self.base,

View File

@@ -49,7 +49,6 @@ impl Drop for Stack {
#[derive(Clone, Copy)]
pub struct FramePrelude {
is_or_frame: u8,
pub num_cells: usize,
}
@@ -62,7 +61,6 @@ pub struct AndFramePrelude {
pub struct AndFrame {
pub prelude: AndFramePrelude,
_marker: PhantomData<Addr>,
}
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 univ_prelude: FramePrelude,
pub e: usize,
@@ -135,7 +115,6 @@ pub struct OrFramePrelude {
pub struct OrFrame {
pub prelude: OrFramePrelude,
_marker: PhantomData<Addr>
}
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 {
pub fn size_of(num_cells: usize) -> usize {
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);
and_frame.prelude.univ_prelude.is_or_frame = 0;
and_frame.prelude.univ_prelude.num_cells = num_cells;
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);
or_frame.prelude.univ_prelude.is_or_frame = 1;
or_frame.prelude.univ_prelude.num_cells = num_cells;
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 }
}
#[inline]
pub fn truncate(&mut self, b: usize) {
if b == 0 {
self.inner_truncate(mem::align_of::<Addr>());
@@ -289,42 +247,14 @@ impl Stack {
}
}
#[inline]
fn inner_truncate(&mut self, b: usize) {
let mut b = 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;
}
let base = b + self.buf.base as usize;
if base < self.buf.top as usize {
self.buf.top = base as *const _;
}
}
}
pub fn drop_in_place(&mut self) {
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::collections::VecDeque;
use std::io::Read;
use std::iter::Rev;
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
where
I: DoubleEndedIterator<Item = Term>,
@@ -53,7 +27,11 @@ where
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 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>,
pub(crate) wam: &'a mut Machine,
parser: Parser<'a, R>,
parser: Parser<'a, Stream>,
pub(crate) flags: MachineFlags,
term_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) {
self.wam.indices.in_situ_code_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(
src: &'a mut ParsingStream<R>,
src: &'a mut ParsingStream<Stream>,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
wam: &'a mut Machine,
@@ -326,7 +304,8 @@ impl<'a, R: Read> TermStream<'a, R> {
}
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 mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
let mut max_var_length = 0;
@@ -337,12 +316,16 @@ impl MachineState {
printer.quoted = 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
// names in the 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.
// 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 names in the
// 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.print_strings_as_strs = true;
printer.drop_toplevel_spec();
printer.see_all_locs();
@@ -354,8 +337,8 @@ impl MachineState {
}
// reset the machine, but keep the heap contents as they were.
// this prevents clashes between underscored variable names
// in the same query.
// this prevents clashes between underscored variable names in the
// same query.
fn reset_with_heap_preservation(&mut self) {
let heap = self.heap.take();
self.reset();
@@ -379,13 +362,16 @@ impl MachineState {
wam.code_repo.cached_query = code;
self.cp = LocalCodePtr::TopLevel(0, 0);
self.at_end_of_expansion = false;
self.flags.double_quotes = DoubleQuotes::Chars;
self.query_stepper(
&mut wam.indices,
&mut wam.policies,
&mut wam.code_repo,
&mut readline::input_stream(),
&mut Stream::stdout(),
);
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);
self.reset_with_heap_preservation();
Some(output.result())
}
}

View File

@@ -13,7 +13,7 @@ use indexmap::{IndexMap, IndexSet};
use std::borrow::BorrowMut;
use std::cell::Cell;
use std::collections::VecDeque;
use std::io::Read;
use std::convert::TryFrom;
use std::mem;
use std::ops::DerefMut;
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> {
term_stream: &'b mut TermStream<'a, R>,
struct CompositeIndices<'a, 'b, 'c> {
term_stream: &'b mut TermStream<'a>,
index_src: IndexSource<'c, IndexStore>,
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(
term_stream: &'b mut TermStream<'a, R>,
term_stream: &'b mut TermStream<'a>,
index_src: IndexSource<'c, IndexStore>,
static_code_dir: Option<IndexSource<'c, CodeDir>>,
) -> Self {
@@ -212,8 +212,8 @@ fn setup_op_decl(
};
let prec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Integer(bi)) => match bi.to_usize() {
Some(n) if n <= 1200 => n,
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
Ok(n) if n <= 1200 => n,
_ => 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>
{
match term {
Term::Clause(_, ref name, ref mut terms, Some(_))
if name.as_str() == "/" && terms.len() == 2 =>
Term::Clause(_, ref slash, ref mut terms, Some(_))
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
{
let arity = *terms.pop().unwrap();
let name = *terms.pop().unwrap();
let arity = arity
.to_constant()
.and_then(|c| c.to_integer())
.and_then(|n| n.to_usize())
.and_then(|c| {
match c {
Constant::Integer(n) => n.to_usize(),
Constant::Fixnum(n) => usize::try_from(n).ok(),
_ => None
}
})
.ok_or(ParserError::InvalidModuleExport)?;
let name = name
@@ -242,7 +247,11 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserErro
.and_then(|c| c.to_atom())
.ok_or(ParserError::InvalidModuleExport)?;
if slash.as_str() == "/" {
Ok((name, arity))
} else {
Ok((name, arity + 2))
}
}
_ => 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>);
fn setup_qualified_import(
@@ -551,8 +586,8 @@ fn draw_from_term_dir_impl(
}
}
fn draw_from_term_dir<R: Read>(
indices: &CompositeIndices<R>,
fn draw_from_term_dir(
indices: &CompositeIndices,
intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
top_level_term_dirs: &mut TermDirQuantum,
key: &PredicateKey,
@@ -589,8 +624,8 @@ fn draw_from_term_dir<R: Read>(
);
}
fn setup_declaration<'a, 'b, 'c, R: Read>(
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
fn setup_declaration<'a, 'b, 'c>(
indices: &mut CompositeIndices<'a, 'b, 'c>,
flags: MachineFlags,
mut terms: Vec<Box<Term>>,
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())?;
Ok(Declaration::NonCountedBacktracking(name, arity))
}
("set_prolog_flag", 2) => {
Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?))
}
("multifile", 1) => {
let mut term = *terms.pop().unwrap();
match setup_predicate_indicator(&mut term) {
Ok((name, arity)) =>
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))),
_ =>
Ok((name, arity)) => {
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity)))
}
_ => {
setup_scoped_predicate_indicator(&mut term)
.map(|key| {
Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
})
}
}
}
("use_module", 1) => {
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)
}
}
}
@@ -767,9 +809,9 @@ impl RelationWorker {
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,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term,
) -> Result<QueryTerm, ParserError> {
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,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term,
) -> Result<QueryTerm, ParserError> {
match term {
@@ -864,9 +906,9 @@ impl RelationWorker {
}
}
fn setup_query<'a, 'b, 'c, R: Read>(
fn setup_query<'a, 'b, 'c>(
&mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
terms: Vec<Box<Term>>,
blocks_cuts: bool,
) -> Result<Vec<QueryTerm>, ParserError> {
@@ -917,10 +959,10 @@ impl RelationWorker {
Ok(query_terms)
}
fn setup_hook<'a, 'b, 'c, R: Read>(
fn setup_hook<'a, 'b, 'c>(
&mut self,
hook: CompileTimeHook,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term,
) -> Result<CompileTimeHookCompileInfo, ParserError> {
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,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
mut terms: Vec<Box<Term>>,
blocks_cuts: 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,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
terms: Vec<Box<Term>>,
blocks_cuts: bool,
) -> 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,
term: &mut Term,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
) {
let inner_term = match term {
Term::Clause(_, ref name, ref mut inner_terms, _)
@@ -1015,9 +1057,9 @@ impl RelationWorker {
*term = inner_term;
}
fn try_term_to_tl<'a, 'b, 'c, R: Read>(
fn try_term_to_tl<'a, 'b, 'c>(
&mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
term: Term,
blocks_cuts: bool,
) -> Result<TopLevel, ParserError> {
@@ -1051,19 +1093,20 @@ impl RelationWorker {
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
}
}
term =>
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)),
term => {
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,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
terms: I,
blocks_cuts: bool,
) -> Result<VecDeque<TopLevel>, ParserError>
where
I: IntoIterator<Item = Term>, R: Read
I: IntoIterator<Item = Term>
{
let mut results = VecDeque::new();
@@ -1074,9 +1117,9 @@ impl RelationWorker {
Ok(results)
}
fn parse_queue<'a, 'b, 'c, R: Read>(
fn parse_queue<'a, 'b, 'c>(
&mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
indices: &mut CompositeIndices<'a, 'b, 'c>,
) -> Result<VecDeque<TopLevel>, ParserError> {
let mut queue = VecDeque::new();
@@ -1090,8 +1133,7 @@ impl RelationWorker {
fn absorb(&mut self, other: RelationWorker) {
self.queue.extend(other.queue.into_iter());
self.dynamic_clauses
.extend(other.dynamic_clauses.into_iter());
self.dynamic_clauses.extend(other.dynamic_clauses.into_iter());
}
}
@@ -1099,8 +1141,8 @@ pub type DynamicClause = Vec<(Term, Term)>;
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
pub struct TopLevelBatchWorker<'a, R: Read> {
pub(crate) term_stream: TermStream<'a, R>,
pub struct TopLevelBatchWorker<'a> {
pub(crate) term_stream: TermStream<'a>,
rel_worker: RelationWorker,
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
pub(crate) dynamic_clause_map: DynamicClauseMap,
@@ -1110,14 +1152,14 @@ pub struct TopLevelBatchWorker<'a, R: Read> {
pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
}
impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
impl<'a> TopLevelBatchWorker<'a> {
pub fn new(
inner: &'a mut ParsingStream<R>,
stream: &'a mut ParsingStream<Stream>,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
wam: &'a mut Machine,
) -> 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 col_num = term_stream.col_num();
@@ -1248,7 +1290,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
TopLevel::Declaration(decl) =>
return Ok(Some(decl)),
TopLevel::Query(_) =>
return Err(SessionError::NamelessEntry),
return Err(SessionError::QueryCannotBeDefinedAsFact),
}
}

View File

@@ -4,52 +4,183 @@ macro_rules! interm {
};
}
macro_rules! heap_str {
($s:expr) => {
HeapCellValue::Addr(Addr::Str($s))
};
}
macro_rules! heap_integer {
($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)))
};
/* A simple macro to count the arguments in a variadic list
* of token trees.
*/
macro_rules! count_tt {
() => { 0 };
($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 };
($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
}
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) => (
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),*]) => (
vec![ HeapCellValue::NamedStr($len, clause_name!($name), None), $($args),* ]
(constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
from_constant!($e, $h, $arity, $aux_lens, $addendum)
);
($name:expr, $len:expr, [$($args:expr),*], $fix: expr) => (
vec![ HeapCellValue::NamedStr($len, clause_name!($name), Some($fix)), $($args),* ]
(constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
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 {
@@ -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 {
($r:expr) => {
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 {
($idx:expr, $ip:expr, $mod_name:expr) => {{
let mut idx = $idx.0.borrow_mut();
@@ -238,6 +357,7 @@ macro_rules! index_store {
in_situ_module_dir: ModuleStubDir::new(),
op_dir: $op_dir,
modules: $modules,
stream_aliases: StreamAliasDir::new(),
}
};
}

View File

@@ -6,27 +6,16 @@ use crate::prolog::forms::*;
use crate::prolog::iterators::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::MachineState;
use crate::prolog::machine::streams::Stream;
use std::collections::VecDeque;
use std::io::Read;
type SubtermDeque = VecDeque<(usize, usize)>;
impl<'a> TermRef<'a> {
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 type PrologStream = ParsingStream<Stream>;
pub mod readline {
use prolog_parser::ast::*;
use crate::prolog::machine::streams::Stream;
use crate::prolog::rustyline::error::ReadlineError;
use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
use std::io::{Cursor, Read};
@@ -52,10 +41,10 @@ pub mod readline {
}
impl ReadlineStream {
fn input_stream(pending_input: String) -> Self {
pub fn input_stream(pending_input: String) -> Stream {
let mut rl = Editor::<()>::new();
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> {
@@ -93,15 +82,14 @@ pub mod readline {
result => {
result
}
}
}
}
#[inline]
pub fn input_stream() -> crate::PrologStream {
let reader: Box<dyn Read> = Box::new(ReadlineStream::input_stream(String::from("")));
parsing_stream(reader)
pub fn input_stream() -> Stream {
let input_stream = ReadlineStream::input_stream(String::from(""));
Stream::from(input_stream)
}
}
@@ -119,24 +107,17 @@ impl MachineState {
}
}
fn push_stub_addr(machine_st: &mut MachineState) {
let h = machine_st.heap.h();
machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
#[inline]
pub(crate)
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(
machine_st: &mut MachineState,
queue: &mut SubtermDeque,
term: TermRef,
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));
}
}
struct TermWriter<'a> {
machine_st: &'a mut MachineState,
queue: SubtermDeque,
var_dict: HeapVarDict,
}
pub struct TermWriteResult {
@@ -144,76 +125,135 @@ pub struct TermWriteResult {
pub(crate) var_dict: HeapVarDict,
}
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
let heap_loc = machine_st.heap.h();
impl<'a> TermWriter<'a> {
#[inline]
fn new(machine_st: &'a mut MachineState) -> Self {
TermWriter {
machine_st,
queue: SubtermDeque::new(),
var_dict: HeapVarDict::new(),
}
}
let mut queue = SubtermDeque::new();
let mut var_dict = HeapVarDict::new();
#[inline]
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) {
let h = machine_st.heap.h();
let h = self.machine_st.heap.h();
match &term {
&TermRef::Cons(lvl, ..) => {
queue.push_back((2, h + 1));
machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
self.queue.push_back((2, h + 1));
self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
push_stub_addr(machine_st);
push_stub_addr(machine_st);
self.push_stub_addr();
self.push_stub_addr();
if let Level::Root = lvl {
continue;
}
}
&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());
machine_st.heap.push(named);
self.machine_st.heap.push(named);
for _ in 0..subterms.len() {
push_stub_addr(machine_st);
self.push_stub_addr();
}
if let Level::Root = lvl {
continue;
}
}
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => {
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h)))
}
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(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(_) => {
if let Some((arity, site_h)) = queue.pop_front() {
if let Some((arity, site_h)) = self.queue.pop_front() {
if arity > 1 {
queue.push_front((arity - 1, site_h + 1));
self.queue.push_front((arity - 1, site_h + 1));
}
}
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) => {
if let Some((arity, site_h)) = queue.pop_front() {
if let Some(addr) = var_dict.get(var).cloned() {
machine_st.heap[site_h] = HeapCellValue::Addr(addr);
if let Some((arity, site_h)) = self.queue.pop_front() {
if let Some(addr) = self.var_dict.get(var).cloned() {
self.machine_st.heap[site_h] = HeapCellValue::Addr(addr);
} else {
var_dict.insert(var.clone(), Addr::HeapCell(site_h));
self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
}
if arity > 1 {
queue.push_front((arity - 1, site_h + 1));
self.queue.push_front((arity - 1, site_h + 1));
}
}
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 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 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) {
match self {
&mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
@@ -117,6 +123,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
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 {
QueryInstruction::SetVoid(subterms)
}

View File

@@ -24,26 +24,30 @@
% make '$compile_batch', a system routine, callable.
'$$compile_batch' :- '$compile_batch'.
'$instruction_match'([Item], []) :-
( atom(Item) -> !,
'$instruction_match'(Term, VarList) :-
( var(Term) ->
throw(error(instantiation_error, repl/0))
;
Term = [Item] -> !,
( atom(Item) ->
( Item == user ->
catch('$$compile_batch', E, '$print_exception_with_check'(E))
; consult(Item)
)
; !,
;
catch(throw(error(type_error(atom, Item), repl/0)),
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) :-
( expand_goals(Term0, Term) -> true
; 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
% copy_term/3 prior to failure.
@@ -57,34 +61,78 @@
_,
false),
( EqPrec < FPrec -> true
; '$quoted_token'(F) -> true
; EqPrec == FPrec,
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) ->
write(Var),
write(' = '),
( '$needs_bracketing'(Value, (=)) ->
write('('),
write_term(Value, [quoted(true), variable_names(VarList)]),
write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
write(')')
; write_term(Value, [quoted(true), variable_names(VarList)])
; write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)])
)
; G == [] ->
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) ->
write(Var),
write(' = '),
( '$needs_bracketing'(Value, (=)) ->
write('('),
write_term(Value, [quoted(true), variable_names(VarList)]),
write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
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) ->
write(' ')
; true
@@ -92,16 +140,16 @@
)
; G == [] ->
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_eq'(G2, VarList).
'$write_eq'(G, VarList) :-
'$write_last_goal'(G, VarList).
'$write_eq'(G2, VarList, MaxDepth).
'$write_eq'(G, VarList, MaxDepth) :-
'$write_last_goal'(G, VarList, MaxDepth).
'$graphic_token_char'(C) :-
memberchk(C, ['#', '$', '&', '*', '+', '-', '.', ('/'), ':',
@@ -118,27 +166,52 @@
'$graphic_token_char'(Char).
'$write_eqs_and_read_input'(B, VarList) :-
sort(VarList, SortedVarList),
'$extend_var_list'(VarList, VarList, NewVarList),
sort(NewVarList, SortedVarList),
'$get_b_value'(B0),
'$gather_goals'(SortedVarList, VarList, Goals),
'$gather_goals'(SortedVarList, SortedVarList, Goals),
( B0 == B ->
( Goals == [] ->
write('true.'), nl
; thread_goals(Goals, ThreadedGoals, (',')),
'$write_eq'(ThreadedGoals, VarList),
'$write_eq'(ThreadedGoals, NewVarList, 20),
write('.'),
nl
)
; thread_goals(Goals, ThreadedGoals, (',')),
'$write_eq'(ThreadedGoals, VarList),
'$raw_input_read_char'(C),
( C == (';'), !,
write(' ;'), nl, false
; C == ('.'), !,
write(' ...'), nl
)
'$write_eq'(ThreadedGoals, NewVarList, 20),
'$read_input'(ThreadedGoals, NewVarList)
).
'$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) :-
( var(Var) ->
QueryVars = [Var | QueryVars1],
@@ -153,10 +226,8 @@
).
'$gather_goals'([], VarList, Goals) :-
'$get_attr_var_queue_beyond'(0, AttrVars),
'$gather_query_vars'(VarList, QueryVars),
'$call_attribute_goals'(QueryVars, AttrVars),
'$fetch_attribute_goals'(Goals).
copy_term(QueryVars, QueryVars, Goals).
'$gather_goals'([Var = Value | Pairs], VarList, Goals) :-
( ( nonvar(Value)
; '$is_a_different_variable'(Pairs, Value)
@@ -167,7 +238,7 @@
).
'$print_exception'(E) :-
write_term('caught: ', [quoted(false)]),
write_term('caught: ', [quoted(false), max_depth(20)]),
writeq(E),
nl.

View File

@@ -58,7 +58,13 @@ impl fmt::Display for FactInstruction {
&FactInstruction::GetConstant(lvl, ref constant, ref r) => {
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) => {
write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
}
@@ -86,7 +92,13 @@ impl fmt::Display for QueryInstruction {
&QueryInstruction::PutConstant(lvl, ref constant, ref r) => {
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) => {
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 {
match self {
&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!(
f,
"{}/{} (op, priority: {}, spec: {})",
@@ -154,8 +170,16 @@ impl fmt::Display for HeapCellValue {
&HeapCellValue::NamedStr(arity, ref name, None) => {
write!(f, "{}/{}", name.as_str(), arity)
}
&HeapCellValue::PartialString(ref pstr) => {
write!(f, "pstr ( buf: {}, tail: {} )", pstr.block_as_str(), pstr.tail_addr())
&HeapCellValue::PartialString(ref pstr, has_tail) => {
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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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::DBRef(ref db_ref) => write!(f, "Addr::DBRef({})", db_ref),
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
&Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
&Addr::Str(s) => write!(f, "Addr::Str({})", s),
&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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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) => {
write!(f, "cannot overwrite import {}", msg)
}
&SessionError::InvalidFileName(ref filename) => {
write!(f, "filename {} is invalid", filename)
}
&SessionError::ModuleNotFound => write!(f, "module not found."),
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
write!(
f,
@@ -282,7 +316,44 @@ impl fmt::Display for SessionError {
&SessionError::NamelessEntry => {
write!(f, "the predicate head is not an atom or clause.")
}
&SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
&SessionError::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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Number::Fixnum(n) => write!(f, "{}", n),
&Number::Float(fl) => write!(f, "{}", fl),
&Number::Integer(ref bi) => write!(f, "{}", bi),
&Number::Rational(ref r) => write!(f, "{}", r),

View File

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

View File

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

View File

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

View File

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