summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Thom <markjordanthom@gmail.com>2022-03-06 09:39:28 -0700
committerMark Thom <markjordanthom@gmail.com>2022-03-06 09:45:05 -0700
commit2d19243b3bac3cbad6679d6254cd7b6a2e6d1d4e (patch)
tree757dd97e0944f8041ed52c61aa709b8ef037fd2d
parent9ded1447ece6547f775b61d860579bef68af1260 (diff)
parent0c19c5690978b7ddbc180e9886f75ee25a5e1257 (diff)
Merge branch 'rebis-dev' into 0.9.0 releasev0.9.0
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock792
-rw-r--r--Cargo.toml41
-rw-r--r--README.md20
-rw-r--r--build.rs35
-rw-r--r--crates/instructions-template/Cargo.lock129
-rw-r--r--crates/instructions-template/Cargo.toml14
-rw-r--r--crates/instructions-template/src/lib.rs3290
-rw-r--r--crates/prolog_parser/Cargo.lock265
-rw-r--r--crates/prolog_parser/Cargo.toml26
-rw-r--r--crates/prolog_parser/src/ast.rs782
-rw-r--r--crates/prolog_parser/src/put_back_n.rs71
-rw-r--r--crates/prolog_parser/src/tabled_rc.rs154
-rw-r--r--crates/static-string-indexing/Cargo.toml11
-rw-r--r--crates/static-string-indexing/src/lib.rs177
-rw-r--r--crates/to-syn-value/Cargo.toml10
-rw-r--r--crates/to-syn-value/src/lib.rs3
-rw-r--r--crates/to-syn-value_derive/Cargo.toml14
-rw-r--r--crates/to-syn-value_derive/src/lib.rs20
-rw-r--r--src/allocator.rs78
-rw-r--r--src/arena.rs801
-rw-r--r--src/arithmetic.rs674
-rw-r--r--src/atom_table.rs366
-rw-r--r--src/bin/scryer-prolog.rs8
-rw-r--r--src/clause_types.rs994
-rw-r--r--src/codegen.rs690
-rw-r--r--src/debray_allocator.rs124
-rw-r--r--src/examples/least_time.pl16
-rw-r--r--src/fixtures.rs42
-rw-r--r--src/forms.rs524
-rw-r--r--src/heap_iter.rs2714
-rw-r--r--src/heap_print.rs1739
-rw-r--r--src/indexing.rs387
-rw-r--r--src/instructions.rs847
-rw-r--r--src/iterators.rs219
-rw-r--r--src/lib.rs31
-rw-r--r--src/lib/arithmetic.pl6
-rw-r--r--src/lib/atts.pl52
-rw-r--r--src/lib/between.pl19
-rw-r--r--src/lib/builtins.pl425
-rw-r--r--src/lib/charsio.pl20
-rw-r--r--src/lib/clpz.pl4
-rw-r--r--src/lib/crypto.pl7
-rw-r--r--src/lib/dcgs.pl181
-rw-r--r--src/lib/error.pl4
-rw-r--r--src/lib/files.pl2
-rw-r--r--src/lib/format.pl51
-rw-r--r--src/lib/iso_ext.pl44
-rw-r--r--src/lib/lists.pl34
-rw-r--r--src/lib/ordsets.pl2
-rw-r--r--src/lib/pio.pl4
-rw-r--r--src/lib/random.pl6
-rw-r--r--src/lib/reif.pl1
-rw-r--r--src/lib/serialization/abnf.pl14
-rw-r--r--src/lib/serialization/json.pl18
-rw-r--r--src/lib/sgml.pl10
-rw-r--r--src/lib/tabling/trie.pl2
-rw-r--r--src/lib/time.pl4
-rw-r--r--src/lib/ugraphs.pl630
-rw-r--r--src/lib/uuid.pl6
-rw-r--r--src/loader.pl100
-rw-r--r--src/machine/arithmetic_ops.rs2016
-rw-r--r--src/machine/attributed_variables.rs169
-rw-r--r--src/machine/code_repo.rs177
-rw-r--r--src/machine/code_walker.rs26
-rw-r--r--src/machine/compile.rs918
-rw-r--r--src/machine/copier.rs396
-rw-r--r--src/machine/dispatch.rs4886
-rw-r--r--src/machine/gc.rs1100
-rw-r--r--src/machine/heap.rs614
-rw-r--r--src/machine/load_state.rs585
-rw-r--r--src/machine/loader.rs1879
-rw-r--r--src/machine/machine_errors.rs858
-rw-r--r--src/machine/machine_indices.rs767
-rw-r--r--src/machine/machine_state.rs1634
-rw-r--r--src/machine/machine_state_impl.rs5086
-rw-r--r--src/machine/mock_wam.rs851
-rw-r--r--src/machine/mod.rs996
-rw-r--r--src/machine/partial_string.rs1312
-rw-r--r--src/machine/preprocessor.rs540
-rw-r--r--src/machine/stack.rs209
-rw-r--r--src/machine/streams.rs1685
-rw-r--r--src/machine/system_calls.rs9726
-rw-r--r--src/machine/term_stream.rs89
-rw-r--r--src/macros.rs813
-rw-r--r--src/parser/ast.rs632
-rw-r--r--src/parser/char_reader.rs747
-rw-r--r--src/parser/lexer.rs (renamed from crates/prolog_parser/src/lexer.rs)661
-rw-r--r--src/parser/macros.rs (renamed from crates/prolog_parser/src/macros.rs)8
-rw-r--r--src/parser/mod.rs (renamed from crates/prolog_parser/src/lib.rs)14
-rw-r--r--src/parser/parser.rs (renamed from crates/prolog_parser/src/parser.rs)483
-rw-r--r--src/raw_block.rs105
-rw-r--r--src/read.rs479
-rw-r--r--src/targets.rs158
-rw-r--r--src/tests/bom.rs (renamed from crates/prolog_parser/tests/bom.rs)17
-rw-r--r--src/tests/builtins.pl8
-rw-r--r--src/tests/call_with_inference_limit.pl25
-rw-r--r--src/tests/parse_tokens.rs (renamed from crates/prolog_parser/tests/parse_tokens.rs)49
-rw-r--r--src/toplevel.pl112
-rw-r--r--src/types.rs810
-rw-r--r--src/write.rs674
-rw-r--r--tests-pl/issue839-op3.pl2
-rw-r--r--tests/scryer/helper.rs19
-rw-r--r--tests/scryer/issues.rs38
-rw-r--r--tests/scryer/main.rs1
-rw-r--r--tests/scryer/src_tests.rs19
106 files changed, 36968 insertions, 23181 deletions
diff --git a/.gitignore b/.gitignore
index eafdaf52..f63be9e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+src/static_atoms.rs
target/
+
diff --git a/Cargo.lock b/Cargo.lock
index 7e94a23e..4d699f11 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+version = 3
+
[[package]]
name = "arrayvec"
version = "0.5.2"
@@ -8,9 +10,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "assert_cmd"
-version = "1.0.3"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2475b58cd94eb4f70159f4fd8844ba3b807532fe3131b3373fae060bbe30396"
+checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe"
dependencies = [
"bstr",
"doc-comment",
@@ -34,9 +36,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
-version = "1.1.0"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a"
+checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "base64"
@@ -100,9 +102,9 @@ dependencies = [
[[package]]
name = "bstr"
-version = "0.2.15"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
@@ -111,9 +113,9 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.6.0"
+version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9"
+checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byte-tools"
@@ -123,15 +125,15 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
-version = "1.4.2"
+version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
-version = "1.0.66"
+version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
+checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
[[package]]
name = "cfg-if"
@@ -153,12 +155,23 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
- "num-traits 0.2.14",
+ "num-traits",
"time",
"winapi 0.3.9",
]
[[package]]
+name = "clipboard-win"
+version = "4.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3db8340083d28acb43451166543b98c838299b7e0863621be53a338adceea0ed"
+dependencies = [
+ "error-code",
+ "str-buf",
+ "winapi 0.3.9",
+]
+
+[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -169,9 +182,9 @@ dependencies = [
[[package]]
name = "core-foundation"
-version = "0.9.1"
+version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
+checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
dependencies = [
"core-foundation-sys",
"libc",
@@ -179,9 +192,9 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
-version = "0.8.2"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cpu-time"
@@ -229,10 +242,10 @@ dependencies = [
]
[[package]]
-name = "difference"
-version = "2.0.0"
+name = "difflib"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "digest"
@@ -277,10 +290,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
-name = "downcast"
-version = "0.10.0"
+name = "ed25519"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc"
+dependencies = [
+ "signature",
+]
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "endian-type"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d"
+checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
+
+[[package]]
+name = "error-code"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff"
+dependencies = [
+ "libc",
+ "str-buf",
+]
+
+[[package]]
+name = "fd-lock"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfc110fe50727d46a428eed832df40affe9bf74d077cac1bf3f2718e823f14c5"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "windows-sys",
+]
[[package]]
name = "foreign-types"
@@ -298,16 +347,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
-name = "fs2"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
-dependencies = [
- "libc",
- "winapi 0.3.9",
-]
-
-[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -340,19 +379,28 @@ dependencies = [
]
[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
name = "generic-array"
-version = "0.12.3"
+version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "getrandom"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if 1.0.0",
"libc",
@@ -361,9 +409,9 @@ dependencies = [
[[package]]
name = "git-version"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94918e83f1e01dedc2e361d00ce9487b14c58c7f40bab148026fa39d42cb41e2"
+checksum = "f6b0decc02f4636b9ccad390dcbe77b722a77efedfa393caf8379a51d5c61899"
dependencies = [
"git-version-macro",
"proc-macro-hack",
@@ -371,21 +419,21 @@ dependencies = [
[[package]]
name = "git-version-macro"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657"
+checksum = "fe69f1cbdb6e28af2bac214e943b99ce8a0a06b447d15d3e61161b0423139f3f"
dependencies = [
"proc-macro-hack",
- "proc-macro2 1.0.24",
- "quote 1.0.8",
- "syn 1.0.60",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
]
[[package]]
name = "gmp-mpfr-sys"
-version = "1.4.2"
+version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e"
+checksum = "a146a7357ce9573bdcc416fc4a99b960e166e72d8eaffa7c59966d51866b5bfb"
dependencies = [
"libc",
"winapi 0.3.9",
@@ -393,9 +441,18 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.9.1"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
[[package]]
name = "hostname"
@@ -424,15 +481,29 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "1.6.1"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg 1.0.1",
"hashbrown",
]
[[package]]
+name = "instructions-template"
+version = "0.1.0"
+dependencies = [
+ "indexmap",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "strum",
+ "strum_macros",
+ "syn 1.0.81",
+ "to-syn-value",
+ "to-syn-value_derive",
+]
+
+[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -442,16 +513,25 @@ dependencies = [
]
[[package]]
+name = "itertools"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+dependencies = [
+ "either",
+]
+
+[[package]]
name = "itoa"
-version = "0.4.7"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "js-sys"
-version = "0.3.47"
+version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
+checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
dependencies = [
"wasm-bindgen",
]
@@ -503,19 +583,20 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.85"
+version = "0.2.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3"
+checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
[[package]]
name = "libsodium-sys"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a685b64f837b339074115f2e7f7b431ac73681d08d75b389db7498b8892b8a58"
+checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd"
dependencies = [
"cc",
"libc",
"pkg-config",
+ "walkdir",
]
[[package]]
@@ -558,7 +639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21"
dependencies = [
"log",
- "phf",
+ "phf 0.7.24",
"phf_codegen",
"serde",
"serde_derive",
@@ -576,9 +657,18 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "memchr"
-version = "2.3.4"
+version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "memoffset"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+dependencies = [
+ "autocfg 1.0.1",
+]
[[package]]
name = "mio"
@@ -612,10 +702,29 @@ dependencies = [
]
[[package]]
+name = "modular-bitfield"
+version = "0.11.2"
+source = "git+https://github.com/mthom/modular-bitfield#213535c684af277563678179d8496f11b84a283f"
+dependencies = [
+ "modular-bitfield-impl",
+ "static_assertions",
+]
+
+[[package]]
+name = "modular-bitfield-impl"
+version = "0.11.2"
+source = "git+https://github.com/mthom/modular-bitfield#213535c684af277563678179d8496f11b84a283f"
+dependencies = [
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
+]
+
+[[package]]
name = "native-tls"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4"
+checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
dependencies = [
"lazy_static",
"libc",
@@ -647,6 +756,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
+name = "nibble_vec"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
+dependencies = [
+ "smallvec",
+]
+
+[[package]]
name = "nix"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -661,14 +779,15 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.19.1"
+version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2"
+checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"libc",
+ "memoffset",
]
[[package]]
@@ -679,7 +798,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg 1.0.1",
"num-integer",
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
@@ -689,7 +808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg 1.0.1",
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
@@ -701,7 +820,7 @@ dependencies = [
"autocfg 1.0.1",
"num-bigint",
"num-integer",
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
@@ -712,16 +831,7 @@ dependencies = [
"num-bigint",
"num-integer",
"num-rational",
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
-dependencies = [
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
@@ -735,9 +845,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.5.2"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
+checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "opaque-debug"
@@ -747,38 +857,38 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "openssl"
-version = "0.10.32"
+version = "0.10.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70"
+checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"foreign-types",
- "lazy_static",
"libc",
+ "once_cell",
"openssl-sys",
]
[[package]]
name = "openssl-probe"
-version = "0.1.2"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
+checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "openssl-src"
-version = "111.13.0+1.1.1i"
+version = "300.0.2+3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "045e4dc48af57aad93d665885789b43222ae26f4886494da12d1ed58d309dcb6"
+checksum = "14a760a11390b1a5daf72074d4f6ff1a6e772534ae191f999f57e9ee8146d1fb"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
-version = "0.9.60"
+version = "0.9.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6"
+checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf"
dependencies = [
"autocfg 1.0.1",
"cc",
@@ -790,12 +900,11 @@ dependencies = [
[[package]]
name = "ordered-float"
-version = "0.5.2"
+version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
+checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d"
dependencies = [
- "num-traits 0.1.43",
- "unreachable",
+ "num-traits",
]
[[package]]
@@ -828,7 +937,18 @@ version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18"
dependencies = [
- "phf_shared",
+ "phf_shared 0.7.24",
+]
+
+[[package]]
+name = "phf"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37"
+dependencies = [
+ "phf_macros",
+ "phf_shared 0.9.0",
+ "proc-macro-hack",
]
[[package]]
@@ -837,8 +957,8 @@ version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
dependencies = [
- "phf_generator",
- "phf_shared",
+ "phf_generator 0.7.24",
+ "phf_shared 0.7.24",
]
[[package]]
@@ -847,30 +967,63 @@ version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
dependencies = [
- "phf_shared",
+ "phf_shared 0.7.24",
"rand 0.6.5",
]
[[package]]
+name = "phf_generator"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082"
+dependencies = [
+ "phf_shared 0.9.0",
+ "rand 0.8.4",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86"
+dependencies = [
+ "phf_generator 0.9.1",
+ "phf_shared 0.9.0",
+ "proc-macro-hack",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
+]
+
+[[package]]
name = "phf_shared"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
dependencies = [
- "siphasher",
+ "siphasher 0.2.3",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9"
+dependencies = [
+ "siphasher 0.3.7",
]
[[package]]
name = "pkg-config"
-version = "0.3.19"
+version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
+checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
[[package]]
name = "ppv-lite86"
-version = "0.2.10"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "precomputed-hash"
@@ -880,11 +1033,12 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "predicates"
-version = "1.0.7"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eeb433456c1a57cc93554dea3ce40b4c19c4057e41c55d4a0f3d84ea71c325aa"
+checksum = "5c6ce811d0b2e103743eec01db1c50612221f173084ce2f7941053e94b6bb474"
dependencies = [
- "difference",
+ "difflib",
+ "itertools",
"predicates-core",
]
@@ -896,12 +1050,12 @@ checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
[[package]]
name = "predicates-tree"
-version = "1.0.2"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2"
+checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7"
dependencies = [
"predicates-core",
- "treeline",
+ "termtree",
]
[[package]]
@@ -921,23 +1075,11 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.24"
+version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [
- "unicode-xid 0.2.1",
-]
-
-[[package]]
-name = "prolog_parser"
-version = "0.8.68"
-dependencies = [
- "indexmap",
- "lexical",
- "num-rug-adapter",
- "ordered-float",
- "rug",
- "unicode_reader",
+ "unicode-xid 0.2.2",
]
[[package]]
@@ -951,11 +1093,21 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.8"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.32",
+]
+
+[[package]]
+name = "radix_trie"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
+dependencies = [
+ "endian-type",
+ "nibble_vec",
]
[[package]]
@@ -979,14 +1131,14 @@ dependencies = [
[[package]]
name = "rand"
-version = "0.8.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
"libc",
- "rand_chacha 0.3.0",
- "rand_core 0.6.1",
- "rand_hc 0.3.0",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.3",
+ "rand_hc 0.3.1",
]
[[package]]
@@ -1001,12 +1153,12 @@ dependencies = [
[[package]]
name = "rand_chacha"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
- "rand_core 0.6.1",
+ "rand_core 0.6.3",
]
[[package]]
@@ -1026,9 +1178,9 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
-version = "0.6.1"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
@@ -1044,11 +1196,11 @@ dependencies = [
[[package]]
name = "rand_hc"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [
- "rand_core 0.6.1",
+ "rand_core 0.6.3",
]
[[package]]
@@ -1121,9 +1273,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_syscall"
-version = "0.2.4"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
@@ -1135,7 +1287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
- "redox_syscall 0.2.4",
+ "redox_syscall 0.2.10",
]
[[package]]
@@ -1146,12 +1298,9 @@ checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
[[package]]
name = "regex-automata"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
-dependencies = [
- "byteorder",
-]
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "remove_dir_all"
@@ -1199,9 +1348,9 @@ dependencies = [
[[package]]
name = "rug"
-version = "1.11.0"
+version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45"
+checksum = "ee0c6e98de59509e62e09f3456b23cebb75dad21928882016f169bb628843459"
dependencies = [
"az",
"gmp-mpfr-sys",
@@ -1209,20 +1358,29 @@ dependencies = [
]
[[package]]
+name = "rustversion"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
+
+[[package]]
name = "rustyline"
-version = "7.1.0"
+version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8227301bfc717136f0ecbd3d064ba8199e44497a0bdd46bb01ede4387cfd2cec"
+checksum = "790487c3881a63489ae77126f57048b42d62d3b2bafbf37453ea19eedb6340d6"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
+ "clipboard-win",
"dirs-next",
- "fs2",
+ "fd-lock",
"libc",
"log",
"memchr",
- "nix 0.19.1",
+ "nix 0.22.2",
+ "radix_trie",
"scopeguard",
+ "smallvec",
"unicode-segmentation",
"unicode-width",
"utf8parse",
@@ -1236,6 +1394,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
name = "schannel"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1253,7 +1420,7 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scryer-prolog"
-version = "0.8.128"
+version = "0.9.0"
dependencies = [
"assert_cmd",
"base64",
@@ -1263,19 +1430,23 @@ dependencies = [
"crossterm",
"dirs-next",
"divrem",
- "downcast",
+ "fxhash",
"git-version",
"hostname",
"indexmap",
+ "instructions-template",
"lazy_static",
+ "lexical",
"libc",
+ "modular-bitfield",
"native-tls",
"nix 0.15.0",
"num-rug-adapter",
"openssl",
"ordered-float",
+ "phf 0.9.0",
"predicates-core",
- "prolog_parser",
+ "proc-macro2 1.0.32",
"ref_thread_local",
"ring",
"ripemd160",
@@ -1283,17 +1454,20 @@ dependencies = [
"rug",
"rustyline",
"select",
+ "serial_test",
"sha3",
"slice-deque",
+ "smallvec",
"sodiumoxide",
- "unicode_reader",
+ "static-string-indexing",
+ "static_assertions",
]
[[package]]
name = "security-framework"
-version = "2.0.0"
+version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69"
+checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467"
dependencies = [
"bitflags",
"core-foundation",
@@ -1304,9 +1478,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.0.0"
+version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b"
+checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
dependencies = [
"core-foundation-sys",
"libc",
@@ -1324,26 +1498,26 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.123"
+version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
+checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
[[package]]
name = "serde_derive"
-version = "1.0.123"
+version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
+checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
- "proc-macro2 1.0.24",
- "quote 1.0.8",
- "syn 1.0.60",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
]
[[package]]
name = "serde_json"
-version = "1.0.61"
+version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
+checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3"
dependencies = [
"itoa",
"ryu",
@@ -1351,6 +1525,28 @@ dependencies = [
]
[[package]]
+name = "serial_test"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
+dependencies = [
+ "lazy_static",
+ "parking_lot",
+ "serial_test_derive",
+]
+
+[[package]]
+name = "serial_test_derive"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5"
+dependencies = [
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
+]
+
+[[package]]
name = "sha3"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1376,24 +1572,36 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
[[package]]
+name = "signature"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788"
+
+[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
[[package]]
+name = "siphasher"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
+
+[[package]]
name = "slab"
-version = "0.4.2"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
+checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "slice-deque"
@@ -1408,16 +1616,17 @@ dependencies = [
[[package]]
name = "smallvec"
-version = "1.6.1"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
+checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "sodiumoxide"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7038b67c941e23501573cb7242ffb08709abe9b11eb74bceff875bbda024a6a8"
+checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028"
dependencies = [
+ "ed25519",
"libc",
"libsodium-sys",
"serde",
@@ -1430,12 +1639,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
+name = "static-string-indexing"
+version = "0.1.0"
+dependencies = [
+ "indexmap",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
+ "walkdir",
+]
+
+[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
+name = "str-buf"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a"
+
+[[package]]
name = "string_cache"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1443,7 +1669,7 @@ checksum = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67"
dependencies = [
"lazy_static",
"new_debug_unreachable",
- "phf_shared",
+ "phf_shared 0.7.24",
"precomputed-hash",
"serde",
"string_cache_codegen",
@@ -1456,10 +1682,10 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6"
dependencies = [
- "phf_generator",
- "phf_shared",
- "proc-macro2 1.0.24",
- "quote 1.0.8",
+ "phf_generator 0.7.24",
+ "phf_shared 0.7.24",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
"string_cache_shared",
]
@@ -1470,6 +1696,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
[[package]]
+name = "strum"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
+
+[[package]]
+name = "strum_macros"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
+dependencies = [
+ "heck",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "rustversion",
+ "syn 1.0.81",
+]
+
+[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1488,13 +1733,13 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.60"
+version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
+checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [
- "proc-macro2 1.0.24",
- "quote 1.0.8",
- "unicode-xid 0.2.1",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "unicode-xid 0.2.2",
]
[[package]]
@@ -1505,8 +1750,8 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"cfg-if 1.0.0",
"libc",
- "rand 0.8.3",
- "redox_syscall 0.2.4",
+ "rand 0.8.4",
+ "redox_syscall 0.2.10",
"remove_dir_all",
"winapi 0.3.9",
]
@@ -1523,6 +1768,12 @@ dependencies = [
]
[[package]]
+name = "termtree"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16"
+
+[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1533,28 +1784,39 @@ dependencies = [
]
[[package]]
-name = "treeline"
+name = "to-syn-value"
version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
+dependencies = [
+ "syn 1.0.81",
+ "to-syn-value_derive",
+]
+
+[[package]]
+name = "to-syn-value_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
+]
[[package]]
name = "typenum"
-version = "1.12.0"
+version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
+checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "unicode-segmentation"
-version = "1.7.1"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
@@ -1564,28 +1826,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "unicode-xid"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
-
-[[package]]
-name = "unicode_reader"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a"
-dependencies = [
- "smallvec",
- "unicode-segmentation",
-]
-
-[[package]]
-name = "unreachable"
-version = "1.0.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
-dependencies = [
- "void",
-]
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "untrusted"
@@ -1595,9 +1838,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "utf-8"
-version = "0.7.5"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8parse"
@@ -1607,9 +1850,9 @@ checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "vcpkg"
-version = "0.2.11"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "void"
@@ -1627,6 +1870,17 @@ dependencies = [
]
[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi 0.3.9",
+ "winapi-util",
+]
+
+[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1634,9 +1888,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
-version = "0.2.70"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
+checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
@@ -1644,53 +1898,53 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.70"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
+checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
dependencies = [
"bumpalo",
"lazy_static",
"log",
- "proc-macro2 1.0.24",
- "quote 1.0.8",
- "syn 1.0.60",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.70"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
+checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
dependencies = [
- "quote 1.0.8",
+ "quote 1.0.10",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.70"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
+checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [
- "proc-macro2 1.0.24",
- "quote 1.0.8",
- "syn 1.0.60",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.70"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
+checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "web-sys"
-version = "0.3.47"
+version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
+checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -1725,12 +1979,64 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
+name = "windows-sys"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6"
+dependencies = [
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
+
+[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 0e4b144e..8e81a947 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "scryer-prolog"
-version = "0.8.128"
+version = "0.9.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021"
description = "A modern Prolog implementation written mostly in Rust."
@@ -12,34 +12,45 @@ categories = ["command-line-utilities"]
build = "build.rs"
[workspace]
-members = ["crates/prolog_parser", "crates/num-rug-adapter"]
+members = ["crates/num-rug-adapter",
+ "crates/static-string-indexing",
+ "crates/instructions-template",
+ "crates/to-syn-value",
+ "crates/to-syn-value_derive"]
+
+[features]
+num = ["num-rug-adapter"]
+# no default features to make num tests work
+# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
+# see rust-lang/cargo#7160
+default = ["rug"]
[build-dependencies]
indexmap = "1.0.2"
-
-[features]
-default = ["rug", "prolog_parser/rug"]
-num = ["num-rug-adapter", "prolog_parser/num"]
+static-string-indexing = { path = "./crates/static-string-indexing" }
+instructions-template = { path = "./crates/instructions-template" }
+proc-macro2 = "*"
[dependencies]
cpu-time = "1.0.0"
crossterm = "0.16.0"
dirs-next = "2.0.0"
divrem = "0.1.0"
-downcast = "0.10.0"
+fxhash = "0.2.1"
git-version = "0.3.4"
hostname = "0.3.1"
indexmap = "1.0.2"
lazy_static = "1.4.0"
+lexical = "5.2.2"
libc = "0.2.62"
+modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2"
nix = "0.15.0"
num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" }
-ordered-float = "0.5.0"
-prolog_parser = { path = "./crates/prolog_parser", default-features = false }
+ordered-float = "2.1.1"
+phf = { version = "0.9", features = ["macros"] }
ref_thread_local = "0.0.0"
-rug = { version = "1.4.0", optional = true }
-rustyline = "7.0.0"
-unicode_reader = "1.0.0"
+rug = { version = "1.12.0", optional = true }
+rustyline = "9.0.0"
ring = "0.16.13"
ripemd160 = "0.8.0"
sha3 = "0.8.2"
@@ -50,9 +61,15 @@ chrono = "0.4.11"
select = "0.4.3"
roxmltree = "0.11.0"
base64 = "0.12.3"
+smallvec = "*"
sodiumoxide = "0.2.6"
+static_assertions = "1.1.0"
slice-deque = "0.3.0"
[dev-dependencies]
assert_cmd = "1.0.3"
predicates-core = "1.0.2"
+serial_test = "0.5.1"
+
+[profile.release]
+debug = true \ No newline at end of file
diff --git a/README.md b/README.md
index 7e008bf8..154fc451 100644
--- a/README.md
+++ b/README.md
@@ -61,10 +61,14 @@ Extend Scryer Prolog to include the following, among other features:
- [x] A simple sockets library representing TCP connections as streams.
- [x] Incremental compilation and loading process, newly written,
primarily in Prolog.
+- [ ] Improvements to the WAM compiler and heap representation:
+ - [ ] Replacing choice points pivoting on inlined semi-deterministic predicates
+ (`atom`, `var`, etc) with if/else ladders. (_in progress_)
+ - [ ] Inlining all built-ins and system call instructions.
+ - [ ] Greatly reducing the number of instructions used to compile disjunctives.
+ - [ ] Storing short atoms to heap cells without writing them to the atom table.
- [ ] A compacting garbage collector satisfying the five properties of
- "Precise Garbage Collection in Prolog." (_in progress_, see
- the [`rebis-dev` branch](https://github.com/mthom/scryer-prolog/tree/rebis-dev)
- and its [announcement](https://github.com/mthom/scryer-prolog/discussions/1167))
+ "Precise Garbage Collection in Prolog." (_in progress_)
- [ ] Mode declarations.
## Phase 3
@@ -132,6 +136,8 @@ $> cargo run [--release]
The optional `--release` flag will perform various optimizations,
producing a faster executable.
+Scryer Prolog must be built with **Rust 1.57 and up**.
+
### Docker Install (All Platforms)
First, install [Docker](https://docs.docker.com/get-docker/) on Linux,
@@ -205,9 +211,10 @@ predicates it defines. For example, with the program shown above:
; What = pure_world.
```
-Press `SPACE` to show further answers, if any exist. Press `RETURN` or
-&nbsp;`.` to abort the search and return to the toplevel&nbsp;prompt.
-Press&nbsp;`h` to show a help message.
+Press `SPACE` to show further answers, if any exist. Press `RETURN`
+or&nbsp;`.` to abort the search and return to the
+toplevel&nbsp;prompt. Press&nbsp;`f` to see the next 5 answers, and
+`a` to see all answers. Press&nbsp;`h` to show a help message.
To quit Scryer Prolog, use the standard predicate `halt/0`:
@@ -554,6 +561,7 @@ The modules that ship with Scryer&nbsp;Prolog are also called
* [`uuid`](src/lib/uuid.pl) UUIDv4 generation and hex representation
* [`tls`](src/lib/tls.pl)
Predicates for negotiating TLS connections explicitly.
+* [`ugraphs`](src/lib/ugraphs.pl) Graph manipulation library
To use predicates provided by the `lists` library, write:
diff --git a/build.rs b/build.rs
index 0133c93e..e0f1d16e 100644
--- a/build.rs
+++ b/build.rs
@@ -1,8 +1,12 @@
+use static_string_indexing::index_static_strings;
+use instructions_template::generate_instructions_rs;
+
use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
+use std::process::Command;
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
let entries = match current_dir.read_dir() {
@@ -48,6 +52,37 @@ fn main() {
let mut m = IndexMap::new();\n",
)
.unwrap();
+
find_prolog_files(&mut libraries, "", &lib_path);
libraries.write_all(b"\n m\n };\n}\n").unwrap();
+
+ let instructions_path = Path::new(&out_dir).join("instructions.rs");
+ let mut instructions_file = File::create(&instructions_path).unwrap();
+
+ let quoted_output = generate_instructions_rs();
+
+ instructions_file
+ .write_all(quoted_output.to_string().as_bytes())
+ .unwrap();
+
+ Command::new("rustfmt")
+ .arg(instructions_path.as_os_str())
+ .spawn().unwrap()
+ .wait().unwrap();
+
+ let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
+ let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
+
+ let quoted_output = index_static_strings(&instructions_path);
+
+ static_atoms_file
+ .write_all(quoted_output.to_string().as_bytes())
+ .unwrap();
+
+ Command::new("rustfmt")
+ .arg(static_atoms_path.as_os_str())
+ .spawn().unwrap()
+ .wait().unwrap();
+
+ println!("cargo:rerun-if-changed=src/");
}
diff --git a/crates/instructions-template/Cargo.lock b/crates/instructions-template/Cargo.lock
new file mode 100644
index 00000000..08be8ba3
--- /dev/null
+++ b/crates/instructions-template/Cargo.lock
@@ -0,0 +1,129 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "instructions-template"
+version = "0.1.0"
+dependencies = [
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "strum",
+ "strum_macros",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "392a54546fda6b7cc663379d0e6ce8b324cf88aecc5a499838e1be9781bdce2e"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
+
+[[package]]
+name = "strum"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
+
+[[package]]
+name = "strum_macros"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.84"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "to-syn-value"
+version = "0.1.0"
+dependencies = [
+ "syn",
+ "to-syn-value_derive",
+]
+
+[[package]]
+name = "to-syn-value_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
diff --git a/crates/instructions-template/Cargo.toml b/crates/instructions-template/Cargo.toml
new file mode 100644
index 00000000..92f130ed
--- /dev/null
+++ b/crates/instructions-template/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "instructions-template"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+indexmap = "*"
+proc-macro2 = "*"
+quote = "*"
+strum = "0.23"
+strum_macros = "0.23"
+syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
+to-syn-value = { path = "../to-syn-value" }
+to-syn-value_derive = { path = "../to-syn-value_derive" } \ No newline at end of file
diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs
new file mode 100644
index 00000000..774bf40d
--- /dev/null
+++ b/crates/instructions-template/src/lib.rs
@@ -0,0 +1,3290 @@
+// use crate::atom_table::*;
+// use crate::machine::machine_indices::*;
+// use crate::types::*;
+//
+
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, ToTokens, TokenStreamExt};
+use strum_macros::{EnumDiscriminants, EnumProperty, EnumString};
+use syn::*;
+use to_syn_value_derive::ToDeriveInput;
+
+/*
+ * This crate exists to generate the Instruction enum in
+ * src/instructions.rs and its adjoining impl functions. The types
+ * defined in it are empty and serve only as schema for the generation
+ * of Instruction. They mimick most of the structure of the previous
+ * Line instruction type. The strum crate is used to provide reflection
+ * on each of the node types to the tree walker.
+ */
+
+use std::any::*;
+use std::str::FromStr;
+
+struct ArithmeticTerm;
+struct Atom;
+struct CodeIndex;
+struct Death;
+struct HeapCellValue;
+struct IndexingLine;
+struct Level;
+struct NextOrFail;
+struct RegType;
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum CompareNumber {
+ #[strum_discriminants(strum(props(Arity = "2", Name = ">")))]
+ NumberGreaterThan(ArithmeticTerm, ArithmeticTerm),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "<")))]
+ NumberLessThan(ArithmeticTerm, ArithmeticTerm),
+ #[strum_discriminants(strum(props(Arity = "2", Name = ">=")))]
+ NumberGreaterThanOrEqual(ArithmeticTerm, ArithmeticTerm),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "=<")))]
+ NumberLessThanOrEqual(ArithmeticTerm, ArithmeticTerm),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "=\\=")))]
+ NumberNotEqual(ArithmeticTerm, ArithmeticTerm),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "=:=")))]
+ NumberEqual(ArithmeticTerm, ArithmeticTerm),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum CompareTerm {
+ #[strum_discriminants(strum(props(Arity = "2", Name = "@<")))]
+ TermLessThan,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "@=<")))]
+ TermLessThanOrEqual,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "@>=")))]
+ TermGreaterThanOrEqual,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "@>")))]
+ TermGreaterThan,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "==")))]
+ TermEqual,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "\\==")))]
+ TermNotEqual,
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum ClauseType {
+ BuiltIn(BuiltInClauseType),
+ #[strum_discriminants(strum(props(Arity = "arity", Name = "$call")))]
+ CallN(usize),
+ Inlined(InlinedClauseType),
+ #[strum_discriminants(strum(props(Arity = "arity", Name = "call_named")))]
+ Named(usize, Atom, CodeIndex), // name, arity, index.
+ System(SystemClauseType),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum BuiltInClauseType {
+ #[strum_discriminants(strum(props(Arity = "1", Name = "acyclic_term")))]
+ AcyclicTerm,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "arg")))]
+ Arg,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "compare")))]
+ Compare,
+ CompareTerm(CompareTerm),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "copy_term")))]
+ CopyTerm,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "functor")))]
+ Functor,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "ground")))]
+ Ground,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "is")))]
+ Is(RegType, ArithmeticTerm),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))]
+ KeySort,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "read")))]
+ Read,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "sort")))]
+ Sort,
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum InlinedClauseType {
+ CompareNumber(CompareNumber),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "atom")))]
+ IsAtom(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "atomic")))]
+ IsAtomic(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "compound")))]
+ IsCompound(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "integer")))]
+ IsInteger(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "number")))]
+ IsNumber(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "rational")))]
+ IsRational(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "float")))]
+ IsFloat(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "nonvar")))]
+ IsNonVar(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "var")))]
+ IsVar(RegType),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum REPLCodePtr {
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$add_discontiguous_predicate")))]
+ AddDiscontiguousPredicate,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$add_dynamic_predicate")))]
+ AddDynamicPredicate,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$add_multifile_predicate")))]
+ AddMultifilePredicate,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$add_goal_expansion_clause")))]
+ AddGoalExpansionClause,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$add_term_expansion_clause")))]
+ AddTermExpansionClause,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$add_in_situ_filename_module")))]
+ AddInSituFilenameModule,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$clause_to_evacuable")))]
+ ClauseToEvacuable,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$scoped_clause_to_evacuable")))]
+ ScopedClauseToEvacuable,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$conclude_load")))]
+ ConcludeLoad,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$declare_module")))]
+ DeclareModule,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$load_compiled_library")))]
+ LoadCompiledLibrary,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_source")))]
+ LoadContextSource,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_file")))]
+ LoadContextFile,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_dir")))]
+ LoadContextDirectory,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_module")))]
+ LoadContextModule,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_stream")))]
+ LoadContextStream,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$pop_load_context")))]
+ PopLoadContext,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$pop_load_state_payload")))]
+ PopLoadStatePayload,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$push_load_state_payload")))]
+ PushLoadStatePayload,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$push_load_context")))]
+ PushLoadContext,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$use_module")))]
+ UseModule,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$built_in_property")))]
+ BuiltInProperty,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$meta_predicate_property")))]
+ MetaPredicateProperty,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$multifile_property")))]
+ MultifileProperty,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$discontiguous_property")))]
+ DiscontiguousProperty,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$dynamic_property")))]
+ DynamicProperty,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
+ AbolishClause,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$asserta")))]
+ Asserta,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$assertz")))]
+ Assertz,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
+ Retract,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$is_consistent_with_term_queue")))]
+ IsConsistentWithTermQueue,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$flush_term_queue")))]
+ FlushTermQueue,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$remove_module_exports")))]
+ RemoveModuleExports,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$add_non_counted_backtracking")))]
+ AddNonCountedBacktracking,
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum SystemClauseType {
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_chars")))]
+ AtomChars,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_codes")))]
+ AtomCodes,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_length")))]
+ AtomLength,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$bind_from_register")))]
+ BindFromRegister,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$call_continuation")))]
+ CallContinuation,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$char_code")))]
+ CharCode,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$char_type")))]
+ CharType,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$chars_to_number")))]
+ CharsToNumber,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$codes_to_number")))]
+ CodesToNumber,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$copy_term_without_attr_vars")))]
+ CopyTermWithoutAttrVars,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$check_cp")))]
+ CheckCutPoint,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$close")))]
+ Close,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$copy_to_lh")))]
+ CopyToLiftedHeap,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$create_partial_string")))]
+ CreatePartialString,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$current_hostname")))]
+ CurrentHostname,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$current_input")))]
+ CurrentInput,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$current_output")))]
+ CurrentOutput,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$directory_files")))]
+ DirectoryFiles,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$file_size")))]
+ FileSize,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$file_exists")))]
+ FileExists,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$directory_exists")))]
+ DirectoryExists,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$directory_separator")))]
+ DirectorySeparator,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$make_directory")))]
+ MakeDirectory,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$make_directory_path")))]
+ MakeDirectoryPath,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_file")))]
+ DeleteFile,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$rename_file")))]
+ RenameFile,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$working_directory")))]
+ WorkingDirectory,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_directory")))]
+ DeleteDirectory,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$path_canonical")))]
+ PathCanonical,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))]
+ FileTime,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_non_head")))]
+ DeleteAttribute,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_head")))]
+ DeleteHeadAttribute,
+ #[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
+ DynamicModuleResolution(usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
+ EnqueueAttributedVar,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
+ FetchGlobalVar,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))]
+ FirstStream,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$flush_output")))]
+ FlushOutput,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$get_byte")))]
+ GetByte,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$get_char")))]
+ GetChar,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$get_n_chars")))]
+ GetNChars,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$get_code")))]
+ GetCode,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_single_char")))]
+ GetSingleChar,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$reset_attr_var_state")))]
+ ResetAttrVarState,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$truncate_if_no_lh_growth_diff")))]
+ TruncateIfNoLiftedHeapGrowthDiff,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$truncate_if_no_lh_growth")))]
+ TruncateIfNoLiftedHeapGrowth,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$get_attr_list")))]
+ GetAttributedVariableList,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_attr_var_queue_delim")))]
+ GetAttrVarQueueDelimiter,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$get_attr_var_queue_beyond")))]
+ GetAttrVarQueueBeyond,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_b_value")))]
+ GetBValue,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$get_cont_chunk")))]
+ GetContinuationChunk,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$get_next_db_ref")))]
+ GetNextDBRef,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$get_next_op_db_ref")))]
+ GetNextOpDBRef,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$is_partial_string")))]
+ IsPartialString,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$halt")))]
+ Halt,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$get_lh_from_offset")))]
+ GetLiftedHeapFromOffset,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$get_lh_from_offset_diff")))]
+ GetLiftedHeapFromOffsetDiff,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_scc_cleaner")))]
+ GetSCCCleaner,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$head_is_dynamic")))]
+ HeadIsDynamic,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$install_scc_cleaner")))]
+ InstallSCCCleaner,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$install_inference_counter")))]
+ InstallInferenceCounter,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$lh_length")))]
+ LiftedHeapLength,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$load_library_as_stream")))]
+ LoadLibraryAsStream,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$module_exists")))]
+ ModuleExists,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$nextEP")))]
+ NextEP,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$no_such_predicate")))]
+ NoSuchPredicate,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$number_to_chars")))]
+ NumberToChars,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$number_to_codes")))]
+ NumberToCodes,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$op")))]
+ OpDeclaration,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$open")))]
+ Open,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$set_stream_options")))]
+ SetStreamOptions,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$next_stream")))]
+ NextStream,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$partial_string_tail")))]
+ PartialStringTail,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_byte")))]
+ PeekByte,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_char")))]
+ PeekChar,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_code")))]
+ PeekCode,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$points_to_cont_reset_marker")))]
+ PointsToContinuationResetMarker,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$put_byte")))]
+ PutByte,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$put_char")))]
+ PutChar,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$put_chars")))]
+ PutChars,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$put_code")))]
+ PutCode,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$read_query_term")))]
+ ReadQueryTerm,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$read_term")))]
+ ReadTerm,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$redo_attr_var_binding")))]
+ RedoAttrVarBinding,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$remove_call_policy_check")))]
+ RemoveCallPolicyCheck,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$remove_inference_counter")))]
+ RemoveInferenceCounter,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$reset_cont_marker")))]
+ ResetContinuationMarker,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$restore_cut_policy")))]
+ RestoreCutPolicy,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp")))]
+ SetCutPoint(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$set_input")))]
+ SetInput,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$set_output")))]
+ SetOutput,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$store_backtrackable_global_var")))]
+ StoreBacktrackableGlobalVar,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$store_global_var")))]
+ StoreGlobalVar,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$stream_property")))]
+ StreamProperty,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$set_stream_position")))]
+ SetStreamPosition,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$inference_level")))]
+ InferenceLevel,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))]
+ CleanUpBlock,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$erase_ball")))]
+ EraseBall,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))]
+ Fail,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))]
+ GetBall,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_current_block")))]
+ GetCurrentBlock,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_cp")))]
+ GetCutPoint,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_staggered_cp")))]
+ GetStaggeredCutPoint,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_double_quotes")))]
+ GetDoubleQuotes,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$install_new_block")))]
+ InstallNewBlock,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$maybe")))]
+ Maybe,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$current_time")))]
+ CurrentTime,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$quoted_token")))]
+ QuotedToken,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$read_term_from_chars")))]
+ ReadTermFromChars,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$reset_block")))]
+ ResetBlock,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$return_from_verify_attr")))]
+ ReturnFromVerifyAttr,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))]
+ SetBall,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))]
+ SetCutPointByDefault(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))]
+ SetDoubleQuotes,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$set_seed")))]
+ SetSeed,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$skip_max_list")))]
+ SkipMaxList,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$sleep")))]
+ Sleep,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$socket_client_open")))]
+ SocketClientOpen,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$socket_server_open")))]
+ SocketServerOpen,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$socket_server_accept")))]
+ SocketServerAccept,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$socket_server_close")))]
+ SocketServerClose,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$tls_accept_client")))]
+ TLSAcceptClient,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$tls_client_connect")))]
+ TLSClientConnect,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$succeed")))]
+ Succeed,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$term_attributed_variables")))]
+ TermAttributedVariables,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$term_variables")))]
+ TermVariables,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$term_variables_under_max_depth")))]
+ TermVariablesUnderMaxDepth,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$truncate_lh_to")))]
+ TruncateLiftedHeapTo,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$unify_with_occurs_check")))]
+ UnifyWithOccursCheck,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$unwind_environments")))]
+ UnwindEnvironments,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$unwind_stack")))]
+ UnwindStack,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$wam_instructions")))]
+ WAMInstructions,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$write_term")))]
+ WriteTerm,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$write_term_to_chars")))]
+ WriteTermToChars,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$scryer_prolog_version")))]
+ ScryerPrologVersion,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$crypto_random_byte")))]
+ CryptoRandomByte,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_data_hash")))]
+ CryptoDataHash,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_hkdf")))]
+ CryptoDataHKDF,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))]
+ CryptoPasswordHash,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_encrypt")))]
+ CryptoDataEncrypt,
+ #[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
+ CryptoDataDecrypt,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_curve_scalar_mult")))]
+ CryptoCurveScalarMult,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
+ Ed25519Sign,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))]
+ Ed25519Verify,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))]
+ Ed25519NewKeyPair,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))]
+ Ed25519KeyPairPublicKey,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$curve25519_scalar_mult")))]
+ Curve25519ScalarMult,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))]
+ FirstNonOctet,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))]
+ LoadHTML,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$load_xml")))]
+ LoadXML,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$getenv")))]
+ GetEnv,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$setenv")))]
+ SetEnv,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$unsetenv")))]
+ UnsetEnv,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$shell")))]
+ Shell,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))]
+ PID,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))]
+ CharsBase64,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$devour_whitespace")))]
+ DevourWhitespace,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$is_sto_enabled")))]
+ IsSTOEnabled,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$set_sto_as_unify")))]
+ SetSTOAsUnify,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$set_nsto_as_unify")))]
+ SetNSTOAsUnify,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$set_sto_with_error_as_unify")))]
+ SetSTOWithErrorAsUnify,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$home_directory")))]
+ HomeDirectory,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$debug_hook")))]
+ DebugHook,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$popcount")))]
+ PopCount,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))]
+ CpuNow,
+ REPL(REPLCodePtr),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum InstructionTemplate {
+ #[strum_discriminants(strum(props(Arity = "3", Name = "get_constant")))]
+ GetConstant(Level, HeapCellValue, RegType),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "get_list")))]
+ GetList(Level, RegType),
+ #[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))]
+ GetPartialString(Level, Atom, RegType, bool),
+ #[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))]
+ GetStructure(Atom, usize, RegType),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))]
+ GetVariable(RegType, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "get_value")))]
+ GetValue(RegType, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "unify_constant")))]
+ UnifyConstant(HeapCellValue),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "unify_local_value")))]
+ UnifyLocalValue(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "unify_variable")))]
+ UnifyVariable(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "unify_value")))]
+ UnifyValue(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "unify_void")))]
+ UnifyVoid(usize),
+ // query instruction
+ #[strum_discriminants(strum(props(Arity = "3", Name = "put_constant")))]
+ PutConstant(Level, HeapCellValue, RegType),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "put_list")))]
+ PutList(Level, RegType),
+ #[strum_discriminants(strum(props(Arity = "4", Name = "put_partial_string")))]
+ PutPartialString(Level, Atom, RegType, bool),
+ #[strum_discriminants(strum(props(Arity = "3", Name = "put_structure")))]
+ PutStructure(Atom, usize, RegType),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))]
+ PutUnsafeValue(usize, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "put_value")))]
+ PutValue(RegType, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "put_variable")))]
+ PutVariable(RegType, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "set_constant")))]
+ SetConstant(HeapCellValue),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "set_local_value")))]
+ SetLocalValue(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "set_variable")))]
+ SetVariable(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "set_value")))]
+ SetValue(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "set_void")))]
+ SetVoid(usize),
+ // cut instruction
+ #[strum_discriminants(strum(props(Arity = "1", Name = "cut")))]
+ Cut(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "get_level")))]
+ GetLevel(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "get_level_and_unify")))]
+ GetLevelAndUnify(RegType),
+ #[strum_discriminants(strum(props(Arity = "0", Name = "neck_cut")))]
+ NeckCut,
+ // choice instruction
+ #[strum_discriminants(strum(props(Arity = "3", Name = "dynamic_else")))]
+ DynamicElse(usize, Death, NextOrFail),
+ #[strum_discriminants(strum(props(Arity = "3", Name = "dynamic_internal_else")))]
+ DynamicInternalElse(usize, Death, NextOrFail),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "default_retry_me_else")))]
+ DefaultRetryMeElse(usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "default_trust_me")))]
+ DefaultTrustMe(usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "retry_me_else")))]
+ RetryMeElse(usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "trust_me")))]
+ TrustMe(usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "default_trust_me")))]
+ TryMeElse(usize),
+ // arithmetic instruction
+ #[strum_discriminants(strum(props(Arity = "2", Name = "add")))]
+ Add(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "sub")))]
+ Sub(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "mul")))]
+ Mul(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "pow")))]
+ Pow(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "int_pow")))]
+ IntPow(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "i_div")))]
+ IDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "max")))]
+ Max(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "min")))]
+ Min(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "int_floor_div")))]
+ IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "r_div")))]
+ RDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "div")))]
+ Div(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "shl")))]
+ Shl(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "shr")))]
+ Shr(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "xor")))]
+ Xor(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "and")))]
+ And(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "or")))]
+ Or(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "mod")))]
+ Mod(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "rem")))]
+ Rem(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "gcd")))]
+ Gcd(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "sign")))]
+ Sign(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "cos")))]
+ Cos(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "sin")))]
+ Sin(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "tan")))]
+ Tan(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "log")))]
+ Log(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "exp")))]
+ Exp(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "acos")))]
+ ACos(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "asin")))]
+ ASin(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "atan")))]
+ ATan(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "atan2")))]
+ ATan2(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "sqrt")))]
+ Sqrt(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "abs")))]
+ Abs(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "float")))]
+ Float(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "truncate")))]
+ Truncate(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "round")))]
+ Round(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "ceiling")))]
+ Ceiling(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "floor")))]
+ Floor(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "neg")))]
+ Neg(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "plus")))]
+ Plus(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "bitwise_complement")))]
+ BitwiseComplement(ArithmeticTerm, usize),
+ // control instructions
+ #[strum_discriminants(strum(props(Arity = "1", Name = "allocate")))]
+ Allocate(usize), // num_frames.
+ #[strum_discriminants(strum(props(Arity = "0", Name = "deallocate")))]
+ Deallocate,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "jmp_by_call")))]
+ JmpByCall(usize, usize), // arity, relative offset.
+ #[strum_discriminants(strum(props(Arity = "3", Name = "jmp_by_execute")))]
+ JmpByExecute(usize, usize), // arity, relative offset.
+ #[strum_discriminants(strum(props(Arity = "1", Name = "rev_jmp_by")))]
+ RevJmpBy(usize),
+ #[strum_discriminants(strum(props(Arity = "0", Name = "proceed")))]
+ Proceed,
+ // indexing.
+ #[strum_discriminants(strum(props(Arity = "1", Name = "indexing_code")))]
+ IndexingCode(Vec<IndexingLine>),
+ // break from loop instruction.
+ #[strum_discriminants(strum(props(Arity = "0", Name = "break_from_dispatch")))]
+ BreakFromDispatchLoop,
+ // swap the verify attr interrupt instruction with the next control instruction.
+ #[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))]
+ InstallVerifyAttr,
+ // call verify_attrs.
+ #[strum_discriminants(strum(props(Arity = "0", Name = "verify_attr_interrupt")))]
+ VerifyAttrInterrupt,
+ // procedures
+ CallClause(ClauseType, usize, usize, bool, bool), // ClauseType,
+ // arity,
+ // perm_vars,
+ // last_call,
+ // use_default_call_policy.
+}
+
+fn derive_input(ty: &Type) -> Option<DeriveInput> {
+ let clause_type: Type = parse_quote!{ ClauseType };
+ let built_in_clause_type: Type = parse_quote! { BuiltInClauseType };
+ let inlined_clause_type: Type = parse_quote! { InlinedClauseType };
+ let system_clause_type: Type = parse_quote! { SystemClauseType };
+ let compare_term_type: Type = parse_quote! { CompareTerm };
+ let compare_number_type: Type = parse_quote! { CompareNumber };
+ let repl_code_ptr_type: Type = parse_quote! { REPLCodePtr };
+
+ if ty == &clause_type {
+ Some(ClauseType::to_derive_input())
+ } else if ty == &built_in_clause_type {
+ Some(BuiltInClauseType::to_derive_input())
+ } else if ty == &inlined_clause_type {
+ Some(InlinedClauseType::to_derive_input())
+ } else if ty == &system_clause_type {
+ Some(SystemClauseType::to_derive_input())
+ } else if ty == &compare_number_type {
+ Some(CompareNumber::to_derive_input())
+ } else if ty == &compare_term_type {
+ Some(CompareTerm::to_derive_input())
+ } else if ty == &repl_code_ptr_type {
+ Some(REPLCodePtr::to_derive_input())
+ } else {
+ None
+ }
+}
+
+impl ToTokens for Arity {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Arity::Static(arity) => {
+ arity.to_tokens(tokens);
+ }
+ Arity::Ident(arity) => {
+ let ident = format_ident!("{}", arity);
+ tokens.append(ident);
+ }
+ }
+ }
+}
+
+fn add_discriminant_data<DiscriminantT>(
+ variant: &Variant,
+ prefix: &'static str,
+ variant_data: &mut Vec<(&'static str, Arity, Variant)>,
+) -> (&'static str, Arity)
+ where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug
+{
+ let name = prop_from_ident::<DiscriminantT>(&variant.ident, "Name");
+ let arity = Arity::from(prop_from_ident::<DiscriminantT>(&variant.ident, "Arity"));
+
+ if prefix == "Call" {
+ let mut variant = variant.clone();
+ variant.attrs.clear();
+
+ variant_data.push((name, arity, variant));
+ }
+
+ (name, arity)
+}
+
+fn generate_instruction_preface() -> TokenStream {
+ quote! {
+ use crate::arena::*;
+ use crate::arithmetic::*;
+ use crate::atom_table::*;
+ use crate::forms::*;
+ use crate::machine::heap::*;
+ use crate::machine::machine_errors::MachineStub;
+ use crate::machine::machine_indices::CodeIndex;
+ use crate::parser::ast::*;
+ use crate::types::*;
+
+ use indexmap::IndexMap;
+ use slice_deque::SliceDeque;
+
+ use std::collections::VecDeque;
+
+ fn reg_type_into_functor(r: RegType) -> MachineStub {
+ match r {
+ RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]),
+ RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]),
+ }
+ }
+
+ impl Level {
+ fn into_functor(self) -> MachineStub {
+ match self {
+ Level::Root => functor!(atom!("level"), [atom(atom!("root"))]),
+ Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]),
+ Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]),
+ }
+ }
+ }
+
+ impl ArithmeticTerm {
+ fn into_functor(&self, arena: &mut Arena) -> MachineStub {
+ match self {
+ &ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
+ &ArithmeticTerm::Interm(i) => {
+ functor!(atom!("intermediate"), [fixnum(i)])
+ }
+ &ArithmeticTerm::Number(n) => {
+ vec![HeapCellValue::from((n, arena))]
+ }
+ }
+ }
+ }
+
+ #[derive(Debug, Clone, Copy)]
+ pub enum NextOrFail {
+ Next(usize),
+ Fail(usize),
+ }
+
+ impl Default for NextOrFail {
+ fn default() -> Self {
+ NextOrFail::Fail(0)
+ }
+ }
+
+ impl NextOrFail {
+ #[inline]
+ pub fn is_next(&self) -> bool {
+ if let NextOrFail::Next(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+ }
+
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+ pub enum Death {
+ Finite(usize),
+ Infinity,
+ }
+
+ impl Default for Death {
+ fn default() -> Self {
+ Death::Infinity
+ }
+ }
+
+ #[derive(Clone, Copy, Debug)]
+ pub enum IndexedChoiceInstruction {
+ Retry(usize),
+ Trust(usize),
+ Try(usize),
+ }
+
+ impl IndexedChoiceInstruction {
+ pub(crate) fn offset(&self) -> usize {
+ match self {
+ &IndexedChoiceInstruction::Retry(offset) => offset,
+ &IndexedChoiceInstruction::Trust(offset) => offset,
+ &IndexedChoiceInstruction::Try(offset) => offset,
+ }
+ }
+
+ pub(crate) fn to_functor(&self) -> MachineStub {
+ match self {
+ &IndexedChoiceInstruction::Try(offset) => {
+ functor!(atom!("try"), [fixnum(offset)])
+ }
+ &IndexedChoiceInstruction::Trust(offset) => {
+ functor!(atom!("trust"), [fixnum(offset)])
+ }
+ &IndexedChoiceInstruction::Retry(offset) => {
+ functor!(atom!("retry"), [fixnum(offset)])
+ }
+ }
+ }
+ }
+
+ /// `IndexingInstruction` cf. page 110 of wambook.
+ #[derive(Clone, Debug)]
+ pub enum IndexingInstruction {
+ // The first index is the optimal argument being indexed.
+ SwitchOnTerm(
+ usize,
+ IndexingCodePtr,
+ IndexingCodePtr,
+ IndexingCodePtr,
+ IndexingCodePtr,
+ ),
+ SwitchOnConstant(IndexMap<Literal, IndexingCodePtr>),
+ SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>),
+ }
+
+ #[derive(Debug, Clone, Copy)]
+ pub enum IndexingCodePtr {
+ External(usize), // the index points past the indexing instruction prelude.
+ DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction.
+ Fail,
+ Internal(usize), // the index points into the indexing instruction prelude.
+ }
+
+ impl IndexingCodePtr {
+ #[allow(dead_code)]
+ pub fn to_functor(self) -> MachineStub {
+ match self {
+ IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]),
+ IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
+ IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
+ IndexingCodePtr::Fail => {
+ vec![atom_as_cell!(atom!("fail"))]
+ },
+ }
+ }
+ }
+
+ impl IndexingInstruction {
+ pub fn to_functor(&self, mut h: usize) -> MachineStub {
+ match self {
+ &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
+ functor!(
+ atom!("switch_on_term"),
+ [
+ fixnum(arg),
+ indexing_code_ptr(h, vars),
+ indexing_code_ptr(h, constants),
+ indexing_code_ptr(h, lists),
+ indexing_code_ptr(h, structures)
+ ]
+ )
+ }
+ &IndexingInstruction::SwitchOnConstant(ref constants) => {
+ let mut key_value_list_stub = vec![];
+ let orig_h = h;
+
+ h += 2; // skip the 2-cell "switch_on_constant" functor.
+
+ for (c, ptr) in constants.iter() {
+ let key_value_pair = functor!(
+ atom!(":"),
+ [literal(*c), indexing_code_ptr(h + 3, *ptr)]
+ );
+
+ key_value_list_stub.push(list_loc_as_cell!(h + 1));
+ key_value_list_stub.push(str_loc_as_cell!(h + 3));
+ key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len()));
+
+ h += key_value_pair.len() + 3;
+ key_value_list_stub.extend(key_value_pair.into_iter());
+ }
+
+ key_value_list_stub.push(empty_list_as_cell!());
+
+ functor!(
+ atom!("switch_on_constant"),
+ [str(orig_h, 0)],
+ [key_value_list_stub]
+ )
+ }
+ &IndexingInstruction::SwitchOnStructure(ref structures) => {
+ let mut key_value_list_stub = vec![];
+ let orig_h = h;
+
+ h += 2; // skip the 2-cell "switch_on_constant" functor.
+
+ for ((name, arity), ptr) in structures.iter() {
+ let predicate_indicator_stub = functor!(
+ atom!("/"),
+ [atom(name), fixnum(*arity)]
+ );
+
+ let key_value_pair = functor!(
+ atom!(":"),
+ [str(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
+ [predicate_indicator_stub]
+ );
+
+ key_value_list_stub.push(list_loc_as_cell!(h + 1));
+ key_value_list_stub.push(str_loc_as_cell!(h + 3));
+ key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len()));
+
+ h += key_value_pair.len() + 3;
+ key_value_list_stub.extend(key_value_pair.into_iter());
+ }
+
+ key_value_list_stub.push(empty_list_as_cell!());
+
+ functor!(
+ atom!("switch_on_structure"),
+ [str(orig_h, 0)],
+ [key_value_list_stub]
+ )
+ }
+ }
+ }
+ }
+
+ /// A `Line` is an instruction (cf. page 98 of wambook).
+ #[derive(Clone, Debug)]
+ pub enum IndexingLine {
+ Indexing(IndexingInstruction),
+ IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
+ DynamicIndexedChoice(SliceDeque<usize>),
+ }
+
+ impl From<IndexingInstruction> for IndexingLine {
+ #[inline]
+ fn from(instr: IndexingInstruction) -> Self {
+ IndexingLine::Indexing(instr)
+ }
+ }
+
+ impl From<VecDeque<IndexedChoiceInstruction>> for IndexingLine {
+ #[inline]
+ fn from(instrs: VecDeque<IndexedChoiceInstruction>) -> Self {
+ IndexingLine::IndexedChoice(instrs.into_iter().collect())
+ }
+ }
+
+ fn arith_instr_unary_functor(
+ h: usize,
+ name: Atom,
+ arena: &mut Arena,
+ at: &ArithmeticTerm,
+ t: usize,
+ ) -> MachineStub {
+ let at_stub = at.into_functor(arena);
+ functor!(name, [str(h, 0), fixnum(t)], [at_stub])
+ }
+
+ fn arith_instr_bin_functor(
+ h: usize,
+ name: Atom,
+ arena: &mut Arena,
+ at_1: &ArithmeticTerm,
+ at_2: &ArithmeticTerm,
+ t: usize,
+ ) -> MachineStub {
+ let at_1_stub = at_1.into_functor(arena);
+ let at_2_stub = at_2.into_functor(arena);
+
+ functor!(
+ name,
+ [str(h, 0), str(h, 1), fixnum(t)],
+ [at_1_stub, at_2_stub]
+ )
+ }
+
+ pub type Code = Vec<Instruction>;
+
+ impl Instruction {
+ #[inline]
+ pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec<IndexingLine>> {
+ match self {
+ Instruction::IndexingCode(ref mut indexing_code) => Some(indexing_code),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_indexing_line(&self) -> Option<&Vec<IndexingLine>> {
+ match self {
+ Instruction::IndexingCode(ref indexing_code) => Some(indexing_code),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn is_head_instr(&self) -> bool {
+ match self {
+ Instruction::GetConstant(..) |
+ Instruction::GetList(..) |
+ Instruction::GetPartialString(..) |
+ Instruction::GetStructure(..) |
+ Instruction::GetValue(..) |
+ Instruction::UnifyConstant(..) |
+ Instruction::UnifyLocalValue(..) |
+ Instruction::UnifyVariable(..) |
+ Instruction::UnifyValue(..) |
+ Instruction::UnifyVoid(..) |
+ Instruction::GetVariable(..) |
+ Instruction::PutConstant(..) |
+ Instruction::PutList(..) |
+ Instruction::PutPartialString(..) |
+ Instruction::PutStructure(..) |
+ Instruction::PutUnsafeValue(..) |
+ Instruction::PutValue(..) |
+ Instruction::PutVariable(..) |
+ Instruction::SetConstant(..) |
+ Instruction::SetLocalValue(..) |
+ Instruction::SetVariable(..) |
+ Instruction::SetValue(..) |
+ Instruction::SetVoid(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn enqueue_functors(
+ &self,
+ mut h: usize,
+ arena: &mut Arena,
+ functors: &mut Vec<MachineStub>,
+ ) {
+ match self {
+ &Instruction::IndexingCode(ref indexing_instrs) => {
+ for indexing_instr in indexing_instrs {
+ match indexing_instr {
+ IndexingLine::Indexing(indexing_instr) => {
+ let section = indexing_instr.to_functor(h);
+ h += section.len();
+ functors.push(section);
+ }
+ IndexingLine::IndexedChoice(indexed_choice_instrs) => {
+ for indexed_choice_instr in indexed_choice_instrs {
+ let section = indexed_choice_instr.to_functor();
+ h += section.len();
+ functors.push(section);
+ }
+ }
+ IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
+ for indexed_choice_instr in indexed_choice_instrs {
+ let section = functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]);
+
+ h += section.len();
+ functors.push(section);
+ }
+ }
+ }
+ }
+ }
+ instr => functors.push(instr.to_functor(h, arena)),
+ }
+ }
+
+ fn to_functor(&self, h: usize, arena: &mut Arena) -> MachineStub {
+ match self {
+ &Instruction::InstallVerifyAttr => {
+ functor!(atom!("install_verify_attr"))
+ }
+ &Instruction::VerifyAttrInterrupt => {
+ functor!(atom!("verify_attr_interrupt"))
+ }
+ &Instruction::DynamicElse(birth, death, next_or_fail) => {
+ match (death, next_or_fail) {
+ (Death::Infinity, NextOrFail::Next(i)) => {
+ functor!(
+ atom!("dynamic_else"),
+ [fixnum(birth), atom(atom!("inf")), fixnum(i)]
+ )
+ }
+ (Death::Infinity, NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_else"),
+ [fixnum(birth), atom(atom!("inf")), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_else"),
+ [fixnum(birth), fixnum(d), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Next(i)) => {
+ functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)])
+ }
+ }
+ }
+ &Instruction::DynamicInternalElse(birth, death, next_or_fail) => {
+ match (death, next_or_fail) {
+ (Death::Infinity, NextOrFail::Next(i)) => {
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), atom(atom!("inf")), fixnum(i)]
+ )
+ }
+ (Death::Infinity, NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), atom(atom!("inf")), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), fixnum(d), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Next(i)) => {
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), fixnum(d), fixnum(i)]
+ )
+ }
+ }
+ }
+ &Instruction::TryMeElse(offset) => {
+ functor!(atom!("try_me_else"), [fixnum(offset)])
+ }
+ &Instruction::RetryMeElse(offset) => {
+ functor!(atom!("retry_me_else"), [fixnum(offset)])
+ }
+ &Instruction::TrustMe(offset) => {
+ functor!(atom!("trust_me"), [fixnum(offset)])
+ }
+ &Instruction::DefaultRetryMeElse(offset) => {
+ functor!(atom!("default_retry_me_else"), [fixnum(offset)])
+ }
+ &Instruction::DefaultTrustMe(offset) => {
+ functor!(atom!("default_trust_me"), [fixnum(offset)])
+ }
+ &Instruction::Cut(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("cut"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::GetLevel(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_level"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::GetLevelAndUnify(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_level_and_unify"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::NeckCut => {
+ functor!(atom!("neck_cut"))
+ }
+ &Instruction::Add(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t)
+ }
+ &Instruction::Sub(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t)
+ }
+ &Instruction::Mul(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t)
+ }
+ &Instruction::IntPow(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t)
+ }
+ &Instruction::Pow(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t)
+ }
+ &Instruction::IDiv(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t)
+ }
+ &Instruction::Max(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t)
+ }
+ &Instruction::Min(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t)
+ }
+ &Instruction::IntFloorDiv(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t)
+ }
+ &Instruction::RDiv(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t)
+ }
+ &Instruction::Div(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t)
+ }
+ &Instruction::Shl(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t)
+ }
+ &Instruction::Shr(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t)
+ }
+ &Instruction::Xor(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t)
+ }
+ &Instruction::And(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t)
+ }
+ &Instruction::Or(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t)
+ }
+ &Instruction::Mod(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t)
+ }
+ &Instruction::Rem(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
+ }
+ &Instruction::ATan2(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
+ }
+ &Instruction::Gcd(ref at_1, ref at_2, t) => {
+ arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t)
+ }
+ &Instruction::Sign(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("sign"), arena, at, t)
+ }
+ &Instruction::Cos(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("cos"), arena, at, t)
+ }
+ &Instruction::Sin(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("sin"), arena, at, t)
+ }
+ &Instruction::Tan(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("tan"), arena, at, t)
+ }
+ &Instruction::Log(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("log"), arena, at, t)
+ }
+ &Instruction::Exp(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("exp"), arena, at, t)
+ }
+ &Instruction::ACos(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("acos"), arena, at, t)
+ }
+ &Instruction::ASin(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("asin"), arena, at, t)
+ }
+ &Instruction::ATan(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
+ }
+ &Instruction::Sqrt(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
+ }
+ &Instruction::Abs(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
+ }
+ &Instruction::Float(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("float"), arena, at, t)
+ }
+ &Instruction::Truncate(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("truncate"), arena, at, t)
+ }
+ &Instruction::Round(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("round"), arena, at, t)
+ }
+ &Instruction::Ceiling(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t)
+ }
+ &Instruction::Floor(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("floor"), arena, at, t)
+ }
+ &Instruction::Neg(ref at, t) => arith_instr_unary_functor(
+ h,
+ atom!("-"),
+ arena,
+ at,
+ t,
+ ),
+ &Instruction::Plus(ref at, t) => arith_instr_unary_functor(
+ h,
+ atom!("+"),
+ arena,
+ at,
+ t,
+ ),
+ &Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
+ h,
+ atom!("\\"),
+ arena,
+ at,
+ t,
+ ),
+ &Instruction::IndexingCode(_) => {
+ // this case is covered in enqueue_functors, which
+ // should be called instead (to_functor is a private
+ // function for this reason).
+ vec![]
+ }
+ &Instruction::Allocate(num_frames) => {
+ functor!(atom!("allocate"), [fixnum(num_frames)])
+ }
+ &Instruction::CallNamed(arity, name, ..) => {
+ functor!(atom!("call"), [atom(name), fixnum(arity)])
+ }
+ &Instruction::ExecuteNamed(arity, name, ..) => {
+ functor!(atom!("execute"), [atom(name), fixnum(arity)])
+ }
+ &Instruction::DefaultCallNamed(arity, name, ..) => {
+ functor!(atom!("call_default"), [atom(name), fixnum(arity)])
+ }
+ &Instruction::DefaultExecuteNamed(arity, name, ..) => {
+ functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
+ }
+ &Instruction::CallN(arity, _) => {
+ functor!(atom!("call_n"), [fixnum(arity)])
+ }
+ &Instruction::ExecuteN(arity, _) => {
+ functor!(atom!("execute_n"), [fixnum(arity)])
+ }
+ &Instruction::DefaultCallN(arity, _) => {
+ functor!(atom!("call_default_n"), [fixnum(arity)])
+ }
+ &Instruction::DefaultExecuteN(arity, _) => {
+ functor!(atom!("execute_default_n"), [fixnum(arity)])
+ }
+ &Instruction::CallTermGreaterThan(_) |
+ &Instruction::CallTermLessThan(_) |
+ &Instruction::CallTermGreaterThanOrEqual(_) |
+ &Instruction::CallTermLessThanOrEqual(_) |
+ &Instruction::CallTermEqual(_) |
+ &Instruction::CallTermNotEqual(_) |
+ &Instruction::CallNumberGreaterThan(..) |
+ &Instruction::CallNumberLessThan(..) |
+ &Instruction::CallNumberGreaterThanOrEqual(..) |
+ &Instruction::CallNumberLessThanOrEqual(..) |
+ &Instruction::CallNumberEqual(..) |
+ &Instruction::CallNumberNotEqual(..) |
+ &Instruction::CallIs(..) |
+ &Instruction::CallAcyclicTerm(_) |
+ &Instruction::CallArg(_) |
+ &Instruction::CallCompare(_) |
+ &Instruction::CallCopyTerm(_) |
+ &Instruction::CallFunctor(_) |
+ &Instruction::CallGround(_) |
+ &Instruction::CallKeySort(_) |
+ &Instruction::CallRead(_) |
+ &Instruction::CallSort(_) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("call"), [atom(name), fixnum(arity)])
+ }
+ //
+ &Instruction::ExecuteTermGreaterThan(_) |
+ &Instruction::ExecuteTermLessThan(_) |
+ &Instruction::ExecuteTermGreaterThanOrEqual(_) |
+ &Instruction::ExecuteTermLessThanOrEqual(_) |
+ &Instruction::ExecuteTermEqual(_) |
+ &Instruction::ExecuteTermNotEqual(_) |
+ &Instruction::ExecuteNumberGreaterThan(..) |
+ &Instruction::ExecuteNumberLessThan(..) |
+ &Instruction::ExecuteNumberGreaterThanOrEqual(..) |
+ &Instruction::ExecuteNumberLessThanOrEqual(..) |
+ &Instruction::ExecuteNumberEqual(..) |
+ &Instruction::ExecuteNumberNotEqual(..) |
+ &Instruction::ExecuteAcyclicTerm(_) |
+ &Instruction::ExecuteArg(_) |
+ &Instruction::ExecuteCompare(_) |
+ &Instruction::ExecuteCopyTerm(_) |
+ &Instruction::ExecuteFunctor(_) |
+ &Instruction::ExecuteGround(_) |
+ &Instruction::ExecuteIs(..) |
+ &Instruction::ExecuteKeySort(_) |
+ &Instruction::ExecuteRead(_) |
+ &Instruction::ExecuteSort(_) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("execute"), [atom(name), fixnum(arity)])
+ }
+ //
+ &Instruction::DefaultCallTermGreaterThan(_) |
+ &Instruction::DefaultCallTermLessThan(_) |
+ &Instruction::DefaultCallTermGreaterThanOrEqual(_) |
+ &Instruction::DefaultCallTermLessThanOrEqual(_) |
+ &Instruction::DefaultCallTermEqual(_) |
+ &Instruction::DefaultCallTermNotEqual(_) |
+ &Instruction::DefaultCallNumberGreaterThan(..) |
+ &Instruction::DefaultCallNumberLessThan(..) |
+ &Instruction::DefaultCallNumberGreaterThanOrEqual(..) |
+ &Instruction::DefaultCallNumberLessThanOrEqual(..) |
+ &Instruction::DefaultCallNumberEqual(..) |
+ &Instruction::DefaultCallNumberNotEqual(..) |
+ &Instruction::DefaultCallAcyclicTerm(_) |
+ &Instruction::DefaultCallArg(_) |
+ &Instruction::DefaultCallCompare(_) |
+ &Instruction::DefaultCallCopyTerm(_) |
+ &Instruction::DefaultCallFunctor(_) |
+ &Instruction::DefaultCallGround(_) |
+ &Instruction::DefaultCallIs(..) |
+ &Instruction::DefaultCallKeySort(_) |
+ &Instruction::DefaultCallRead(_) |
+ &Instruction::DefaultCallSort(_) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("call_default"), [atom(name), fixnum(arity)])
+ }
+ //
+ &Instruction::DefaultExecuteTermGreaterThan(_) |
+ &Instruction::DefaultExecuteTermLessThan(_) |
+ &Instruction::DefaultExecuteTermGreaterThanOrEqual(_) |
+ &Instruction::DefaultExecuteTermLessThanOrEqual(_) |
+ &Instruction::DefaultExecuteTermEqual(_) |
+ &Instruction::DefaultExecuteTermNotEqual(_) |
+ &Instruction::DefaultExecuteNumberGreaterThan(..) |
+ &Instruction::DefaultExecuteNumberLessThan(..) |
+ &Instruction::DefaultExecuteNumberGreaterThanOrEqual(..) |
+ &Instruction::DefaultExecuteNumberLessThanOrEqual(..) |
+ &Instruction::DefaultExecuteNumberEqual(..) |
+ &Instruction::DefaultExecuteNumberNotEqual(..) |
+ &Instruction::DefaultExecuteAcyclicTerm(_) |
+ &Instruction::DefaultExecuteArg(_) |
+ &Instruction::DefaultExecuteCompare(_) |
+ &Instruction::DefaultExecuteCopyTerm(_) |
+ &Instruction::DefaultExecuteFunctor(_) |
+ &Instruction::DefaultExecuteGround(_) |
+ &Instruction::DefaultExecuteIs(..) |
+ &Instruction::DefaultExecuteKeySort(_) |
+ &Instruction::DefaultExecuteRead(_) |
+ &Instruction::DefaultExecuteSort(_) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
+ }
+ &Instruction::CallIsAtom(_, _) |
+ &Instruction::CallIsAtomic(_, _) |
+ &Instruction::CallIsCompound(_, _) |
+ &Instruction::CallIsInteger(_, _) |
+ &Instruction::CallIsNumber(_, _) |
+ &Instruction::CallIsRational(_, _) |
+ &Instruction::CallIsFloat(_, _) |
+ &Instruction::CallIsNonVar(_, _) |
+ &Instruction::CallIsVar(_, _) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("call"), [atom(name), fixnum(arity)])
+ }
+ &Instruction::ExecuteIsAtom(_, _) |
+ &Instruction::ExecuteIsAtomic(_, _) |
+ &Instruction::ExecuteIsCompound(_, _) |
+ &Instruction::ExecuteIsInteger(_, _) |
+ &Instruction::ExecuteIsNumber(_, _) |
+ &Instruction::ExecuteIsRational(_, _) |
+ &Instruction::ExecuteIsFloat(_, _) |
+ &Instruction::ExecuteIsNonVar(_, _) |
+ &Instruction::ExecuteIsVar(_, _) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("execute"), [atom(name), fixnum(arity)])
+ }
+ //
+ &Instruction::CallAtomChars(_) |
+ &Instruction::CallAtomCodes(_) |
+ &Instruction::CallAtomLength(_) |
+ &Instruction::CallBindFromRegister(_) |
+ &Instruction::CallContinuation(_) |
+ &Instruction::CallCharCode(_) |
+ &Instruction::CallCharType(_) |
+ &Instruction::CallCharsToNumber(_) |
+ &Instruction::CallCodesToNumber(_) |
+ &Instruction::CallCopyTermWithoutAttrVars(_) |
+ &Instruction::CallCheckCutPoint(_) |
+ &Instruction::CallClose(_) |
+ &Instruction::CallCopyToLiftedHeap(_) |
+ &Instruction::CallCreatePartialString(_) |
+ &Instruction::CallCurrentHostname(_) |
+ &Instruction::CallCurrentInput(_) |
+ &Instruction::CallCurrentOutput(_) |
+ &Instruction::CallDirectoryFiles(_) |
+ &Instruction::CallFileSize(_) |
+ &Instruction::CallFileExists(_) |
+ &Instruction::CallDirectoryExists(_) |
+ &Instruction::CallDirectorySeparator(_) |
+ &Instruction::CallMakeDirectory(_) |
+ &Instruction::CallMakeDirectoryPath(_) |
+ &Instruction::CallDeleteFile(_) |
+ &Instruction::CallRenameFile(_) |
+ &Instruction::CallWorkingDirectory(_) |
+ &Instruction::CallDeleteDirectory(_) |
+ &Instruction::CallPathCanonical(_) |
+ &Instruction::CallFileTime(_) |
+ &Instruction::CallDeleteAttribute(_) |
+ &Instruction::CallDeleteHeadAttribute(_) |
+ &Instruction::CallDynamicModuleResolution(..) |
+ &Instruction::CallEnqueueAttributedVar(_) |
+ &Instruction::CallFetchGlobalVar(_) |
+ &Instruction::CallFirstStream(_) |
+ &Instruction::CallFlushOutput(_) |
+ &Instruction::CallGetByte(_) |
+ &Instruction::CallGetChar(_) |
+ &Instruction::CallGetNChars(_) |
+ &Instruction::CallGetCode(_) |
+ &Instruction::CallGetSingleChar(_) |
+ &Instruction::CallResetAttrVarState(_) |
+ &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff(_) |
+ &Instruction::CallTruncateIfNoLiftedHeapGrowth(_) |
+ &Instruction::CallGetAttributedVariableList(_) |
+ &Instruction::CallGetAttrVarQueueDelimiter(_) |
+ &Instruction::CallGetAttrVarQueueBeyond(_) |
+ &Instruction::CallGetBValue(_) |
+ &Instruction::CallGetContinuationChunk(_) |
+ &Instruction::CallGetNextDBRef(_) |
+ &Instruction::CallGetNextOpDBRef(_) |
+ &Instruction::CallIsPartialString(_) |
+ &Instruction::CallHalt(_) |
+ &Instruction::CallGetLiftedHeapFromOffset(_) |
+ &Instruction::CallGetLiftedHeapFromOffsetDiff(_) |
+ &Instruction::CallGetSCCCleaner(_) |
+ &Instruction::CallHeadIsDynamic(_) |
+ &Instruction::CallInstallSCCCleaner(_) |
+ &Instruction::CallInstallInferenceCounter(_) |
+ &Instruction::CallLiftedHeapLength(_) |
+ &Instruction::CallLoadLibraryAsStream(_) |
+ &Instruction::CallModuleExists(_) |
+ &Instruction::CallNextEP(_) |
+ &Instruction::CallNoSuchPredicate(_) |
+ &Instruction::CallNumberToChars(_) |
+ &Instruction::CallNumberToCodes(_) |
+ &Instruction::CallOpDeclaration(_) |
+ &Instruction::CallOpen(_) |
+ &Instruction::CallSetStreamOptions(_) |
+ &Instruction::CallNextStream(_) |
+ &Instruction::CallPartialStringTail(_) |
+ &Instruction::CallPeekByte(_) |
+ &Instruction::CallPeekChar(_) |
+ &Instruction::CallPeekCode(_) |
+ &Instruction::CallPointsToContinuationResetMarker(_) |
+ &Instruction::CallPutByte(_) |
+ &Instruction::CallPutChar(_) |
+ &Instruction::CallPutChars(_) |
+ &Instruction::CallPutCode(_) |
+ &Instruction::CallReadQueryTerm(_) |
+ &Instruction::CallReadTerm(_) |
+ &Instruction::CallRedoAttrVarBinding(_) |
+ &Instruction::CallRemoveCallPolicyCheck(_) |
+ &Instruction::CallRemoveInferenceCounter(_) |
+ &Instruction::CallResetContinuationMarker(_) |
+ &Instruction::CallRestoreCutPolicy(_) |
+ &Instruction::CallSetCutPoint(..) |
+ &Instruction::CallSetInput(_) |
+ &Instruction::CallSetOutput(_) |
+ &Instruction::CallStoreBacktrackableGlobalVar(_) |
+ &Instruction::CallStoreGlobalVar(_) |
+ &Instruction::CallStreamProperty(_) |
+ &Instruction::CallSetStreamPosition(_) |
+ &Instruction::CallInferenceLevel(_) |
+ &Instruction::CallCleanUpBlock(_) |
+ &Instruction::CallEraseBall(_) |
+ &Instruction::CallFail(_) |
+ &Instruction::CallGetBall(_) |
+ &Instruction::CallGetCurrentBlock(_) |
+ &Instruction::CallGetCutPoint(_) |
+ &Instruction::CallGetStaggeredCutPoint(_) |
+ &Instruction::CallGetDoubleQuotes(_) |
+ &Instruction::CallInstallNewBlock(_) |
+ &Instruction::CallMaybe(_) |
+ &Instruction::CallCpuNow(_) |
+ &Instruction::CallCurrentTime(_) |
+ &Instruction::CallQuotedToken(_) |
+ &Instruction::CallReadTermFromChars(_) |
+ &Instruction::CallResetBlock(_) |
+ &Instruction::CallReturnFromVerifyAttr(_) |
+ &Instruction::CallSetBall(_) |
+ &Instruction::CallSetCutPointByDefault(..) |
+ &Instruction::CallSetDoubleQuotes(_) |
+ &Instruction::CallSetSeed(_) |
+ &Instruction::CallSkipMaxList(_) |
+ &Instruction::CallSleep(_) |
+ &Instruction::CallSocketClientOpen(_) |
+ &Instruction::CallSocketServerOpen(_) |
+ &Instruction::CallSocketServerAccept(_) |
+ &Instruction::CallSocketServerClose(_) |
+ &Instruction::CallTLSAcceptClient(_) |
+ &Instruction::CallTLSClientConnect(_) |
+ &Instruction::CallSucceed(_) |
+ &Instruction::CallTermAttributedVariables(_) |
+ &Instruction::CallTermVariables(_) |
+ &Instruction::CallTermVariablesUnderMaxDepth(_) |
+ &Instruction::CallTruncateLiftedHeapTo(_) |
+ &Instruction::CallUnifyWithOccursCheck(_) |
+ &Instruction::CallUnwindEnvironments(_) |
+ &Instruction::CallUnwindStack(_) |
+ &Instruction::CallWAMInstructions(_) |
+ &Instruction::CallWriteTerm(_) |
+ &Instruction::CallWriteTermToChars(_) |
+ &Instruction::CallScryerPrologVersion(_) |
+ &Instruction::CallCryptoRandomByte(_) |
+ &Instruction::CallCryptoDataHash(_) |
+ &Instruction::CallCryptoDataHKDF(_) |
+ &Instruction::CallCryptoPasswordHash(_) |
+ &Instruction::CallCryptoDataEncrypt(_) |
+ &Instruction::CallCryptoDataDecrypt(_) |
+ &Instruction::CallCryptoCurveScalarMult(_) |
+ &Instruction::CallEd25519Sign(_) |
+ &Instruction::CallEd25519Verify(_) |
+ &Instruction::CallEd25519NewKeyPair(_) |
+ &Instruction::CallEd25519KeyPairPublicKey(_) |
+ &Instruction::CallCurve25519ScalarMult(_) |
+ &Instruction::CallFirstNonOctet(_) |
+ &Instruction::CallLoadHTML(_) |
+ &Instruction::CallLoadXML(_) |
+ &Instruction::CallGetEnv(_) |
+ &Instruction::CallSetEnv(_) |
+ &Instruction::CallUnsetEnv(_) |
+ &Instruction::CallShell(_) |
+ &Instruction::CallPID(_) |
+ &Instruction::CallCharsBase64(_) |
+ &Instruction::CallDevourWhitespace(_) |
+ &Instruction::CallIsSTOEnabled(_) |
+ &Instruction::CallSetSTOAsUnify(_) |
+ &Instruction::CallSetNSTOAsUnify(_) |
+ &Instruction::CallSetSTOWithErrorAsUnify(_) |
+ &Instruction::CallHomeDirectory(_) |
+ &Instruction::CallDebugHook(_) |
+ &Instruction::CallAddDiscontiguousPredicate(_) |
+ &Instruction::CallAddDynamicPredicate(_) |
+ &Instruction::CallAddMultifilePredicate(_) |
+ &Instruction::CallAddGoalExpansionClause(_) |
+ &Instruction::CallAddTermExpansionClause(_) |
+ &Instruction::CallAddInSituFilenameModule(_) |
+ &Instruction::CallClauseToEvacuable(_) |
+ &Instruction::CallScopedClauseToEvacuable(_) |
+ &Instruction::CallConcludeLoad(_) |
+ &Instruction::CallDeclareModule(_) |
+ &Instruction::CallLoadCompiledLibrary(_) |
+ &Instruction::CallLoadContextSource(_) |
+ &Instruction::CallLoadContextFile(_) |
+ &Instruction::CallLoadContextDirectory(_) |
+ &Instruction::CallLoadContextModule(_) |
+ &Instruction::CallLoadContextStream(_) |
+ &Instruction::CallPopLoadContext(_) |
+ &Instruction::CallPopLoadStatePayload(_) |
+ &Instruction::CallPushLoadContext(_) |
+ &Instruction::CallPushLoadStatePayload(_) |
+ &Instruction::CallUseModule(_) |
+ &Instruction::CallBuiltInProperty(_) |
+ &Instruction::CallMetaPredicateProperty(_) |
+ &Instruction::CallMultifileProperty(_) |
+ &Instruction::CallDiscontiguousProperty(_) |
+ &Instruction::CallDynamicProperty(_) |
+ &Instruction::CallAbolishClause(_) |
+ &Instruction::CallAsserta(_) |
+ &Instruction::CallAssertz(_) |
+ &Instruction::CallRetract(_) |
+ &Instruction::CallIsConsistentWithTermQueue(_) |
+ &Instruction::CallFlushTermQueue(_) |
+ &Instruction::CallRemoveModuleExports(_) |
+ &Instruction::CallAddNonCountedBacktracking(_) |
+ &Instruction::CallPopCount(_) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("call"), [atom(name), fixnum(arity)])
+ }
+ //
+ &Instruction::ExecuteAtomChars(_) |
+ &Instruction::ExecuteAtomCodes(_) |
+ &Instruction::ExecuteAtomLength(_) |
+ &Instruction::ExecuteBindFromRegister(_) |
+ &Instruction::ExecuteContinuation(_) |
+ &Instruction::ExecuteCharCode(_) |
+ &Instruction::ExecuteCharType(_) |
+ &Instruction::ExecuteCharsToNumber(_) |
+ &Instruction::ExecuteCodesToNumber(_) |
+ &Instruction::ExecuteCopyTermWithoutAttrVars(_) |
+ &Instruction::ExecuteCheckCutPoint(_) |
+ &Instruction::ExecuteClose(_) |
+ &Instruction::ExecuteCopyToLiftedHeap(_) |
+ &Instruction::ExecuteCreatePartialString(_) |
+ &Instruction::ExecuteCurrentHostname(_) |
+ &Instruction::ExecuteCurrentInput(_) |
+ &Instruction::ExecuteCurrentOutput(_) |
+ &Instruction::ExecuteDirectoryFiles(_) |
+ &Instruction::ExecuteFileSize(_) |
+ &Instruction::ExecuteFileExists(_) |
+ &Instruction::ExecuteDirectoryExists(_) |
+ &Instruction::ExecuteDirectorySeparator(_) |
+ &Instruction::ExecuteMakeDirectory(_) |
+ &Instruction::ExecuteMakeDirectoryPath(_) |
+ &Instruction::ExecuteDeleteFile(_) |
+ &Instruction::ExecuteRenameFile(_) |
+ &Instruction::ExecuteWorkingDirectory(_) |
+ &Instruction::ExecuteDeleteDirectory(_) |
+ &Instruction::ExecutePathCanonical(_) |
+ &Instruction::ExecuteFileTime(_) |
+ &Instruction::ExecuteDeleteAttribute(_) |
+ &Instruction::ExecuteDeleteHeadAttribute(_) |
+ &Instruction::ExecuteDynamicModuleResolution(_, _) |
+ &Instruction::ExecuteEnqueueAttributedVar(_) |
+ &Instruction::ExecuteFetchGlobalVar(_) |
+ &Instruction::ExecuteFirstStream(_) |
+ &Instruction::ExecuteFlushOutput(_) |
+ &Instruction::ExecuteGetByte(_) |
+ &Instruction::ExecuteGetChar(_) |
+ &Instruction::ExecuteGetNChars(_) |
+ &Instruction::ExecuteGetCode(_) |
+ &Instruction::ExecuteGetSingleChar(_) |
+ &Instruction::ExecuteResetAttrVarState(_) |
+ &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff(_) |
+ &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth(_) |
+ &Instruction::ExecuteGetAttributedVariableList(_) |
+ &Instruction::ExecuteGetAttrVarQueueDelimiter(_) |
+ &Instruction::ExecuteGetAttrVarQueueBeyond(_) |
+ &Instruction::ExecuteGetBValue(_) |
+ &Instruction::ExecuteGetContinuationChunk(_) |
+ &Instruction::ExecuteGetNextDBRef(_) |
+ &Instruction::ExecuteGetNextOpDBRef(_) |
+ &Instruction::ExecuteIsPartialString(_) |
+ &Instruction::ExecuteHalt(_) |
+ &Instruction::ExecuteGetLiftedHeapFromOffset(_) |
+ &Instruction::ExecuteGetLiftedHeapFromOffsetDiff(_) |
+ &Instruction::ExecuteGetSCCCleaner(_) |
+ &Instruction::ExecuteHeadIsDynamic(_) |
+ &Instruction::ExecuteInstallSCCCleaner(_) |
+ &Instruction::ExecuteInstallInferenceCounter(_) |
+ &Instruction::ExecuteLiftedHeapLength(_) |
+ &Instruction::ExecuteLoadLibraryAsStream(_) |
+ &Instruction::ExecuteModuleExists(_) |
+ &Instruction::ExecuteNextEP(_) |
+ &Instruction::ExecuteNoSuchPredicate(_) |
+ &Instruction::ExecuteNumberToChars(_) |
+ &Instruction::ExecuteNumberToCodes(_) |
+ &Instruction::ExecuteOpDeclaration(_) |
+ &Instruction::ExecuteOpen(_) |
+ &Instruction::ExecuteSetStreamOptions(_) |
+ &Instruction::ExecuteNextStream(_) |
+ &Instruction::ExecutePartialStringTail(_) |
+ &Instruction::ExecutePeekByte(_) |
+ &Instruction::ExecutePeekChar(_) |
+ &Instruction::ExecutePeekCode(_) |
+ &Instruction::ExecutePointsToContinuationResetMarker(_) |
+ &Instruction::ExecutePutByte(_) |
+ &Instruction::ExecutePutChar(_) |
+ &Instruction::ExecutePutChars(_) |
+ &Instruction::ExecutePutCode(_) |
+ &Instruction::ExecuteReadQueryTerm(_) |
+ &Instruction::ExecuteReadTerm(_) |
+ &Instruction::ExecuteRedoAttrVarBinding(_) |
+ &Instruction::ExecuteRemoveCallPolicyCheck(_) |
+ &Instruction::ExecuteRemoveInferenceCounter(_) |
+ &Instruction::ExecuteResetContinuationMarker(_) |
+ &Instruction::ExecuteRestoreCutPolicy(_) |
+ &Instruction::ExecuteSetCutPoint(_, _) |
+ &Instruction::ExecuteSetInput(_) |
+ &Instruction::ExecuteSetOutput(_) |
+ &Instruction::ExecuteStoreBacktrackableGlobalVar(_) |
+ &Instruction::ExecuteStoreGlobalVar(_) |
+ &Instruction::ExecuteStreamProperty(_) |
+ &Instruction::ExecuteSetStreamPosition(_) |
+ &Instruction::ExecuteInferenceLevel(_) |
+ &Instruction::ExecuteCleanUpBlock(_) |
+ &Instruction::ExecuteEraseBall(_) |
+ &Instruction::ExecuteFail(_) |
+ &Instruction::ExecuteGetBall(_) |
+ &Instruction::ExecuteGetCurrentBlock(_) |
+ &Instruction::ExecuteGetCutPoint(_) |
+ &Instruction::ExecuteGetStaggeredCutPoint(_) |
+ &Instruction::ExecuteGetDoubleQuotes(_) |
+ &Instruction::ExecuteInstallNewBlock(_) |
+ &Instruction::ExecuteMaybe(_) |
+ &Instruction::ExecuteCpuNow(_) |
+ &Instruction::ExecuteCurrentTime(_) |
+ &Instruction::ExecuteQuotedToken(_) |
+ &Instruction::ExecuteReadTermFromChars(_) |
+ &Instruction::ExecuteResetBlock(_) |
+ &Instruction::ExecuteReturnFromVerifyAttr(_) |
+ &Instruction::ExecuteSetBall(_) |
+ &Instruction::ExecuteSetCutPointByDefault(_, _) |
+ &Instruction::ExecuteSetDoubleQuotes(_) |
+ &Instruction::ExecuteSetSeed(_) |
+ &Instruction::ExecuteSkipMaxList(_) |
+ &Instruction::ExecuteSleep(_) |
+ &Instruction::ExecuteSocketClientOpen(_) |
+ &Instruction::ExecuteSocketServerOpen(_) |
+ &Instruction::ExecuteSocketServerAccept(_) |
+ &Instruction::ExecuteSocketServerClose(_) |
+ &Instruction::ExecuteTLSAcceptClient(_) |
+ &Instruction::ExecuteTLSClientConnect(_) |
+ &Instruction::ExecuteSucceed(_) |
+ &Instruction::ExecuteTermAttributedVariables(_) |
+ &Instruction::ExecuteTermVariables(_) |
+ &Instruction::ExecuteTermVariablesUnderMaxDepth(_) |
+ &Instruction::ExecuteTruncateLiftedHeapTo(_) |
+ &Instruction::ExecuteUnifyWithOccursCheck(_) |
+ &Instruction::ExecuteUnwindEnvironments(_) |
+ &Instruction::ExecuteUnwindStack(_) |
+ &Instruction::ExecuteWAMInstructions(_) |
+ &Instruction::ExecuteWriteTerm(_) |
+ &Instruction::ExecuteWriteTermToChars(_) |
+ &Instruction::ExecuteScryerPrologVersion(_) |
+ &Instruction::ExecuteCryptoRandomByte(_) |
+ &Instruction::ExecuteCryptoDataHash(_) |
+ &Instruction::ExecuteCryptoDataHKDF(_) |
+ &Instruction::ExecuteCryptoPasswordHash(_) |
+ &Instruction::ExecuteCryptoDataEncrypt(_) |
+ &Instruction::ExecuteCryptoDataDecrypt(_) |
+ &Instruction::ExecuteCryptoCurveScalarMult(_) |
+ &Instruction::ExecuteEd25519Sign(_) |
+ &Instruction::ExecuteEd25519Verify(_) |
+ &Instruction::ExecuteEd25519NewKeyPair(_) |
+ &Instruction::ExecuteEd25519KeyPairPublicKey(_) |
+ &Instruction::ExecuteCurve25519ScalarMult(_) |
+ &Instruction::ExecuteFirstNonOctet(_) |
+ &Instruction::ExecuteLoadHTML(_) |
+ &Instruction::ExecuteLoadXML(_) |
+ &Instruction::ExecuteGetEnv(_) |
+ &Instruction::ExecuteSetEnv(_) |
+ &Instruction::ExecuteUnsetEnv(_) |
+ &Instruction::ExecuteShell(_) |
+ &Instruction::ExecutePID(_) |
+ &Instruction::ExecuteCharsBase64(_) |
+ &Instruction::ExecuteDevourWhitespace(_) |
+ &Instruction::ExecuteIsSTOEnabled(_) |
+ &Instruction::ExecuteSetSTOAsUnify(_) |
+ &Instruction::ExecuteSetNSTOAsUnify(_) |
+ &Instruction::ExecuteSetSTOWithErrorAsUnify(_) |
+ &Instruction::ExecuteHomeDirectory(_) |
+ &Instruction::ExecuteDebugHook(_) |
+ &Instruction::ExecuteAddDiscontiguousPredicate(_) |
+ &Instruction::ExecuteAddDynamicPredicate(_) |
+ &Instruction::ExecuteAddMultifilePredicate(_) |
+ &Instruction::ExecuteAddGoalExpansionClause(_) |
+ &Instruction::ExecuteAddTermExpansionClause(_) |
+ &Instruction::ExecuteAddInSituFilenameModule(_) |
+ &Instruction::ExecuteClauseToEvacuable(_) |
+ &Instruction::ExecuteScopedClauseToEvacuable(_) |
+ &Instruction::ExecuteConcludeLoad(_) |
+ &Instruction::ExecuteDeclareModule(_) |
+ &Instruction::ExecuteLoadCompiledLibrary(_) |
+ &Instruction::ExecuteLoadContextSource(_) |
+ &Instruction::ExecuteLoadContextFile(_) |
+ &Instruction::ExecuteLoadContextDirectory(_) |
+ &Instruction::ExecuteLoadContextModule(_) |
+ &Instruction::ExecuteLoadContextStream(_) |
+ &Instruction::ExecutePopLoadContext(_) |
+ &Instruction::ExecutePopLoadStatePayload(_) |
+ &Instruction::ExecutePushLoadContext(_) |
+ &Instruction::ExecutePushLoadStatePayload(_) |
+ &Instruction::ExecuteUseModule(_) |
+ &Instruction::ExecuteBuiltInProperty(_) |
+ &Instruction::ExecuteMetaPredicateProperty(_) |
+ &Instruction::ExecuteMultifileProperty(_) |
+ &Instruction::ExecuteDiscontiguousProperty(_) |
+ &Instruction::ExecuteDynamicProperty(_) |
+ &Instruction::ExecuteAbolishClause(_) |
+ &Instruction::ExecuteAsserta(_) |
+ &Instruction::ExecuteAssertz(_) |
+ &Instruction::ExecuteRetract(_) |
+ &Instruction::ExecuteIsConsistentWithTermQueue(_) |
+ &Instruction::ExecuteFlushTermQueue(_) |
+ &Instruction::ExecuteRemoveModuleExports(_) |
+ &Instruction::ExecuteAddNonCountedBacktracking(_) |
+ &Instruction::ExecutePopCount(_) => {
+ let (name, arity) = self.to_name_and_arity();
+ functor!(atom!("execute"), [atom(name), fixnum(arity)])
+ }
+ //
+ &Instruction::Deallocate => {
+ functor!(atom!("deallocate"))
+ }
+ &Instruction::JmpByCall(_, offset, ..) => {
+ functor!(atom!("jmp_by_call"), [fixnum(offset)])
+ }
+ &Instruction::JmpByExecute(_, offset, ..) => {
+ functor!(atom!("jmp_by_execute"), [fixnum(offset)])
+ }
+ &Instruction::RevJmpBy(offset) => {
+ functor!(atom!("rev_jmp_by"), [fixnum(offset)])
+ }
+ &Instruction::Proceed => {
+ functor!(atom!("proceed"))
+ }
+ &Instruction::GetConstant(lvl, c, r) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("get_constant"),
+ [str(h, 0), cell(c), str(h, 1)],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::GetList(lvl, r) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("get_list"),
+ [str(h, 0), str(h, 1)],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::GetPartialString(lvl, s, r, has_tail) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("get_partial_string"),
+ [
+ str(h, 0),
+ string(h, s),
+ str(h, 1),
+ boolean(has_tail)
+ ],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::GetStructure(name, arity, r) => {
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("get_structure"),
+ [atom(name), fixnum(arity), str(h, 0)],
+ [rt_stub]
+ )
+ }
+ &Instruction::GetValue(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::GetVariable(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::UnifyConstant(c) => {
+ functor!(atom!("unify_constant"), [cell(c)])
+ }
+ &Instruction::UnifyLocalValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::UnifyVariable(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::UnifyValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("unify_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::UnifyVoid(vars) => {
+ functor!(atom!("unify_void"), [fixnum(vars)])
+ }
+ &Instruction::PutUnsafeValue(norm, arg) => {
+ functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)])
+ }
+ &Instruction::PutConstant(lvl, c, r) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_constant"),
+ [str(h, 0), cell(c), str(h, 1)],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::PutList(lvl, r) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_list"),
+ [str(h, 0), str(h, 1)],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::PutPartialString(lvl, s, r, has_tail) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_partial_string"),
+ [
+ str(h, 0),
+ string(h, s),
+ str(h, 1),
+ boolean(has_tail)
+ ],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::PutStructure(name, arity, r) => {
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_structure"),
+ [atom(name), fixnum(arity), str(h, 0)],
+ [rt_stub]
+ )
+ }
+ &Instruction::PutValue(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::PutVariable(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::SetConstant(c) => {
+ functor!(atom!("set_constant"), [cell(c)])
+ }
+ &Instruction::SetLocalValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::SetVariable(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("set_variable"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::SetValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("set_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::SetVoid(vars) => {
+ functor!(atom!("set_void"), [fixnum(vars)])
+ }
+ &Instruction::BreakFromDispatchLoop => {
+ functor!(atom!("$break_from_dispatch_loop"))
+ }
+ }
+ }
+ }
+ }
+}
+
+pub fn generate_instructions_rs() -> TokenStream {
+ let input = InstructionTemplate::to_derive_input();
+ let mut instr_data = InstructionData::new();
+
+ instr_data.generate_instruction_enum_loop(input);
+
+ let instr_variants: Vec<_> = instr_data.instr_variants
+ .iter()
+ .cloned()
+ .map(|(_, _, _, variant)| variant)
+ .collect();
+
+ fn attributeless_enum<T: ToDeriveInput>() -> Vec<Variant> {
+ if let Data::Enum(DataEnum { mut variants, .. }) = T::to_derive_input().data {
+ for variant in &mut variants {
+ variant.attrs.clear();
+ }
+
+ variants.into_iter().collect()
+ } else {
+ unreachable!()
+ }
+ }
+
+ let clause_type_variants = attributeless_enum::<ClauseType>();
+ let builtin_type_variants = attributeless_enum::<BuiltInClauseType>();
+ let inlined_type_variants = attributeless_enum::<InlinedClauseType>();
+ let system_clause_type_variants = attributeless_enum::<SystemClauseType>();
+ let repl_code_ptr_variants = attributeless_enum::<REPLCodePtr>();
+ let compare_number_variants = attributeless_enum::<CompareNumber>();
+ let compare_term_variants = attributeless_enum::<CompareTerm>();
+
+ let mut clause_type_from_name_and_arity_arms = vec![];
+ let mut clause_type_to_instr_arms = vec![];
+ let mut clause_type_name_arms = vec![];
+
+ for (name, arity, variant) in instr_data.compare_number_variants {
+ let ident = variant.ident.clone();
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::Inlined(
+ InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#variant_fields),*))
+ )
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::Inlined(
+ InlinedClauseType::CompareNumber(CompareNumber::#ident)
+ )
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::CompareNumber(CompareNumber::#ident(..))
+ ) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::CompareNumber(CompareNumber::#ident)
+ ) => (atom!(#name), #arity)
+ }
+ });
+
+ let ident = variant.ident;
+ let instr_ident = format_ident!("Call{}", ident);
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#placeholder_ids),*))
+ ) => Instruction::#instr_ident(#(#placeholder_ids),*, 0)
+ }
+ );
+ }
+
+ for (name, arity, variant) in instr_data.compare_term_variants {
+ let ident = variant.ident.clone();
+
+ clause_type_from_name_and_arity_arms.push(quote! {
+ (atom!(#name), #arity) => ClauseType::BuiltIn(
+ BuiltInClauseType::CompareTerm(CompareTerm::#ident)
+ )
+ });
+
+ clause_type_name_arms.push(
+ quote! {
+ ClauseType::BuiltIn(
+ BuiltInClauseType::CompareTerm(CompareTerm::#ident)
+ ) => atom!(#name)
+ }
+ );
+
+ let ident = variant.ident;
+ let instr_ident = format_ident!("Call{}", ident);
+
+ clause_type_to_instr_arms.push(
+ quote! {
+ ClauseType::BuiltIn(
+ BuiltInClauseType::CompareTerm(CompareTerm::#ident)
+ ) => Instruction::#instr_ident(0)
+ }
+ );
+ }
+
+ for (name, arity, variant) in instr_data.builtin_type_variants {
+ let ident = variant.ident.clone();
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::BuiltIn(
+ BuiltInClauseType::#ident(#(#variant_fields),*)
+ )
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::BuiltIn(
+ BuiltInClauseType::#ident
+ )
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::BuiltIn(
+ BuiltInClauseType::#ident(..)
+ ) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::BuiltIn(
+ BuiltInClauseType::#ident
+ ) => atom!(#name)
+ }
+ });
+
+ let ident = variant.ident;
+ let instr_ident = format_ident!("Call{}", ident);
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::BuiltIn(
+ BuiltInClauseType::#ident(#(#placeholder_ids),*)
+ ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+ }
+ } else {
+ quote! {
+ ClauseType::BuiltIn(
+ BuiltInClauseType::#ident
+ ) => Instruction::#instr_ident(0)
+ }
+ });
+ }
+
+ for (name, arity, variant) in instr_data.inlined_type_variants {
+ let ident = variant.ident.clone();
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ if field.ty.type_id() == TypeId::of::<usize>() {
+ quote! { #arity }
+ } else {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::Inlined(
+ InlinedClauseType::#ident(#(#variant_fields),*)
+ )
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::Inlined(
+ InlinedClauseType::#ident
+ )
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::#ident(..)
+ ) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::#ident
+ ) => atom!(#name)
+ }
+ });
+
+ let ident = variant.ident;
+ let instr_ident = format_ident!("Call{}", ident);
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::#ident(#(#placeholder_ids),*)
+ ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+ }
+ );
+ }
+
+ for (name, arity, variant) in instr_data.system_clause_type_variants {
+ let ident = variant.ident.clone();
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ if field.ty == parse_quote! { usize } {
+ quote! { #arity }
+ } else {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ if ident.to_string() == "SetCutPoint" {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(
+ SystemClauseType::#ident(temp_v!(1))
+ )
+ }
+ } else if ident.to_string() == "SetCutPointByDefault" {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(
+ SystemClauseType::#ident(temp_v!(1))
+ )
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(
+ SystemClauseType::#ident(#(#variant_fields),*)
+ )
+ }
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(
+ SystemClauseType::#ident
+ )
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::#ident(..)
+ ) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::#ident
+ ) => atom!(#name)
+ }
+ });
+
+ let ident = variant.ident;
+ let instr_ident = if ident != "CallContinuation" {
+ format_ident!("Call{}", ident)
+ } else {
+ ident.clone()
+ };
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::#ident(#(#placeholder_ids),*)
+ ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+ }
+ } else {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::#ident
+ ) => Instruction::#instr_ident(0)
+ }
+ });
+ }
+
+ for (name, arity, variant) in instr_data.repl_code_ptr_variants {
+ let ident = variant.ident.clone();
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ if field.ty.type_id() == TypeId::of::<usize>() {
+ quote! { #arity }
+ } else {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident(#(#variant_fields),*)
+ ))
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident
+ ))
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::REPL(REPLCodePtr::#ident(..))
+ ) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::REPL(REPLCodePtr::#ident)
+ ) => atom!(#name)
+ }
+ });
+
+ let ident = variant.ident;
+ let instr_ident = format_ident!("Call{}", ident);
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident(#(#placeholder_ids),*)
+ )) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+ }
+ } else {
+ quote! {
+ ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident
+ )) => Instruction::#instr_ident(0)
+ }
+ });
+ }
+
+ for (name, arity, variant) in instr_data.clause_type_variants {
+ let ident = variant.ident.clone();
+
+ if ident == "Named" {
+ clause_type_from_name_and_arity_arms.push(quote! {
+ (name, arity) => ClauseType::Named(arity, name, CodeIndex::default())
+ });
+
+ clause_type_to_instr_arms.push(quote! {
+ ClauseType::Named(arity, name, idx) => Instruction::CallNamed(arity, name, idx, 0)
+ });
+
+ clause_type_name_arms.push(quote! {
+ ClauseType::Named(_, name, _) => *name
+ });
+
+ continue;
+ }
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ if field.ty == parse_quote! { usize } {
+ quote! { #arity }
+ } else {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::#ident(#(#variant_fields),*)
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::#ident
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::#ident(..) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::#ident => atom!(#name)
+ }
+ });
+
+ let ident = variant.ident;
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::#ident(#(#placeholder_ids),*) =>
+ Instruction::#ident(#(#placeholder_ids),*,0)
+ }
+ } else {
+ quote! {
+ ClauseType::#ident => Instruction::#ident(0)
+ }
+ });
+ }
+
+ let to_execute_arms: Vec<_> = instr_data.instr_variants
+ .iter()
+ .cloned()
+ .filter_map(|(_, _, _, variant)| {
+ let variant_ident = variant.ident.clone();
+ let variant_string = variant.ident.to_string();
+
+ let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+ fields.unnamed.len()
+ } else {
+ 0
+ };
+
+ let placeholder_ids: Vec<_> = (0 .. enum_arity)
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ if variant_string.starts_with("Call") {
+ let execute_ident = format_ident!("Execute{}", variant_string["Call".len() ..]);
+
+ Some(if enum_arity == 0 {
+ quote! {
+ Instruction::#variant_ident =>
+ Instruction::#execute_ident
+ }
+ } else {
+ quote! {
+ Instruction::#variant_ident(#(#placeholder_ids),*) =>
+ Instruction::#execute_ident(#(#placeholder_ids),*)
+ }
+ })
+ } else if variant_string.starts_with("DefaultCall") {
+ let execute_ident =
+ format_ident!("DefaultExecute{}", variant_string["DefaultCall".len() ..]);
+
+ Some(if enum_arity == 0 {
+ quote! {
+ Instruction::#variant_ident =>
+ Instruction::#execute_ident
+ }
+ } else {
+ quote! {
+ Instruction::#variant_ident(#(#placeholder_ids),*) =>
+ Instruction::#execute_ident(#(#placeholder_ids),*)
+ }
+ })
+ } else if variant_string == "JmpByCall" {
+ Some(quote! {
+ Instruction::JmpByCall(#(#placeholder_ids),*) =>
+ Instruction::JmpByExecute(#(#placeholder_ids),*)
+ })
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ let is_execute_arms: Vec<_> = instr_data.instr_variants
+ .iter()
+ .cloned()
+ .filter_map(|(_, _, _, variant)| {
+ let variant_ident = variant.ident.clone();
+ let variant_string = variant.ident.to_string();
+
+ let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+ fields.unnamed.len()
+ } else {
+ 0
+ };
+
+ if variant_string.starts_with("Execute") {
+ Some(if enum_arity == 0 {
+ quote! {
+ Instruction::#variant_ident => true
+ }
+ } else {
+ quote! {
+ Instruction::#variant_ident(..) => true
+ }
+ })
+ } else if variant_string.starts_with("DefaultExecute") {
+ Some(if enum_arity == 0 {
+ quote! {
+ Instruction::#variant_ident => true
+ }
+ } else {
+ quote! {
+ Instruction::#variant_ident(..) => true
+ }
+ })
+ } else if variant_string == "JmpByExecute" {
+ Some(quote! {
+ Instruction::#variant_ident(..) => true
+ })
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ let to_default_arms: Vec<_> = instr_data.instr_variants
+ .iter()
+ .cloned()
+ .filter_map(|(_, _, countable_inference, variant)| {
+ if !is_non_default_callable(&variant.ident) {
+ return None;
+ }
+
+ if let CountableInference::HasDefault = countable_inference {
+ let variant_ident = variant.ident.clone();
+ let def_variant_ident = format_ident!("Default{}", variant.ident);
+ let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+ fields.unnamed.len()
+ } else {
+ unreachable!()
+ };
+
+ let placeholder_ids: Vec<_> = (0 .. enum_arity)
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ Some(quote! {
+ Instruction::#variant_ident(#(#placeholder_ids),*) =>
+ Instruction::#def_variant_ident(#(#placeholder_ids),*)
+ })
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ let perm_vars_mut_arms: Vec<_> = instr_data.instr_variants
+ .iter()
+ .cloned()
+ .filter_map(|(_, _, _, variant)| {
+ if !is_callable(&variant.ident) && !is_jmp(&variant.ident) {
+ return None;
+ }
+
+ let variant_ident = variant.ident.clone();
+ let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+ fields.unnamed.len()
+ } else {
+ 0
+ };
+
+ let placeholder_ids: Vec<_> = (1 .. enum_arity)
+ .map(|_| format_ident!("_"))
+ .collect();
+
+ Some(if enum_arity == 1 {
+ quote! {
+ Instruction::#variant_ident(ref mut perm_vars) => Some(perm_vars)
+ }
+ } else {
+ quote! {
+ Instruction::#variant_ident(#(#placeholder_ids),*, ref mut perm_vars) =>
+ Some(perm_vars)
+ }
+ })
+ })
+ .collect();
+
+ let control_flow_arms: Vec<_> = instr_data.instr_variants
+ .iter()
+ .cloned()
+ .filter_map(|(_, _, _, variant)| {
+ if !is_callable(&variant.ident) && !is_jmp(&variant.ident) {
+ return None;
+ }
+
+ let variant_ident = variant.ident.clone();
+
+ Some(quote! {
+ Instruction::#variant_ident(..) => true
+ })
+ })
+ .collect();
+
+ let instr_macro_arms: Vec<_> = instr_data.instr_variants
+ .iter()
+ .rev() // produce default, execute & default & execute cases first.
+ .cloned()
+ .filter_map(|(name, arity, _, variant)| {
+ let variant_ident = variant.ident.clone();
+ let variant_string = variant.ident.to_string();
+ let arity = match arity {
+ Arity::Static(arity) => arity,
+ _ => 1
+ };
+
+ Some(if variant_string.starts_with("Execute") {
+ quote! {
+ (#name, execute, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ } else if variant_string.starts_with("Call") {
+ quote! {
+ (#name, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ } else if variant_string.starts_with("DefaultExecute") {
+ quote! {
+ (#name, execute, default, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ } else if variant_string.starts_with("DefaultCall") {
+ quote! {
+ (#name, default, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ } else {
+ if arity == 0 {
+ quote! {
+ (#name) => {
+ Instruction::#variant_ident
+ }
+ }
+ } else {
+ quote! {
+ (#name, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ }
+ })
+ })
+ .collect();
+
+ let name_and_arity_arms: Vec<_> = instr_data.instr_variants
+ .into_iter()
+ .map(|(name,arity,_,variant)| {
+ let ident = &variant.ident;
+
+ let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+ fields.unnamed.len()
+ } else {
+ 0
+ };
+
+ match arity {
+ Arity::Static(_) if enum_arity == 0 => {
+ quote! { &Instruction::#ident => (atom!(#name), #arity) }
+ }
+ Arity::Static(_) => {
+ quote! { &Instruction::#ident(..) => (atom!(#name), #arity) }
+ }
+ Arity::Ident(_) if enum_arity == 0 => {
+ quote! { &Instruction::#ident(#arity) => (atom!(#name), #arity) }
+ }
+ Arity::Ident(_) => {
+ quote! { &Instruction::#ident(#arity, ..) => (atom!(#name), #arity) }
+ }
+ }
+ })
+ .collect();
+
+ let preface_tokens = generate_instruction_preface();
+
+ quote! {
+ #preface_tokens
+
+ #[derive(Clone, Debug)]
+ pub enum CompareTerm {
+ #(
+ #compare_term_variants,
+ )*
+ }
+
+ #[derive(Clone, Copy, Debug)]
+ pub enum CompareNumber {
+ #(
+ #compare_number_variants,
+ )*
+ }
+
+ impl CompareNumber {
+ pub fn set_terms(&mut self, l_at_1: ArithmeticTerm, l_at_2: ArithmeticTerm) {
+ match self {
+ CompareNumber::NumberGreaterThan(ref mut at_1, ref mut at_2) |
+ CompareNumber::NumberLessThan(ref mut at_1, ref mut at_2) |
+ CompareNumber::NumberGreaterThanOrEqual(ref mut at_1, ref mut at_2) |
+ CompareNumber::NumberLessThanOrEqual(ref mut at_1, ref mut at_2) |
+ CompareNumber::NumberNotEqual(ref mut at_1, ref mut at_2) |
+ CompareNumber::NumberEqual(ref mut at_1, ref mut at_2) => {
+ *at_1 = l_at_1;
+ *at_2 = l_at_2;
+ }
+ }
+ }
+ }
+
+ #[derive(Clone, Debug)]
+ pub enum BuiltInClauseType {
+ #(
+ #builtin_type_variants,
+ )*
+ }
+
+ #[derive(Clone, Debug)]
+ pub enum InlinedClauseType {
+ #(
+ #inlined_type_variants,
+ )*
+ }
+
+ #[derive(Clone, Debug)]
+ pub enum SystemClauseType {
+ #(
+ #system_clause_type_variants,
+ )*
+ }
+
+ #[derive(Clone, Debug)]
+ pub enum REPLCodePtr {
+ #(
+ #repl_code_ptr_variants,
+ )*
+ }
+
+ #[derive(Clone, Debug)]
+ pub enum ClauseType {
+ #(
+ #clause_type_variants,
+ )*
+ }
+
+ impl ClauseType {
+ pub fn from(name: Atom, arity: usize) -> ClauseType {
+ match (name, arity) {
+ #(
+ #clause_type_from_name_and_arity_arms,
+ )*
+ }
+ }
+
+ pub fn to_instr(self) -> Instruction {
+ match self {
+ #(
+ #clause_type_to_instr_arms,
+ )*
+ }
+ }
+
+ pub fn is_builtin(&self) -> bool {
+ if let ClauseType::BuiltIn(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn is_inlined(&self) -> bool {
+ if let ClauseType::Inlined(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn name(&self) -> Atom {
+ match self {
+ #(
+ #clause_type_name_arms,
+ )*
+ }
+ }
+ }
+
+ #[derive(Clone, Debug)]
+ pub enum Instruction {
+ #(
+ #instr_variants,
+ )*
+ }
+
+ impl Instruction {
+ pub fn to_name_and_arity(&self) -> (Atom, usize) {
+ match self {
+ #(
+ #name_and_arity_arms,
+ )*
+ }
+ }
+
+ pub fn to_default(self) -> Instruction {
+ match self {
+ #(
+ #to_default_arms,
+ )*
+ _ => self,
+ }
+ }
+
+ pub fn to_execute(self) -> Instruction {
+ match self {
+ #(
+ #to_execute_arms,
+ )*
+ _ => self
+ }
+ }
+
+ pub fn is_execute(&self) -> bool {
+ match self {
+ #(
+ #is_execute_arms,
+ )*
+ _ => false,
+ }
+ }
+
+ pub fn perm_vars_mut(&mut self) -> Option<&mut usize> {
+ match self {
+ #(
+ #perm_vars_mut_arms,
+ )*
+ _ => None,
+ }
+ }
+
+ pub fn is_ctrl_instr(&self) -> bool {
+ match self {
+ &Instruction::Allocate(_) |
+ &Instruction::Deallocate |
+ &Instruction::Proceed |
+ &Instruction::RevJmpBy(_) => true,
+ #(
+ #control_flow_arms,
+ )*
+ _ => false,
+ }
+ }
+
+ pub fn is_query_instr(&self) -> bool {
+ match self {
+ &Instruction::GetVariable(..) |
+ &Instruction::PutConstant(..) |
+ &Instruction::PutList(..) |
+ &Instruction::PutPartialString(..) |
+ &Instruction::PutStructure(..) |
+ &Instruction::PutUnsafeValue(..) |
+ &Instruction::PutValue(..) |
+ &Instruction::PutVariable(..) |
+ &Instruction::SetConstant(..) |
+ &Instruction::SetLocalValue(..) |
+ &Instruction::SetVariable(..) |
+ &Instruction::SetValue(..) |
+ &Instruction::SetVoid(..) => true,
+ _ => false,
+ }
+ }
+ }
+
+ #[macro_export]
+ macro_rules! _instr {
+ #(
+ #instr_macro_arms
+ );*
+ }
+
+ pub use _instr as instr; // https://github.com/rust-lang/rust/pull/52234#issuecomment-976702997
+ }
+}
+
+fn is_callable(id: &Ident) -> bool {
+ let id = id.to_string();
+
+ id.starts_with("Call") || id.starts_with("Execute") || id.starts_with("DefaultCall") ||
+ id.starts_with("DefaultExecute")
+}
+
+fn is_non_default_callable(id: &Ident) -> bool {
+ let id = id.to_string();
+ id.starts_with("Call") || id.starts_with("Execute")
+}
+
+fn is_jmp(id: &Ident) -> bool {
+ let id = id.to_string();
+ id.starts_with("JmpByCall") || id.starts_with("JmpByExecute")
+}
+
+fn create_instr_variant(id: Ident, mut variant: Variant) -> Variant {
+ use proc_macro2::Span;
+ use syn::punctuated::Punctuated;
+ use syn::token::Paren;
+
+ // add the perm_vars usize field to the variant.
+
+ if is_callable(&id) || is_jmp(&id) {
+ let field = Field {
+ attrs: vec![],
+ vis: Visibility::Inherited,
+ ident: None,
+ colon_token: None,
+ ty: parse_quote! { usize },
+ };
+
+ match &mut variant.fields {
+ Fields::Unnamed(ref mut fields) => {
+ fields.unnamed.push(field);
+ }
+ Fields::Unit => {
+ variant.fields = Fields::Unnamed(FieldsUnnamed {
+ paren_token: Paren(Span::call_site()),
+ unnamed: {
+ let mut fields_seq = Punctuated::new();
+ fields_seq.push(field);
+ fields_seq
+ }
+ });
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+ }
+
+ variant.ident = id;
+ variant.attrs.clear();
+
+ variant
+}
+
+fn prop_from_ident<DiscriminantT>(id: &Ident, key: &'static str) -> &'static str
+ where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug
+{
+ let disc = match DiscriminantT::from_str(id.to_string().as_str()) {
+ Ok(disc) => disc,
+ Err(_) => {
+ panic!("can't generate discriminant {}", id);
+ }
+ };
+
+ match disc.get_str(key) {
+ Some(prop) => prop,
+ None => {
+ panic!("can't find property {} of discriminant {:?}", key, disc);
+ }
+ }
+}
+
+#[derive(Clone, Copy)]
+enum Arity {
+ Static(usize),
+ Ident(&'static str)
+}
+
+impl From<&'static str> for Arity {
+ fn from(arity: &'static str) -> Self {
+ usize::from_str_radix(&arity, 10)
+ .map(|n| Arity::Static(n))
+ .unwrap_or_else(|_| Arity::Ident(arity))
+ }
+}
+
+#[derive(Clone, Copy)]
+enum CountableInference {
+ HasDefault,
+ NotCounted,
+}
+
+struct InstructionData {
+ instr_variants: Vec<(&'static str, Arity, CountableInference, Variant)>,
+ clause_type_variants: Vec<(&'static str, Arity, Variant)>,
+ builtin_type_variants: Vec<(&'static str, Arity, Variant)>,
+ inlined_type_variants: Vec<(&'static str, Arity, Variant)>,
+ system_clause_type_variants: Vec<(&'static str, Arity, Variant)>,
+ compare_number_variants: Vec<(&'static str, Arity, Variant)>,
+ compare_term_variants: Vec<(&'static str, Arity, Variant)>,
+ repl_code_ptr_variants: Vec<(&'static str, Arity, Variant)>,
+}
+
+impl InstructionData {
+ fn new() -> Self {
+ Self {
+ instr_variants: vec![],
+ clause_type_variants: vec![],
+ builtin_type_variants: vec![],
+ inlined_type_variants: vec![],
+ system_clause_type_variants: vec![],
+ compare_number_variants: vec![],
+ compare_term_variants: vec![],
+ repl_code_ptr_variants: vec![],
+ }
+ }
+
+ fn label_variant(&mut self, id: &Ident, prefix: &'static str, variant: Variant) {
+ let (name, arity, countable_inference) = if id == "CompareNumber" {
+ let (name, arity) = add_discriminant_data::<CompareNumberDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.compare_number_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else if id == "CompareTerm" {
+ let (name, arity) = add_discriminant_data::<CompareTermDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.compare_term_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else if id == "BuiltInClauseType" {
+ let (name, arity) = add_discriminant_data::<BuiltInClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.builtin_type_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else if id == "InlinedClauseType" {
+ let (name, arity) = add_discriminant_data::<InlinedClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.inlined_type_variants,
+ );
+
+ (name, arity, CountableInference::NotCounted)
+ } else if id == "REPLCodePtr" {
+ let (name, arity) = add_discriminant_data::<REPLCodePtrDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.repl_code_ptr_variants,
+ );
+
+ (name, arity, CountableInference::NotCounted)
+ } else if id == "SystemClauseType" {
+ let (name, arity) = add_discriminant_data::<SystemClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.system_clause_type_variants,
+ );
+
+ (name, arity, CountableInference::NotCounted)
+ } else if id == "InstructionTemplate" {
+ ( prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Name"),
+ Arity::from(prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Arity")),
+ CountableInference::NotCounted
+ )
+ } else if id == "ClauseType" {
+ let (name, arity) = add_discriminant_data::<ClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.clause_type_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else {
+ panic!("type ID is: {}", id);
+ };
+
+ let v_string = variant.ident.to_string();
+
+ let v_ident = if v_string.starts_with("Call") {
+ format_ident!("{}", v_string["Call".len() ..])
+ } else {
+ variant.ident.clone()
+ };
+
+ let generated_variant = create_instr_variant(
+ format_ident!("{}{}", prefix, v_ident),
+ variant.clone(),
+ );
+
+ self.instr_variants.push(
+ (name, arity, countable_inference, generated_variant)
+ );
+ }
+
+ fn generate_instruction_enum_loop(&mut self, input: syn::DeriveInput) {
+ if let Data::Enum(DataEnum { variants, .. }) = input.data {
+ for mut variant in variants {
+ if let Some(field) = variant.fields.iter().next() {
+ if let Some(input) = derive_input(&field.ty) {
+ self.generate_instruction_enum_loop(input);
+ continue;
+ }
+ }
+
+ if input.ident == "InstructionTemplate" {
+ variant.attrs.clear();
+ self.label_variant(&input.ident, "", variant);
+ continue;
+ }
+
+ self.label_variant(&input.ident, "Call", variant.clone());
+ self.label_variant(&input.ident, "Execute", variant.clone());
+
+ if input.ident == "BuiltInClauseType" ||
+ input.ident == "CompareNumber" ||
+ input.ident == "CompareTerm" ||
+ input.ident == "ClauseType"
+ {
+ self.label_variant(&input.ident, "DefaultCall", variant.clone());
+ self.label_variant(&input.ident, "DefaultExecute", variant);
+ }
+ }
+ } else {
+ panic!("{} must be an enum!", input.ident);
+ }
+ }
+}
diff --git a/crates/prolog_parser/Cargo.lock b/crates/prolog_parser/Cargo.lock
deleted file mode 100644
index 57d62880..00000000
--- a/crates/prolog_parser/Cargo.lock
+++ /dev/null
@@ -1,265 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-[[package]]
-name = "arrayvec"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
-dependencies = [
- "nodrop",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
-
-[[package]]
-name = "az"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
-[[package]]
-name = "gmp-mpfr-sys"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "lexical"
-version = "2.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e0d09e60c187a6d0a3fa418aec8587c6a4ae9de872f6126f2134f319b5ed10d"
-dependencies = [
- "cfg-if",
- "lexical-core",
- "rustc_version",
-]
-
-[[package]]
-name = "lexical-core"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
-dependencies = [
- "arrayvec",
- "cfg-if",
- "rustc_version",
- "ryu",
- "static_assertions",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3"
-
-[[package]]
-name = "nodrop"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
-
-[[package]]
-name = "num-bigint"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
-dependencies = [
- "autocfg",
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
-dependencies = [
- "autocfg",
- "num-bigint",
- "num-integer",
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-rug-adapter"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7470b6acf85abce0771203112db4181d03f7b8a6be49f0e842a78030192f8a58"
-dependencies = [
- "libc",
- "num-bigint",
- "num-integer",
- "num-rational",
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
-dependencies = [
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "ordered-float"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
-dependencies = [
- "num-traits 0.1.43",
- "unreachable",
-]
-
-[[package]]
-name = "prolog_parser"
-version = "0.8.68"
-dependencies = [
- "lexical",
- "num-rug-adapter",
- "ordered-float",
- "rug",
- "unicode_reader",
-]
-
-[[package]]
-name = "rug"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45"
-dependencies = [
- "az",
- "gmp-mpfr-sys",
- "libc",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-dependencies = [
- "semver",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
-[[package]]
-name = "smallvec"
-version = "1.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
-
-[[package]]
-name = "static_assertions"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
-
-[[package]]
-name = "unicode_reader"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a"
-dependencies = [
- "smallvec",
- "unicode-segmentation",
-]
-
-[[package]]
-name = "unreachable"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
-dependencies = [
- "void",
-]
-
-[[package]]
-name = "void"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/crates/prolog_parser/Cargo.toml b/crates/prolog_parser/Cargo.toml
deleted file mode 100644
index dc19afbd..00000000
--- a/crates/prolog_parser/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "prolog_parser"
-version = "0.8.68"
-authors = ["Mark Thom <markjordanthom@gmail.com>"]
-edition = "2021"
-repository = "https://github.com/mthom/scryer-prolog"
-description = " An operator precedence parser for the Rebis development version of Scryer Prolog, an up and coming ISO Prolog implementation."
-license = "BSD-3-Clause"
-
-[dependencies]
-indexmap = "1.0.2"
-lexical = "5.2.1"
-ordered-float = "0.5.0"
-rug = { optional = true, version = "1.4.0" }
-num-rug-adapter = { optional = true, path = "../num-rug-adapter" }
-unicode_reader = "1.0.0"
-
-[lib]
-path = "src/lib.rs"
-
-[features]
-num = ["num-rug-adapter"]
-# no default features to make num tests work
-# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
-# see rust-lang/cargo#7160
-# default = ["rug"]
diff --git a/crates/prolog_parser/src/ast.rs b/crates/prolog_parser/src/ast.rs
deleted file mode 100644
index ac794e6e..00000000
--- a/crates/prolog_parser/src/ast.rs
+++ /dev/null
@@ -1,782 +0,0 @@
-use crate::rug::{Integer, Rational};
-use crate::tabled_rc::*;
-use ordered_float::*;
-
-use crate::put_back_n::*;
-
-use std::cell::Cell;
-use std::cmp::Ordering;
-use std::fmt;
-use std::hash::{Hash, Hasher};
-use std::io::{Bytes, Error as IOError, Read};
-use std::ops::Deref;
-use std::rc::Rc;
-use std::vec::Vec;
-
-use indexmap::IndexMap;
-use unicode_reader::CodePoints;
-
-pub type Atom = String;
-
-pub type Var = String;
-
-pub type Specifier = u32;
-
-pub const MAX_ARITY: usize = 1023;
-
-pub const XFX: u32 = 0x0001;
-pub const XFY: u32 = 0x0002;
-pub const YFX: u32 = 0x0004;
-pub const XF: u32 = 0x0010;
-pub const YF: u32 = 0x0020;
-pub const FX: u32 = 0x0040;
-pub const FY: u32 = 0x0080;
-pub const DELIMITER: u32 = 0x0100;
-pub const TERM: u32 = 0x1000;
-pub const LTERM: u32 = 0x3000;
-
-pub const NEGATIVE_SIGN: u32 = 0x0200;
-
-#[macro_export]
-macro_rules! clause_name {
- ($name: expr, $tbl: expr) => {
- $crate::ast::ClauseName::User($crate::tabled_rc::TabledRc::new($name, $tbl.clone()))
- };
- ($name: expr) => {
- $crate::ast::ClauseName::BuiltIn($name)
- };
-}
-
-#[macro_export]
-macro_rules! atom {
- ($e:expr, $tbl:expr) => {
- $crate::ast::Constant::Atom(
- $crate::ast::ClauseName::User($crate::tabled_rc!($e, $tbl)),
- None,
- )
- };
- ($e:expr) => {
- $crate::ast::Constant::Atom($crate::clause_name!($e), None)
- };
-}
-
-#[macro_export]
-macro_rules! rc_atom {
- ($e:expr) => {
- Rc::new(String::from($e))
- };
-}
-macro_rules! is_term {
- ($x:expr) => {
- ($x & $crate::ast::TERM) != 0
- };
-}
-
-macro_rules! is_lterm {
- ($x:expr) => {
- ($x & $crate::ast::LTERM) != 0
- };
-}
-
-macro_rules! is_op {
- ($x:expr) => {
- $x & ($crate::ast::XF
- | $crate::ast::YF
- | $crate::ast::FX
- | $crate::ast::FY
- | $crate::ast::XFX
- | $crate::ast::XFY
- | $crate::ast::YFX)
- != 0
- };
-}
-
-macro_rules! is_negate {
- ($x:expr) => {
- ($x & $crate::ast::NEGATIVE_SIGN) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_prefix {
- ($x:expr) => {
- $x & ($crate::ast::FX | $crate::ast::FY) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_postfix {
- ($x:expr) => {
- $x & ($crate::ast::XF | $crate::ast::YF) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_infix {
- ($x:expr) => {
- ($x & ($crate::ast::XFX | $crate::ast::XFY | $crate::ast::YFX)) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_xfx {
- ($x:expr) => {
- ($x & $crate::ast::XFX) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_xfy {
- ($x:expr) => {
- ($x & $crate::ast::XFY) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_yfx {
- ($x:expr) => {
- ($x & $crate::ast::YFX) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_yf {
- ($x:expr) => {
- ($x & $crate::ast::YF) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_xf {
- ($x:expr) => {
- ($x & $crate::ast::XF) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_fx {
- ($x:expr) => {
- ($x & $crate::ast::FX) != 0
- };
-}
-
-#[macro_export]
-macro_rules! is_fy {
- ($x:expr) => {
- ($x & $crate::ast::FY) != 0
- };
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum RegType {
- Perm(usize),
- Temp(usize),
-}
-
-impl Default for RegType {
- fn default() -> Self {
- RegType::Temp(0)
- }
-}
-
-impl RegType {
- pub fn reg_num(self) -> usize {
- match self {
- RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num,
- }
- }
-
- pub fn is_perm(self) -> bool {
- matches!(self, RegType::Perm(_))
- }
-}
-
-impl fmt::Display for RegType {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- RegType::Perm(val) => write!(f, "Y{}", val),
- RegType::Temp(val) => write!(f, "X{}", val),
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum VarReg {
- ArgAndNorm(RegType, usize),
- Norm(RegType),
-}
-
-impl VarReg {
- pub fn norm(self) -> RegType {
- match self {
- VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg,
- }
- }
-}
-
-impl fmt::Display for VarReg {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
- VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
- VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
- VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
- }
- }
-}
-
-impl Default for VarReg {
- fn default() -> Self {
- VarReg::Norm(RegType::default())
- }
-}
-
-#[macro_export]
-macro_rules! temp_v {
- ($x:expr) => {
- $crate::ast::RegType::Temp($x)
- };
-}
-
-#[macro_export]
-macro_rules! perm_v {
- ($x:expr) => {
- $crate::ast::RegType::Perm($x)
- };
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub enum GenContext {
- Head,
- Mid(usize),
- Last(usize), // Mid & Last: chunk_num
-}
-
-impl GenContext {
- pub fn chunk_num(self) -> usize {
- match self {
- GenContext::Head => 0,
- GenContext::Mid(cn) | GenContext::Last(cn) => cn,
- }
- }
-}
-
-pub type OpDirKey = (ClauseName, Fixity);
-
-#[derive(Debug, Clone)]
-pub struct OpDirValue(pub SharedOpDesc);
-
-impl OpDirValue {
- pub fn new(spec: Specifier, priority: usize) -> Self {
- OpDirValue(SharedOpDesc::new(priority, spec))
- }
-
- #[inline]
- pub fn shared_op_desc(&self) -> SharedOpDesc {
- self.0.clone()
- }
-}
-
-// name and fixity -> operator type and precedence.
-pub type OpDir = IndexMap<OpDirKey, OpDirValue>;
-
-#[derive(Debug, Clone, Copy)]
-pub struct MachineFlags {
- pub double_quotes: DoubleQuotes,
-}
-
-impl Default for MachineFlags {
- fn default() -> Self {
- MachineFlags {
- double_quotes: DoubleQuotes::default(),
- }
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub enum DoubleQuotes {
- Atom,
- Chars,
- Codes,
-}
-
-impl DoubleQuotes {
- pub fn is_chars(self) -> bool {
- matches!(self, DoubleQuotes::Chars)
- }
-
- pub fn is_atom(self) -> bool {
- matches!(self, DoubleQuotes::Atom)
- }
-
- pub fn is_codes(self) -> bool {
- matches!(self, DoubleQuotes::Codes)
- }
-}
-
-impl Default for DoubleQuotes {
- fn default() -> Self {
- DoubleQuotes::Chars
- }
-}
-
-pub fn default_op_dir() -> OpDir {
- let mut op_dir = OpDir::new();
-
- op_dir.insert((clause_name!(":-"), Fixity::In), OpDirValue::new(XFX, 1200));
- op_dir.insert((clause_name!(":-"), Fixity::Pre), OpDirValue::new(FX, 1200));
- op_dir.insert((clause_name!("?-"), Fixity::Pre), OpDirValue::new(FX, 1200));
- op_dir.insert((clause_name!(","), Fixity::In), OpDirValue::new(XFY, 1000));
-
- op_dir
-}
-
-#[derive(Debug, Clone)]
-pub enum ArithmeticError {
- NonEvaluableFunctor(Constant, usize),
- UninstantiatedVar,
-}
-
-#[derive(Debug)]
-pub enum ParserError {
- BackQuotedString(usize, usize),
- UnexpectedChar(char, usize, usize),
- UnexpectedEOF,
- IO(IOError),
- IncompleteReduction(usize, usize),
- InvalidSingleQuotedCharacter(char),
- MissingQuote(usize, usize),
- NonPrologChar(usize, usize),
- ParseBigInt(usize, usize),
- Utf8Error(usize, usize),
-}
-
-impl ParserError {
- pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
- match self {
- &ParserError::BackQuotedString(line_num, col_num)
- | &ParserError::UnexpectedChar(_, line_num, col_num)
- | &ParserError::IncompleteReduction(line_num, col_num)
- | &ParserError::MissingQuote(line_num, col_num)
- | &ParserError::NonPrologChar(line_num, col_num)
- | &ParserError::ParseBigInt(line_num, col_num)
- | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
- _ => None,
- }
- }
-
- pub fn as_str(&self) -> &'static str {
- match self {
- ParserError::BackQuotedString(..) => "back_quoted_string",
- ParserError::UnexpectedChar(..) => "unexpected_char",
- ParserError::UnexpectedEOF => "unexpected_end_of_file",
- ParserError::IncompleteReduction(..) => "incomplete_reduction",
- ParserError::InvalidSingleQuotedCharacter(..) => "invalid_single_quoted_character",
- ParserError::IO(_) => "input_output_error",
- ParserError::MissingQuote(..) => "missing_quote",
- ParserError::NonPrologChar(..) => "non_prolog_character",
- ParserError::ParseBigInt(..) => "cannot_parse_big_int",
- ParserError::Utf8Error(..) => "utf8_conversion_error",
- }
- }
-}
-
-impl From<IOError> for ParserError {
- fn from(err: IOError) -> ParserError {
- ParserError::IO(err)
- }
-}
-
-impl From<&IOError> for ParserError {
- fn from(error: &IOError) -> ParserError {
- if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
- ParserError::Utf8Error(0, 0)
- } else {
- ParserError::IO(error.kind().into())
- }
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct CompositeOpDir<'a, 'b> {
- pub primary_op_dir: Option<&'b OpDir>,
- pub secondary_op_dir: &'a OpDir,
-}
-
-impl<'a, 'b> CompositeOpDir<'a, 'b> {
- #[inline]
- pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self {
- CompositeOpDir {
- primary_op_dir,
- secondary_op_dir,
- }
- }
-
- #[inline]
- pub(crate) fn get(&self, name: ClauseName, fixity: Fixity) -> Option<&OpDirValue> {
- let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir {
- primary_op_dir.get(&(name.clone(), fixity))
- } else {
- None
- };
-
- entry.or_else(move || self.secondary_op_dir.get(&(name, fixity)))
- }
-}
-
-#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
-pub enum Fixity {
- In,
- Post,
- Pre,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct SharedOpDesc(Rc<Cell<(usize, Specifier)>>);
-
-impl SharedOpDesc {
- #[inline]
- pub fn new(priority: usize, spec: Specifier) -> Self {
- SharedOpDesc(Rc::new(Cell::new((priority, spec))))
- }
-
- #[inline]
- pub fn ptr_eq(lop_desc: &SharedOpDesc, rop_desc: &SharedOpDesc) -> bool {
- Rc::ptr_eq(&lop_desc.0, &rop_desc.0)
- }
-
- #[inline]
- pub fn arity(&self) -> usize {
- if self.get().1 & (XFX | XFY | YFX) == 0 {
- 1
- } else {
- 2
- }
- }
-
- #[inline]
- pub fn get(&self) -> (usize, Specifier) {
- self.0.get()
- }
-
- #[inline]
- pub fn set(&self, prec: usize, spec: Specifier) {
- self.0.set((prec, spec));
- }
-
- #[inline]
- pub fn prec(&self) -> usize {
- self.0.get().0
- }
-
- #[inline]
- pub fn assoc(&self) -> Specifier {
- self.0.get().1
- }
-}
-
-impl Deref for SharedOpDesc {
- type Target = Cell<(usize, Specifier)>;
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- self.0.deref()
- }
-}
-
-// this ensures that SharedOpDesc (which is not consistently placed in
-// every atom!) doesn't affect the value of an atom hash. If
-// SharedOpDesc values are to be indexed, a BTreeMap or BTreeSet
-// should be used, obviously.
-impl Hash for SharedOpDesc {
- fn hash<H: Hasher>(&self, state: &mut H) {
- 0.hash(state)
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum Constant {
- Atom(ClauseName, Option<SharedOpDesc>),
- Char(char),
- EmptyList,
- Fixnum(isize),
- Integer(Rc<Integer>),
- Rational(Rc<Rational>),
- Float(OrderedFloat<f64>),
- String(Rc<String>),
- Usize(usize),
-}
-
-impl fmt::Display for Constant {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- Constant::Atom(ref atom, _) => {
- if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
- write!(f, "'{}'", atom.as_str())
- } else {
- write!(f, "{}", atom.as_str())
- }
- }
- Constant::Char(c) => write!(f, "'{}'", *c as u32),
- Constant::EmptyList => write!(f, "[]"),
- Constant::Fixnum(n) => write!(f, "{}", n),
- Constant::Integer(ref n) => write!(f, "{}", n),
- Constant::Rational(ref n) => write!(f, "{}", n),
- Constant::Float(ref n) => write!(f, "{}", n),
- Constant::String(ref s) => write!(f, "\"{}\"", &s),
- Constant::Usize(integer) => write!(f, "u{}", integer),
- }
- }
-}
-
-impl Constant {
- pub fn to_atom(&self) -> Option<ClauseName> {
- match self {
- Constant::Atom(a, _) => Some(a.defrock_brackets()),
- _ => None,
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub enum ClauseName {
- BuiltIn(&'static str),
- User(TabledRc<Atom>),
-}
-
-impl fmt::Display for ClauseName {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.as_str())
- }
-}
-
-impl Hash for ClauseName {
- fn hash<H: Hasher>(&self, state: &mut H) {
- (*self.as_str()).hash(state)
- }
-}
-
-impl PartialEq for ClauseName {
- fn eq(&self, other: &ClauseName) -> bool {
- *self.as_str() == *other.as_str()
- }
-}
-
-impl Eq for ClauseName {}
-
-impl Ord for ClauseName {
- fn cmp(&self, other: &ClauseName) -> Ordering {
- (*self.as_str()).cmp(other.as_str())
- }
-}
-
-impl PartialOrd for ClauseName {
- fn partial_cmp(&self, other: &ClauseName) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl<'a> From<&'a TabledRc<Atom>> for ClauseName {
- fn from(name: &'a TabledRc<Atom>) -> ClauseName {
- ClauseName::User(name.clone())
- }
-}
-
-impl ClauseName {
- #[inline]
- pub fn owning_module(&self) -> Self {
- match self {
- ClauseName::User(ref name) => {
- let module = name.owning_module();
- ClauseName::User(TabledRc {
- atom: module.clone(),
- table: TabledData::new(module),
- })
- }
- _ => clause_name!("user"),
- }
- }
-
- #[inline]
- pub fn to_rc(&self) -> Rc<String> {
- match self {
- ClauseName::BuiltIn(s) => Rc::new(s.to_string()),
- ClauseName::User(ref rc) => rc.inner(),
- }
- }
-
- #[inline]
- pub fn with_table(self, atom_tbl: TabledData<Atom>) -> Self {
- match self {
- ClauseName::BuiltIn(_) => self,
- ClauseName::User(mut name) => {
- name.table = atom_tbl;
- ClauseName::User(name)
- }
- }
- }
-
- #[inline]
- pub fn has_table(&self, atom_tbl: &TabledData<Atom>) -> bool {
- match self {
- ClauseName::BuiltIn(_) => false,
- ClauseName::User(ref name) => &name.table == atom_tbl,
- }
- }
-
- #[inline]
- pub fn has_table_of(&self, other: &ClauseName) -> bool {
- match self {
- ClauseName::BuiltIn(_) => {
- matches!(other, ClauseName::BuiltIn(_))
- }
- ClauseName::User(ref name) => other.has_table(&name.table),
- }
- }
-
- #[inline]
- pub fn as_str(&self) -> &str {
- match self {
- ClauseName::BuiltIn(s) => s,
- ClauseName::User(ref name) => name.as_ref(),
- }
- }
-
- #[inline]
- pub fn is_char(&self) -> bool {
- !self.as_str().is_empty() && self.as_str().chars().nth(1).is_none()
- }
-
- pub fn defrock_brackets(&self) -> Self {
- fn defrock_brackets(s: &str) -> &str {
- if s.starts_with('(') && s.ends_with(')') {
- &s[1..s.len() - 1]
- } else {
- s
- }
- }
-
- match self {
- ClauseName::BuiltIn(s) => ClauseName::BuiltIn(defrock_brackets(s)),
- ClauseName::User(s) => {
- ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(), s.table))
- }
- }
- }
-}
-
-impl AsRef<str> for ClauseName {
- #[inline]
- fn as_ref(&self) -> &str {
- self.as_str()
- }
-}
-
-#[derive(Debug, Clone)]
-pub enum Term {
- AnonVar,
- Clause(
- Cell<RegType>,
- ClauseName,
- Vec<Box<Term>>,
- Option<SharedOpDesc>,
- ),
- Cons(Cell<RegType>, Box<Term>, Box<Term>),
- Constant(Cell<RegType>, Constant),
- Var(Cell<VarReg>, Rc<Var>),
-}
-
-impl Term {
- pub fn shared_op_desc(&self) -> Option<SharedOpDesc> {
- match self {
- Term::Clause(_, _, _, ref spec) => spec.clone(),
- Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(),
- _ => None,
- }
- }
-
- pub fn into_constant(self) -> Option<Constant> {
- match self {
- Term::Constant(_, c) => Some(c),
- _ => None,
- }
- }
-
- pub fn first_arg(&self) -> Option<&Term> {
- match self {
- Term::Clause(_, _, ref terms, _) => terms.first().map(|bt| bt.as_ref()),
- _ => None,
- }
- }
-
- pub fn set_name(&mut self, new_name: ClauseName) {
- match self {
- Term::Constant(_, Constant::Atom(ref mut atom, _))
- | Term::Clause(_, ref mut atom, ..) => {
- *atom = new_name;
- }
- _ => {}
- }
- }
-
- pub fn name(&self) -> Option<ClauseName> {
- match self {
- &Term::Constant(_, Constant::Atom(ref atom, _)) | &Term::Clause(_, ref atom, ..) => {
- Some(atom.clone())
- }
- _ => None,
- }
- }
-
- pub fn arity(&self) -> usize {
- match self {
- Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
- _ => 0,
- }
- }
-}
-
-fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> {
- if let 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 type ParsingStream<R> = PutBackN<CodePoints<Bytes<R>>>;
-
-use unicode_reader::BadUtf8Error;
-
-#[inline]
-pub fn parsing_stream<R: Read>(src: R) -> Result<ParsingStream<R>, ParserError> {
- let mut stream = put_back_n(CodePoints::from(src.bytes()));
- match stream.peek() {
- None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
- Some(Err(error)) => Err(ParserError::from(error)),
- Some(Ok(c)) => {
- if *c == '\u{feff}' {
- // skip UTF-8 BOM
- stream.next();
- }
- Ok(stream)
- }
- }
-}
diff --git a/crates/prolog_parser/src/put_back_n.rs b/crates/prolog_parser/src/put_back_n.rs
deleted file mode 100644
index 8bef7f30..00000000
--- a/crates/prolog_parser/src/put_back_n.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-use std::iter::Peekable;
-
-#[derive(Debug, Clone)]
-pub struct PutBackN<I: Iterator> {
- top: Vec<I::Item>,
- iter: Peekable<I>,
-}
-
-pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
- where I: IntoIterator
-{
- PutBackN {
- top: Vec::new(),
- iter: iterable.into_iter().peekable(),
- }
-}
-
-impl<I: Iterator> PutBackN<I> {
- #[inline]
- pub(crate)
- fn put_back(&mut self, item: I::Item) {
- self.top.push(item);
- }
-
- #[inline]
- pub fn take_buf(&mut self) -> Vec<I::Item> {
- std::mem::replace(&mut self.top, vec![])
- }
-
- #[inline]
- pub(crate)
- fn peek(&mut self) -> Option<&I::Item> {
- if self.top.is_empty() {
- /* This is a kludge for Ctrl-D not being
- * handled properly if self.iter().peek() isn't called
- * first. */
- match self.iter.peek() {
- Some(_) => {
- self.iter.next().and_then(move |item| {
- self.top.push(item);
- self.top.last()
- })
- }
- None => {
- None
- }
- }
- } else {
- self.top.last()
- }
- }
-
- #[inline]
- pub(crate)
- fn put_back_all<DEI: DoubleEndedIterator<Item = I::Item>>(&mut self, iter: DEI) {
- self.top.extend(iter.rev());
- }
-}
-
-impl<I: Iterator> Iterator for PutBackN<I> {
- type Item = I::Item;
-
- #[inline]
- fn next(&mut self) -> Option<I::Item> {
- if self.top.is_empty() {
- self.iter.next()
- } else {
- self.top.pop()
- }
- }
-}
diff --git a/crates/prolog_parser/src/tabled_rc.rs b/crates/prolog_parser/src/tabled_rc.rs
deleted file mode 100644
index 47f87d30..00000000
--- a/crates/prolog_parser/src/tabled_rc.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-use std::cell::{RefCell, RefMut};
-use std::cmp::Ordering;
-use std::collections::HashSet;
-use std::fmt;
-use std::hash::{Hash, Hasher};
-use std::ops::Deref;
-use std::rc::Rc;
-
-pub struct TabledData<T> {
- table: Rc<RefCell<HashSet<Rc<T>>>>,
- pub(crate) module_name: Rc<String>,
-}
-
-impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledData<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("TabledData")
- .field("table", &self.table)
- .field("module_name", &self.table)
- .finish()
- }
-}
-
-impl<T> Clone for TabledData<T> {
- fn clone(&self) -> Self {
- TabledData {
- table: self.table.clone(),
- module_name: self.module_name.clone(),
- }
- }
-}
-
-impl<T: PartialEq> PartialEq for TabledData<T> {
- fn eq(&self, other: &TabledData<T>) -> bool {
- Rc::ptr_eq(&self.table, &other.table) && self.module_name == other.module_name
- }
-}
-
-impl<T: Hash + Eq> TabledData<T> {
- #[inline]
- pub fn new(module_name: Rc<String>) -> Self {
- TabledData {
- table: Rc::new(RefCell::new(HashSet::new())),
- module_name,
- }
- }
-
- #[inline]
- pub fn borrow_mut(&self) -> RefMut<HashSet<Rc<T>>> {
- self.table.borrow_mut()
- }
-}
-
-pub struct TabledRc<T: Hash + Eq> {
- pub(crate) atom: Rc<T>,
- pub table: TabledData<T>,
-}
-
-impl<T: Hash + Eq + fmt::Debug> fmt::Debug for TabledRc<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("TabledRc")
- .field("atom", &self.atom)
- .field("table", &self.table)
- .finish()
- }
-}
-
-// this Clone instance is manually defined to prevent the compiler
-// from complaining when deriving Clone for StringList.
-impl<T: Hash + Eq> Clone for TabledRc<T> {
- fn clone(&self) -> Self {
- TabledRc {
- atom: self.atom.clone(),
- table: self.table.clone(),
- }
- }
-}
-
-impl<T: Ord + Hash + Eq> PartialOrd for TabledRc<T> {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.atom.cmp(&other.atom))
- }
-}
-
-impl<T: Ord + Hash + Eq> Ord for TabledRc<T> {
- fn cmp(&self, other: &Self) -> Ordering {
- self.atom.cmp(&other.atom)
- }
-}
-
-impl<T: Hash + Eq> PartialEq for TabledRc<T> {
- fn eq(&self, other: &TabledRc<T>) -> bool {
- self.atom == other.atom
- }
-}
-
-impl<T: Hash + Eq> Eq for TabledRc<T> {}
-
-impl<T: Hash + Eq> Hash for TabledRc<T> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.atom.hash(state)
- }
-}
-
-impl<T: Hash + Eq + ToString> TabledRc<T> {
- pub fn new(atom: T, table: TabledData<T>) -> Self {
- let atom = match table.borrow_mut().take(&atom) {
- Some(atom) => atom,
- None => Rc::new(atom),
- };
-
- table.borrow_mut().insert(atom.clone());
-
- TabledRc { atom, table }
- }
-
- #[inline]
- pub fn inner(&self) -> Rc<T> {
- self.atom.clone()
- }
-
- #[inline]
- pub(crate) fn owning_module(&self) -> Rc<String> {
- self.table.module_name.clone()
- }
-}
-
-impl<T: Hash + Eq> Drop for TabledRc<T> {
- fn drop(&mut self) {
- if Rc::strong_count(&self.atom) == 2 {
- self.table.borrow_mut().remove(&self.atom);
- }
- }
-}
-
-impl<T: Hash + Eq> Deref for TabledRc<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &*self.atom
- }
-}
-
-impl<T: Hash + Eq + fmt::Display> fmt::Display for TabledRc<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", &*self.atom)
- }
-}
-
-#[macro_export]
-macro_rules! tabled_rc {
- ($e:expr, $tbl:expr) => {
- $crate::tabled_rc::TabledRc::new(String::from($e), $tbl.clone())
- };
-}
diff --git a/crates/static-string-indexing/Cargo.toml b/crates/static-string-indexing/Cargo.toml
new file mode 100644
index 00000000..1432ae68
--- /dev/null
+++ b/crates/static-string-indexing/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "static-string-indexing"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+proc-macro2 = "*"
+syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
+indexmap = "*"
+walkdir = "2"
+quote = "*"
diff --git a/crates/static-string-indexing/src/lib.rs b/crates/static-string-indexing/src/lib.rs
new file mode 100644
index 00000000..390c5405
--- /dev/null
+++ b/crates/static-string-indexing/src/lib.rs
@@ -0,0 +1,177 @@
+use proc_macro2::TokenStream;
+use syn::*;
+use syn::parse::*;
+use syn::visit::*;
+
+use indexmap::IndexSet;
+
+struct StaticStrVisitor {
+ static_strs: IndexSet<String>,
+}
+
+impl StaticStrVisitor {
+ fn new() -> Self {
+ Self { static_strs: IndexSet::new() }
+ }
+}
+
+struct MacroFnArgs {
+ args: Vec<Expr>,
+}
+
+struct ReadHeapCellExprAndArms {
+ expr: Expr,
+ arms: Vec<Arm>,
+}
+
+impl Parse for ReadHeapCellExprAndArms {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut arms = vec![];
+ let expr = input.parse()?;
+
+ input.parse::<Token![,]>()?;
+ arms.push(input.parse()?);
+
+ while !input.is_empty() {
+ if let Ok(_) = input.parse::<Token![,]>() {}
+ arms.push(input.parse()?);
+ }
+
+ Ok(ReadHeapCellExprAndArms { expr, arms })
+ }
+}
+
+impl Parse for MacroFnArgs {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut args = vec![];
+
+ if !input.is_empty() {
+ args.push(input.parse()?);
+ }
+
+ while !input.is_empty() {
+ if let Ok(_) = input.parse::<Token![,]>() {}
+ args.push(input.parse()?);
+ }
+
+ Ok(MacroFnArgs { args })
+ }
+}
+
+impl<'ast> Visit<'ast> for StaticStrVisitor {
+ fn visit_macro(&mut self, m: &'ast Macro) {
+ let Macro { path, .. } = m;
+
+ if path.is_ident("atom") {
+ if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() {
+ self.static_strs.insert(string.value());
+ }
+ } else if path.is_ident("read_heap_cell") {
+ if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() {
+ self.visit_expr(&m.expr);
+
+ for e in m.arms {
+ self.visit_arm(&e);
+ }
+ }
+ } else {
+ if let Some(m) = m.parse_body::<MacroFnArgs>().ok() {
+ for e in m.args {
+ self.visit_expr(&e);
+ }
+ }
+ }
+ }
+}
+
+pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream {
+ use quote::*;
+
+ use std::ffi::OsStr;
+ use std::fs::File;
+ use std::io::Read;
+
+ use walkdir::WalkDir;
+
+ fn filter_rust_files(e: &walkdir::DirEntry) -> bool {
+ if e.path().is_dir() {
+ return true;
+ }
+
+ e.path().extension().and_then(OsStr::to_str) == Some("rs")
+ }
+
+ let mut visitor = StaticStrVisitor::new();
+
+ fn process_filepath(path: &std::path::Path) -> std::result::Result<syn::File, ()> {
+ let mut src = String::new();
+
+ let mut file = match File::open(path) {
+ Ok(file) => file,
+ Err(_) => return Err(()),
+ };
+
+ match file.read_to_string(&mut src) {
+ Ok(_) => {}
+ Err(e) => {
+ panic!("error reading file: {:?}", e);
+ }
+ }
+
+ let syntax = match syn::parse_file(&src) {
+ Ok(s) => s,
+ Err(e) => {
+ panic!("parse error: {} in file {:?}", e, path);
+ }
+ };
+ Ok(syntax)
+ }
+
+ for entry in WalkDir::new("src/")
+ .into_iter()
+ .filter_entry(filter_rust_files)
+ {
+ let entry = entry.unwrap();
+
+ if entry.path().is_dir() {
+ continue;
+ }
+
+ let syntax = match process_filepath(entry.path()) {
+ Ok(syntax) => syntax,
+ Err(_) => continue,
+ };
+
+ visitor.visit_file(&syntax);
+ }
+
+ match process_filepath(instruction_rs_path) {
+ Ok(syntax) => visitor.visit_file(&syntax),
+ Err(_) => {}
+ }
+
+ let indices = (0..visitor.static_strs.len()).map(|i| i << 3);
+ let indices_iter = indices.clone();
+
+ let static_strs_len = visitor.static_strs.len();
+ let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect();
+
+ quote! {
+ use phf;
+
+ static STRINGS: [&'static str; #static_strs_len] = [
+ #(
+ #static_strs,
+ )*
+ ];
+
+ #[macro_export]
+ macro_rules! atom {
+ #((#static_strs) => { Atom { index: #indices_iter } };)*
+ }
+
+ static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
+ #(#static_strs => { Atom { index: #indices } },)*
+ };
+ }
+}
diff --git a/crates/to-syn-value/Cargo.toml b/crates/to-syn-value/Cargo.toml
new file mode 100644
index 00000000..3fa4953d
--- /dev/null
+++ b/crates/to-syn-value/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "to-syn-value"
+version = "0.1.0"
+authors = ["Mark Thom <markjordanthom@gmail.com>"]
+edition = "2021"
+publish = false
+
+[dependencies]
+syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
+to-syn-value_derive = { path = "../to-syn-value_derive" } \ No newline at end of file
diff --git a/crates/to-syn-value/src/lib.rs b/crates/to-syn-value/src/lib.rs
new file mode 100644
index 00000000..753c44a9
--- /dev/null
+++ b/crates/to-syn-value/src/lib.rs
@@ -0,0 +1,3 @@
+pub trait ToDeriveInput {
+ fn to_derive_input() -> syn::DeriveInput;
+}
diff --git a/crates/to-syn-value_derive/Cargo.toml b/crates/to-syn-value_derive/Cargo.toml
new file mode 100644
index 00000000..9dc0e8ac
--- /dev/null
+++ b/crates/to-syn-value_derive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "to-syn-value_derive"
+version = "0.1.0"
+authors = ["Mark Thom <markjordanthom@gmail.com>"]
+edition = "2021"
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "*"
+syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
+quote = "*" \ No newline at end of file
diff --git a/crates/to-syn-value_derive/src/lib.rs b/crates/to-syn-value_derive/src/lib.rs
new file mode 100644
index 00000000..13845ac4
--- /dev/null
+++ b/crates/to-syn-value_derive/src/lib.rs
@@ -0,0 +1,20 @@
+use syn::*;
+use quote::*;
+
+#[proc_macro_derive(ToDeriveInput)]
+pub fn derive_to_derive_input(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let derive_input = parse_macro_input!(input as DeriveInput);
+ let ty_name = derive_input.ident.clone();
+
+ quote! {
+ use to_syn_value::*;
+
+ impl ToDeriveInput for #ty_name {
+ fn to_derive_input() -> syn::DeriveInput {
+ syn::parse_quote! {
+ #derive_input
+ }
+ }
+ }
+ }.into()
+}
diff --git a/src/allocator.rs b/src/allocator.rs
index cc8de305..a8fbc693 100644
--- a/src/allocator.rs
+++ b/src/allocator.rs
@@ -1,53 +1,57 @@
-use prolog_parser::ast::*;
-use prolog_parser::temp_v;
+use crate::parser::ast::*;
+use crate::temp_v;
use crate::fixtures::*;
use crate::forms::*;
+use crate::instructions::*;
use crate::machine::machine_indices::*;
use crate::targets::*;
use std::cell::Cell;
use std::rc::Rc;
-pub(crate) trait Allocator<'a> {
+pub(crate) trait Allocator {
fn new() -> Self;
- fn mark_anon_var<Target>(&mut self, _: Level, _: GenContext, _: &mut Vec<Target>)
- where
- Target: CompilationTarget<'a>;
- fn mark_non_var<Target>(
+ fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self,
- _: Level,
- _: GenContext,
- _: &'a Cell<RegType>,
- _: &mut Vec<Target>,
- ) where
- Target: CompilationTarget<'a>;
- fn mark_reserved_var<Target>(
+ lvl: Level,
+ context: GenContext,
+ code: &mut Code,
+ );
+
+ fn mark_non_var<'a, Target: CompilationTarget<'a>>(
+ &mut self,
+ lvl: Level,
+ context: GenContext,
+ cell: &'a Cell<RegType>,
+ code: &mut Code,
+ );
+
+ fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
- _: Rc<Var>,
- _: Level,
- _: &'a Cell<VarReg>,
- _: GenContext,
- _: &mut Vec<Target>,
- _: RegType,
- _: bool,
- ) where
- Target: CompilationTarget<'a>;
- fn mark_var<Target>(
+ var_name: Rc<String>,
+ lvl: Level,
+ cell: &'a Cell<VarReg>,
+ term_loc: GenContext,
+ code: &mut Code,
+ r: RegType,
+ is_new_var: bool,
+ );
+
+ fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
- _: Rc<Var>,
- _: Level,
- _: &'a Cell<VarReg>,
- _: GenContext,
- _: &mut Vec<Target>,
- ) where
- Target: CompilationTarget<'a>;
+ var_name: Rc<String>,
+ lvl: Level,
+ cell: &'a Cell<VarReg>,
+ context: GenContext,
+ code: &mut Code,
+ );
fn reset(&mut self);
fn reset_contents(&mut self) {}
- fn reset_arg(&mut self, _: usize);
- fn reset_at_head(&mut self, _: &Vec<Box<Term>>);
+ fn reset_arg(&mut self, arg_num: usize);
+ fn reset_at_head(&mut self, args: &Vec<Term>);
fn advance_arg(&mut self);
@@ -56,7 +60,7 @@ pub(crate) trait Allocator<'a> {
fn take_bindings(self) -> AllocVarDict;
- fn drain_var_data(
+ fn drain_var_data<'a>(
&mut self,
vs: VariableFixtures<'a>,
num_of_chunks: usize,
@@ -83,17 +87,17 @@ pub(crate) trait Allocator<'a> {
perm_vs
}
- fn get(&self, var: Rc<Var>) -> RegType {
+ fn get(&self, var: Rc<String>) -> RegType {
self.bindings()
.get(&var)
.map_or(temp_v!(0), |v| v.as_reg_type())
}
- fn is_unbound(&self, var: Rc<Var>) -> bool {
+ fn is_unbound(&self, var: Rc<String>) -> bool {
self.get(var).reg_num() == 0
}
- fn record_register(&mut self, var: Rc<Var>, r: RegType) {
+ fn record_register(&mut self, var: Rc<String>, r: RegType) {
match self.bindings_mut().get_mut(&var).unwrap() {
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarData::Perm(ref mut s) => *s = r.reg_num(),
diff --git a/src/arena.rs b/src/arena.rs
new file mode 100644
index 00000000..0dde0751
--- /dev/null
+++ b/src/arena.rs
@@ -0,0 +1,801 @@
+use crate::machine::loader::LiveLoadState;
+use crate::machine::machine_indices::*;
+use crate::machine::streams::*;
+use crate::read::*;
+
+use modular_bitfield::prelude::*;
+use ordered_float::OrderedFloat;
+use rug::{Integer, Rational};
+
+use std::alloc;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::mem;
+use std::net::TcpListener;
+use std::ops::{Deref, DerefMut};
+use std::ptr;
+
+#[macro_export]
+macro_rules! arena_alloc {
+ ($e:expr, $arena:expr) => {{
+ let result = $e;
+ #[allow(unused_unsafe)]
+ unsafe { $arena.alloc(result) }
+ }};
+}
+
+#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
+#[bits = 7]
+pub enum ArenaHeaderTag {
+ F64 = 0b01,
+ Integer = 0b10,
+ Rational = 0b11,
+ OssifiedOpDir = 0b0000100,
+ LiveLoadState = 0b0001000,
+ InactiveLoadState = 0b1011000,
+ InputFileStream = 0b10000,
+ OutputFileStream = 0b10100,
+ NamedTcpStream = 0b011100,
+ NamedTlsStream = 0b100000,
+ ReadlineStream = 0b110000,
+ StaticStringStream = 0b110100,
+ ByteStream = 0b111000,
+ StandardOutputStream = 0b1100,
+ StandardErrorStream = 0b11000,
+ NullStream = 0b111100,
+ TcpListener = 0b1000000,
+ Dropped = 0b1000100,
+}
+
+#[bitfield]
+#[derive(Copy, Clone, Debug)]
+pub struct ArenaHeader {
+ size: B56,
+ m: bool,
+ tag: ArenaHeaderTag,
+}
+
+const_assert!(mem::size_of::<ArenaHeader>() == 8);
+
+impl ArenaHeader {
+ #[inline]
+ pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self {
+ ArenaHeader::new()
+ .with_size(size)
+ .with_tag(tag)
+ .with_m(false)
+ }
+
+ #[inline]
+ pub fn get_tag(self) -> ArenaHeaderTag {
+ self.tag()
+ }
+}
+
+#[derive(Debug, PartialOrd, Ord)]
+pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
+
+impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
+ fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
+ self.0 == other.0 || &**self == &**other
+ }
+}
+
+impl<T: ?Sized + PartialEq> Eq for TypedArenaPtr<T> {}
+
+impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
+ #[inline(always)]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ (&*self as &T).hash(hasher)
+ }
+}
+
+impl<T: ?Sized> Clone for TypedArenaPtr<T> {
+ fn clone(&self) -> Self {
+ TypedArenaPtr(self.0)
+ }
+}
+
+impl<T: ?Sized> Copy for TypedArenaPtr<T> {}
+
+impl<T: ?Sized> Deref for TypedArenaPtr<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { self.0.as_ref() }
+ }
+}
+
+impl<T: ?Sized> DerefMut for TypedArenaPtr<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe { self.0.as_mut() }
+ }
+}
+
+impl<T: fmt::Display> fmt::Display for TypedArenaPtr<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", **self)
+ }
+}
+
+impl<T: ?Sized> TypedArenaPtr<T> {
+ #[inline]
+ pub const fn new(data: *mut T) -> Self {
+ unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
+ }
+
+ #[inline]
+ pub fn as_ptr(&self) -> *mut T {
+ self.0.as_ptr()
+ }
+
+ #[inline]
+ pub fn header_ptr(&self) -> *const ArenaHeader {
+ let mut ptr = self.as_ptr() as *const u8 as usize;
+ ptr -= mem::size_of::<*const ArenaHeader>();
+ ptr as *const ArenaHeader
+ }
+
+ #[inline]
+ fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
+ let mut ptr = self.as_ptr() as *const u8 as usize;
+ ptr -= mem::size_of::<*const ArenaHeader>();
+ ptr as *mut ArenaHeader
+ }
+
+ #[inline]
+ pub fn get_mark_bit(&self) -> bool {
+ unsafe { (*self.header_ptr()).m() }
+ }
+
+ #[inline]
+ pub fn set_tag(&mut self, tag: ArenaHeaderTag) {
+ unsafe { (*self.header_ptr_mut()).set_tag(tag); }
+ }
+
+ #[inline]
+ pub fn get_tag(&self) -> ArenaHeaderTag {
+ unsafe { (*self.header_ptr()).get_tag() }
+ }
+
+ #[inline]
+ pub fn mark(&mut self) {
+ unsafe {
+ (*self.header_ptr_mut()).set_m(true);
+ }
+ }
+
+ #[inline]
+ pub fn unmark(&mut self) {
+ unsafe {
+ (*self.header_ptr_mut()).set_m(false);
+ }
+ }
+}
+
+pub trait ArenaAllocated {
+ type PtrToAllocated;
+
+ fn tag() -> ArenaHeaderTag;
+ fn size(&self) -> usize;
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated
+ where
+ Self: Sized;
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct F64Ptr(pub TypedArenaPtr<OrderedFloat<f64>>);
+
+impl fmt::Display for F64Ptr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", *self)
+ }
+}
+
+impl Deref for F64Ptr {
+ type Target = TypedArenaPtr<OrderedFloat<f64>>;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl DerefMut for F64Ptr {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+impl ArenaAllocated for OrderedFloat<f64> {
+ type PtrToAllocated = F64Ptr;
+
+ #[inline]
+ fn tag() -> ArenaHeaderTag {
+ ArenaHeaderTag::F64
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ mem::size_of::<Self>()
+ }
+
+ #[inline]
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
+ unsafe {
+ ptr::write(dst, self);
+ F64Ptr(TypedArenaPtr::new(dst as *mut Self))
+ }
+ }
+}
+
+impl ArenaAllocated for Integer {
+ type PtrToAllocated = TypedArenaPtr<Integer>;
+
+ #[inline]
+ fn tag() -> ArenaHeaderTag {
+ ArenaHeaderTag::Integer
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ mem::size_of::<Self>()
+ }
+
+ #[inline]
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
+ unsafe {
+ ptr::write(dst, self);
+ TypedArenaPtr::new(dst as *mut Self)
+ }
+ }
+}
+
+impl ArenaAllocated for Rational {
+ type PtrToAllocated = TypedArenaPtr<Rational>;
+
+ #[inline]
+ fn tag() -> ArenaHeaderTag {
+ ArenaHeaderTag::Rational
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ mem::size_of::<Self>()
+ }
+
+ #[inline]
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
+ unsafe {
+ ptr::write(dst, self);
+ TypedArenaPtr::new(dst as *mut Self)
+ }
+ }
+}
+
+impl ArenaAllocated for OssifiedOpDir {
+ type PtrToAllocated = TypedArenaPtr<OssifiedOpDir>;
+
+ #[inline]
+ fn tag() -> ArenaHeaderTag {
+ ArenaHeaderTag::OssifiedOpDir
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ mem::size_of::<Self>()
+ }
+
+ #[inline]
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
+ unsafe {
+ ptr::write(dst, self);
+ TypedArenaPtr::new(dst as *mut Self)
+ }
+ }
+}
+
+impl ArenaAllocated for LiveLoadState {
+ type PtrToAllocated = TypedArenaPtr<LiveLoadState>;
+
+ #[inline]
+ fn tag() -> ArenaHeaderTag {
+ ArenaHeaderTag::LiveLoadState
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ mem::size_of::<Self>()
+ }
+
+ #[inline]
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
+ unsafe {
+ ptr::write(dst, self);
+ TypedArenaPtr::new(dst as *mut Self)
+ }
+ }
+}
+
+impl ArenaAllocated for TcpListener {
+ type PtrToAllocated = TypedArenaPtr<TcpListener>;
+
+ #[inline]
+ fn tag() -> ArenaHeaderTag {
+ ArenaHeaderTag::TcpListener
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ mem::size_of::<Self>()
+ }
+
+ #[inline]
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
+ unsafe {
+ ptr::write(dst, self);
+ TypedArenaPtr::new(dst as *mut Self)
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+struct AllocSlab {
+ next: *mut AllocSlab,
+ header: ArenaHeader,
+}
+
+#[derive(Debug)]
+pub struct Arena(*mut AllocSlab);
+
+unsafe impl Send for Arena {}
+unsafe impl Sync for Arena {}
+
+impl Arena {
+ #[inline]
+ pub fn new() -> Self {
+ Arena(ptr::null_mut())
+ }
+
+ pub unsafe fn alloc<T: ArenaAllocated>(&mut self, value: T) -> T::PtrToAllocated {
+ let size = value.size() + mem::size_of::<AllocSlab>();
+
+ let align = mem::align_of::<AllocSlab>();
+ let layout = alloc::Layout::from_size_align_unchecked(size, align);
+
+ let slab = alloc::alloc(layout) as *mut AllocSlab;
+
+ (*slab).next = self.0;
+ (*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag());
+
+ let offset = (*slab).payload_offset();
+ let result = value.copy_to_arena(offset as *mut T);
+
+ self.0 = slab;
+
+ result
+ }
+}
+
+unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
+ use crate::parser::char_reader::CharReader;
+
+ match value.header.tag() {
+ ArenaHeaderTag::Integer => {
+ ptr::drop_in_place(value.payload_offset::<Integer>());
+ }
+ ArenaHeaderTag::Rational => {
+ ptr::drop_in_place(value.payload_offset::<Rational>());
+ }
+ ArenaHeaderTag::InputFileStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<InputFileStream>>>());
+ }
+ ArenaHeaderTag::OutputFileStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<OutputFileStream>>());
+ }
+ ArenaHeaderTag::NamedTcpStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTcpStream>>>());
+ }
+ ArenaHeaderTag::NamedTlsStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
+ }
+ ArenaHeaderTag::ReadlineStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
+ }
+ ArenaHeaderTag::StaticStringStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<StaticStringStream>>());
+ }
+ ArenaHeaderTag::ByteStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<ByteStream>>>());
+ }
+ ArenaHeaderTag::OssifiedOpDir => {
+ ptr::drop_in_place(value.payload_offset::<OssifiedOpDir>());
+ }
+ ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
+ ptr::drop_in_place(value.payload_offset::<LiveLoadState>());
+ }
+ ArenaHeaderTag::Dropped => {
+ }
+ ArenaHeaderTag::TcpListener => {
+ ptr::drop_in_place(value.payload_offset::<TcpListener>());
+ }
+ ArenaHeaderTag::StandardOutputStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
+ }
+ ArenaHeaderTag::StandardErrorStream => {
+ ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>());
+ }
+ ArenaHeaderTag::F64 | ArenaHeaderTag::NullStream => {
+ }
+ }
+}
+
+impl Drop for Arena {
+ fn drop(&mut self) {
+ let mut ptr = self.0;
+
+ while !ptr.is_null() {
+ unsafe {
+ let ptr_r = &*ptr;
+
+ let layout = alloc::Layout::from_size_align_unchecked(
+ ptr_r.slab_size(),
+ mem::align_of::<AllocSlab>(),
+ );
+
+ drop_slab_in_place(&mut *ptr);
+
+ let next_ptr = ptr_r.next;
+ alloc::dealloc(ptr as *mut u8, layout);
+ ptr = next_ptr;
+ }
+ }
+
+ self.0 = ptr::null_mut();
+ }
+}
+
+const_assert!(mem::size_of::<AllocSlab>() == 16);
+
+impl AllocSlab {
+ #[inline]
+ fn slab_size(&self) -> usize {
+ self.header.size() as usize + mem::size_of::<AllocSlab>()
+ }
+
+ fn payload_offset<T>(&self) -> *mut T {
+ let mut ptr = (self as *const AllocSlab) as usize;
+ ptr += mem::size_of::<AllocSlab>();
+ ptr as *mut T
+ }
+}
+
+const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
+
+#[cfg(test)]
+mod tests {
+ use crate::machine::mock_wam::*;
+ use crate::machine::partial_string::*;
+
+ use ordered_float::OrderedFloat;
+ use rug::{Integer, Rational};
+
+ #[test]
+ fn float_ptr_cast() {
+ let mut wam = MockWAM::new();
+
+ let f = OrderedFloat(0f64);
+ let mut fp = arena_alloc!(f, &mut wam.machine_st.arena);
+ let cell = HeapCellValue::from(fp);
+
+ assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
+ assert_eq!(fp.get_mark_bit(), false);
+ assert_eq!(**fp, f);
+
+ fp.mark();
+
+ assert_eq!(fp.get_mark_bit(), true);
+
+ read_heap_cell!(cell,
+ (HeapCellValueTag::F64, ptr) => {
+ assert_eq!(**ptr, f)
+ }
+ _ => { unreachable!() }
+ );
+ }
+
+ #[test]
+ fn heap_cell_value_const_cast() {
+ let mut wam = MockWAM::new();
+ let const_value = HeapCellValue::from(ConsPtr::build_with(
+ 0x0000_5555_ff00_0431 as *const _,
+ ConsPtrMaskTag::Cons,
+ ));
+
+ match const_value.to_untyped_arena_ptr() {
+ Some(arena_ptr) => {
+ assert_eq!(arena_ptr.into_bytes(), const_value.into_bytes());
+ }
+ None => {
+ assert!(false);
+ }
+ }
+
+ let stream = Stream::from_static_string("test", &mut wam.machine_st.arena);
+ let stream_cell =
+ HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons));
+
+ match stream_cell.to_untyped_arena_ptr() {
+ Some(arena_ptr) => {
+ assert_eq!(arena_ptr.into_bytes(), stream_cell.into_bytes());
+ }
+ None => {
+ assert!(false);
+ }
+ }
+ }
+
+ #[test]
+ fn heap_put_literal_tests() {
+ let mut wam = MockWAM::new();
+
+ // integer
+
+ let big_int = 2 * Integer::from(1u64 << 63);
+ let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
+
+ assert!(!big_int_ptr.as_ptr().is_null());
+
+ let cell = HeapCellValue::from(Literal::Integer(big_int_ptr));
+ assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
+
+ let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
+ Some(ptr) => ptr,
+ None => {
+ assert!(false);
+ unreachable!()
+ }
+ };
+
+ match_untyped_arena_ptr!(untyped_arena_ptr,
+ (ArenaHeaderTag::Integer, n) => {
+ assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
+ }
+ _ => unreachable!()
+ );
+
+ read_heap_cell!(cell,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Integer, n) => {
+ assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
+ }
+ _ => { unreachable!() }
+ )
+ }
+ _ => { unreachable!() }
+ );
+
+ // rational
+
+ let big_rat = 2 * Rational::from(1u64 << 63);
+ let big_rat_ptr: TypedArenaPtr<Rational> = arena_alloc!(big_rat, &mut wam.machine_st.arena);
+
+ assert!(!big_rat_ptr.as_ptr().is_null());
+
+ let rat_cell = typed_arena_ptr_as_cell!(big_rat_ptr);
+ assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
+
+ match rat_cell.to_untyped_arena_ptr() {
+ Some(untyped_arena_ptr) => {
+ assert_eq!(
+ Some(big_rat_ptr.header_ptr()),
+ Some(untyped_arena_ptr.into()),
+ );
+ }
+ None => {
+ assert!(false); // we fail.
+ }
+ }
+
+ // assert_eq!(wam.machine_st.heap[1usize].get_tag(), HeapCellValueTag::Cons);
+
+ read_heap_cell!(rat_cell,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Rational, n) => {
+ assert_eq!(&*n, &(2 * Rational::from(1u64 << 63)));
+ }
+ _ => unreachable!()
+ )
+ }
+ _ => { unreachable!() }
+ );
+
+ // atom
+
+ let f_atom = atom!("f");
+ let g_atom = atom!("g");
+
+ assert_eq!(f_atom.as_str(), "f");
+ assert_eq!(g_atom.as_str(), "g");
+
+ let f_atom_cell = atom_as_cell!(f_atom);
+ let g_atom_cell = atom_as_cell!(g_atom);
+
+ assert_eq!(f_atom_cell.get_tag(), HeapCellValueTag::Atom);
+
+ match f_atom_cell.to_atom() {
+ Some(atom) => {
+ assert_eq!(f_atom, atom);
+ assert_eq!(atom.as_str(), "f");
+ }
+ None => {
+ assert!(false);
+ }
+ }
+
+ read_heap_cell!(f_atom_cell,
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ assert_eq!(f_atom, atom);
+ assert_eq!(arity, 0);
+ assert_eq!(atom.as_str(), "f");
+ }
+ _ => { unreachable!() }
+ );
+
+ read_heap_cell!(g_atom_cell,
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ assert_eq!(g_atom, atom);
+ assert_eq!(arity, 0);
+ assert_eq!(atom.as_str(), "g");
+ }
+ _ => { unreachable!() }
+ );
+
+ // complete string
+
+ let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "ronan", &mut wam.machine_st.atom_tbl);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+
+ assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr);
+
+ match pstr_cell.to_pstr() {
+ Some(pstr) => {
+ assert_eq!(pstr.as_str_from(0), "ronan");
+ }
+ None => {
+ assert!(false);
+ }
+ }
+
+ read_heap_cell!(pstr_cell,
+ (HeapCellValueTag::PStr, pstr_atom) => {
+ let pstr = PartialString::from(pstr_atom);
+ assert_eq!(pstr.as_str_from(0), "ronan");
+ }
+ _ => { unreachable!() }
+ );
+
+ // fixnum
+
+ let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
+
+ assert_eq!(fixnum_cell.get_tag(), HeapCellValueTag::Fixnum);
+
+ match fixnum_cell.to_fixnum() {
+ Some(n) => assert_eq!(n.get_num(), 3),
+ None => assert!(false),
+ }
+
+ read_heap_cell!(fixnum_cell,
+ (HeapCellValueTag::Fixnum, n) => {
+ assert_eq!(n.get_num(), 3);
+ }
+ _ => { unreachable!() }
+ );
+
+ let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 55));
+
+ assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
+
+ match fixnum_b_cell.to_fixnum() {
+ Some(n) => assert_eq!(n.get_num(), 1 << 55),
+ None => assert!(false),
+ }
+
+ match Fixnum::build_with_checked(1 << 57) {
+ Ok(_) => assert!(false),
+ _ => assert!(true),
+ }
+
+ match Fixnum::build_with_checked(i64::MAX) {
+ Ok(_) => assert!(false),
+ _ => assert!(true),
+ }
+
+ match Fixnum::build_with_checked(i64::MIN) {
+ Ok(_) => assert!(false),
+ _ => assert!(true),
+ }
+
+ match Fixnum::build_with_checked(-1) {
+ Ok(n) => assert_eq!(n.get_num(), -1),
+ _ => assert!(false),
+ }
+
+ match Fixnum::build_with_checked((1 << 56) - 1) {
+ Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1),
+ _ => assert!(false),
+ }
+
+ match Fixnum::build_with_checked(-(1 << 56)) {
+ Ok(n) => assert_eq!(n.get_num(), -(1 << 56)),
+ _ => assert!(false),
+ }
+
+ match Fixnum::build_with_checked(-(1 << 56) - 1) {
+ Ok(_n) => assert!(false),
+ _ => assert!(true),
+ }
+
+ match Fixnum::build_with_checked(-1) {
+ Ok(n) => assert_eq!(-n, Fixnum::build_with(1)),
+ _ => assert!(false),
+ }
+
+ // float
+
+ let float = OrderedFloat(3.1415926f64);
+ let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena);
+
+ assert!(!float_ptr.as_ptr().is_null());
+
+ let float_cell = typed_arena_ptr_as_cell!(float_ptr);
+ assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
+
+ match float_cell.to_untyped_arena_ptr() {
+ Some(untyped_arena_ptr) => {
+ assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),);
+ }
+ None => {
+ assert!(false); // we fail.
+ }
+ }
+
+ // char
+
+ let c = 'c';
+ let char_cell = char_as_cell!(c);
+
+ read_heap_cell!(char_cell,
+ (HeapCellValueTag::Char, c) => {
+ assert_eq!(c, 'c');
+ }
+ _ => { unreachable!() }
+ );
+
+ let c = 'Ћ';
+ let cyrillic_char_cell = char_as_cell!(c);
+
+ read_heap_cell!(cyrillic_char_cell,
+ (HeapCellValueTag::Char, c) => {
+ assert_eq!(c, 'Ћ');
+ }
+ _ => { unreachable!() }
+ );
+
+ // empty list
+
+ let cell = empty_list_as_cell!();
+
+ read_heap_cell!(cell,
+ (HeapCellValueTag::Atom, (el, _arity)) => {
+ assert_eq!(el.flat_index() as usize, empty_list_as_cell!().get_value());
+ assert_eq!(el.as_str(), "[]");
+ }
+ _ => { unreachable!() }
+ );
+ }
+}
diff --git a/src/arithmetic.rs b/src/arithmetic.rs
index f5a3beeb..894e9d1f 100644
--- a/src/arithmetic.rs
+++ b/src/arithmetic.rs
@@ -1,18 +1,19 @@
-use prolog_parser::ast::*;
-use prolog_parser::{atom, clause_name};
-
-use crate::clause_types::*;
+use crate::allocator::*;
+use crate::arena::*;
+use crate::atom_table::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
+use crate::types::*;
+
+use crate::parser::ast::*;
+use crate::parser::rug::ops::PowAssign;
+use crate::parser::rug::{Assign, Integer, Rational};
-use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
-use crate::rug::ops::PowAssign;
-use crate::rug::{Assign, Integer, Rational};
use ordered_float::*;
use std::cell::Cell;
@@ -20,10 +21,33 @@ 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};
+use std::ops::Div;
use std::rc::Rc;
use std::vec::Vec;
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ArithmeticTerm {
+ Reg(RegType),
+ Interm(usize),
+ Number(Number),
+}
+
+impl ArithmeticTerm {
+ pub(crate) fn interm_or(&self, interm: usize) -> usize {
+ if let &ArithmeticTerm::Interm(interm) = self {
+ interm
+ } else {
+ interm
+ }
+ }
+}
+
+impl Default for ArithmeticTerm {
+ fn default() -> Self {
+ ArithmeticTerm::Number(Number::default())
+ }
+}
+
#[derive(Debug)]
pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
@@ -37,31 +61,30 @@ impl<'a> ArithInstructionIterator<'a> {
.push(TermIterState::subterm_to_state(lvl, term));
}
- fn new(term: &'a Term) -> Result<Self, ArithmeticError> {
+ fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
let state = match term {
- &Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
- &Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
- match ClauseType::from(name.clone(), terms.len(), fixity.clone()) {
- ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => {
- Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
- }
- ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
- let ct = ClauseType::Named(clause_name!("float"), 1, CodeIndex::default());
- Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
- }
- _ => Err(ArithmeticError::NonEvaluableFunctor(
- Constant::Atom(name.clone(), fixity.clone()),
- terms.len(),
- )),
- }?
- }
- &Term::Constant(ref cell, ref cons) => {
- TermIterState::Constant(Level::Shallow, cell, cons)
- }
- &Term::Cons(_, _, _) => {
- return Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))
- }
- &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
+ Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
+ Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) {
+ ct @ ClauseType::Named(..) => {
+ Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
+ }
+ ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
+ let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
+ Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
+ }
+ _ => Err(ArithmeticError::NonEvaluableFunctor(
+ Literal::Atom(*name),
+ terms.len(),
+ )),
+ }?,
+ Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
+ Term::Cons(..) | Term::PartialString(..) => {
+ return Err(ArithmeticError::NonEvaluableFunctor(
+ Literal::Atom(atom!(".")),
+ 2,
+ ))
+ }
+ Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
};
Ok(ArithInstructionIterator {
@@ -72,9 +95,9 @@ impl<'a> ArithInstructionIterator<'a> {
#[derive(Debug)]
pub(crate) enum ArithTermRef<'a> {
- Constant(&'a Constant),
- Op(ClauseName, usize), // name, arity.
- Var(&'a Cell<VarReg>, Rc<Var>),
+ Literal(&'a Literal),
+ Op(Atom, usize), // name, arity.
+ Var(Level, &'a Cell<VarReg>, Rc<String>),
}
impl<'a> Iterator for ArithInstructionIterator<'a> {
@@ -97,14 +120,23 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
ct,
subterms,
));
- self.push_subterm(lvl, subterms[child_num].as_ref());
+
+ self.push_subterm(lvl, &subterms[child_num]);
}
}
- TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))),
- TermIterState::Var(_, cell, var) => {
- return Some(Ok(ArithTermRef::Var(cell, var.clone())))
+ TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
+ TermIterState::Var(lvl, cell, var) => {
+ // the expression is the second argument of an
+ // is/2 but the iterator can't see that, so the
+ // level needs to be demoted manually.
+ return Some(Ok(ArithTermRef::Var(lvl.child_level(), cell, var.clone())));
+ }
+ _ => {
+ return Some(Err(ArithmeticError::NonEvaluableFunctor(
+ Literal::Atom(atom!(".")),
+ 2,
+ )));
}
- _ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
};
}
@@ -113,8 +145,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
}
#[derive(Debug)]
-pub(crate) struct ArithmeticEvaluator<'a> {
- bindings: &'a AllocVarDict,
+pub(crate) struct ArithmeticEvaluator<'a, TermMarker> {
+ marker: &'a mut TermMarker,
interm: Vec<ArithmeticTerm>,
interm_c: usize,
}
@@ -129,82 +161,99 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
type Iter = ArithInstructionIterator<'a>;
fn iter(self) -> Result<Self::Iter, ArithmeticError> {
- ArithInstructionIterator::new(self)
+ ArithInstructionIterator::from(self)
}
}
-impl<'a> ArithmeticEvaluator<'a> {
- pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
+fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
+ match c {
+ Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
+ Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
+ Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))),
+ Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
+ Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
+ Number::Float(OrderedFloat(f64::consts::E)),
+ )),
+ Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
+ Number::Float(OrderedFloat(f64::consts::PI)),
+ )),
+ Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
+ Number::Float(OrderedFloat(f64::EPSILON)),
+ )),
+ _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
+ }
+
+ Ok(())
+}
+
+impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
+ pub(crate) fn new(marker: &'a mut TermMarker, target_int: usize) -> Self {
ArithmeticEvaluator {
- bindings,
+ marker,
interm: Vec::new(),
interm_c: target_int,
}
}
fn get_unary_instr(
- name: ClauseName,
+ &self,
+ name: Atom,
a1: ArithmeticTerm,
t: usize,
- ) -> Result<ArithmeticInstruction, ArithmeticError> {
- match name.as_str() {
- "abs" => Ok(ArithmeticInstruction::Abs(a1, t)),
- "-" => Ok(ArithmeticInstruction::Neg(a1, t)),
- "+" => Ok(ArithmeticInstruction::Plus(a1, t)),
- "cos" => Ok(ArithmeticInstruction::Cos(a1, t)),
- "sin" => Ok(ArithmeticInstruction::Sin(a1, t)),
- "tan" => Ok(ArithmeticInstruction::Tan(a1, t)),
- "log" => Ok(ArithmeticInstruction::Log(a1, t)),
- "exp" => Ok(ArithmeticInstruction::Exp(a1, t)),
- "sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)),
- "acos" => Ok(ArithmeticInstruction::ACos(a1, t)),
- "asin" => Ok(ArithmeticInstruction::ASin(a1, t)),
- "atan" => Ok(ArithmeticInstruction::ATan(a1, t)),
- "float" => Ok(ArithmeticInstruction::Float(a1, t)),
- "truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)),
- "round" => Ok(ArithmeticInstruction::Round(a1, t)),
- "ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
- "floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
- "sign" => Ok(ArithmeticInstruction::Sign(a1, t)),
- "\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
- _ => Err(ArithmeticError::NonEvaluableFunctor(
- Constant::Atom(name, None),
- 1,
- )),
+ ) -> Result<Instruction, ArithmeticError> {
+ match name {
+ atom!("abs") => Ok(Instruction::Abs(a1, t)),
+ atom!("-") => Ok(Instruction::Neg(a1, t)),
+ atom!("+") => Ok(Instruction::Plus(a1, t)),
+ atom!("cos") => Ok(Instruction::Cos(a1, t)),
+ atom!("sin") => Ok(Instruction::Sin(a1, t)),
+ atom!("tan") => Ok(Instruction::Tan(a1, t)),
+ atom!("log") => Ok(Instruction::Log(a1, t)),
+ atom!("exp") => Ok(Instruction::Exp(a1, t)),
+ atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
+ atom!("acos") => Ok(Instruction::ACos(a1, t)),
+ atom!("asin") => Ok(Instruction::ASin(a1, t)),
+ atom!("atan") => Ok(Instruction::ATan(a1, t)),
+ atom!("float") => Ok(Instruction::Float(a1, t)),
+ atom!("truncate") => Ok(Instruction::Truncate(a1, t)),
+ atom!("round") => Ok(Instruction::Round(a1, t)),
+ atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)),
+ atom!("floor") => Ok(Instruction::Floor(a1, t)),
+ atom!("sign") => Ok(Instruction::Sign(a1, t)),
+ atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
+ _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
}
}
fn get_binary_instr(
- name: ClauseName,
+ &self,
+ name: Atom,
a1: ArithmeticTerm,
a2: ArithmeticTerm,
t: usize,
- ) -> Result<ArithmeticInstruction, ArithmeticError> {
- match name.as_str() {
- "+" => Ok(ArithmeticInstruction::Add(a1, a2, t)),
- "-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)),
- "/" => Ok(ArithmeticInstruction::Div(a1, a2, t)),
- "//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)),
- "max" => Ok(ArithmeticInstruction::Max(a1, a2, t)),
- "min" => Ok(ArithmeticInstruction::Min(a1, a2, t)),
- "div" => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)),
- "rdiv" => Ok(ArithmeticInstruction::RDiv(a1, a2, t)),
- "*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)),
- "**" => Ok(ArithmeticInstruction::Pow(a1, a2, t)),
- "^" => Ok(ArithmeticInstruction::IntPow(a1, a2, t)),
- ">>" => Ok(ArithmeticInstruction::Shr(a1, a2, t)),
- "<<" => Ok(ArithmeticInstruction::Shl(a1, a2, t)),
- "/\\" => Ok(ArithmeticInstruction::And(a1, a2, t)),
- "\\/" => Ok(ArithmeticInstruction::Or(a1, a2, t)),
- "xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
- "mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
- "rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
- "gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
- "atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
- _ => Err(ArithmeticError::NonEvaluableFunctor(
- Constant::Atom(name, None),
- 2,
- )),
+ ) -> Result<Instruction, ArithmeticError> {
+ match name {
+ atom!("+") => Ok(Instruction::Add(a1, a2, t)),
+ atom!("-") => Ok(Instruction::Sub(a1, a2, t)),
+ atom!("/") => Ok(Instruction::Div(a1, a2, t)),
+ atom!("//") => Ok(Instruction::IDiv(a1, a2, t)),
+ atom!("max") => Ok(Instruction::Max(a1, a2, t)),
+ atom!("min") => Ok(Instruction::Min(a1, a2, t)),
+ atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)),
+ atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)),
+ atom!("*") => Ok(Instruction::Mul(a1, a2, t)),
+ atom!("**") => Ok(Instruction::Pow(a1, a2, t)),
+ atom!("^") => Ok(Instruction::IntPow(a1, a2, t)),
+ atom!(">>") => Ok(Instruction::Shr(a1, a2, t)),
+ atom!("<<") => Ok(Instruction::Shl(a1, a2, t)),
+ atom!("/\\") => Ok(Instruction::And(a1, a2, t)),
+ atom!("\\/") => Ok(Instruction::Or(a1, a2, t)),
+ atom!("xor") => Ok(Instruction::Xor(a1, a2, t)),
+ atom!("mod") => Ok(Instruction::Mod(a1, a2, t)),
+ atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
+ atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
+ atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
+ _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
}
}
@@ -219,9 +268,9 @@ impl<'a> ArithmeticEvaluator<'a> {
fn instr_from_clause(
&mut self,
- name: ClauseName,
+ name: Atom,
arity: usize,
- ) -> Result<ArithmeticInstruction, ArithmeticError> {
+ ) -> Result<Instruction, ArithmeticError> {
match arity {
1 => {
let a1 = self.interm.pop().unwrap();
@@ -233,7 +282,7 @@ impl<'a> ArithmeticEvaluator<'a> {
a1.interm_or(0)
};
- Self::get_unary_instr(name, a1, ninterm)
+ self.get_unary_instr(name, a1, ninterm)
}
2 => {
let a2 = self.interm.pop().unwrap();
@@ -257,67 +306,55 @@ impl<'a> ArithmeticEvaluator<'a> {
min_interm
};
- Self::get_binary_instr(name, a1, a2, ninterm)
+ self.get_binary_instr(name, a1, a2, ninterm)
}
_ => Err(ArithmeticError::NonEvaluableFunctor(
- Constant::Atom(name, None),
+ Literal::Atom(name),
arity,
)),
}
}
- 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()))),
- &Constant::Float(ref n) => self
- .interm
- .push(ArithmeticTerm::Number(Number::Float(n.clone()))),
- &Constant::Rational(ref n) => self
- .interm
- .push(ArithmeticTerm::Number(Number::Rational(n.clone()))),
- &Constant::Atom(ref name, _) if name.as_str() == "e" => {
- self.interm
- .push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
- f64::consts::E,
- ))))
- }
- &Constant::Atom(ref name, _) if name.as_str() == "pi" => {
- self.interm
- .push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
- f64::consts::PI,
- ))))
- }
- &Constant::Atom(ref name, _) if name.as_str() == "epsilon" => {
- self.interm
- .push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
- f64::EPSILON,
- ))))
- }
- _ => return Err(ArithmeticError::NonEvaluableFunctor(c.clone(), 0)),
- }
-
- Ok(())
- }
-
- pub(crate) fn eval<Iter>(&mut self, src: Iter) -> Result<ArithCont, ArithmeticError>
- where
- Iter: ArithmeticTermIter<'a>,
+ pub(crate) fn eval(
+ &mut self,
+ src: &'a Term,
+ term_loc: GenContext,
+ ) -> Result<ArithCont, ArithmeticError>
{
let mut code = vec![];
+ let mut iter = src.iter()?;
- for term_ref in src.iter()? {
+ while let Some(term_ref) = iter.next() {
match term_ref? {
- ArithTermRef::Constant(c) => self.push_constant(c)?,
- ArithTermRef::Var(cell, name) => {
+ ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
+ ArithTermRef::Var(lvl, cell, name) => {
let r = if cell.get().norm().reg_num() == 0 {
- match self.bindings.get(&name) {
- Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
- Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
- _ => return Err(ArithmeticError::UninstantiatedVar),
- }
+ let mut getter = || {
+ use crate::targets::QueryInstruction;
+
+ loop {
+ match self.marker.bindings().get(&name) {
+ Some(&VarData::Temp(_, t, _)) if t != 0 =>
+ return RegType::Temp(t),
+ Some(&VarData::Perm(p)) if p != 0 =>
+ return RegType::Perm(p),
+ _ => {
+ self.marker.mark_var::<QueryInstruction>(
+ name.clone(),
+ lvl,
+ cell,
+ term_loc,
+ &mut code,
+ );
+ }
+ }
+ }
+ };
+
+ getter()
+ /*
+ _ => return Err(ArithmeticError::UninstantiatedVar),
+ */
} else {
cell.get().norm()
};
@@ -325,7 +362,7 @@ impl<'a> ArithmeticEvaluator<'a> {
self.interm.push(ArithmeticTerm::Reg(r));
}
ArithTermRef::Op(name, arity) => {
- code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?));
+ code.push(self.instr_from_clause(name, arity)?);
}
}
}
@@ -335,27 +372,31 @@ impl<'a> ArithmeticEvaluator<'a> {
}
// integer division rounding function -- 9.1.3.1.
-pub(crate) fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
+pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
match n {
- &Number::Integer(_) => RefOrOwned::Borrowed(n),
- &Number::Float(OrderedFloat(f)) => RefOrOwned::Owned(Number::from(
- Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)),
- )),
- &Number::Fixnum(n) => RefOrOwned::Owned(Number::from(n)),
+ &Number::Integer(_) | &Number::Fixnum(_) => *n,
+ &Number::Float(OrderedFloat(f)) => fixnum!(Number, f.floor() as i64, arena),
&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(Number::from(floor))
+ Number::Integer(arena_alloc!(floor, arena))
}
}
}
+impl From<Fixnum> for Integer {
+ #[inline]
+ fn from(n: Fixnum) -> Integer {
+ Integer::from(n.get_num())
+ }
+}
+
// floating point rounding function -- 9.1.4.1.
pub(crate) fn rnd_f(n: &Number) -> f64 {
match n {
- &Number::Fixnum(n) => n as f64,
+ &Number::Fixnum(n) => n.get_num() as f64,
&Number::Integer(ref n) => n.to_f64(),
&Number::Float(OrderedFloat(f)) => f,
&Number::Rational(ref r) => r.to_f64(),
@@ -392,27 +433,27 @@ where
}
#[inline]
-fn float_fn_to_f(n: isize) -> Result<f64, EvalError> {
+pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
classify_float(n as f64, rnd_f)
}
#[inline]
-fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
+pub(crate) 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> {
+pub(crate) 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> {
+pub(crate) 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> {
+pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
}
@@ -425,161 +466,36 @@ fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
}
}
-impl Add<Number> for Number {
- type Output = Result<Number, EvalError>;
-
- fn add(self, rhs: Number) -> Self::Output {
- match (self, rhs) {
- (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::from(Rational::from(&*n1) + &*n2))
- }
- (Number::Rational(n1), Number::Float(OrderedFloat(n2)))
- | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
- Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
- }
- (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
- Ok(Number::Float(add_f(f1, f2)?))
- }
- (Number::Rational(r1), Number::Rational(r2)) => {
- Ok(Number::from(Rational::from(&*r1) + &*r2))
- }
- }
- }
-}
-
-impl Neg for Number {
- type Output = Number;
-
- fn neg(self) -> Self::Output {
- match self {
- Number::Fixnum(n) => {
- if let Some(n) = n.checked_neg() {
- Number::Fixnum(n)
- } else {
- Number::from(-Integer::from(n))
- }
- }
- Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
- Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
- Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
- }
- }
-}
-
-impl Sub<Number> for Number {
- type Output = Result<Number, EvalError>;
-
- fn sub(self, rhs: Number) -> Self::Output {
- self.add(-rhs)
- }
-}
-
-impl Mul<Number> for Number {
- type Output = Result<Number, EvalError>;
-
- fn mul(self, rhs: Number) -> Self::Output {
- match (self, rhs) {
- (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(Rc::new(Rational::from(&*n1) * &*n2)))
- }
- (Number::Rational(n1), Number::Float(OrderedFloat(n2)))
- | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
- Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?))
- }
- (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
- Ok(Number::Float(mul_f(f1, f2)?))
- }
- (Number::Rational(r1), Number::Rational(r2)) => {
- Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2)))
- }
- }
- }
-}
-
impl Div<Number> for Number {
type Output = Result<Number, EvalError>;
fn div(self, rhs: Number) -> Self::Output {
match (self, rhs) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
- float_fn_to_f(n1)?,
- float_fn_to_f(n2)?,
+ float_fn_to_f(n1.get_num())?,
+ float_fn_to_f(n2.get_num())?,
)?)),
(Number::Fixnum(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
- float_fn_to_f(n1)?,
+ float_fn_to_f(n1.get_num())?,
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)?,
+ float_fn_to_f(n2.get_num())?,
)?)),
(Number::Fixnum(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
- float_fn_to_f(n1)?,
+ float_fn_to_f(n1.get_num())?,
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)?,
+ float_fn_to_f(n2.get_num())?,
)?)),
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
- Ok(Number::Float(div_f(float_fn_to_f(n1)?, n2)?))
+ Ok(Number::Float(div_f(float_fn_to_f(n1.get_num())?, n2)?))
}
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
- Ok(Number::Float(div_f(n1, float_fn_to_f(n2)?)?))
+ Ok(Number::Float(div_f(n1, float_fn_to_f(n2.get_num())?)?))
}
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
float_i_to_f(&n1)?,
@@ -620,14 +536,14 @@ 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(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).eq(&n2),
- (&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2 as f64)),
+ (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().eq(&**n2),
+ (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
+ (&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.get_num().eq(&**n2),
+ (&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
+ (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2),
+ (&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2.get_num() as f64)),
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2),
- (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(&n2),
+ (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(n2),
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())),
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
#[cfg(feature = "num")]
@@ -659,6 +575,46 @@ impl PartialEq for Number {
impl Eq for Number {}
+impl PartialOrd<usize> for Number {
+ #[inline]
+ fn partial_cmp(&self, rhs: &usize) -> Option<Ordering> {
+ match self {
+ Number::Fixnum(n) => {
+ let n = n.get_num();
+
+ if n < 0i64 {
+ Some(Ordering::Less)
+ } else {
+ (n as usize).partial_cmp(rhs)
+ }
+ }
+ Number::Integer(n) => (&**n).partial_cmp(rhs),
+ Number::Rational(r) => (&**r).partial_cmp(rhs),
+ Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)),
+ }
+ }
+}
+
+impl PartialEq<usize> for Number {
+ #[inline]
+ fn eq(&self, rhs: &usize) -> bool {
+ match self {
+ Number::Fixnum(n) => {
+ let n = n.get_num();
+
+ if n < 0i64 {
+ false
+ } else {
+ (n as usize).eq(rhs)
+ }
+ }
+ Number::Integer(n) => (&**n).eq(rhs),
+ Number::Rational(r) => (&**r).eq(rhs),
+ Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)),
+ }
+ }
+}
+
impl PartialOrd for Number {
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
Some(self.cmp(rhs))
@@ -668,92 +624,78 @@ impl PartialOrd for Number {
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(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).cmp(&n2),
- (&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2 as f64)),
- (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
- (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
+ (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()),
+ (&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(&*n2),
+ (Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2.get_num())),
+ (&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(&*n2),
+ (Number::Rational(n1), &Number::Fixnum(n2)) => {
+ (&**n1).cmp(&Rational::from(n2.get_num()))
+ }
+ (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2),
+ (&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)),
+ (&Number::Integer(n1), &Number::Integer(n2)) => (*n1).cmp(&*n2),
+ (&Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2),
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
- (&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
+ (&Number::Integer(n1), &Number::Rational(n2)) => {
#[cfg(feature = "num")]
{
Rational::from(&**n1).cmp(n2)
}
#[cfg(not(feature = "num"))]
{
- (&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
+ (&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less)
}
}
- (&Number::Rational(ref n1), &Number::Integer(ref n2)) => {
+ (&Number::Rational(n1), &Number::Integer(n2)) => {
#[cfg(feature = "num")]
{
(&**n1).cmp(&Rational::from(&**n2))
}
#[cfg(not(feature = "num"))]
{
- (&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
+ (&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less)
}
}
- (&Number::Rational(ref n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
- (&Number::Float(n1), &Number::Rational(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
+ (&Number::Rational(n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
+ (&Number::Float(n1), &Number::Rational(n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
(&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
- (&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.cmp(&r2),
+ (&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2),
}
}
}
-impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
+impl TryFrom<HeapCellValue> for Number {
type Error = ();
- fn try_from((addr, heap): (Addr, &'a Heap)) -> Result<Number, Self::Error> {
- match addr {
- 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::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(()),
- }
- }
-}
-
-impl<'a> From<&'a Integer> for Number {
#[inline]
- fn from(src: &'a Integer) -> Self {
- Number::Integer(Rc::new(Integer::from(src)))
+ fn try_from(value: HeapCellValue) -> Result<Number, Self::Error> {
+ read_heap_cell!(value,
+ (HeapCellValueTag::Cons, c) => {
+ match_untyped_arena_ptr!(c,
+ (ArenaHeaderTag::F64, n) => {
+ Ok(Number::Float(*n))
+ }
+ (ArenaHeaderTag::Integer, n) => {
+ Ok(Number::Integer(n))
+ }
+ (ArenaHeaderTag::Rational, n) => {
+ Ok(Number::Rational(n))
+ }
+ _ => {
+ Err(())
+ }
+ )
+ }
+ (HeapCellValueTag::F64, n) => {
+ Ok(Number::Float(**n))
+ }
+ (HeapCellValueTag::Fixnum, n) => {
+ Ok(Number::Fixnum(n))
+ }
+ _ => {
+ Err(())
+ }
+ )
}
}
diff --git a/src/atom_table.rs b/src/atom_table.rs
new file mode 100644
index 00000000..b925273a
--- /dev/null
+++ b/src/atom_table.rs
@@ -0,0 +1,366 @@
+use crate::parser::ast::MAX_ARITY;
+use crate::raw_block::*;
+use crate::types::*;
+
+use std::borrow::Borrow;
+use std::cmp::Ordering;
+use std::hash::{Hash, Hasher};
+use std::mem;
+use std::ptr;
+use std::slice;
+use std::str;
+
+use indexmap::IndexSet;
+
+use modular_bitfield::prelude::*;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct Atom {
+ pub index: usize,
+}
+
+const_assert!(mem::size_of::<Atom>() == 8);
+
+include!(concat!(env!("OUT_DIR"), "/static_atoms.rs"));
+
+impl<'a> From<&'a Atom> for Atom {
+ #[inline]
+ fn from(atom: &'a Atom) -> Self {
+ *atom
+ }
+}
+
+impl From<bool> for Atom {
+ #[inline]
+ fn from(value: bool) -> Self {
+ if value { atom!("true") } else { atom!("false") }
+ }
+}
+
+#[cfg(test)]
+use std::cell::RefCell;
+
+const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
+const ATOM_TABLE_ALIGN: usize = 8;
+
+#[cfg(test)]
+thread_local! {
+ static ATOM_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut());
+}
+
+#[cfg(not(test))]
+static mut ATOM_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
+
+#[cfg(test)]
+fn set_atom_tbl_buf_base(ptr: *const u8) {
+ ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| {
+ *atom_table_buf_base.borrow_mut() = ptr;
+ });
+}
+
+#[cfg(test)]
+pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
+ ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| *atom_table_buf_base.borrow())
+}
+
+#[cfg(not(test))]
+fn set_atom_tbl_buf_base(ptr: *const u8) {
+ unsafe {
+ ATOM_TABLE_BUF_BASE = ptr;
+ }
+}
+
+#[cfg(not(test))]
+pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
+ unsafe { ATOM_TABLE_BUF_BASE }
+}
+
+impl RawBlockTraits for AtomTable {
+ #[inline]
+ fn init_size() -> usize {
+ ATOM_TABLE_INIT_SIZE
+ }
+
+ #[inline]
+ fn align() -> usize {
+ ATOM_TABLE_ALIGN
+ }
+}
+
+#[bitfield]
+#[derive(Copy, Clone, Debug)]
+struct AtomHeader {
+ #[allow(unused)] m: bool,
+ len: B50,
+ #[allow(unused)] padding: B13,
+}
+
+impl AtomHeader {
+ fn build_with(len: u64) -> Self {
+ AtomHeader::new().with_len(len).with_m(false)
+ }
+}
+
+impl Borrow<str> for Atom {
+ #[inline]
+ fn borrow(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl Hash for Atom {
+ #[inline]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ self.as_str().hash(hasher)
+ // hasher.write_usize(self.index)
+ }
+}
+
+#[macro_export]
+macro_rules! is_char {
+ ($s:expr) => {
+ !$s.is_empty() && $s.chars().nth(1).is_none()
+ };
+}
+
+impl Atom {
+ #[inline]
+ pub fn buf(self) -> *const u8 {
+ let ptr = self.as_ptr();
+
+ if ptr.is_null() {
+ return ptr::null();
+ }
+
+ (ptr as usize + mem::size_of::<AtomHeader>()) as *const u8
+ }
+
+ #[inline(always)]
+ pub fn is_static(self) -> bool {
+ self.index < STRINGS.len() << 3
+ }
+
+ #[inline(always)]
+ pub fn as_ptr(self) -> *const u8 {
+ if self.is_static() {
+ ptr::null()
+ } else {
+ (get_atom_tbl_buf_base() as usize + self.index - (STRINGS.len() << 3)) as *const u8
+ }
+ }
+
+ #[inline(always)]
+ pub fn from(index: usize) -> Self {
+ Self { index }
+ }
+
+ #[inline(always)]
+ pub fn len(self) -> usize {
+ if self.is_static() {
+ STRINGS[self.index >> 3].len()
+ } else {
+ unsafe { ptr::read(self.as_ptr() as *const AtomHeader).len() as _ }
+ }
+ }
+
+ #[inline(always)]
+ pub fn flat_index(self) -> u64 {
+ (self.index >> 3) as u64
+ }
+
+ pub fn as_char(self) -> Option<char> {
+ let s = self.as_str();
+ let mut it = s.chars();
+
+ let c1 = it.next();
+ let c2 = it.next();
+
+ if c2.is_none() { c1 } else { None }
+ }
+
+ #[inline]
+ pub fn chars(&self) -> str::Chars {
+ self.as_str().chars()
+ }
+
+ #[inline]
+ pub fn as_str(&self) -> &str {
+ unsafe {
+ let ptr = self.as_ptr();
+
+ if ptr.is_null() {
+ return STRINGS[self.index >> 3];
+ }
+
+ let header = ptr::read::<AtomHeader>(ptr as *const _);
+ let len = header.len() as usize;
+ let buf = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
+
+ str::from_utf8_unchecked(slice::from_raw_parts(buf, len))
+ }
+ }
+
+ pub fn defrock_brackets(&self, atom_tbl: &mut AtomTable) -> Self {
+ let s = self.as_str();
+
+ let s = if s.starts_with('(') && s.ends_with(')') {
+ &s['('.len_utf8()..s.len() - ')'.len_utf8()]
+ } else {
+ return *self;
+ };
+
+ atom_tbl.build_with(s)
+ }
+}
+
+unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
+ ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
+ let str_ptr = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
+ ptr::copy_nonoverlapping(string.as_ptr(), str_ptr as *mut u8, string.len());
+}
+
+impl PartialOrd for Atom {
+ #[inline]
+ fn partial_cmp(&self, other: &Atom) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Atom {
+ #[inline]
+ fn cmp(&self, other: &Atom) -> Ordering {
+ self.as_str().cmp(other.as_str())
+ }
+}
+
+#[derive(Debug)]
+pub struct AtomTable {
+ block: RawBlock<AtomTable>,
+ pub table: IndexSet<Atom>,
+}
+
+impl Drop for AtomTable {
+ fn drop(&mut self) {
+ self.block.deallocate();
+ }
+}
+
+impl AtomTable {
+ #[inline]
+ pub fn new() -> Self {
+ let table = Self {
+ block: RawBlock::new(),
+ table: IndexSet::new(),
+ };
+
+ set_atom_tbl_buf_base(table.block.base);
+ table
+ }
+
+ #[inline]
+ pub fn buf(&self) -> *const u8 {
+ self.block.base as *const u8
+ }
+
+ #[inline]
+ pub fn top(&self) -> *const u8 {
+ self.block.top
+ }
+
+ #[inline(always)]
+ fn lookup_str(&self, string: &str) -> Option<Atom> {
+ STATIC_ATOMS_MAP.get(string).or_else(|| self.table.get(string)).cloned()
+ }
+
+ pub fn build_with(&mut self, string: &str) -> Atom {
+ if let Some(atom) = self.lookup_str(string) {
+ return atom;
+ }
+
+ unsafe {
+ let size = mem::size_of::<AtomHeader>() + string.len();
+ let align_offset = 8 * mem::align_of::<AtomHeader>();
+ let size = (size & !(align_offset - 1)) + align_offset;
+
+ let len_ptr = {
+ let mut ptr;
+
+ loop {
+ ptr = self.block.alloc(size);
+
+ if ptr.is_null() {
+ self.block.grow();
+ set_atom_tbl_buf_base(self.block.base);
+ } else {
+ break;
+ }
+ }
+
+ ptr
+ };
+
+ let ptr_base = self.block.base as usize;
+
+ write_to_ptr(string, len_ptr);
+
+ let atom = Atom {
+ index: (STRINGS.len() << 3) + len_ptr as usize - ptr_base,
+ };
+
+ self.table.insert(atom);
+
+ atom
+ }
+ }
+}
+
+#[bitfield]
+#[repr(u64)]
+#[derive(Copy, Clone, Debug)]
+pub struct AtomCell {
+ name: B46,
+ arity: B10,
+ #[allow(unused)] f: bool,
+ #[allow(unused)] m: bool,
+ #[allow(unused)] tag: B6,
+}
+
+impl AtomCell {
+ #[inline]
+ pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self {
+ if arity > 0 {
+ debug_assert!(arity as usize <= MAX_ARITY);
+
+ AtomCell::new()
+ .with_name(name)
+ .with_arity(arity)
+ .with_f(false)
+ .with_tag(tag as u8)
+ } else {
+ AtomCell::new()
+ .with_name(name)
+ .with_f(false)
+ .with_tag(tag as u8)
+ }
+ }
+
+ #[inline]
+ pub fn get_index(self) -> usize {
+ self.name() as usize
+ }
+
+ #[inline]
+ pub fn get_name(self) -> Atom {
+ Atom::from(self.get_index() << 3)
+ }
+
+ #[inline]
+ pub fn get_arity(self) -> usize {
+ self.arity() as usize
+ }
+
+ #[inline]
+ pub fn get_name_and_arity(self) -> (Atom, usize) {
+ (Atom::from(self.get_index() << 3), self.get_arity())
+ }
+}
diff --git a/src/bin/scryer-prolog.rs b/src/bin/scryer-prolog.rs
index a1cf2a99..f8d3aa6e 100644
--- a/src/bin/scryer-prolog.rs
+++ b/src/bin/scryer-prolog.rs
@@ -1,16 +1,12 @@
fn main() {
use nix::sys::signal;
- use scryer_prolog::read::readline;
use scryer_prolog::*;
let handler = signal::SigHandler::Handler(handle_sigint);
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
- let mut wam = machine::Machine::new(
- readline::input_stream(),
- machine::Stream::stdout(),
- machine::Stream::stderr(),
- );
+ let mut wam = machine::Machine::new();
+
wam.run_top_level();
}
diff --git a/src/clause_types.rs b/src/clause_types.rs
deleted file mode 100644
index cb654867..00000000
--- a/src/clause_types.rs
+++ /dev/null
@@ -1,994 +0,0 @@
-use prolog_parser::ast::*;
-use prolog_parser::{clause_name, temp_v};
-
-use crate::forms::Number;
-use crate::machine::machine_indices::*;
-use crate::rug::rand::RandState;
-
-use ref_thread_local::{ref_thread_local, RefThreadLocal};
-
-use std::collections::BTreeMap;
-
-#[derive(Debug, Clone, Copy, Eq, PartialEq)]
-pub(crate) enum CompareNumberQT {
- GreaterThan,
- LessThan,
- GreaterThanOrEqual,
- LessThanOrEqual,
- NotEqual,
- Equal,
-}
-
-impl CompareNumberQT {
- fn name(self) -> &'static str {
- match self {
- CompareNumberQT::GreaterThan => ">",
- CompareNumberQT::LessThan => "<",
- CompareNumberQT::GreaterThanOrEqual => ">=",
- CompareNumberQT::LessThanOrEqual => "=<",
- CompareNumberQT::NotEqual => "=\\=",
- CompareNumberQT::Equal => "=:=",
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum CompareTermQT {
- LessThan,
- LessThanOrEqual,
- GreaterThanOrEqual,
- GreaterThan,
-}
-
-impl CompareTermQT {
- fn name<'a>(self) -> &'a str {
- match self {
- CompareTermQT::GreaterThan => "@>",
- CompareTermQT::LessThan => "@<",
- CompareTermQT::GreaterThanOrEqual => "@>=",
- CompareTermQT::LessThanOrEqual => "@=<",
- }
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) enum ArithmeticTerm {
- Reg(RegType),
- Interm(usize),
- Number(Number),
-}
-
-impl ArithmeticTerm {
- pub(crate) fn interm_or(&self, interm: usize) -> usize {
- if let &ArithmeticTerm::Interm(interm) = self {
- interm
- } else {
- interm
- }
- }
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub(crate) enum InlinedClauseType {
- CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
- IsAtom(RegType),
- IsAtomic(RegType),
- IsCompound(RegType),
- IsInteger(RegType),
- IsNumber(RegType),
- IsRational(RegType),
- IsFloat(RegType),
- IsNonVar(RegType),
- IsVar(RegType),
-}
-
-ref_thread_local! {
- pub(crate)static managed RANDOM_STATE: RandState<'static> = RandState::new();
-}
-
-ref_thread_local! {
- pub(crate)static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = {
- let mut m = BTreeMap::new();
-
- let r1 = temp_v!(1);
- let r2 = temp_v!(2);
-
- m.insert((">", 2),
- ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThan, ar_reg!(r1), ar_reg!(r2))));
- m.insert(("<", 2),
- ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThan, ar_reg!(r1), ar_reg!(r2))));
- m.insert((">=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThanOrEqual, ar_reg!(r1), ar_reg!(r2))));
- m.insert(("=<", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual, ar_reg!(r1), ar_reg!(r2))));
- m.insert(("=:=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::Equal, ar_reg!(r1), ar_reg!(r2))));
- m.insert(("=\\=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual, ar_reg!(r1), ar_reg!(r2))));
- m.insert(("atom", 1), ClauseType::Inlined(InlinedClauseType::IsAtom(r1)));
- m.insert(("atomic", 1), ClauseType::Inlined(InlinedClauseType::IsAtomic(r1)));
- m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1)));
- m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1)));
- m.insert(("number", 1), ClauseType::Inlined(InlinedClauseType::IsNumber(r1)));
- m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(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)));
- m.insert(("acyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm));
- m.insert(("arg", 3), ClauseType::BuiltIn(BuiltInClauseType::Arg));
- m.insert(("compare", 3), ClauseType::BuiltIn(BuiltInClauseType::Compare));
- m.insert(("@>", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThan)));
- m.insert(("@<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThan)));
- 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(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
- m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor));
- m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground));
- m.insert(("is", 2), ClauseType::BuiltIn(BuiltInClauseType::Is(r1, ar_reg!(r2))));
- m.insert(("keysort", 2), ClauseType::BuiltIn(BuiltInClauseType::KeySort));
- m.insert(("\\==", 2), ClauseType::BuiltIn(BuiltInClauseType::NotEq));
- m.insert(("read", 2), ClauseType::BuiltIn(BuiltInClauseType::Read));
- m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort));
-
- m
- };
-}
-
-impl InlinedClauseType {
- pub(crate) fn name(&self) -> &'static str {
- match self {
- &InlinedClauseType::CompareNumber(qt, ..) => qt.name(),
- &InlinedClauseType::IsAtom(..) => "atom",
- &InlinedClauseType::IsAtomic(..) => "atomic",
- &InlinedClauseType::IsCompound(..) => "compound",
- &InlinedClauseType::IsNumber(..) => "number",
- &InlinedClauseType::IsInteger(..) => "integer",
- &InlinedClauseType::IsRational(..) => "rational",
- &InlinedClauseType::IsFloat(..) => "float",
- &InlinedClauseType::IsNonVar(..) => "nonvar",
- &InlinedClauseType::IsVar(..) => "var",
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub(crate) enum SystemClauseType {
- AtomChars,
- AtomCodes,
- AtomLength,
- BindFromRegister,
- CallContinuation,
- CharCode,
- CharType,
- CharsToNumber,
- CodesToNumber,
- CopyTermWithoutAttrVars,
- CheckCutPoint,
- Close,
- CopyToLiftedHeap,
- CreatePartialString,
- CurrentHostname,
- CurrentInput,
- CurrentOutput,
- DirectoryFiles,
- FileSize,
- FileExists,
- DirectoryExists,
- DirectorySeparator,
- MakeDirectory,
- MakeDirectoryPath,
- DeleteFile,
- RenameFile,
- DeleteDirectory,
- WorkingDirectory,
- PathCanonical,
- FileTime,
- DeleteAttribute,
- DeleteHeadAttribute,
- DynamicModuleResolution(usize),
- EnqueueAttributedVar,
- FetchGlobalVar,
- FirstStream,
- FlushOutput,
- GetByte,
- GetChar,
- GetNChars,
- GetCode,
- GetSingleChar,
- ResetAttrVarState,
- TruncateIfNoLiftedHeapGrowthDiff,
- TruncateIfNoLiftedHeapGrowth,
- GetAttributedVariableList,
- GetAttrVarQueueDelimiter,
- GetAttrVarQueueBeyond,
- GetBValue,
- GetContinuationChunk,
- GetNextDBRef,
- GetNextOpDBRef,
- IsPartialString,
- LookupDBRef,
- LookupOpDBRef,
- Halt,
- GetLiftedHeapFromOffset,
- GetLiftedHeapFromOffsetDiff,
- GetSCCCleaner,
- HeadIsDynamic,
- InstallSCCCleaner,
- InstallInferenceCounter,
- LiftedHeapLength,
- LoadLibraryAsStream,
- ModuleExists,
- NextEP,
- NoSuchPredicate,
- NumberToChars,
- NumberToCodes,
- OpDeclaration,
- Open,
- SetStreamOptions,
- NextStream,
- PartialStringTail,
- PeekByte,
- PeekChar,
- PeekCode,
- PointsToContinuationResetMarker,
- PutByte,
- PutChar,
- PutChars,
- PutCode,
- REPL(REPLCodePtr),
- ReadQueryTerm,
- ReadTerm,
- RedoAttrVarBinding,
- RemoveCallPolicyCheck,
- RemoveInferenceCounter,
- ResetContinuationMarker,
- RestoreCutPolicy,
- SetCutPoint(RegType),
- SetInput,
- SetOutput,
- StoreBacktrackableGlobalVar,
- StoreGlobalVar,
- StreamProperty,
- SetStreamPosition,
- InferenceLevel,
- CleanUpBlock,
- EraseBall,
- Fail,
- GetBall,
- GetCurrentBlock,
- GetCutPoint,
- GetDoubleQuotes,
- InstallNewBlock,
- Maybe,
- CpuNow,
- CurrentTime,
- QuotedToken,
- ReadTermFromChars,
- ResetBlock,
- ReturnFromVerifyAttr,
- SetBall,
- SetCutPointByDefault(RegType),
- SetDoubleQuotes,
- SetSeed,
- SkipMaxList,
- Sleep,
- SocketClientOpen,
- SocketServerOpen,
- SocketServerAccept,
- SocketServerClose,
- TLSAcceptClient,
- TLSClientConnect,
- Succeed,
- TermAttributedVariables,
- TermVariables,
- TruncateLiftedHeapTo,
- UnifyWithOccursCheck,
- UnwindEnvironments,
- UnwindStack,
- Variant,
- WAMInstructions,
- WriteTerm,
- WriteTermToChars,
- ScryerPrologVersion,
- CryptoRandomByte,
- CryptoDataHash,
- CryptoDataHKDF,
- CryptoPasswordHash,
- CryptoDataEncrypt,
- CryptoDataDecrypt,
- CryptoCurveScalarMult,
- Ed25519Sign,
- Ed25519Verify,
- Ed25519NewKeyPair,
- Ed25519KeyPairPublicKey,
- Curve25519ScalarMult,
- FirstNonOctet,
- LoadHTML,
- LoadXML,
- GetEnv,
- SetEnv,
- UnsetEnv,
- Shell,
- PID,
- CharsBase64,
- DevourWhitespace,
- IsSTOEnabled,
- SetSTOAsUnify,
- SetNSTOAsUnify,
- SetSTOWithErrorAsUnify,
- HomeDirectory,
- DebugHook,
- PopCount
-}
-
-impl SystemClauseType {
- pub(crate) fn name(&self) -> ClauseName {
- match self {
- &SystemClauseType::AtomChars => clause_name!("$atom_chars"),
- &SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
- &SystemClauseType::AtomLength => clause_name!("$atom_length"),
- &SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
- &SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
- &SystemClauseType::CharCode => clause_name!("$char_code"),
- &SystemClauseType::CharType => clause_name!("$char_type"),
- &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
- &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
- &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::CurrentHostname => clause_name!("$current_hostname"),
- &SystemClauseType::CurrentOutput => clause_name!("$current_output"),
- &SystemClauseType::DirectoryFiles => clause_name!("$directory_files"),
- &SystemClauseType::FileSize => clause_name!("$file_size"),
- &SystemClauseType::FileExists => clause_name!("$file_exists"),
- &SystemClauseType::DirectoryExists => clause_name!("$directory_exists"),
- &SystemClauseType::DirectorySeparator => clause_name!("$directory_separator"),
- &SystemClauseType::MakeDirectory => clause_name!("$make_directory"),
- &SystemClauseType::MakeDirectoryPath => clause_name!("$make_directory_path"),
- &SystemClauseType::DeleteFile => clause_name!("$delete_file"),
- &SystemClauseType::RenameFile => clause_name!("$rename_file"),
- &SystemClauseType::DeleteDirectory => clause_name!("$delete_directory"),
- &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
- &SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
- &SystemClauseType::FileTime => clause_name!("$file_time"),
- &SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => {
- clause_name!("$add_discontiguous_predicate")
- }
- &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => {
- clause_name!("$add_dynamic_predicate")
- }
- &SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => {
- clause_name!("$add_multifile_predicate")
- }
- &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => {
- clause_name!("$add_goal_expansion_clause")
- }
- &SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => {
- clause_name!("$add_term_expansion_clause")
- }
- &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => {
- clause_name!("$clause_to_evacuable")
- }
- &SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable) => {
- clause_name!("$scoped_clause_to_evacuable")
- }
- &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => clause_name!("$conclude_load"),
- &SystemClauseType::REPL(REPLCodePtr::DeclareModule) => clause_name!("$declare_module"),
- &SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => {
- clause_name!("$load_compiled_library")
- }
- &SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) => {
- clause_name!("$push_load_state_payload")
- }
- &SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule) => {
- clause_name!("$add_in_situ_filename_module")
- }
- &SystemClauseType::REPL(REPLCodePtr::Asserta) => clause_name!("$asserta"),
- &SystemClauseType::REPL(REPLCodePtr::Assertz) => clause_name!("$assertz"),
- &SystemClauseType::REPL(REPLCodePtr::Retract) => clause_name!("$retract_clause"),
- &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
- &SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => {
- clause_name!("$push_load_context")
- }
- &SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => {
- clause_name!("$pop_load_context")
- }
- &SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => {
- clause_name!("$pop_load_state_payload")
- }
- &SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => {
- clause_name!("$prolog_lc_source")
- }
- &SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => {
- clause_name!("$prolog_lc_file")
- }
- &SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => {
- clause_name!("$prolog_lc_dir")
- }
- &SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => {
- clause_name!("$prolog_lc_module")
- }
- &SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => {
- clause_name!("$prolog_lc_stream")
- }
- &SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => {
- clause_name!("$cpp_meta_predicate_property")
- }
- &SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => {
- clause_name!("$cpp_built_in_property")
- }
- &SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => {
- clause_name!("$cpp_dynamic_property")
- }
- &SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => {
- clause_name!("$cpp_multifile_property")
- }
- &SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => {
- clause_name!("$cpp_discontiguous_property")
- }
- &SystemClauseType::REPL(REPLCodePtr::AbolishClause) => clause_name!("$abolish_clause"),
- &SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => {
- clause_name!("$is_consistent_with_term_queue")
- }
- &SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => {
- clause_name!("$flush_term_queue")
- }
- &SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => {
- clause_name!("$remove_module_exports")
- }
- &SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => {
- clause_name!("$add_non_counted_backtracking")
- }
- &SystemClauseType::Close => clause_name!("$close"),
- &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
- &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
- &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
- &SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"),
- &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
- &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
- &SystemClauseType::FirstStream => clause_name!("$first_stream"),
- &SystemClauseType::FlushOutput => clause_name!("$flush_output"),
- &SystemClauseType::GetByte => clause_name!("$get_byte"),
- &SystemClauseType::GetChar => clause_name!("$get_char"),
- &SystemClauseType::GetNChars => clause_name!("$get_n_chars"),
- &SystemClauseType::GetCode => clause_name!("$get_code"),
- &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
- &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
- &SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
- clause_name!("$truncate_if_no_lh_growth")
- }
- &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
- clause_name!("$truncate_if_no_lh_growth_diff")
- }
- &SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"),
- &SystemClauseType::GetAttrVarQueueDelimiter => {
- clause_name!("$get_attr_var_queue_delim")
- }
- &SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
- &SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"),
- &SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
- &SystemClauseType::GetLiftedHeapFromOffsetDiff => {
- clause_name!("$get_lh_from_offset_diff")
- }
- &SystemClauseType::GetBValue => clause_name!("$get_b_value"),
- // &SystemClauseType::GetClause => clause_name!("$get_clause"),
- &SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"),
- &SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"),
- &SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"),
- &SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"),
- &SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
- // &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
- &SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
- &SystemClauseType::Halt => clause_name!("$halt"),
- &SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
- &SystemClauseType::Open => clause_name!("$open"),
- &SystemClauseType::SetStreamOptions => clause_name!("$set_stream_options"),
- &SystemClauseType::OpDeclaration => clause_name!("$op"),
- &SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
- &SystemClauseType::InstallInferenceCounter => {
- clause_name!("$install_inference_counter")
- }
- &SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
- &SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
- &SystemClauseType::PeekByte => clause_name!("$peek_byte"),
- &SystemClauseType::PeekChar => clause_name!("$peek_char"),
- &SystemClauseType::PeekCode => clause_name!("$peek_code"),
- &SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
- &SystemClauseType::Maybe => clause_name!("maybe"),
- &SystemClauseType::CpuNow => clause_name!("$cpu_now"),
- &SystemClauseType::CurrentTime => clause_name!("$current_time"),
- // &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
- // clause_name!("$module_asserta")
- // }
- // &SystemClauseType::ModuleAssertDynamicPredicateToBack => {
- // clause_name!("$module_assertz")
- // }
- // &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
- &SystemClauseType::ModuleExists => clause_name!("$module_exists"),
- &SystemClauseType::NextStream => clause_name!("$next_stream"),
- &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
- &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
- &SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
- &SystemClauseType::PointsToContinuationResetMarker => {
- clause_name!("$points_to_cont_reset_marker")
- }
- &SystemClauseType::PutByte => {
- clause_name!("$put_byte")
- }
- &SystemClauseType::PutChar => {
- clause_name!("$put_char")
- }
- &SystemClauseType::PutChars => {
- clause_name!("$put_chars")
- }
- &SystemClauseType::PutCode => {
- clause_name!("$put_code")
- }
- &SystemClauseType::QuotedToken => {
- clause_name!("$quoted_token")
- }
- &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::StreamProperty => clause_name!("$stream_property"),
- &SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
- &SystemClauseType::StoreBacktrackableGlobalVar => {
- clause_name!("$store_back_trackable_global_var")
- }
- &SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
- &SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
- &SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
- &SystemClauseType::EraseBall => clause_name!("$erase_ball"),
- &SystemClauseType::Fail => clause_name!("$fail"),
- &SystemClauseType::GetBall => clause_name!("$get_ball"),
- &SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
- &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
- &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
- &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::ResetBlock => clause_name!("$reset_block"),
- &SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
- &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
- &SystemClauseType::SetBall => clause_name!("$set_ball"),
- &SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
- &SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"),
- &SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"),
- &SystemClauseType::Sleep => clause_name!("$sleep"),
- &SystemClauseType::SocketClientOpen => clause_name!("$socket_client_open"),
- &SystemClauseType::SocketServerOpen => clause_name!("$socket_server_open"),
- &SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"),
- &SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"),
- &SystemClauseType::TLSAcceptClient => clause_name!("$tls_accept_client"),
- &SystemClauseType::TLSClientConnect => clause_name!("$tls_client_connect"),
- &SystemClauseType::Succeed => clause_name!("$succeed"),
- &SystemClauseType::TermAttributedVariables => {
- clause_name!("$term_attributed_variables")
- }
- &SystemClauseType::TermVariables => clause_name!("$term_variables"),
- &SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
- &SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
- &SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"),
- &SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
- &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"),
- &SystemClauseType::ScryerPrologVersion => clause_name!("$scryer_prolog_version"),
- &SystemClauseType::CryptoRandomByte => clause_name!("$crypto_random_byte"),
- &SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"),
- &SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"),
- &SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
- &SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
- &SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
- &SystemClauseType::CryptoCurveScalarMult => clause_name!("$crypto_curve_scalar_mult"),
- &SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"),
- &SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
- &SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
- &SystemClauseType::Ed25519KeyPairPublicKey => {
- clause_name!("$ed25519_keypair_public_key")
- }
- &SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"),
- &SystemClauseType::FirstNonOctet => clause_name!("$first_non_octet"),
- &SystemClauseType::LoadHTML => clause_name!("$load_html"),
- &SystemClauseType::LoadXML => clause_name!("$load_xml"),
- &SystemClauseType::GetEnv => clause_name!("$getenv"),
- &SystemClauseType::SetEnv => clause_name!("$setenv"),
- &SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
- &SystemClauseType::Shell => clause_name!("$shell"),
- &SystemClauseType::PID => clause_name!("$pid"),
- &SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
- &SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"),
- &SystemClauseType::DevourWhitespace => clause_name!("$devour_whitespace"),
- &SystemClauseType::IsSTOEnabled => clause_name!("$is_sto_enabled"),
- &SystemClauseType::SetSTOAsUnify => clause_name!("$set_sto_as_unify"),
- &SystemClauseType::SetNSTOAsUnify => clause_name!("$set_nsto_as_unify"),
- &SystemClauseType::HomeDirectory => clause_name!("$home_directory"),
- &SystemClauseType::SetSTOWithErrorAsUnify => {
- clause_name!("$set_sto_with_error_as_unify")
- }
- &SystemClauseType::DebugHook => clause_name!("$debug_hook"),
- &SystemClauseType::PopCount => clause_name!("$popcount"),
- }
- }
-
- pub(crate) fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
- match (name, arity) {
- ("$abolish_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)),
- ("$add_dynamic_predicate", 4) => {
- Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate))
- }
- ("$add_multifile_predicate", 4) => {
- Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate))
- }
- ("$add_discontiguous_predicate", 4) => Some(SystemClauseType::REPL(
- REPLCodePtr::AddDiscontiguousPredicate,
- )),
- ("$add_goal_expansion_clause", 3) => {
- Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause))
- }
- ("$add_term_expansion_clause", 2) => {
- Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause))
- }
- ("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
- ("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
- ("$atom_length", 2) => Some(SystemClauseType::AtomLength),
- ("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
- ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
- ("$char_code", 2) => Some(SystemClauseType::CharCode),
- ("$char_type", 2) => Some(SystemClauseType::CharType),
- ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
- ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
- ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
- ("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
- ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
- ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
- ("$close", 2) => Some(SystemClauseType::Close),
- ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
- ("$current_input", 1) => Some(SystemClauseType::CurrentInput),
- ("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
- ("$first_stream", 1) => Some(SystemClauseType::FirstStream),
- ("$next_stream", 2) => Some(SystemClauseType::NextStream),
- ("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
- ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
- ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
- ("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
- ("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef),
- ("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef),
- ("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef),
- ("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)),
- ("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
- ("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
- ("$peek_byte", 2) => Some(SystemClauseType::PeekByte),
- ("$peek_char", 2) => Some(SystemClauseType::PeekChar),
- ("$peek_code", 2) => Some(SystemClauseType::PeekCode),
- ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
- ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
- ("$get_byte", 2) => Some(SystemClauseType::GetByte),
- ("$get_char", 2) => Some(SystemClauseType::GetChar),
- ("$get_n_chars", 3) => Some(SystemClauseType::GetNChars),
- ("$get_code", 2) => Some(SystemClauseType::GetCode),
- ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
- ("$points_to_cont_reset_marker", 1) => {
- Some(SystemClauseType::PointsToContinuationResetMarker)
- }
- ("$put_byte", 2) => Some(SystemClauseType::PutByte),
- ("$put_char", 2) => Some(SystemClauseType::PutChar),
- ("$put_chars", 2) => Some(SystemClauseType::PutChars),
- ("$put_code", 2) => Some(SystemClauseType::PutCode),
- ("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
- ("$truncate_if_no_lh_growth", 1) => {
- Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
- }
- ("$truncate_if_no_lh_growth_diff", 2) => {
- Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff)
- }
- ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
- ("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
- ("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
- ("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
- ("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
- ("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
- ("$halt", 1) => Some(SystemClauseType::Halt),
- ("$head_is_dynamic", 2) => Some(SystemClauseType::HeadIsDynamic),
- ("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
- ("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
- ("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
- ("$maybe", 0) => Some(SystemClauseType::Maybe),
- ("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
- ("$current_time", 1) => Some(SystemClauseType::CurrentTime),
- ("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
- ("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate),
- ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
- ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
- ("$op", 3) => Some(SystemClauseType::OpDeclaration),
- ("$open", 7) => Some(SystemClauseType::Open),
- ("$set_stream_options", 5) => Some(SystemClauseType::SetStreamOptions),
- ("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
- ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
- ("$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),
- ("$stream_property", 3) => Some(SystemClauseType::StreamProperty),
- ("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition),
- ("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
- ("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
- ("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
- ("$fail", 0) => Some(SystemClauseType::Fail),
- ("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
- ("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
- ("$get_ball", 1) => Some(SystemClauseType::GetBall),
- ("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk),
- ("$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),
- ("$nextEP", 3) => Some(SystemClauseType::NextEP),
- ("$read_query_term", 5) => Some(SystemClauseType::ReadQueryTerm),
- ("$read_term", 5) => Some(SystemClauseType::ReadTerm),
- ("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
- ("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
- ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
- ("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
- ("$set_ball", 1) => Some(SystemClauseType::SetBall),
- ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
- ("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
- ("$set_seed", 1) => Some(SystemClauseType::SetSeed),
- ("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
- ("$sleep", 1) => Some(SystemClauseType::Sleep),
- ("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen),
- ("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen),
- ("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept),
- ("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose),
- ("$tls_accept_client", 4) => Some(SystemClauseType::TLSAcceptClient),
- ("$tls_client_connect", 3) => Some(SystemClauseType::TLSClientConnect),
- ("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
- ("$store_backtrackable_global_var", 2) => {
- Some(SystemClauseType::StoreBacktrackableGlobalVar)
- }
- ("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables),
- ("$term_variables", 2) => Some(SystemClauseType::TermVariables),
- ("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
- ("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
- ("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
- ("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
- ("$directory_files", 2) => Some(SystemClauseType::DirectoryFiles),
- ("$file_size", 2) => Some(SystemClauseType::FileSize),
- ("$file_exists", 1) => Some(SystemClauseType::FileExists),
- ("$directory_exists", 1) => Some(SystemClauseType::DirectoryExists),
- ("$directory_separator", 1) => Some(SystemClauseType::DirectorySeparator),
- ("$make_directory", 1) => Some(SystemClauseType::MakeDirectory),
- ("$make_directory_path", 1) => Some(SystemClauseType::MakeDirectoryPath),
- ("$delete_file", 1) => Some(SystemClauseType::DeleteFile),
- ("$rename_file", 2) => Some(SystemClauseType::RenameFile),
- ("$delete_directory", 1) => Some(SystemClauseType::DeleteDirectory),
- ("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
- ("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
- ("$file_time", 3) => Some(SystemClauseType::FileTime),
- ("$clause_to_evacuable", 2) => {
- Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable))
- }
- ("$scoped_clause_to_evacuable", 3) => {
- Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable))
- }
- ("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)),
- ("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
- ("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)),
- ("$load_compiled_library", 3) => {
- Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary))
- }
- ("$push_load_state_payload", 1) => {
- Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload))
- }
- ("$add_in_situ_filename_module", 1) => {
- Some(SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule))
- }
- ("$asserta", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)),
- ("$assertz", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)),
- ("$retract_clause", 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)),
- ("$is_consistent_with_term_queue", 4) => Some(SystemClauseType::REPL(
- REPLCodePtr::IsConsistentWithTermQueue,
- )),
- ("$flush_term_queue", 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)),
- ("$remove_module_exports", 2) => {
- Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports))
- }
- ("$add_non_counted_backtracking", 3) => Some(SystemClauseType::REPL(
- REPLCodePtr::AddNonCountedBacktracking,
- )),
- ("$variant", 2) => Some(SystemClauseType::Variant),
- ("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions),
- ("$write_term", 7) => Some(SystemClauseType::WriteTerm),
- ("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
- ("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
- ("$crypto_random_byte", 1) => Some(SystemClauseType::CryptoRandomByte),
- ("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash),
- ("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF),
- ("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
- ("$crypto_data_encrypt", 7) => Some(SystemClauseType::CryptoDataEncrypt),
- ("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt),
- ("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult),
- ("$ed25519_sign", 4) => Some(SystemClauseType::Ed25519Sign),
- ("$ed25519_verify", 4) => Some(SystemClauseType::Ed25519Verify),
- ("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
- ("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
- ("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult),
- ("$first_non_octet", 2) => Some(SystemClauseType::FirstNonOctet),
- ("$load_html", 3) => Some(SystemClauseType::LoadHTML),
- ("$load_xml", 3) => Some(SystemClauseType::LoadXML),
- ("$getenv", 2) => Some(SystemClauseType::GetEnv),
- ("$setenv", 2) => Some(SystemClauseType::SetEnv),
- ("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
- ("$shell", 2) => Some(SystemClauseType::Shell),
- ("$pid", 1) => Some(SystemClauseType::PID),
- ("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
- ("$load_library_as_stream", 3) => Some(SystemClauseType::LoadLibraryAsStream),
- ("$push_load_context", 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)),
- ("$pop_load_state_payload", 1) => {
- Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload))
- }
- ("$pop_load_context", 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)),
- ("$prolog_lc_source", 1) => {
- Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource))
- }
- ("$prolog_lc_file", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)),
- ("$prolog_lc_dir", 1) => {
- Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory))
- }
- ("$prolog_lc_module", 1) => {
- Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule))
- }
- ("$prolog_lc_stream", 1) => {
- Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream))
- }
- ("$cpp_meta_predicate_property", 4) => {
- Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty))
- }
- ("$cpp_built_in_property", 2) => {
- Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty))
- }
- ("$cpp_dynamic_property", 3) => {
- Some(SystemClauseType::REPL(REPLCodePtr::DynamicProperty))
- }
- ("$cpp_multifile_property", 3) => {
- Some(SystemClauseType::REPL(REPLCodePtr::MultifileProperty))
- }
- ("$cpp_discontiguous_property", 3) => {
- Some(SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty))
- }
- ("$devour_whitespace", 1) => Some(SystemClauseType::DevourWhitespace),
- ("$is_sto_enabled", 1) => Some(SystemClauseType::IsSTOEnabled),
- ("$set_sto_as_unify", 0) => Some(SystemClauseType::SetSTOAsUnify),
- ("$set_nsto_as_unify", 0) => Some(SystemClauseType::SetNSTOAsUnify),
- ("$set_sto_with_error_as_unify", 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify),
- ("$home_directory", 1) => Some(SystemClauseType::HomeDirectory),
- ("$debug_hook", 0) => Some(SystemClauseType::DebugHook),
- ("$popcount", 2) => Some(SystemClauseType::PopCount),
- _ => None,
- }
- }
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub(crate) enum BuiltInClauseType {
- AcyclicTerm,
- Arg,
- Compare,
- CompareTerm(CompareTermQT),
- CopyTerm,
- Eq,
- Functor,
- Ground,
- Is(RegType, ArithmeticTerm),
- KeySort,
- NotEq,
- Read,
- Sort,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) enum ClauseType {
- BuiltIn(BuiltInClauseType),
- CallN,
- Inlined(InlinedClauseType),
- Named(ClauseName, usize, CodeIndex), // name, arity, index.
- Op(ClauseName, SharedOpDesc, CodeIndex),
- System(SystemClauseType),
-}
-
-impl BuiltInClauseType {
- pub(crate) fn name(&self) -> ClauseName {
- match self {
- &BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"),
- &BuiltInClauseType::Arg => clause_name!("arg"),
- &BuiltInClauseType::Compare => clause_name!("compare"),
- &BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
- &BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
- &BuiltInClauseType::Eq => clause_name!("=="),
- &BuiltInClauseType::Functor => clause_name!("functor"),
- &BuiltInClauseType::Ground => clause_name!("ground"),
- &BuiltInClauseType::Is(..) => clause_name!("is"),
- &BuiltInClauseType::KeySort => clause_name!("keysort"),
- &BuiltInClauseType::NotEq => clause_name!("\\=="),
- &BuiltInClauseType::Read => clause_name!("read"),
- &BuiltInClauseType::Sort => clause_name!("sort"),
- }
- }
-
- pub(crate) fn arity(&self) -> usize {
- match self {
- &BuiltInClauseType::AcyclicTerm => 1,
- &BuiltInClauseType::Arg => 3,
- &BuiltInClauseType::Compare => 2,
- &BuiltInClauseType::CompareTerm(_) => 2,
- &BuiltInClauseType::CopyTerm => 2,
- &BuiltInClauseType::Eq => 2,
- &BuiltInClauseType::Functor => 3,
- &BuiltInClauseType::Ground => 1,
- &BuiltInClauseType::Is(..) => 2,
- &BuiltInClauseType::KeySort => 2,
- &BuiltInClauseType::NotEq => 2,
- &BuiltInClauseType::Read => 2,
- &BuiltInClauseType::Sort => 2,
- }
- }
-}
-
-impl ClauseType {
- pub(crate) fn spec(&self) -> Option<SharedOpDesc> {
- match self {
- &ClauseType::Op(_, ref spec, _) => Some(spec.clone()),
- &ClauseType::Inlined(InlinedClauseType::CompareNumber(..))
- | &ClauseType::BuiltIn(BuiltInClauseType::Is(..))
- | &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_))
- | &ClauseType::BuiltIn(BuiltInClauseType::NotEq)
- | &ClauseType::BuiltIn(BuiltInClauseType::Eq) => Some(SharedOpDesc::new(700, XFX)),
- _ => None,
- }
- }
-
- pub(crate) fn name(&self) -> ClauseName {
- match self {
- &ClauseType::BuiltIn(ref built_in) => built_in.name(),
- &ClauseType::CallN => clause_name!("$call"),
- &ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
- &ClauseType::Op(ref name, ..) => name.clone(),
- &ClauseType::Named(ref name, ..) => name.clone(),
- &ClauseType::System(ref system) => system.name(),
- }
- }
-
- pub(crate) fn from(name: ClauseName, arity: usize, spec: Option<SharedOpDesc>) -> Self {
- CLAUSE_TYPE_FORMS
- .borrow()
- .get(&(name.as_str(), arity))
- .cloned()
- .unwrap_or_else(|| {
- SystemClauseType::from(name.as_str(), arity)
- .map(ClauseType::System)
- .unwrap_or_else(|| {
- if let Some(spec) = spec {
- ClauseType::Op(name, spec, CodeIndex::default())
- } else if name.as_str() == "$call" {
- ClauseType::CallN
- } else {
- ClauseType::Named(name, arity, CodeIndex::default())
- }
- })
- })
- }
-}
-
-impl From<InlinedClauseType> for ClauseType {
- fn from(inlined_ct: InlinedClauseType) -> Self {
- ClauseType::Inlined(inlined_ct)
- }
-}
diff --git a/src/codegen.rs b/src/codegen.rs
index a678549b..61390257 100644
--- a/src/codegen.rs
+++ b/src/codegen.rs
@@ -1,18 +1,18 @@
-/// Code generation to WAM-like instructions.
-use prolog_parser::ast::*;
-use prolog_parser::tabled_rc::TabledData;
-use prolog_parser::{perm_v, temp_v};
+use crate::atom_table::*;
+use crate::parser::ast::*;
+use crate::{perm_v, temp_v};
use crate::allocator::*;
use crate::arithmetic::*;
-use crate::clause_types::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::indexing::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::targets::*;
+use crate::types::*;
+use crate::instr;
use crate::machine::machine_errors::*;
use indexmap::{IndexMap, IndexSet};
@@ -57,7 +57,9 @@ impl<'a> ConjunctInfo<'a> {
let mut code_index = 0;
for phase in 0.. {
- while let Line::Query(ref query_instr) = &code[code_index] {
+ while code[code_index].is_query_instr() {
+ let query_instr = &mut code[code_index];
+
if !unsafe_var_marker.mark_safe_vars(query_instr) {
unsafe_var_marker.mark_phase(query_instr, phase);
}
@@ -75,7 +77,8 @@ impl<'a> ConjunctInfo<'a> {
code_index = 0;
for phase in 0.. {
- while let Line::Query(ref mut query_instr) = &mut code[code_index] {
+ while code[code_index].is_query_instr() {
+ let query_instr = &mut code[code_index];
unsafe_var_marker.mark_unsafe_vars(query_instr, phase);
code_index += 1;
}
@@ -103,98 +106,110 @@ impl CodeGenSettings {
}
#[inline]
- pub(crate) fn internal_try_me_else(&self, offset: usize) -> ChoiceInstruction {
+ pub(crate) fn internal_try_me_else(&self, offset: usize) -> Instruction {
if let Some(global_clock_time) = self.global_clock_tick {
- ChoiceInstruction::DynamicInternalElse(
+ Instruction::DynamicInternalElse(
global_clock_time,
Death::Infinity,
- if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ if offset == 0 {
+ NextOrFail::Next(0)
+ } else {
+ NextOrFail::Next(offset)
+ },
)
} else {
- ChoiceInstruction::TryMeElse(offset)
+ Instruction::TryMeElse(offset)
}
}
- pub(crate) fn try_me_else(&self, offset: usize) -> ChoiceInstruction {
+ pub(crate) fn try_me_else(&self, offset: usize) -> Instruction {
if let Some(global_clock_tick) = self.global_clock_tick {
- ChoiceInstruction::DynamicElse(
+ Instruction::DynamicElse(
global_clock_tick,
Death::Infinity,
- if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ if offset == 0 {
+ NextOrFail::Next(0)
+ } else {
+ NextOrFail::Next(offset)
+ },
)
} else {
- ChoiceInstruction::TryMeElse(offset)
+ Instruction::TryMeElse(offset)
}
}
- pub(crate) fn internal_retry_me_else(&self, offset: usize) -> ChoiceInstruction {
+ pub(crate) fn internal_retry_me_else(&self, offset: usize) -> Instruction {
if let Some(global_clock_tick) = self.global_clock_tick {
- ChoiceInstruction::DynamicInternalElse(
+ Instruction::DynamicInternalElse(
global_clock_tick,
Death::Infinity,
- if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ if offset == 0 {
+ NextOrFail::Next(0)
+ } else {
+ NextOrFail::Next(offset)
+ },
)
} else {
- ChoiceInstruction::RetryMeElse(offset)
+ Instruction::RetryMeElse(offset)
}
}
- pub(crate) fn retry_me_else(&self, offset: usize) -> ChoiceInstruction {
+ pub(crate) fn retry_me_else(&self, offset: usize) -> Instruction {
if let Some(global_clock_tick) = self.global_clock_tick {
- ChoiceInstruction::DynamicElse(
+ Instruction::DynamicElse(
global_clock_tick,
Death::Infinity,
- if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ if offset == 0 {
+ NextOrFail::Next(0)
+ } else {
+ NextOrFail::Next(offset)
+ },
)
} else if self.non_counted_bt {
- ChoiceInstruction::DefaultRetryMeElse(offset)
+ Instruction::DefaultRetryMeElse(offset)
} else {
- ChoiceInstruction::RetryMeElse(offset)
+ Instruction::RetryMeElse(offset)
}
}
- pub(crate) fn internal_trust_me(&self) -> ChoiceInstruction {
+ pub(crate) fn internal_trust_me(&self) -> Instruction {
if let Some(global_clock_tick) = self.global_clock_tick {
- ChoiceInstruction::DynamicInternalElse(
+ Instruction::DynamicInternalElse(
global_clock_tick,
Death::Infinity,
NextOrFail::Fail(0),
)
} else if self.non_counted_bt {
- ChoiceInstruction::DefaultTrustMe(0)
+ Instruction::DefaultTrustMe(0)
} else {
- ChoiceInstruction::TrustMe(0)
+ Instruction::TrustMe(0)
}
}
- pub(crate) fn trust_me(&self) -> ChoiceInstruction {
+ pub(crate) fn trust_me(&self) -> Instruction {
if let Some(global_clock_tick) = self.global_clock_tick {
- ChoiceInstruction::DynamicElse(
- global_clock_tick,
- Death::Infinity,
- NextOrFail::Fail(0),
- )
+ Instruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0))
} else if self.non_counted_bt {
- ChoiceInstruction::DefaultTrustMe(0)
+ Instruction::DefaultTrustMe(0)
} else {
- ChoiceInstruction::TrustMe(0)
+ Instruction::TrustMe(0)
}
}
}
#[derive(Debug)]
-pub(crate) struct CodeGenerator<TermMarker> {
- atom_tbl: TabledData<Atom>,
+pub(crate) struct CodeGenerator<'a, TermMarker> {
+ pub(crate) atom_tbl: &'a mut AtomTable,
marker: TermMarker,
- pub(crate) var_count: IndexMap<Rc<Var>, usize>,
+ pub(crate) var_count: IndexMap<Rc<String>, usize>,
settings: CodeGenSettings,
pub(crate) skeleton: PredicateSkeleton,
pub(crate) jmp_by_locs: Vec<usize>,
global_jmp_by_locs_offset: usize,
}
-impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
- pub(crate) fn new(atom_tbl: TabledData<Atom>, settings: CodeGenSettings) -> Self {
+impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
+ pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self {
CodeGenerator {
atom_tbl,
marker: Allocator::new(),
@@ -206,7 +221,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
- fn update_var_count<Iter: Iterator<Item = TermRef<'a>>>(&mut self, iter: Iter) {
+ fn update_var_count<'a, Iter: Iterator<Item = TermRef<'a>>>(&mut self, iter: Iter) {
for term in iter {
if let TermRef::Var(_, _, var) = term {
let entry = self.var_count.entry(var).or_insert(0);
@@ -215,23 +230,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
- fn get_var_count(&self, var: &'a Var) -> usize {
+ fn get_var_count(&self, var: &String) -> usize {
*self.var_count.get(var).unwrap()
}
fn mark_var_in_non_callable(
&mut self,
- name: Rc<Var>,
+ name: Rc<String>,
term_loc: GenContext,
- vr: &'a Cell<VarReg>,
+ vr: &Cell<VarReg>,
code: &mut Code,
) -> RegType {
- let mut target = Vec::new();
- self.marker
- .mark_var(name, Level::Shallow, vr, term_loc, &mut target);
+ let mut target = Code::new();
+ self.marker.mark_var::<QueryInstruction>(name, Level::Shallow, vr, term_loc, &mut target);
if !target.is_empty() {
- code.extend(target.into_iter().map(Line::Query));
+ code.extend(target.into_iter());
}
vr.get().norm()
@@ -239,10 +253,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
fn mark_non_callable(
&mut self,
- name: Rc<Var>,
+ name: Rc<String>,
arg: usize,
term_loc: GenContext,
- vr: &'a Cell<VarReg>,
+ vr: &Cell<VarReg>,
code: &mut Code,
) -> RegType {
match self.marker.bindings().get(&name) {
@@ -259,9 +273,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
- fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
+ fn add_or_increment_void_instr<'a, Target>(target: &mut Code)
where
- Target: CompilationTarget<'a>,
+ Target: crate::targets::CompilationTarget<'a>,
{
if let Some(ref mut instr) = target.last_mut() {
if Target::is_void_instr(&*instr) {
@@ -273,61 +287,61 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
target.push(Target::to_void(1));
}
- fn deep_var_instr<Target: CompilationTarget<'a>>(
+ fn deep_var_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
&mut self,
cell: &'a Cell<VarReg>,
- var: &'a Rc<Var>,
+ var: &Rc<String>,
term_loc: GenContext,
is_exposed: bool,
- target: &mut Vec<Target>,
+ target: &mut Code,
) {
if is_exposed || self.get_var_count(var.as_ref()) > 1 {
- self.marker
- .mark_var(var.clone(), Level::Deep, cell, term_loc, target);
+ self.marker.mark_var::<Target>(var.clone(), Level::Deep, cell, term_loc, target);
} else {
- Self::add_or_increment_void_instr(target);
+ Self::add_or_increment_void_instr::<Target>(target);
}
}
- fn subterm_to_instr<Target: CompilationTarget<'a>>(
+ fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
&mut self,
subterm: &'a Term,
term_loc: GenContext,
is_exposed: bool,
- target: &mut Vec<Target>,
+ target: &mut Code,
) {
match subterm {
&Term::AnonVar if is_exposed => {
- self.marker.mark_anon_var(Level::Deep, term_loc, target);
+ self.marker.mark_anon_var::<Target>(Level::Deep, term_loc, target);
}
&Term::AnonVar => {
- Self::add_or_increment_void_instr(target);
+ Self::add_or_increment_void_instr::<Target>(target);
}
- &Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
- self.marker
- .mark_non_var(Level::Deep, term_loc, cell, target);
+ &Term::Cons(ref cell, ..)
+ | &Term::Clause(ref cell, ..)
+ | Term::PartialString(ref cell, ..) => {
+ self.marker.mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
target.push(Target::clause_arg_to_instr(cell.get()));
}
- &Term::Constant(_, ref constant) => {
+ &Term::Literal(_, ref constant) => {
target.push(Target::constant_subterm(constant.clone()));
}
&Term::Var(ref cell, ref var) => {
- self.deep_var_instr(cell, var, term_loc, is_exposed, target);
+ self.deep_var_instr::<Target>(cell, var, term_loc, is_exposed, target);
}
};
}
- fn compile_target<Target, Iter>(
+ fn compile_target<'a, Target, Iter>(
&mut self,
iter: Iter,
term_loc: GenContext,
is_exposed: bool,
- ) -> Vec<Target>
+ ) -> Code
where
- Target: CompilationTarget<'a>,
+ Target: crate::targets::CompilationTarget<'a>,
Iter: Iterator<Item = TermRef<'a>>,
{
- let mut target = Vec::new();
+ let mut target: Code = Vec::new();
for term in iter {
match term {
@@ -335,38 +349,38 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
if let GenContext::Head = term_loc {
self.marker.advance_arg();
} else {
- self.marker.mark_anon_var(lvl, term_loc, &mut target);
+ self.marker.mark_anon_var::<Target>(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()));
+ self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
+ target.push(Target::to_structure(ct.name(), terms.len(), cell.get()));
for subterm in terms {
- self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, &mut target);
+ self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target);
}
}
TermRef::Cons(lvl, cell, head, tail) => {
- self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+ self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push(Target::to_list(lvl, cell.get()));
- self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
- self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
+ self.subterm_to_instr::<Target>(head, term_loc, is_exposed, &mut target);
+ self.subterm_to_instr::<Target>(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::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => {
+ self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
+ target.push(Target::to_pstr(lvl, *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::Literal(lvl @ Level::Shallow, cell, constant) => {
+ self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
+ target.push(Target::to_constant(lvl, *constant, cell.get()));
}
TermRef::PartialString(lvl, cell, string, tail) => {
- self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+ self.marker.mark_non_var::<Target>(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);
+ self.subterm_to_instr::<Target>(tail, term_loc, is_exposed, &mut target);
} else {
target.push(Target::to_pstr(lvl, string, cell.get(), false));
}
@@ -374,7 +388,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
if self.marker.is_unbound(var.clone()) {
if term_loc != GenContext::Head {
- self.marker.mark_reserved_var(
+ self.marker.mark_reserved_var::<Target>(
var.clone(),
lvl,
cell,
@@ -387,12 +401,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
- self.marker
- .mark_var(var.clone(), lvl, cell, term_loc, &mut target);
+ self.marker.mark_var::<Target>(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::<Target>(var.clone(), lvl, cell, term_loc, &mut target);
}
_ => {}
};
@@ -401,7 +413,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
target
}
- fn collect_var_data(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> {
+ fn collect_var_data<'a>(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> {
let mut vs = VariableFixtures::new();
while let Some((chunk_num, lt_arity, chunked_terms)) = iter.next() {
@@ -418,6 +430,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
};
self.update_var_count(chunked_term.post_order_iter());
+
vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
}
}
@@ -436,13 +449,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
match qt {
&QueryTerm::Jump(ref vars) => {
self.jmp_by_locs.push(code.len());
- code.push(jmp_call!(vars.len(), 0, pvs));
+ code.push(instr!("jmp_by_call", vars.len(), 0, pvs));
}
- &QueryTerm::Clause(_, ref ct, ref terms, true) => {
- code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs));
+ &QueryTerm::Clause(_, ref ct, _, true) => {
+ code.push(call_clause_by_default!(ct.clone(), pvs));
}
- &QueryTerm::Clause(_, ref ct, ref terms, false) => {
- code.push(call_clause!(ct.clone(), terms.len(), pvs));
+ &QueryTerm::Clause(_, ref ct, _, false) => {
+ code.push(call_clause!(ct.clone(), pvs));
}
_ => {}
}
@@ -450,50 +463,54 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
fn lco(code: &mut Code) -> usize {
let mut dealloc_index = code.len() - 1;
+ let last_instr = code.pop();
- match code.last_mut() {
- Some(&mut Line::Control(ref mut ctrl)) => match ctrl {
- &mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => {
- *last_call = true;
- }
- &mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => {
- *last_call = true;
- }
- &mut ControlInstruction::Proceed => {}
- _ => {
- dealloc_index += 1;
- }
- },
- Some(&mut Line::Cut(CutInstruction::Cut(_))) => {
+ match last_instr {
+ Some(instr @ Instruction::Proceed) => {
+ code.push(instr);
+ }
+ Some(instr @ Instruction::Cut(_)) => {
dealloc_index += 1;
+ code.push(instr);
}
- _ => {}
- };
+ Some(mut instr) if instr.is_ctrl_instr() => {
+ code.push(if instr.perm_vars_mut().is_some() {
+ instr.to_execute()
+ } else {
+ dealloc_index += 1;
+ instr
+ });
+ }
+ Some(instr) => {
+ code.push(instr);
+ }
+ None => {}
+ }
dealloc_index
}
- fn compile_inlined(
+ fn compile_inlined<'a>(
&mut self,
ct: &InlinedClauseType,
- terms: &'a Vec<Box<Term>>,
+ terms: &'a Vec<Term>,
term_loc: GenContext,
code: &mut Code,
) -> Result<(), CompilationError> {
match ct {
- &InlinedClauseType::CompareNumber(cmp, ..) => {
+ &InlinedClauseType::CompareNumber(mut cmp) => {
self.marker.reset_arg(2);
- let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
- let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
+ let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc)?;
+ let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc)?;
- let at_1 = if let &Term::Var(ref vr, ref name) = terms[0].as_ref() {
+ let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] {
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code))
} else {
at_1.unwrap_or(interm!(1))
};
- let at_2 = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
+ let at_2 = if let &Term::Var(ref vr, ref name) = &terms[1] {
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
} else {
at_2.unwrap_or(interm!(2))
@@ -504,129 +521,133 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(compare_number_instr!(cmp, at_1, at_2));
}
- &InlinedClauseType::IsAtom(..) => match terms[0].as_ref() {
- &Term::Constant(_, Constant::Char(_))
- | &Term::Constant(_, Constant::EmptyList)
- | &Term::Constant(_, Constant::Atom(..)) => {
- code.push(succeed!());
+ &InlinedClauseType::IsAtom(..) => match &terms[0] {
+ &Term::Literal(_, Literal::Char(_))
+ | &Term::Literal(_, Literal::Atom(atom!("[]")))
+ | &Term::Literal(_, Literal::Atom(..)) => {
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_atom!(r));
+ code.push(instr!("atom", r, 0));
}
_ => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
}
},
- &InlinedClauseType::IsAtomic(..) => match terms[0].as_ref() {
- &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => {
- code.push(fail!());
+ &InlinedClauseType::IsAtomic(..) => match &terms[0] {
+ &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => {
+ code.push(instr!("$fail", 0));
}
- &Term::Constant(..) => {
- code.push(succeed!());
+ &Term::Literal(_, Literal::String(_)) => {
+ code.push(instr!("$fail", 0));
+ }
+ &Term::Literal(..) => {
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_atomic!(r));
+ code.push(instr!("atomic", r, 0));
}
},
- &InlinedClauseType::IsCompound(..) => match terms[0].as_ref() {
- &Term::Clause(..) | &Term::Cons(..) => {
- code.push(succeed!());
+ &InlinedClauseType::IsCompound(..) => match &terms[0] {
+ &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) |
+ &Term::Literal(_, Literal::String(..)) => {
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_compound!(r));
+ code.push(instr!("compound", r, 0));
}
_ => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
}
},
- &InlinedClauseType::IsRational(..) => match terms[0].as_ref() {
- &Term::Constant(_, Constant::Rational(_)) => {
- code.push(succeed!());
+ &InlinedClauseType::IsRational(..) => match &terms[0] {
+ &Term::Literal(_, Literal::Rational(_)) => {
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_rational!(r));
+ code.push(instr!("rational", r, 0));
}
_ => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
}
},
- &InlinedClauseType::IsFloat(..) => match terms[0].as_ref() {
- &Term::Constant(_, Constant::Float(_)) => {
- code.push(succeed!());
+ &InlinedClauseType::IsFloat(..) => match &terms[0] {
+ &Term::Literal(_, Literal::Float(_)) => {
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_float!(r));
+ code.push(instr!("float", r, 0));
}
_ => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
}
},
- &InlinedClauseType::IsNumber(..) => match terms[0].as_ref() {
- &Term::Constant(_, Constant::Float(_))
- | &Term::Constant(_, Constant::Rational(_))
- | &Term::Constant(_, Constant::Integer(_))
- | &Term::Constant(_, Constant::Fixnum(_))
- | &Term::Constant(_, Constant::Usize(_)) => {
- code.push(succeed!());
+ &InlinedClauseType::IsNumber(..) => match &terms[0] {
+ &Term::Literal(_, Literal::Float(_))
+ | &Term::Literal(_, Literal::Rational(_))
+ | &Term::Literal(_, Literal::Integer(_))
+ | &Term::Literal(_, Literal::Fixnum(_)) => {
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_number!(r));
+ code.push(instr!("number", r, 0));
}
_ => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
}
},
- &InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() {
+ &InlinedClauseType::IsNonVar(..) => match &terms[0] {
&Term::AnonVar => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_nonvar!(r));
+ code.push(instr!("nonvar", r, 0));
}
_ => {
- code.push(succeed!());
+ code.push(instr!("$succeed", 0));
}
},
- &InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
- &Term::Constant(_, Constant::Integer(_))
- | &Term::Constant(_, Constant::Fixnum(_))
- | &Term::Constant(_, Constant::Usize(_)) => {
- code.push(succeed!());
+ &InlinedClauseType::IsInteger(..) => match &terms[0] {
+ &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => {
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_integer!(r));
+ code.push(instr!("integer", r, 0));
}
_ => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
}
},
- &InlinedClauseType::IsVar(..) => match terms[0].as_ref() {
- &Term::Constant(..) | &Term::Clause(..) | &Term::Cons(..) => {
- code.push(fail!());
+ &InlinedClauseType::IsVar(..) => match &terms[0] {
+ &Term::Literal(..)
+ | &Term::Clause(..)
+ | &Term::Cons(..)
+ | &Term::PartialString(..) => {
+ code.push(instr!("$fail", 0));
}
&Term::AnonVar => {
- code.push(succeed!());
+ code.push(instr!("$succeed", 0));
}
&Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
- code.push(is_var!(r));
+ code.push(instr!("var", r, 0));
}
},
}
@@ -634,117 +655,97 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
Ok(())
}
- fn call_arith_eval(
- &self,
- term: &'a Term,
+ fn compile_arith_expr(
+ &mut self,
+ term: &Term,
target_int: usize,
+ term_loc: GenContext,
) -> Result<ArithCont, ArithmeticError> {
- let mut evaluator = ArithmeticEvaluator::new(&self.marker.bindings(), target_int);
- evaluator.eval(term)
+ let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
+ evaluator.eval(term, term_loc)
}
fn compile_is_call(
&mut self,
- terms: &'a Vec<Box<Term>>,
+ terms: &Vec<Term>,
code: &mut Code,
term_loc: GenContext,
use_default_call_policy: bool,
) -> Result<(), CompilationError> {
- let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
- code.append(&mut acode);
+ macro_rules! compile_expr {
+ ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => ({
+ let (acode, at) = $self.compile_arith_expr(&$terms[1], 1, $term_loc)?;
+ $code.extend(acode.into_iter());
+ at
+ });
+ }
self.marker.reset_arg(2);
- match terms[0].as_ref() {
+ let at = match &terms[0] {
&Term::Var(ref vr, ref name) => {
- let mut target = vec![];
-
- self.marker
- .mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
-
- if !target.is_empty() {
- code.extend(target.into_iter().map(Line::Query));
- }
- }
- &Term::Constant(_, ref c @ Constant::Integer(_))
- | &Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
- code.push(Line::Query(put_constant!(
- Level::Shallow,
- c.clone(),
- temp_v!(1)
- )));
-
- self.marker.advance_arg();
- }
- &Term::Constant(_, ref c @ Constant::Float(_)) => {
- code.push(Line::Query(put_constant!(
+ self.marker.mark_var::<QueryInstruction>(
+ name.clone(),
Level::Shallow,
- c.clone(),
- temp_v!(1)
- )));
+ vr,
+ term_loc,
+ code,
+ );
- self.marker.advance_arg();
+ compile_expr!(self, terms, term_loc, code)
}
- &Term::Constant(_, ref c @ Constant::Rational(_)) => {
- code.push(Line::Query(put_constant!(
- Level::Shallow,
- c.clone(),
- temp_v!(1)
- )));
+ &Term::Literal(_, c @ Literal::Integer(_) |
+ c @ Literal::Float(_) |
+ c @ Literal::Rational(_) |
+ c @ Literal::Fixnum(_)) => {
+ let v = HeapCellValue::from(c);
+ code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
self.marker.advance_arg();
+ compile_expr!(self, terms, term_loc, code)
}
_ => {
- code.push(fail!());
+ code.push(instr!("$fail", 0));
return Ok(());
}
- }
-
- let at = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
- ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
- } else {
- at.unwrap_or(interm!(1))
};
+ let at = at.unwrap_or(interm!(1));
+
Ok(if use_default_call_policy {
- code.push(is_call_by_default!(temp_v!(1), at));
+ code.push(instr!("is", default, temp_v!(1), at, 0));
} else {
- code.push(is_call!(temp_v!(1), at));
+ code.push(instr!("is", temp_v!(1), at, 0));
})
}
#[inline]
- fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell<VarReg>) {
+ fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &Cell<VarReg>) {
let r = self.marker.get(Rc::new(String::from("!")));
cell.set(VarReg::Norm(r));
- code.push(set_cp!(cell.get().norm()));
+ code.push(instr!("$set_cp", cell.get().norm(), 0));
}
fn compile_get_level_and_unify(
&mut self,
code: &mut Code,
- cell: &'a Cell<VarReg>,
- var: Rc<Var>,
+ cell: &Cell<VarReg>,
+ var: Rc<String>,
term_loc: GenContext,
) {
- let mut target = Vec::new();
+ let mut target = Code::new();
self.marker.reset_arg(1);
- self.marker
- .mark_var(var, Level::Shallow, cell, term_loc, &mut target);
+ self.marker.mark_var::<QueryInstruction>(var, Level::Shallow, cell, term_loc, &mut target);
if !target.is_empty() {
- code.extend(
- target
- .into_iter()
- .map(|query_instr| Line::Query(query_instr)),
- );
+ code.extend(target.into_iter());
}
- code.push(get_level_and_unify!(cell.get().norm()));
+ code.push(instr!("get_level_and_unify", cell.get().norm()));
}
- fn compile_seq(
+ fn compile_seq<'a>(
&mut self,
iter: ChunkedIterator<'a>,
conjunct_info: &ConjunctInfo<'a>,
@@ -765,9 +766,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
&QueryTerm::UnblockedCut(ref cell) => self.compile_unblocked_cut(code, cell),
&QueryTerm::BlockedCut => code.push(if chunk_num == 0 {
- Line::Cut(CutInstruction::NeckCut)
+ Instruction::NeckCut
} else {
- Line::Cut(CutInstruction::Cut(perm_v!(1)))
+ Instruction::Cut(perm_v!(1))
}),
&QueryTerm::Clause(
_,
@@ -800,24 +801,25 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
if conjunct_info.allocates() {
let perm_vars = conjunct_info.perm_vars();
- body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
+ body.push(Instruction::Allocate(perm_vars));
if conjunct_info.has_deep_cut {
- body.push(Line::Cut(CutInstruction::GetLevel(perm_v!(1))));
+ body.push(Instruction::GetLevel(perm_v!(1)));
}
}
}
- fn compile_cleanup(
+ fn compile_cleanup<'a>(
&mut self,
code: &mut Code,
- conjunct_info: &ConjunctInfo,
+ conjunct_info: &ConjunctInfo<'a>,
toc: &'a QueryTerm,
) {
// add a proceed to bookend any trailing cuts.
match toc {
- &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()),
- &QueryTerm::Clause(_, ClauseType::Inlined(..), ..) => code.push(proceed!()),
+ &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => {
+ code.push(instr!("proceed"));
+ }
_ => {}
};
@@ -833,14 +835,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
- code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
+ code.insert(dealloc_index, instr!("deallocate"));
}
}
- pub(crate) fn compile_rule<'b: 'a>(
- &mut self,
- rule: &'b Rule,
- ) -> Result<Code, CompilationError> {
+ pub(crate) fn compile_rule(&mut self, rule: &Rule) -> Result<Code, CompilationError> {
let iter = ChunkedIterator::from_rule(rule);
let conjunct_info = self.collect_var_data(iter);
@@ -855,16 +854,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
self.compile_seq_prelude(&conjunct_info, &mut code);
let iter = FactIterator::from_rule_head_clause(args);
- let mut fact = self.compile_target(iter, GenContext::Head, false);
+ let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false);
let mut unsafe_var_marker = UnsafeVarMarker::new();
if !fact.is_empty() {
unsafe_var_marker = self.mark_unsafe_fact_vars(&mut fact);
-
- for fact_instr in fact {
- code.push(Line::Fact(fact_instr));
- }
+ code.extend(fact.into_iter());
}
let iter = ChunkedIterator::from_rule_body(p1, clauses);
@@ -876,18 +872,18 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
Ok(code)
}
- fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
+ fn mark_unsafe_fact_vars(&self, fact: &mut Code) -> UnsafeVarMarker {
let mut safe_vars = IndexSet::new();
for fact_instr in fact.iter_mut() {
match fact_instr {
- &mut FactInstruction::UnifyValue(r) => {
+ &mut Instruction::UnifyValue(r) => {
if !safe_vars.contains(&r) {
- *fact_instr = FactInstruction::UnifyLocalValue(r);
+ *fact_instr = Instruction::UnifyLocalValue(r);
safe_vars.insert(r);
}
}
- &mut FactInstruction::UnifyVariable(r) => {
+ &mut Instruction::UnifyVariable(r) => {
safe_vars.insert(r);
}
_ => {}
@@ -897,10 +893,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
UnsafeVarMarker::from_safe_vars(safe_vars)
}
- pub(crate) fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
+ pub(crate) fn compile_fact(&mut self, term: &Term) -> Code {
self.update_var_count(post_order_iter(term));
let mut vs = VariableFixtures::new();
+
vs.mark_vars_in_chunk(post_order_iter(term), term.arity(), GenContext::Head);
vs.populate_restricting_sets();
@@ -908,28 +905,30 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let mut code = Vec::new();
- if let &Term::Clause(_, _, ref args, _) = term {
+ if let &Term::Clause(_, _, ref args) = term {
self.marker.reset_at_head(args);
let iter = FactInstruction::iter(term);
- let mut compiled_fact = self.compile_target(iter, GenContext::Head, false);
+ let mut compiled_fact = self.compile_target::<FactInstruction, _>(
+ iter,
+ GenContext::Head,
+ false,
+ );
self.mark_unsafe_fact_vars(&mut compiled_fact);
if !compiled_fact.is_empty() {
- for fact_instr in compiled_fact {
- code.push(Line::Fact(fact_instr));
- }
+ code.extend(compiled_fact.into_iter());
}
}
- code.push(proceed!());
+ code.push(instr!("proceed"));
code
}
fn compile_query_line(
&mut self,
- term: &'a QueryTerm,
+ term: &QueryTerm,
term_loc: GenContext,
code: &mut Code,
num_perm_vars_left: usize,
@@ -938,12 +937,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
self.marker.reset_arg(term.arity());
let iter = query_term_post_order_iter(term);
- let query = self.compile_target(iter, term_loc, is_exposed);
+ let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed);
if !query.is_empty() {
- for query_instr in query {
- code.push(Line::Query(query_instr));
- }
+ code.extend(query.into_iter());
}
self.add_conditional_call(code, term, num_perm_vars_left);
@@ -958,84 +955,73 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}
}
- /// Returns the index of the first instantiated argument.
- fn first_instantiated_index(clauses: &[PredicateClause]) -> Option<usize> {
- let mut optimal_index = None;
- let has_args = match clauses.first() {
- Some(clause) => match clause.args() {
- Some(args) => !args.is_empty(),
- None => false,
- },
- None => false,
- };
- if !has_args {
- return optimal_index;
- }
- for clause in clauses.iter() {
- let args = clause.args().unwrap();
- for (i, arg) in args.iter().enumerate() {
- if let Some(optimal_index) = optimal_index {
- if i >= optimal_index {
- break;
- }
- }
- match **arg {
- Term::AnonVar | Term::Var(..) => (),
- _ => {
- match optimal_index {
- Some(ref mut optimal_i) => *optimal_i = i,
- None => optimal_index = Some(i),
- }
- break;
- }
- }
- }
- }
-
- optimal_index
- }
-
- fn split_predicate(clauses: &[PredicateClause], optimal_index: usize) -> Vec<(usize, usize)> {
+ fn split_predicate(clauses: &[PredicateClause]) -> Vec<ClauseSpan> {
let mut subseqs = Vec::new();
- let mut left_index = 0;
+ let mut left = 0;
+ let mut optimal_index = 0;
- if clauses.first().unwrap().args().is_some() {
- for (right_index, clause) in clauses.iter().enumerate() {
- // Can unwrap safely.
- if let Some(arg) = clause.args().unwrap().iter().nth(optimal_index) {
- match **arg {
+ 'outer: for (right, clause) in clauses.iter().enumerate() {
+ if let Some(args) = clause.args() {
+ for (instantiated_arg_index, arg) in args.iter().enumerate() {
+ match arg {
Term::Var(..) | Term::AnonVar => {
- if left_index < right_index {
- subseqs.push((left_index, right_index));
+ }
+ _ => {
+ if optimal_index != instantiated_arg_index {
+ if left >= right {
+ optimal_index = instantiated_arg_index;
+ continue 'outer;
+ }
+
+ subseqs.push(ClauseSpan {
+ left,
+ right,
+ instantiated_arg_index: optimal_index,
+ });
+
+ optimal_index = instantiated_arg_index;
+ left = right;
}
- subseqs.push((right_index, right_index + 1));
- left_index = right_index + 1;
+ continue 'outer;
}
- _ => (),
}
}
}
+
+ if left < right {
+ subseqs.push(ClauseSpan { left, right, instantiated_arg_index: optimal_index });
+ }
+
+ optimal_index = 0;
+
+ subseqs.push(ClauseSpan {
+ left: right,
+ right: right + 1,
+ instantiated_arg_index: optimal_index,
+ });
+
+ left = right + 1;
}
- if left_index < clauses.len() {
- subseqs.push((left_index, clauses.len()));
+ if left < clauses.len() {
+ subseqs.push(ClauseSpan {
+ left,
+ right: clauses.len(),
+ instantiated_arg_index: optimal_index,
+ });
}
subseqs
}
- fn compile_pred_subseq<'b: 'a, I: Indexer>(
+ fn compile_pred_subseq<I: Indexer>(
&mut self,
- clauses: &'b [PredicateClause],
+ clauses: &[PredicateClause],
optimal_index: usize,
) -> Result<Code, CompilationError> {
let mut code = VecDeque::new();
- let mut code_offsets = CodeOffsets::new(
- self.atom_tbl.clone(),
- I::new(),
- optimal_index + 1,
- );
+ let mut code_offsets = CodeOffsets::new(I::new(), optimal_index + 1);
let mut skip_stub_try_me_else = false;
let jmp_by_locs_len = self.jmp_by_locs.len();
@@ -1054,12 +1040,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
if clauses.len() > 1 {
let choice = match i {
0 => self.settings.internal_try_me_else(clause_code.len() + 1),
- //ChoiceInstruction::TryMeElse(clause_code.len() + 1),
+ //Instruction::TryMeElse(clause_code.len() + 1),
_ if i == clauses.len() - 1 => self.settings.internal_trust_me(),
_ => self.settings.internal_retry_me_else(clause_code.len() + 1),
};
- code.push_back(Line::Choice(choice));
+ code.push_back(choice);
} else if self.settings.is_extensible {
/*
generate stub choice instructions for extensible
@@ -1072,9 +1058,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
over them.
*/
- code.push_front(Line::Choice(self.settings.internal_try_me_else(0)));
- //Line::Choice(ChoiceInstruction::TryMeElse(0)));
- skip_stub_try_me_else = !self.settings.is_dynamic(); //true;
+ code.push_front(self.settings.internal_try_me_else(0));
+ skip_stub_try_me_else = !self.settings.is_dynamic();
}
let arg = match clause.args() {
@@ -1087,7 +1072,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
if let Some(arg) = arg {
let index = code.len();
- code_offsets.index_term(arg, index, &mut clause_index_info);
+ code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
}
if !(clauses.len() == 1 && self.settings.is_extensible) {
@@ -1102,7 +1087,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
self.global_jmp_by_locs_offset = jmp_by_locs_len;
if !index_code.is_empty() {
- code.push_front(Line::IndexingCode(index_code));
+ code.push_front(Instruction::IndexingCode(index_code));
if skip_stub_try_me_else {
// skip the TryMeElse(0) also.
@@ -1122,44 +1107,45 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
Ok(Vec::from(code))
}
- pub(crate) fn compile_predicate<'b: 'a>(
+ pub(crate) fn compile_predicate(
&mut self,
- clauses: &'b Vec<PredicateClause>,
+ clauses: &Vec<PredicateClause>,
) -> Result<Code, CompilationError> {
let mut code = Code::new();
- let optimal_index = match Self::first_instantiated_index(&clauses) {
- Some(index) => index,
- None => 0, // Default to first argument indexing.
- };
-
- let split_pred = Self::split_predicate(&clauses, optimal_index);
+ let split_pred = Self::split_predicate(&clauses);
let multi_seq = split_pred.len() > 1;
- for (l, r) in split_pred {
+ for ClauseSpan { left, right, instantiated_arg_index } in split_pred {
let skel_lower_bound = self.skeleton.clauses.len();
let code_segment = if self.settings.is_dynamic() {
- self.compile_pred_subseq::<DynamicCodeIndices>(&clauses[l..r], optimal_index)?
+ self.compile_pred_subseq::<DynamicCodeIndices>(
+ &clauses[left..right],
+ instantiated_arg_index,
+ )?
} else {
- self.compile_pred_subseq::<StaticCodeIndices>(&clauses[l..r], optimal_index)?
+ self.compile_pred_subseq::<StaticCodeIndices>(
+ &clauses[left..right],
+ instantiated_arg_index,
+ )?
};
let clause_start_offset = code.len();
if multi_seq {
- let choice = match l {
+ let choice = match left {
0 => self.settings.try_me_else(code_segment.len() + 1),
- _ if r == clauses.len() => self.settings.trust_me(),
+ _ if right == clauses.len() => self.settings.trust_me(),
_ => self.settings.retry_me_else(code_segment.len() + 1),
};
- code.push(Line::Choice(choice));
+ code.push(choice);
} else if self.settings.is_extensible {
- code.push(Line::Choice(self.settings.try_me_else(0)));
+ code.push(self.settings.try_me_else(0));
}
if self.settings.is_extensible {
- let segment_is_indexed = to_indexing_line(&code_segment[0]).is_some();
+ let segment_is_indexed = code_segment[0].to_indexing_line().is_some();
for clause_index_info in self.skeleton.clauses[skel_lower_bound..].iter_mut() {
clause_index_info.clause_start +=
diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs
index 7525a79a..2161d20e 100644
--- a/src/debray_allocator.rs
+++ b/src/debray_allocator.rs
@@ -1,13 +1,16 @@
use indexmap::IndexMap;
-use prolog_parser::ast::*;
-use prolog_parser::temp_v;
-
use crate::allocator::*;
use crate::fixtures::*;
-use crate::forms::*;
+use crate::forms::Level;
+use crate::instructions::*;
use crate::machine::machine_indices::*;
-use crate::targets::*;
+use crate::parser::ast::*;
+use crate::targets::CompilationTarget;
+
+use crate::temp_v;
+
+use fxhash::FxBuildHasher;
use std::cell::Cell;
use std::collections::BTreeSet;
@@ -15,23 +18,23 @@ use std::rc::Rc;
#[derive(Debug)]
pub(crate) struct DebrayAllocator {
- bindings: IndexMap<Rc<Var>, VarData>,
+ bindings: IndexMap<Rc<String>, VarData, FxBuildHasher>,
arg_c: usize,
temp_lb: usize,
arity: usize, // 0 if not at head.
- contents: IndexMap<usize, Rc<Var>>,
+ contents: IndexMap<usize, Rc<String>, FxBuildHasher>,
in_use: BTreeSet<usize>,
}
impl DebrayAllocator {
- fn is_curr_arg_distinct_from(&self, var: &Var) -> bool {
+ fn is_curr_arg_distinct_from(&self, var: &String) -> bool {
match self.contents.get(&self.arg_c) {
Some(t_var) if **t_var != *var => true,
_ => false,
}
}
- fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool {
+ fn occurs_shallowly_in_head(&self, var: &String, r: usize) -> bool {
match self.bindings.get(var).unwrap() {
&VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)),
_ => false,
@@ -44,7 +47,7 @@ impl DebrayAllocator {
in_use_range || self.in_use.contains(&r)
}
- fn alloc_with_cr(&self, var: &Var) -> usize {
+ fn alloc_with_cr(&self, var: &String) -> usize {
match self.bindings.get(var) {
Some(&VarData::Temp(_, _, ref tvd)) => {
for &(_, reg) in tvd.use_set.iter() {
@@ -70,7 +73,7 @@ impl DebrayAllocator {
}
}
- fn alloc_with_ca(&self, var: &Var) -> usize {
+ fn alloc_with_ca(&self, var: &String) -> usize {
match self.bindings.get(var) {
Some(&VarData::Temp(_, _, ref tvd)) => {
for &(_, reg) in tvd.use_set.iter() {
@@ -98,7 +101,7 @@ impl DebrayAllocator {
}
}
- fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<Var>, usize)> {
+ fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<String>, usize)> {
// we want to allocate a register to the k^{th} parameter, par_k.
// par_k may not be a temporary variable.
let k = self.arg_c;
@@ -123,10 +126,11 @@ impl DebrayAllocator {
}
}
- fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
- where
- Target: CompilationTarget<'a>,
- {
+ fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
+ &mut self,
+ chunk_num: usize,
+ code: &mut Code,
+ ) {
match self.alloc_in_last_goal_hint(chunk_num) {
Some((var, r)) => {
let k = self.arg_c;
@@ -134,7 +138,7 @@ impl DebrayAllocator {
if r != k {
let r = RegType::Temp(r);
- target.push(Target::move_to_register(r, k));
+ code.push(Target::move_to_register(r, k));
self.contents.swap_remove(&k);
self.contents.insert(r.reg_num(), var.clone());
@@ -149,10 +153,10 @@ impl DebrayAllocator {
fn alloc_reg_to_var<'a, Target>(
&mut self,
- var: &Var,
+ var: &String,
lvl: Level,
term_loc: GenContext,
- target: &mut Vec<Target>,
+ target: &mut Vec<Instruction>,
) -> usize
where
Target: CompilationTarget<'a>,
@@ -160,7 +164,7 @@ impl DebrayAllocator {
match term_loc {
GenContext::Head => {
if let Level::Shallow = lvl {
- self.evacuate_arg(0, target);
+ self.evacuate_arg::<Target>(0, target);
self.alloc_with_cr(var)
} else {
self.alloc_with_ca(var)
@@ -169,7 +173,7 @@ impl DebrayAllocator {
GenContext::Mid(_) => self.alloc_with_ca(var),
GenContext::Last(chunk_num) => {
if let Level::Shallow = lvl {
- self.evacuate_arg(chunk_num, target);
+ self.evacuate_arg::<Target>(chunk_num, target);
self.alloc_with_cr(var)
} else {
self.alloc_with_ca(var)
@@ -193,7 +197,7 @@ impl DebrayAllocator {
final_index
}
- fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool {
+ fn in_place(&self, var: &String, term_loc: GenContext, r: RegType, k: usize) -> bool {
match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => match self.bindings().get(var).unwrap() {
@@ -204,49 +208,49 @@ impl DebrayAllocator {
}
}
-impl<'a> Allocator<'a> for DebrayAllocator {
+impl Allocator for DebrayAllocator {
fn new() -> DebrayAllocator {
DebrayAllocator {
arity: 0,
arg_c: 1,
temp_lb: 1,
- bindings: IndexMap::new(),
- contents: IndexMap::new(),
+ bindings: IndexMap::with_hasher(FxBuildHasher::default()),
+ contents: IndexMap::with_hasher(FxBuildHasher::default()),
in_use: BTreeSet::new(),
}
}
- fn mark_anon_var<Target>(&mut self, lvl: Level, term_loc: GenContext, target: &mut Vec<Target>)
- where
- Target: CompilationTarget<'a>,
- {
+ fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
+ &mut self,
+ lvl: Level,
+ term_loc: GenContext,
+ code: &mut Code,
+ ) {
let r = RegType::Temp(self.alloc_reg_to_non_var());
match lvl {
- Level::Deep => target.push(Target::subterm_to_variable(r)),
+ Level::Deep => code.push(Target::subterm_to_variable(r)),
Level::Root | Level::Shallow => {
let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc {
- self.evacuate_arg(chunk_num, target);
+ self.evacuate_arg::<Target>(chunk_num, code);
}
self.arg_c += 1;
- target.push(Target::argument_to_variable(r, k));
+ code.push(Target::argument_to_variable(r, k));
}
};
}
- fn mark_non_var<Target>(
+ fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
term_loc: GenContext,
- cell: &Cell<RegType>,
- target: &mut Vec<Target>,
- ) where
- Target: CompilationTarget<'a>,
- {
+ cell: &'a Cell<RegType>,
+ code: &mut Code,
+ ) {
let r = cell.get();
let r = match lvl {
@@ -254,7 +258,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
let k = self.arg_c;
if let GenContext::Last(chunk_num) = term_loc {
- self.evacuate_arg(chunk_num, target);
+ self.evacuate_arg::<Target>(chunk_num, code);
}
self.arg_c += 1;
@@ -270,20 +274,18 @@ impl<'a> Allocator<'a> for DebrayAllocator {
cell.set(r);
}
- fn mark_var<Target>(
+ fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
- var: Rc<Var>,
+ var: Rc<String>,
lvl: Level,
cell: &'a Cell<VarReg>,
term_loc: GenContext,
- target: &mut Vec<Target>,
- ) where
- Target: CompilationTarget<'a>,
- {
+ code: &mut Code,
+ ) {
let (r, is_new_var) = match self.get(var.clone()) {
RegType::Temp(0) => {
// here, r is temporary *and* unassigned.
- let o = self.alloc_reg_to_var(&var, lvl, term_loc, target);
+ let o = self.alloc_reg_to_var::<Target>(&var, lvl, term_loc, code);
cell.set(VarReg::Norm(RegType::Temp(o)));
(RegType::Temp(o), true)
@@ -297,27 +299,25 @@ impl<'a> Allocator<'a> for DebrayAllocator {
r => (r, false),
};
- self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var);
+ self.mark_reserved_var::<Target>(var, lvl, cell, term_loc, code, r, is_new_var);
}
- fn mark_reserved_var<Target>(
+ fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
- var: Rc<Var>,
+ var: Rc<String>,
lvl: Level,
cell: &'a Cell<VarReg>,
term_loc: GenContext,
- target: &mut Vec<Target>,
+ code: &mut Code,
r: RegType,
is_new_var: bool,
- ) where
- Target: CompilationTarget<'a>,
- {
+ ) {
match lvl {
Level::Root | Level::Shallow => {
let k = self.arg_c;
if self.is_curr_arg_distinct_from(&var) {
- self.evacuate_arg(term_loc.chunk_num(), target);
+ self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
}
self.arg_c += 1;
@@ -326,24 +326,24 @@ impl<'a> Allocator<'a> for DebrayAllocator {
if !self.in_place(&var, term_loc, r, k) {
if is_new_var {
- target.push(Target::argument_to_variable(r, k));
+ code.push(Target::argument_to_variable(r, k));
} else {
- target.push(Target::argument_to_value(r, k));
+ code.push(Target::argument_to_value(r, k));
}
}
}
Level::Deep if is_new_var => {
if let GenContext::Head = term_loc {
if self.occurs_shallowly_in_head(&var, r.reg_num()) {
- target.push(Target::subterm_to_value(r));
+ code.push(Target::subterm_to_value(r));
} else {
- target.push(Target::subterm_to_variable(r));
+ code.push(Target::subterm_to_variable(r));
}
} else {
- target.push(Target::subterm_to_variable(r));
+ code.push(Target::subterm_to_variable(r));
}
}
- Level::Deep => target.push(Target::subterm_to_value(r)),
+ Level::Deep => code.push(Target::subterm_to_value(r)),
};
if !r.is_perm() {
@@ -382,12 +382,12 @@ impl<'a> Allocator<'a> for DebrayAllocator {
self.bindings
}
- fn reset_at_head(&mut self, args: &Vec<Box<Term>>) {
+ fn reset_at_head(&mut self, args: &Vec<Term>) {
self.reset_arg(args.len());
self.arity = args.len();
for (idx, arg) in args.iter().enumerate() {
- if let &Term::Var(_, ref var) = arg.as_ref() {
+ if let &Term::Var(_, ref var) = arg {
let r = self.get(var.clone());
if !r.is_perm() && r.reg_num() == 0 {
diff --git a/src/examples/least_time.pl b/src/examples/least_time.pl
index b93f0b5e..2b599b60 100644
--- a/src/examples/least_time.pl
+++ b/src/examples/least_time.pl
@@ -11,7 +11,7 @@
*/
:- module(least_time, [find_min_time/2,
- write_time_nl/1]).
+ write_time_nl/1]).
:- use_module(library(dcgs)).
@@ -20,12 +20,6 @@
:- 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),
@@ -33,10 +27,10 @@ valid_time([H1,H2,M1,M2], T) :-
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
- )
+ ( H2 =< 3 ->
+ T = true
+ ; T = false
+ )
; T = true
)
; T = false
diff --git a/src/fixtures.rs b/src/fixtures.rs
index 0ecdd9e8..43c3ace8 100644
--- a/src/fixtures.rs
+++ b/src/fixtures.rs
@@ -1,4 +1,4 @@
-use prolog_parser::ast::*;
+use crate::parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
@@ -84,8 +84,8 @@ type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
#[derive(Debug)]
pub(crate) struct VariableFixtures<'a> {
- perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>,
- last_chunk_temp_vars: IndexSet<Rc<Var>>,
+ perm_vars: IndexMap<Rc<String>, VariableFixture<'a>>,
+ last_chunk_temp_vars: IndexSet<Rc<String>>,
}
impl<'a> VariableFixtures<'a> {
@@ -96,11 +96,11 @@ impl<'a> VariableFixtures<'a> {
}
}
- pub(crate) fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
+ pub(crate) fn insert(&mut self, var: Rc<String>, vs: VariableFixture<'a>) {
self.perm_vars.insert(var, vs);
}
- pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<Var>) {
+ pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<String>) {
self.last_chunk_temp_vars.insert(var);
}
@@ -115,7 +115,7 @@ impl<'a> VariableFixtures<'a> {
// Compute the conflict set of u.
// 1.
- let mut use_sets: IndexMap<Rc<Var>, OccurrenceSet> = IndexMap::new();
+ let mut use_sets: IndexMap<Rc<String>, OccurrenceSet> = IndexMap::new();
for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
@@ -153,11 +153,11 @@ impl<'a> VariableFixtures<'a> {
}
}
- fn get_mut(&mut self, u: Rc<Var>) -> Option<&mut VariableFixture<'a>> {
+ fn get_mut(&mut self, u: Rc<String>) -> Option<&mut VariableFixture<'a>> {
self.perm_vars.get_mut(&u)
}
- fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<Var>, VariableFixture<'a>> {
+ fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<String>, VariableFixture<'a>> {
self.perm_vars.iter_mut()
}
@@ -218,11 +218,11 @@ impl<'a> VariableFixtures<'a> {
}
}
- pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<Var>, VariableFixture<'a>> {
+ pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<String>, VariableFixture<'a>> {
self.perm_vars.into_iter()
}
- fn values(&self) -> indexmap::map::Values<Rc<Var>, VariableFixture<'a>> {
+ fn values(&self) -> indexmap::map::Values<Rc<String>, VariableFixture<'a>> {
self.perm_vars.values()
}
@@ -272,10 +272,10 @@ impl UnsafeVarMarker {
}
}
- pub(crate) fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
+ pub(crate) fn mark_safe_vars(&mut self, query_instr: &Instruction) -> bool {
match query_instr {
- &QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
- | &QueryInstruction::SetVariable(r) => {
+ &Instruction::PutVariable(r @ RegType::Temp(_), _) |
+ &Instruction::SetVariable(r) => {
self.safe_vars.insert(r);
true
}
@@ -283,10 +283,10 @@ impl UnsafeVarMarker {
}
}
- pub(crate) fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
+ pub(crate) fn mark_phase(&mut self, query_instr: &Instruction, phase: usize) {
match query_instr {
- &QueryInstruction::PutValue(r @ RegType::Perm(_), _)
- | &QueryInstruction::SetValue(r) => {
+ &Instruction::PutValue(r @ RegType::Perm(_), _) |
+ &Instruction::SetValue(r) => {
let p = self.unsafe_vars.entry(r).or_insert(0);
*p = phase;
}
@@ -294,21 +294,21 @@ impl UnsafeVarMarker {
}
}
- pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
+ pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut Instruction, phase: usize) {
match query_instr {
- &mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
+ &mut Instruction::PutValue(RegType::Perm(i), arg) => {
if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
if p == phase {
- *query_instr = QueryInstruction::PutUnsafeValue(i, arg);
+ *query_instr = Instruction::PutUnsafeValue(i, arg);
self.safe_vars.insert(RegType::Perm(i));
} else {
self.unsafe_vars.insert(RegType::Perm(i), p);
}
}
}
- &mut QueryInstruction::SetValue(r) => {
+ &mut Instruction::SetValue(r) => {
if !self.safe_vars.contains(&r) {
- *query_instr = QueryInstruction::SetLocalValue(r);
+ *query_instr = Instruction::SetLocalValue(r);
self.safe_vars.insert(r);
self.unsafe_vars.remove(&r);
diff --git a/src/forms.rs b/src/forms.rs
index 4f579c8c..aef5ad95 100644
--- a/src/forms.rs
+++ b/src/forms.rs
@@ -1,33 +1,41 @@
-use prolog_parser::ast::*;
-use prolog_parser::parser::OpDesc;
-use prolog_parser::{clause_name, is_infix, is_postfix};
-
-use crate::clause_types::*;
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::instructions::*;
+use crate::machine::heap::*;
use crate::machine::loader::PredicateQueue;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
-use crate::rug::{Integer, Rational};
-use ordered_float::OrderedFloat;
+use crate::parser::ast::*;
+use crate::parser::parser::CompositeOpDesc;
+use crate::parser::rug::{Integer, Rational};
+use crate::types::*;
+
+use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet};
+use ordered_float::OrderedFloat;
use slice_deque::*;
use std::cell::Cell;
+use std::convert::TryFrom;
+use std::fmt;
use std::ops::AddAssign;
use std::path::PathBuf;
use std::rc::Rc;
-pub(crate) type PredicateKey = (ClauseName, usize); // name, arity.
+use crate::{is_infix, is_postfix};
-pub(crate) type Predicate = Vec<PredicateClause>;
+pub type PredicateKey = (Atom, usize); // name, arity.
+
+pub type Predicate = Vec<PredicateClause>;
// vars of predicate, toplevel offset. Vec<Term> is always a vector
// of vars (we get their adjoining cells this way).
-pub(crate) type JumpStub = Vec<Term>;
+pub type JumpStub = Vec<Term>;
#[derive(Debug, Clone)]
-pub(crate) enum TopLevel {
+pub enum TopLevel {
Fact(Term), // Term, line_num, col_num
Predicate(Predicate),
Query(Vec<QueryTerm>),
@@ -35,7 +43,7 @@ pub(crate) enum TopLevel {
}
#[derive(Debug, Clone, Copy)]
-pub(crate) enum AppendOrPrepend {
+pub enum AppendOrPrepend {
Append,
Prepend,
}
@@ -51,7 +59,7 @@ impl AppendOrPrepend {
}
#[derive(Debug, Clone, Copy)]
-pub(crate) enum Level {
+pub enum Level {
Deep,
Root,
Shallow,
@@ -67,12 +75,12 @@ impl Level {
}
#[derive(Debug, Clone)]
-pub(crate) enum QueryTerm {
+pub enum QueryTerm {
// register, clause type, subterms, use default call policy.
- Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
+ Clause(Cell<RegType>, ClauseType, Vec<Term>, bool),
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
UnblockedCut(Cell<VarReg>),
- GetLevelAndUnify(Cell<VarReg>, Rc<Var>),
+ GetLevelAndUnify(Cell<VarReg>, Rc<String>),
Jump(JumpStub),
}
@@ -95,25 +103,25 @@ impl QueryTerm {
}
#[derive(Debug, Clone)]
-pub(crate) struct Rule {
- pub(crate) head: (ClauseName, Vec<Box<Term>>, QueryTerm),
+pub struct Rule {
+ pub(crate) head: (Atom, Vec<Term>, QueryTerm),
pub(crate) clauses: Vec<QueryTerm>,
}
#[derive(Clone, Debug, Hash)]
-pub(crate) enum ListingSource {
+pub enum ListingSource {
DynamicallyGenerated,
- File(ClauseName, PathBuf), // filename, path
+ File(Atom, PathBuf), // filename, path
User,
}
impl ListingSource {
- pub(crate) fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self {
+ pub(crate) fn from_file_and_path(filename: Atom, path_buf: PathBuf) -> Self {
ListingSource::File(filename, path_buf)
}
}
-pub(crate) trait ClauseInfo {
+pub trait ClauseInfo {
fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
match clauses.first() {
Some(cl) => {
@@ -123,14 +131,14 @@ pub(crate) trait ClauseInfo {
}
}
- fn name(&self) -> Option<ClauseName>;
+ fn name(&self) -> Option<Atom>;
fn arity(&self) -> usize;
}
impl ClauseInfo for PredicateKey {
#[inline]
- fn name(&self) -> Option<ClauseName> {
- Some(self.0.clone())
+ fn name(&self) -> Option<Atom> {
+ Some(self.0)
}
#[inline]
@@ -140,28 +148,32 @@ impl ClauseInfo for PredicateKey {
}
impl ClauseInfo for Term {
- fn name(&self) -> Option<ClauseName> {
+ fn name(&self) -> Option<Atom> {
+ //, atom_tbl: &AtomTable) -> Option<StringBuffer> {
match self {
- Term::Clause(_, ref name, ref terms, _) => {
+ Term::Clause(_, name, terms) => {
+ // let str_buf = StringBuffer::from(*name, atom_tbl);
+
match name.as_str() {
+ // str_buf.as_str() {
":-" => {
match terms.len() {
- 1 => None, // a declaration.
- 2 => terms[0].name(),
- _ => Some(clause_name!(":-")),
+ 1 => None, // a declaration.
+ 2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)),
+ _ => Some(*name),
}
}
- _ => Some(name.clone()),
+ _ => Some(*name), //str_buf),
}
}
- Term::Constant(_, Constant::Atom(ref name, _)) => Some(name.clone()),
+ Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)),
_ => None,
}
}
fn arity(&self) -> usize {
match self {
- Term::Clause(_, ref name, ref terms, _) => match name.as_str() {
+ Term::Clause(_, name, terms) => match name.as_str() {
":-" => match terms.len() {
1 => 0,
2 => terms[0].arity(),
@@ -175,8 +187,8 @@ impl ClauseInfo for Term {
}
impl ClauseInfo for Rule {
- fn name(&self) -> Option<ClauseName> {
- Some(self.head.0.clone())
+ fn name(&self) -> Option<Atom> {
+ Some(self.head.0)
}
fn arity(&self) -> usize {
@@ -185,7 +197,7 @@ impl ClauseInfo for Rule {
}
impl ClauseInfo for PredicateClause {
- fn name(&self) -> Option<ClauseName> {
+ fn name(&self) -> Option<Atom> {
match self {
&PredicateClause::Fact(ref term, ..) => term.name(),
&PredicateClause::Rule(ref rule, ..) => rule.name(),
@@ -200,23 +212,20 @@ impl ClauseInfo for PredicateClause {
}
}
-// pub(crate) type CompiledResult = (Predicate, VecDeque<TopLevel>);
-
#[derive(Debug, Clone)]
-pub(crate) enum PredicateClause {
+pub enum PredicateClause {
Fact(Term),
Rule(Rule),
}
impl PredicateClause {
- // TODO: add this to `Term` in `prolog_parser` like `first_arg`.
- pub(crate) fn args(&self) -> Option<&[Box<Term>]> {
- match *self {
- PredicateClause::Fact(ref term, ..) => match term {
- Term::Clause(_, _, args, _) => Some(&args),
+ pub(crate) fn args(&self) -> Option<&[Term]> {
+ match self {
+ PredicateClause::Fact(term, ..) => match term {
+ Term::Clause(_, _, args) => Some(&args),
_ => None,
},
- PredicateClause::Rule(ref rule, ..) => {
+ PredicateClause::Rule(rule, ..) => {
if rule.head.1.is_empty() {
None
} else {
@@ -227,37 +236,34 @@ impl PredicateClause {
}
}
+#[derive(Debug)]
+pub struct ClauseSpan {
+ pub left: usize,
+ pub right: usize,
+ pub instantiated_arg_index: usize,
+}
+
#[derive(Debug, Clone)]
-pub(crate) enum ModuleSource {
- Library(ClauseName),
- File(ClauseName),
+pub enum ModuleSource {
+ Library(Atom),
+ File(Atom),
}
impl ModuleSource {
pub(crate) fn as_functor_stub(&self) -> MachineStub {
match self {
- ModuleSource::Library(ref name) => {
- functor!("library", [clause_name(name.clone())])
+ ModuleSource::Library(name) => {
+ functor!(atom!("library"), [atom(name)])
}
- ModuleSource::File(ref name) => {
- functor!(clause_name(name.clone()))
+ ModuleSource::File(name) => {
+ functor!(name)
}
}
}
}
-// pub(crate) type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
-
-/*
-#[derive(Debug, Clone)]
-pub(crate) enum MultiFileIndicator {
- LocalScoped(ClauseName, usize), // name, arity
- ModuleScoped(ScopedPredicateKey),
-}
-*/
-
#[derive(Clone, Copy, Hash, Debug)]
-pub(crate) enum MetaSpec {
+pub enum MetaSpec {
Minus,
Plus,
Either,
@@ -265,71 +271,71 @@ pub(crate) enum MetaSpec {
}
#[derive(Debug, Clone)]
-pub(crate) enum Declaration {
- Dynamic(ClauseName, usize),
- MetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>), // module name, name, meta-specs
+pub enum Declaration {
+ Dynamic(Atom, usize),
+ MetaPredicate(Atom, Atom, Vec<MetaSpec>), // module name, name, meta-specs
Module(ModuleDecl),
- NonCountedBacktracking(ClauseName, usize), // name, arity
+ NonCountedBacktracking(Atom, usize), // name, arity
Op(OpDecl),
UseModule(ModuleSource),
UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>),
}
-#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
-pub(crate) struct OpDecl {
- pub(crate) prec: usize,
- pub(crate) spec: Specifier,
- pub(crate) name: ClauseName,
+#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)]
+pub struct OpDecl {
+ pub(crate) op_desc: OpDesc,
+ pub(crate) name: Atom,
+}
+
+#[inline(always)]
+pub(crate) fn fixity(spec: u32) -> Fixity {
+ match spec {
+ XFY | XFX | YFX => Fixity::In,
+ XF | YF => Fixity::Post,
+ FX | FY => Fixity::Pre,
+ _ => unreachable!(),
+ }
}
+
impl OpDecl {
#[inline]
- pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self {
- Self { prec, spec, name }
+ pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self {
+ Self { op_desc, name }
}
#[inline]
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
- let prec = self.prec;
- self.prec = 0;
+ let prec = self.op_desc.get_prec();
+ self.op_desc.set(0, self.op_desc.get_spec());
self.insert_into_op_dir(op_dir);
- self.prec = prec;
+ self.op_desc.set(prec, self.op_desc.get_spec());
}
- #[inline]
- pub(crate) fn fixity(&self) -> Fixity {
- match self.spec {
- XFY | XFX | YFX => Fixity::In,
- XF | YF => Fixity::Post,
- FX | FY => Fixity::Pre,
- _ => unreachable!(),
- }
- }
+ pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<OpDesc> {
+ let key = (self.name, fixity(self.op_desc.get_spec() as u32));
- pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
- let key = (self.name.clone(), self.fixity());
-
- match op_dir.get(&key) {
+ match op_dir.get_mut(&key) {
Some(cell) => {
- return Some(cell.shared_op_desc().replace((self.prec, self.spec)));
+ let (old_prec, old_spec) = cell.get();
+ cell.set(self.op_desc.get_prec(), self.op_desc.get_spec());
+ return Some(OpDesc::build_with(old_prec, old_spec));
}
None => {}
}
- op_dir
- .insert(key, OpDirValue::new(self.spec, self.prec))
- .map(|op_dir_value| op_dir_value.shared_op_desc().get())
+ op_dir.insert(key, self.op_desc)
}
pub(crate) fn submit(
&self,
- existing_desc: Option<OpDesc>,
+ existing_desc: Option<CompositeOpDesc>,
op_dir: &mut OpDir,
) -> Result<(), SessionError> {
- let (spec, name) = (self.spec, self.name.clone());
+ let (spec, name) = (self.op_desc.get_spec(), self.name.clone());
- if is_infix!(spec) {
+ if is_infix!(spec as u32) {
if let Some(desc) = existing_desc {
if desc.post > 0 {
return Err(SessionError::OpIsInfixAndPostFix(name));
@@ -337,7 +343,7 @@ impl OpDecl {
}
}
- if is_postfix!(spec) {
+ if is_postfix!(spec as u32) {
if let Some(desc) = existing_desc {
if desc.inf > 0 {
return Err(SessionError::OpIsInfixAndPostFix(name));
@@ -350,22 +356,51 @@ impl OpDecl {
}
}
+#[derive(Debug)]
+pub enum AtomOrString {
+ Atom(Atom),
+ String(String),
+}
+
+impl AtomOrString {
+ #[inline]
+ pub fn as_str(&self) -> &str {
+ match self {
+ AtomOrString::Atom(atom) if atom == &atom!("[]") => "",
+ AtomOrString::Atom(atom) => atom.as_str(),
+ AtomOrString::String(string) => string.as_str(),
+ }
+ }
+
+ #[inline]
+ pub fn to_string(self) -> String {
+ match self {
+ AtomOrString::Atom(atom) => {
+ atom.as_str().to_owned()
+ }
+ AtomOrString::String(string) => {
+ string
+ }
+ }
+ }
+}
+
pub(crate) fn fetch_atom_op_spec(
- name: ClauseName,
- spec: Option<SharedOpDesc>,
+ name: Atom,
+ spec: Option<OpDesc>,
op_dir: &OpDir,
-) -> Option<SharedOpDesc> {
- fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir)
- .or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir))
+) -> Option<OpDesc> {
+ fetch_op_spec_from_existing(name, 2, spec, op_dir)
+ .or_else(|| fetch_op_spec_from_existing(name, 1, spec, op_dir))
}
pub(crate) fn fetch_op_spec_from_existing(
- name: ClauseName,
+ name: Atom,
arity: usize,
- spec: Option<SharedOpDesc>,
+ op_desc: Option<OpDesc>,
op_dir: &OpDir,
-) -> Option<SharedOpDesc> {
- if let Some(ref op_desc) = &spec {
+) -> Option<OpDesc> {
+ if let Some(ref op_desc) = &op_desc {
if op_desc.arity() != arity {
/* it's possible to extend operator functors with
* additional terms. When that happens,
@@ -374,61 +409,56 @@ pub(crate) fn fetch_op_spec_from_existing(
}
}
- spec.or_else(|| fetch_op_spec(name, arity, op_dir))
+ op_desc.or_else(|| fetch_op_spec(name, arity, op_dir))
}
-pub(crate) fn fetch_op_spec(
- name: ClauseName,
- arity: usize,
- op_dir: &OpDir,
-) -> Option<SharedOpDesc> {
+pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option<OpDesc> {
match arity {
- 2 => op_dir
- .get(&(name, Fixity::In))
- .and_then(|OpDirValue(spec)| {
- if spec.prec() > 0 {
- Some(spec.clone())
- } else {
- None
- }
- }),
+ 2 => op_dir.get(&(name, Fixity::In)).and_then(|op_desc| {
+ if op_desc.get_prec() > 0 {
+ Some(*op_desc)
+ } else {
+ None
+ }
+ }),
1 => {
- if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
- if spec.prec() > 0 {
- return Some(spec.clone());
+ if let Some(op_desc) = op_dir.get(&(name.clone(), Fixity::Pre)) {
+ if op_desc.get_prec() > 0 {
+ return Some(*op_desc);
}
}
- op_dir
- .get(&(name.clone(), Fixity::Post))
- .and_then(|OpDirValue(spec)| {
- if spec.prec() > 0 {
- Some(spec.clone())
- } else {
- None
- }
- })
+ op_dir.get(&(name, Fixity::Post)).and_then(|op_desc| {
+ if op_desc.get_prec() > 0 {
+ Some(*op_desc)
+ } else {
+ None
+ }
+ })
+ }
+ 0 => {
+ fetch_atom_op_spec(name, None, op_dir)
}
_ => None,
}
}
-pub(crate) type ModuleDir = IndexMap<ClauseName, Module>;
+pub(crate) type ModuleDir = IndexMap<Atom, Module, FxBuildHasher>;
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
-pub(crate) enum ModuleExport {
+pub enum ModuleExport {
OpDecl(OpDecl),
PredicateKey(PredicateKey),
}
#[derive(Debug, Clone)]
-pub(crate) struct ModuleDecl {
- pub(crate) name: ClauseName,
+pub struct ModuleDecl {
+ pub(crate) name: Atom,
pub(crate) exports: Vec<ModuleExport>,
}
#[derive(Debug)]
-pub(crate) struct Module {
+pub struct Module {
pub(crate) module_decl: ModuleDecl,
pub(crate) code_dir: CodeDir,
pub(crate) op_dir: OpDir,
@@ -440,14 +470,19 @@ pub(crate) struct Module {
// Module's and related types are defined in forms.
impl Module {
- pub(crate) fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self {
+ pub(crate) fn new(
+ module_decl: ModuleDecl,
+ listing_src: ListingSource,
+ ) -> Self {
Module {
module_decl,
- code_dir: CodeDir::new(),
+ code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
op_dir: default_op_dir(),
- meta_predicates: MetaPredicateDir::new(),
- extensible_predicates: ExtensiblePredicates::new(),
- local_extensible_predicates: LocalExtensiblePredicates::new(),
+ meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
+ extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+ local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
+ FxBuildHasher::default(),
+ ),
listing_src,
}
}
@@ -455,71 +490,137 @@ impl Module {
pub(crate) fn new_in_situ(module_decl: ModuleDecl) -> Self {
Module {
module_decl,
- code_dir: CodeDir::new(),
- op_dir: OpDir::new(),
- meta_predicates: MetaPredicateDir::new(),
- extensible_predicates: ExtensiblePredicates::new(),
- local_extensible_predicates: LocalExtensiblePredicates::new(),
+ code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
+ op_dir: OpDir::with_hasher(FxBuildHasher::default()),
+ meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
+ extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+ local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
+ FxBuildHasher::default()
+ ),
listing_src: ListingSource::DynamicallyGenerated,
}
}
}
-#[derive(Debug, Clone)]
-pub(crate) enum Number {
+#[derive(Debug, Copy, Clone)]
+pub enum Number {
Float(OrderedFloat<f64>),
- Integer(Rc<Integer>),
- Rational(Rc<Rational>),
- Fixnum(isize),
+ Integer(TypedArenaPtr<Integer>),
+ Rational(TypedArenaPtr<Rational>),
+ Fixnum(Fixnum),
+}
+
+impl Default for Number {
+ fn default() -> Self {
+ Number::Fixnum(Fixnum::build_with(0))
+ }
+}
+
+impl fmt::Display for Number {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Number::Float(fl) => write!(f, "{}", fl),
+ Number::Integer(n) => write!(f, "{}", n),
+ Number::Rational(r) => write!(f, "{}", r),
+ Number::Fixnum(n) => write!(f, "{}", n.get_num()),
+ }
+ }
+}
+
+pub trait ArenaFrom<T> {
+ fn arena_from(value: T, arena: &mut Arena) -> Self;
}
-impl From<Integer> for Number {
+impl ArenaFrom<Integer> for Number {
#[inline]
- fn from(n: Integer) -> Self {
- Number::Integer(Rc::new(n))
+ fn arena_from(value: Integer, arena: &mut Arena) -> Number {
+ Number::Integer(arena_alloc!(value, arena))
}
}
-impl From<Rational> for Number {
+impl ArenaFrom<Rational> for Number {
#[inline]
- fn from(n: Rational) -> Self {
- Number::Rational(Rc::new(n))
+ fn arena_from(value: Rational, arena: &mut Arena) -> Number {
+ Number::Rational(arena_alloc!(value, arena))
}
}
-impl From<isize> for Number {
+impl ArenaFrom<usize> for Number {
#[inline]
- fn from(n: isize) -> Self {
- Number::Fixnum(n)
+ fn arena_from(value: usize, arena: &mut Arena) -> Number {
+ match i64::try_from(value) {
+ Ok(value) => Fixnum::build_with_checked(value)
+ .map(Number::Fixnum)
+ .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))),
+ Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)),
+ }
}
}
-impl Default for Number {
- fn default() -> Self {
- Number::Float(OrderedFloat(0f64))
+impl ArenaFrom<u64> for Number {
+ #[inline]
+ fn arena_from(value: u64, arena: &mut Arena) -> Number {
+ match i64::try_from(value) {
+ Ok(value) => Fixnum::build_with_checked(value)
+ .map(Number::Fixnum)
+ .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))),
+ Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)),
+ }
}
}
-impl Into<Constant> for Number {
+impl ArenaFrom<i64> 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),
+ fn arena_from(value: i64, arena: &mut Arena) -> Number {
+ Fixnum::build_with_checked(value)
+ .map(Number::Fixnum)
+ .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena)))
+ }
+}
+
+impl ArenaFrom<isize> for Number {
+ #[inline]
+ fn arena_from(value: isize, arena: &mut Arena) -> Number {
+ Fixnum::build_with_checked(value as i64)
+ .map(Number::Fixnum)
+ .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena)))
+ }
+}
+
+impl ArenaFrom<u32> for Number {
+ #[inline]
+ fn arena_from(value: u32, _arena: &mut Arena) -> Number {
+ Number::Fixnum(Fixnum::build_with(value as i64))
+ }
+}
+
+impl ArenaFrom<i32> for Number {
+ #[inline]
+ fn arena_from(value: i32, _arena: &mut Arena) -> Number {
+ Number::Fixnum(Fixnum::build_with(value as i64))
+ }
+}
+
+impl ArenaFrom<Number> for Literal {
+ #[inline]
+ fn arena_from(value: Number, arena: &mut Arena) -> Literal {
+ match value {
+ Number::Fixnum(n) => Literal::Fixnum(n),
+ Number::Integer(n) => Literal::Integer(n),
+ Number::Float(f) => Literal::Float(arena_alloc!(f, arena)),
+ Number::Rational(r) => Literal::Rational(r),
}
}
}
-impl Into<HeapCellValue> for Number {
+impl ArenaFrom<Number> for HeapCellValue {
#[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),
+ fn arena_from(value: Number, arena: &mut Arena) -> HeapCellValue {
+ match value {
+ Number::Fixnum(n) => fixnum_as_cell!(n),
+ Number::Integer(n) => typed_arena_ptr_as_cell!(n),
+ Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)),
+ Number::Rational(n) => typed_arena_ptr_as_cell!(n),
}
}
}
@@ -528,9 +629,9 @@ impl Number {
#[inline]
pub(crate) fn is_positive(&self) -> bool {
match self {
- &Number::Fixnum(n) => n > 0,
+ &Number::Fixnum(n) => n.get_num() > 0,
&Number::Integer(ref n) => &**n > &0,
- &Number::Float(OrderedFloat(f)) => f.is_sign_positive(),
+ &Number::Float(f) => f.is_sign_positive(),
&Number::Rational(ref r) => &**r > &0,
}
}
@@ -538,9 +639,9 @@ impl Number {
#[inline]
pub(crate) fn is_negative(&self) -> bool {
match self {
- &Number::Fixnum(n) => n < 0,
+ &Number::Fixnum(n) => n.get_num() < 0,
&Number::Integer(ref n) => &**n < &0,
- &Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
+ &Number::Float(OrderedFloat(f)) => f.is_sign_negative() && OrderedFloat(f) != -0f64,
&Number::Rational(ref r) => &**r < &0,
}
}
@@ -548,36 +649,28 @@ impl Number {
#[inline]
pub(crate) fn is_zero(&self) -> bool {
match self {
- &Number::Fixnum(n) => n == 0,
+ &Number::Fixnum(n) => n.get_num() == 0,
&Number::Integer(ref n) => &**n == &0,
- &Number::Float(f) => f == OrderedFloat(0f64),
+ &Number::Float(f) => f == OrderedFloat(0f64) || f == OrderedFloat(-0f64),
&Number::Rational(ref r) => &**r == &0,
}
}
#[inline]
- pub(crate) fn abs(self) -> Self {
+ pub(crate) fn is_integer(&self) -> bool {
match self {
- 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::from(Rational::from(r.abs_ref())),
+ Number::Fixnum(_) | Number::Integer(_) => true,
+ _ => false,
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum OptArgIndexKey {
- Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives
- List(usize, usize), // index, IndexingCode location
+ Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
+ List(usize, usize), // index, IndexingCode location
None,
- Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity
+ Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
}
impl OptArgIndexKey {
@@ -589,7 +682,7 @@ impl OptArgIndexKey {
#[inline]
pub(crate) fn arg_num(&self) -> usize {
match &self {
- OptArgIndexKey::Constant(arg_num, ..)
+ OptArgIndexKey::Literal(arg_num, ..)
| OptArgIndexKey::Structure(arg_num, ..)
| OptArgIndexKey::List(arg_num, _) => {
// these are always at least 1.
@@ -607,7 +700,7 @@ impl OptArgIndexKey {
#[inline]
pub(crate) fn switch_on_term_loc(&self) -> Option<usize> {
match &self {
- OptArgIndexKey::Constant(_, loc, ..)
+ OptArgIndexKey::Literal(_, loc, ..)
| OptArgIndexKey::Structure(_, loc, ..)
| OptArgIndexKey::List(_, loc) => Some(*loc),
OptArgIndexKey::None => None,
@@ -617,7 +710,7 @@ impl OptArgIndexKey {
#[inline]
pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) {
match self {
- OptArgIndexKey::Constant(_, ref mut loc, ..)
+ OptArgIndexKey::Literal(_, ref mut loc, ..)
| OptArgIndexKey::Structure(_, ref mut loc, ..)
| OptArgIndexKey::List(_, ref mut loc) => {
*loc = value;
@@ -631,7 +724,7 @@ impl AddAssign<usize> for OptArgIndexKey {
#[inline]
fn add_assign(&mut self, n: usize) {
match self {
- OptArgIndexKey::Constant(_, ref mut o, ..)
+ OptArgIndexKey::Literal(_, ref mut o, ..)
| OptArgIndexKey::List(_, ref mut o)
| OptArgIndexKey::Structure(_, ref mut o, ..) => {
*o += n;
@@ -700,6 +793,7 @@ pub(crate) struct LocalPredicateSkeleton {
pub(crate) is_multifile: bool,
pub(crate) clause_clause_locs: SliceDeque<usize>,
pub(crate) clause_assert_margin: usize,
+ pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
}
impl LocalPredicateSkeleton {
@@ -711,6 +805,7 @@ impl LocalPredicateSkeleton {
is_multifile: false,
clause_clause_locs: sdeq![],
clause_assert_margin: 0,
+ retracted_dynamic_clauses: Some(vec![]),
}
}
@@ -730,6 +825,20 @@ impl LocalPredicateSkeleton {
self.clause_clause_locs.clear();
self.clause_assert_margin = 0;
}
+
+ #[inline]
+ pub(crate) fn add_retracted_dynamic_clause_info(&mut self, clause_info: ClauseIndexInfo) {
+ debug_assert_eq!(self.is_dynamic, true);
+
+ if self.retracted_dynamic_clauses.is_none() {
+ self.retracted_dynamic_clauses = Some(vec![]);
+ }
+
+ self.retracted_dynamic_clauses
+ .as_mut()
+ .unwrap()
+ .push(clause_info);
+ }
}
#[derive(Clone, Debug)]
@@ -758,13 +867,6 @@ impl PredicateSkeleton {
}
}
- #[inline]
- pub(crate) fn reset(&mut self) {
- self.core.clause_clause_locs.clear();
- self.core.clause_assert_margin = 0;
- self.clauses.clear();
- }
-
pub(crate) fn target_pos_of_clause_clause_loc(
&self,
clause_clause_loc: usize,
diff --git a/src/heap_iter.rs b/src/heap_iter.rs
index fd057ac3..c88ad721 100644
--- a/src/heap_iter.rs
+++ b/src/heap_iter.rs
@@ -1,155 +1,271 @@
-use crate::machine::machine_indices::*;
-use crate::machine::machine_state::*;
+pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter};
+use crate::machine::heap::*;
-use indexmap::IndexSet;
+use crate::atom_table::*;
+use crate::types::*;
+
+use modular_bitfield::prelude::*;
-use std::cmp::Ordering;
use std::ops::Deref;
use std::vec::Vec;
+#[inline]
+fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) {
+ read_heap_cell!(heap[h],
+ (HeapCellValueTag::Str
+ | HeapCellValueTag::Lis
+ | HeapCellValueTag::AttrVar
+ | HeapCellValueTag::Var
+ | HeapCellValueTag::PStrLoc, vh) => {
+ if heap[vh].get_mark_bit() {
+ heap[h].set_forwarding_bit(true);
+ }
+ }
+ _ => {}
+ )
+}
+
+#[bitfield]
+#[repr(u64)]
+#[derive(Clone, Copy, Debug)]
+pub struct IterStackLoc {
+ value: B63,
+ m: bool,
+}
+
+impl IterStackLoc {
+ #[inline]
+ pub fn iterable_heap_loc(h: usize) -> Self {
+ IterStackLoc::new().with_m(false).with_value(h as u64)
+ }
+
+ #[inline]
+ pub fn mark_heap_loc(h: usize) -> Self {
+ IterStackLoc::new().with_m(true).with_value(h as u64)
+ }
+}
+
#[derive(Debug)]
-pub(crate) struct HCPreOrderIterator<'a> {
- pub(crate) machine_st: &'a MachineState,
- pub(crate) state_stack: Vec<Addr>,
+pub struct StackfulPreOrderHeapIter<'a> {
+ pub heap: &'a mut Vec<HeapCellValue>,
+ stack: Vec<IterStackLoc>,
+ h: usize,
+}
+
+impl<'a> Drop for StackfulPreOrderHeapIter<'a> {
+ fn drop(&mut self) {
+ while let Some(h) = self.stack.pop() {
+ let h = h.value() as usize;
+
+ self.heap[h].set_forwarding_bit(false);
+ self.heap[h].set_mark_bit(false);
+ }
+
+ self.heap.pop();
+ }
}
-impl<'a> HCPreOrderIterator<'a> {
- pub(crate) fn new(machine_st: &'a MachineState, a: Addr) -> Self {
- HCPreOrderIterator {
- machine_st,
- state_stack: vec![a],
+impl<'a> StackfulPreOrderHeapIter<'a> {
+ #[inline]
+ fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
+ let h = heap.len();
+ heap.push(cell);
+
+ Self {
+ heap,
+ h,
+ stack: vec![IterStackLoc::iterable_heap_loc(h)],
}
}
#[inline]
- pub(crate) fn machine_st(&self) -> &MachineState {
- &self.machine_st
+ pub fn push_stack(&mut self, h: usize) {
+ self.stack.push(IterStackLoc::iterable_heap_loc(h));
}
- fn follow_heap(&mut self, h: usize) -> Addr {
- match &self.machine_st.heap[h] {
- &HeapCellValue::NamedStr(arity, _, _) => {
- for idx in (1..arity + 1).rev() {
- self.state_stack.push(Addr::HeapCell(h + idx));
- }
+ #[inline]
+ pub fn stack_last(&self) -> Option<usize> {
+ for h in self.stack.iter().rev() {
+ let is_readable_marked = h.m();
+ let h = h.value() as usize;
+ let cell = self.heap[h];
- Addr::Str(h)
+ if cell.get_forwarding_bit() == Some(true) {
+ return Some(h);
+ } else if cell.get_mark_bit() && !is_readable_marked {
+ continue;
}
- &HeapCellValue::Addr(a) => self.follow(a),
- HeapCellValue::PartialString(..) => self.follow(Addr::PStrLocation(h, 0)),
- HeapCellValue::Atom(..)
- | HeapCellValue::DBRef(_)
- | HeapCellValue::Integer(_)
- | HeapCellValue::Rational(_) => Addr::Con(h),
- HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(h),
- HeapCellValue::Stream(_) => Addr::Stream(h),
- HeapCellValue::TcpListener(_) => Addr::TcpListener(h),
+
+ return Some(h);
}
+
+ None
}
- // called under the assumption that the location at r is about to
- // be visited, and so any follow up states need to be added to
- // state_stack. returns the dereferenced Addr from Ref.
- fn follow(&mut self, addr: Addr) -> Addr {
- let da = self.machine_st.store(self.machine_st.deref(addr));
+ #[inline]
+ pub fn stack_is_empty(&self) -> bool {
+ self.stack.is_empty()
+ }
- match da {
- Addr::Lis(a) => {
- self.state_stack.push(Addr::HeapCell(a + 1));
- self.state_stack.push(Addr::HeapCell(a));
+ #[inline]
+ pub fn focus(&self) -> usize {
+ self.h
+ }
- da
- }
- Addr::PStrLocation(h, n) => {
- 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::EmptyList);
- }
+ #[inline]
+ pub fn pop_stack(&mut self) -> Option<HeapCellValue> {
+ while let Some(h) = self.stack.pop() {
+ let is_readable_marked = h.m();
+ let h = h.value() as usize;
+ self.h = h;
- self.state_stack.push(Addr::Char(c));
- } else if has_tail {
- return self.follow(Addr::HeapCell(h + 1));
- }
- } else {
- unreachable!()
- }
+ let cell = &mut self.heap[h];
- Addr::PStrLocation(h, n)
- }
- Addr::Str(s) => {
- self.follow_heap(s) // record terms of structure.
+ if cell.get_forwarding_bit() == Some(true) {
+ cell.set_forwarding_bit(false);
+ } else if cell.get_mark_bit() && !is_readable_marked {
+ cell.set_mark_bit(false);
+ continue;
}
- Addr::Con(h) => {
- if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h]
- {
- 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
- }
- } else {
- Addr::Con(h)
- }
+
+ return Some(*cell);
+ }
+
+ None
+ }
+
+ fn push_if_unmarked(&mut self, h: usize) {
+ if !self.heap[h].get_mark_bit() {
+ self.heap[h].set_mark_bit(true);
+ self.stack.push(IterStackLoc::iterable_heap_loc(h));
+ }
+ }
+
+ fn follow(&mut self) -> Option<HeapCellValue> {
+ while let Some(h) = self.stack.pop() {
+ let is_readable_marked = h.m();
+ let h = h.value() as usize;
+
+ self.h = h;
+ let cell = &mut self.heap[h];
+
+ if cell.get_forwarding_bit() == Some(true) {
+ let copy = *cell;
+ cell.set_forwarding_bit(false);
+ return Some(copy);
+ } else if cell.get_mark_bit() && !is_readable_marked {
+ cell.set_mark_bit(false);
+ continue;
}
- da => da,
+
+ read_heap_cell!(*cell,
+ (HeapCellValueTag::Str, vh) => {
+ self.stack.push(IterStackLoc::iterable_heap_loc(vh));
+ }
+ (HeapCellValueTag::Lis, vh) => {
+ self.push_if_unmarked(vh);
+
+ self.stack.push(IterStackLoc::iterable_heap_loc(vh + 1));
+ forward_if_referent_marked(&mut self.heap, vh + 1);
+
+ self.stack.push(IterStackLoc::mark_heap_loc(vh));
+ forward_if_referent_marked(&mut self.heap, vh);
+
+ return Some(self.heap[h]);
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::Var, vh) => {
+ self.push_if_unmarked(h);
+ self.stack.push(IterStackLoc::iterable_heap_loc(vh));
+ forward_if_referent_marked(&mut self.heap, vh);
+ }
+ (HeapCellValueTag::PStrOffset, offset) => {
+ self.push_if_unmarked(offset);
+ self.stack.push(IterStackLoc::iterable_heap_loc(h+1));
+
+ return Some(self.heap[h]);
+ }
+ (HeapCellValueTag::PStr) => {
+ self.push_if_unmarked(h);
+
+ forward_if_referent_marked(&mut self.heap, h+1);
+ self.stack.push(IterStackLoc::iterable_heap_loc(h+1));
+
+ return Some(self.heap[h]);
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity > 0 {
+ self.push_if_unmarked(h);
+ }
+
+ for h in (h + 1 .. h + arity + 1).rev() {
+ forward_if_referent_marked(&mut self.heap, h);
+ self.stack.push(IterStackLoc::iterable_heap_loc(h));
+ }
+
+ return Some(self.heap[h]);
+ }
+ _ => {
+ return Some(*cell);
+ }
+ )
}
+
+ None
}
}
-impl<'a> Iterator for HCPreOrderIterator<'a> {
- type Item = Addr;
+impl<'a> Iterator for StackfulPreOrderHeapIter<'a> {
+ type Item = HeapCellValue;
+ #[inline]
fn next(&mut self) -> Option<Self::Item> {
- self.state_stack.pop().map(|a| self.follow(a))
+ self.follow()
}
}
-pub(crate) trait MutStackHCIterator<'b>
-where
- Self: Iterator,
-{
- type MutStack;
+#[inline(always)]
+pub(crate) fn stackless_preorder_iter(
+ heap: &mut Vec<HeapCellValue>,
+ cell: HeapCellValue,
+) -> StacklessPreOrderHeapIter<IteratorUMP> {
+ StacklessPreOrderHeapIter::new(heap, cell)
+}
- fn stack(&'b mut self) -> Self::MutStack;
+#[inline(always)]
+pub(crate) fn stackful_preorder_iter(
+ heap: &mut Vec<HeapCellValue>,
+ cell: HeapCellValue,
+) -> StackfulPreOrderHeapIter {
+ StackfulPreOrderHeapIter::new(heap, cell)
}
#[derive(Debug)]
-pub(crate) struct HCPostOrderIterator<'a> {
- base_iter: HCPreOrderIterator<'a>,
- parent_stack: Vec<(usize, Addr)>, // number of children, parent node.
+pub(crate) struct PostOrderIterator<Iter: Iterator<Item = HeapCellValue>> {
+ base_iter: Iter,
+ base_iter_valid: bool,
+ parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node.
}
-impl<'a> Deref for HCPostOrderIterator<'a> {
- type Target = HCPreOrderIterator<'a>;
+impl<Iter: Iterator<Item = HeapCellValue>> Deref for PostOrderIterator<Iter> {
+ type Target = Iter;
fn deref(&self) -> &Self::Target {
&self.base_iter
}
}
-impl<'a> HCPostOrderIterator<'a> {
- pub(crate) fn new(base_iter: HCPreOrderIterator<'a>) -> Self {
- HCPostOrderIterator {
+impl<Iter: Iterator<Item = HeapCellValue>> PostOrderIterator<Iter> {
+ pub(crate) fn new(base_iter: Iter) -> Self {
+ PostOrderIterator {
base_iter,
+ base_iter_valid: true,
parent_stack: vec![],
}
}
}
-impl<'a> Iterator for HCPostOrderIterator<'a> {
- type Item = Addr;
+impl<Iter: Iterator<Item = HeapCellValue>> Iterator for PostOrderIterator<Iter> {
+ type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> {
loop {
@@ -161,179 +277,2317 @@ impl<'a> Iterator for HCPostOrderIterator<'a> {
self.parent_stack.push((child_count - 1, node));
}
- if let Some(item) = self.base_iter.next() {
- 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)));
- // }
-
- self.parent_stack.push((2, Addr::PStrLocation(h, n)));
- }
- _ => {
- unreachable!()
- }
+ if self.base_iter_valid {
+ if let Some(item) = self.base_iter.next() {
+ read_heap_cell!(item,
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ self.parent_stack.push((arity, item));
+ }
+ (HeapCellValueTag::Lis) => {
+ self.parent_stack.push((2, item));
+ }
+ (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
+ self.parent_stack.push((1, item));
}
- }
- _ => {
- return Some(item);
- }
+ _ => {
+ return Some(item);
+ }
+ );
+
+ continue;
+ } else {
+ self.base_iter_valid = false;
}
- } else {
+ }
+
+ if self.parent_stack.is_empty() {
return None;
}
}
}
}
-impl MachineState {
- pub(crate) fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> {
- HCPreOrderIterator::new(self, a)
- }
+pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator<StackfulPreOrderHeapIter<'a>>;
- pub(crate) fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> {
- HCPostOrderIterator::new(HCPreOrderIterator::new(self, a))
- }
+impl<'a> LeftistPostOrderHeapIter<'a> {
+ #[inline]
+ pub fn pop_stack(&mut self) {
+ if let Some((child_count, _)) = self.parent_stack.last() {
+ for _ in 0 .. *child_count {
+ self.base_iter.pop_stack();
+ }
- pub(crate) fn acyclic_pre_order_iter<'a>(&'a self, a: Addr) -> HCAcyclicIterator<'a> {
- HCAcyclicIterator::new(HCPreOrderIterator::new(self, a))
+ self.parent_stack.pop();
+ }
}
- pub(crate) fn zipped_acyclic_pre_order_iter<'a>(
- &'a self,
- a1: Addr,
- a2: Addr,
- ) -> HCZippedAcyclicIterator<'a> {
- HCZippedAcyclicIterator::new(
- HCPreOrderIterator::new(self, a1),
- HCPreOrderIterator::new(self, a2),
- )
+ #[inline]
+ pub fn parent_stack_len(&self) -> usize {
+ self.parent_stack.len()
}
}
-impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCPreOrderIterator<'a> {
- type MutStack = &'b mut Vec<Addr>;
-
- fn stack(&'b mut self) -> Self::MutStack {
- &mut self.state_stack
- }
+#[inline]
+pub(crate) fn stackful_post_order_iter<'a>(
+ heap: &'a mut Heap,
+ cell: HeapCellValue,
+) -> LeftistPostOrderHeapIter<'a> {
+ PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell))
}
-#[derive(Debug)]
-pub(crate) struct HCAcyclicIterator<'a> {
- iter: HCPreOrderIterator<'a>,
- seen: IndexSet<Addr>,
+pub(crate) type RightistPostOrderHeapIter<'a> =
+ PostOrderIterator<StacklessPreOrderHeapIter<'a, IteratorUMP>>;
+
+#[inline]
+pub(crate) fn stackless_post_order_iter<'a>(
+ heap: &'a mut Heap,
+ cell: HeapCellValue,
+) -> RightistPostOrderHeapIter<'a> {
+ PostOrderIterator::new(stackless_preorder_iter(heap, cell))
}
-impl<'a> HCAcyclicIterator<'a> {
- pub(crate) fn new(iter: HCPreOrderIterator<'a>) -> Self {
- HCAcyclicIterator {
- iter,
- seen: IndexSet::new(),
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::machine::mock_wam::*;
+
+ #[test]
+ fn heap_stackless_iter_tests() {
+ let mut wam = MockWAM::new();
+
+ let f_atom = atom!("f");
+ let a_atom = atom!("a");
+ let b_atom = atom!("b");
+
+ wam.machine_st
+ .heap
+ .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 2)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom, 0)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom, 0)
+ );
+
+ assert_eq!(iter.next(), None);
}
- }
-}
-impl<'a> Deref for HCAcyclicIterator<'a> {
- type Target = HCPreOrderIterator<'a>;
+ all_cells_unmarked(&wam.machine_st.heap);
- fn deref(&self) -> &Self::Target {
- &self.iter
- }
-}
+ wam.machine_st.heap.clear();
-impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCAcyclicIterator<'a> {
- type MutStack = &'b mut Vec<Addr>;
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(0))
+ ]
+ ));
- fn stack(&'b mut self) -> Self::MutStack {
- self.iter.stack()
- }
-}
+ for _ in 0..20 {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0));
-impl<'a> Iterator for HCAcyclicIterator<'a> {
- type Item = Addr;
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 4)
+ );
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
- fn next(&mut self) -> Option<Self::Item> {
- while let Some(addr) = self.iter.stack().pop() {
- if !self.seen.contains(&addr) {
- self.iter.stack().push(addr.clone());
- self.seen.insert(addr);
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
- break;
- }
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(1))
+ ]
+ ));
+
+ for _ in 0..200000 {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 4)
+ );
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1));
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ {
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(0),
+ );
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0));
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ // term is: [a, b]
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(a_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(atom_as_cell!(b_atom));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(0),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.pop();
+
+ // now make the list cyclic.
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(0),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ // first a 'dangling' partial string, later modified to be a two-part complete string,
+ // then a three-part cyclic string involving an uncompacted list of chars.
+ let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1),
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ assert_eq!(wam.machine_st.heap[0], pstr_cell);
+ assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+
+ let pstr_second_var_cell = put_partial_string(
+ &mut wam.machine_st.heap,
+ "def",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(3),
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ assert_eq!(wam.machine_st.heap[0], pstr_cell);
+ assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2));
+ assert_eq!(wam.machine_st.heap[2], pstr_second_cell);
+ assert_eq!(wam.machine_st.heap[3], heap_loc_as_cell!(3));
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(4));
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ pstr_loc_as_cell!(4),
+ );
+
+ let pstr_offset_cell = pstr_offset_as_cell!(0);
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ wam.machine_st.heap.truncate(4);
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
+
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+ let pstr_offset_cell = pstr_offset_as_cell!(0);
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+
+ assert_eq!(iter.next(), None);
+
+ assert_eq!(iter.heap[4], pstr_offset_as_cell!(0));
+ assert_eq!(iter.heap[5], fixnum_as_cell!(Fixnum::build_with(1i64)));
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.extend(functor);
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ // drop the iterator before the iteration is complete to test
+ // that modified heap cells are restored to their
+ // pre-traversal state by the stackless iterator's Drop
+ // instance.
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5));
+ assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3));
+ assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5));
+ assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!());
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ // drop the iterator before the iteration is complete to test
+ // that modified heap cells are restored to their
+ // pre-traversal state by the stackless iterator's Drop
+ // instance.
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5));
+ assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3));
+ assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5));
+ assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!());
+
+ wam.machine_st.heap[4] = list_loc_as_cell!(1);
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(3));
+ wam.machine_st.heap.push(heap_loc_as_cell!(3));
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(iter.next().unwrap(), heap_loc_as_cell!(3));
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3));
+
+ wam.machine_st.heap.clear();
+
+ // print L = [L|L].
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
+ // this is what happens! this next line! We would like it not to happen though.
+ assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(1));
+
+ wam.machine_st.heap.clear();
+
+ // term is [X,f(Y),Z].
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2
+ wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3
+ wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4
+ wam.machine_st.heap.push(heap_loc_as_cell!(8));
+ wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6
+ wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7
+ wam.machine_st.heap.push(list_loc_as_cell!(9));
+ wam.machine_st.heap.push(heap_loc_as_cell!(9));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
+ wam.machine_st.heap.push(heap_loc_as_cell!(12));
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(4)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(9)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(9)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ attr_var_as_cell!(11)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1)
+ );
+ assert_eq!(iter.next(), None);
+ }
+
+ // now populate the attributes list. the iteration must not change.
+ let clpz_atom = atom!("clpz");
+ let p_atom = atom!("p");
+
+ wam.machine_st.heap.pop();
+
+ wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12
+ wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13
+ wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14
+ wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15
+ wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16
+ wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17
+ wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18
+ wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19
+ wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20
+ wam.machine_st.heap.push(empty_list_as_cell!()); // 21
+ wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22
+ wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23
+
+ {
+ let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(4)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(9)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(9)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ attr_var_as_cell!(11)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1)
+ );
+ assert_eq!(iter.next(), None);
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!());
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!());
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23));
+
+ wam.machine_st.heap.clear();
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ fixnum_as_cell!(Fixnum::build_with(0))
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ fixnum_as_cell!(Fixnum::build_with(0))
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(wam.machine_st.heap.len(), 0);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
+
+ wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ str_loc_as_cell!(1),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("g"),2)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("y"))
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ str_loc_as_cell!(1)
+ );
+
+ assert!(iter.next().is_none());
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2));
+ wam.machine_st.heap.push(str_loc_as_cell!(0));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ str_loc_as_cell!(0),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("g"),2)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("y"))
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ str_loc_as_cell!(0)
+ );
+
+ assert!(iter.next().is_none());
}
- self.iter.next()
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("X")));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+ wam.machine_st.heap.push(list_loc_as_cell!(8));
+ wam.machine_st.heap.push(str_loc_as_cell!(4));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(7),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(8)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("="), 2)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("g"), 2)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("y"))
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("X"))
+ );
+
+ assert!(iter.next().is_none());
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2));
+ assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(0));
+ assert_eq!(wam.machine_st.heap[3], atom_as_cell!(atom!("y")));
+ assert_eq!(wam.machine_st.heap[4], atom_as_cell!(atom!("="), 2));
+ assert_eq!(wam.machine_st.heap[5], atom_as_cell!(atom!("X")));
+ assert_eq!(wam.machine_st.heap[6], heap_loc_as_cell!(0));
+ assert_eq!(wam.machine_st.heap[7], list_loc_as_cell!(8));
+ assert_eq!(wam.machine_st.heap[8], str_loc_as_cell!(4));
+ assert_eq!(wam.machine_st.heap[9], empty_list_as_cell!());
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+
+ {
+ let mut iter = stackless_preorder_iter(
+ &mut wam.machine_st.heap,
+ str_loc_as_cell!(0),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("f"), 2)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1)
+ );
+
+ assert!(iter.next().is_none());
+ }
+
+ assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2));
+ assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1));
}
-}
-#[derive(Debug)]
-pub(crate) struct HCZippedAcyclicIterator<'a> {
- i1: HCPreOrderIterator<'a>,
- i2: HCPreOrderIterator<'a>,
- seen: IndexSet<(Addr, Addr)>,
- pub(crate) first_to_expire: Ordering,
-}
+ #[test]
+ fn heap_stackful_iter_tests() {
+ let mut wam = MockWAM::new();
+
+ let f_atom = atom!("f");
+ let a_atom = atom!("a");
+ let b_atom = atom!("b");
+
+ wam.machine_st.heap
+ .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+
+ {
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 2)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(0))
+ ]
+ ));
+
+ for _ in 0..20 {
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 4)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ {
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+ let mut var = heap_loc_as_cell!(0);
+
+ // self-referencing variables are copied with their forwarding
+ // and marking bits set to true. it suffices to check only the
+ // forwarding bit to detect cycles of all kinds, including
+ // unbound/self-referencing variables.
+
+ var.set_forwarding_bit(true);
+ var.set_mark_bit(true);
+
+ assert_eq!(iter.next().unwrap(), var);
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
-impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCZippedAcyclicIterator<'a> {
- type MutStack = (&'b mut Vec<Addr>, &'b mut Vec<Addr>);
+ {
+ // mutually referencing variables.
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
- fn stack(&'b mut self) -> Self::MutStack {
- (self.i1.stack(), self.i2.stack())
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ // term is: [a, b]
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(a_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(atom_as_cell!(b_atom));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.pop();
+
+ // now make the list cyclic.
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ {
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ // the cycle will be iterated twice before being detected.
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ {
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ // cut the iteration short to check that all cells are
+ // unmarked and unforwarded by the Drop instance of
+ // StackfulPreOrderHeapIter.
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3));
+ assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom));
+ assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0));
+
+ wam.machine_st.heap.clear();
+
+ // first a 'dangling' partial string, later modified to be a
+ // two-part complete string, then a three-part cyclic string
+ // involving an uncompacted list of chars.
+
+ let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+
+ {
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1),
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ // here
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(heap_loc_as_cell!(2));
+
+ let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl);
+ let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+
+ {
+ let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(3),
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
+
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
+
+ {
+ let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+ let pstr_offset_cell = pstr_offset_as_cell!(0);
+
+ // pstr_offset_cell.set_forwarding_bit(true);
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
+ assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64)));
+
+ assert_eq!(iter.next(), None);
+ }
+
+ /*
+ {
+ let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
+ let string: String = iter.chars().collect();
+ assert_eq!(string, "abc def");
+ }
+ */
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
+
+ {
+ let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+ let pstr_offset_cell = pstr_offset_as_cell!(0);
+
+ // pstr_offset_cell.set_forwarding_bit(true);
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
+ assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64)));
+
+ let h = iter.focus();
+
+ assert_eq!(h, 5);
+ assert_eq!(unmark_cell_bits!(iter.heap[4]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(iter.heap[5]), fixnum_as_cell!(Fixnum::build_with(1i64)));
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.extend(functor);
+
+ {
+ let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap[4] = list_loc_as_cell!(1);
+
+ {
+ let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ let mut link_back = list_loc_as_cell!(1);
+ link_back.set_forwarding_bit(true);
+
+ assert_eq!(iter.next().unwrap(), link_back);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+
+ {
+ let mut iter = StackfulPreOrderHeapIter::new(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(0),
+ );
+
+ let mut cyclic_link = list_loc_as_cell!(1);
+ cyclic_link.set_forwarding_bit(true);
+
+ assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(iter.next().unwrap(), cyclic_link);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(pstr_as_cell!(atom!("a string")));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = stackful_preorder_iter(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(0),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ pstr_as_cell!(atom!("a string"))
+ );
+
+ assert_eq!(
+ iter.next().unwrap(),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("X")));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+ wam.machine_st.heap.push(list_loc_as_cell!(8));
+ wam.machine_st.heap.push(str_loc_as_cell!(4));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = stackful_preorder_iter(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(0),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(atom!("g"), 2)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ str_loc_as_cell!(1)
+ );
+
+ assert_eq!(
+ iter.next().unwrap(),
+ atom_as_cell!(atom!("y"))
+ );
+
+ assert!(iter.next().is_none());
+ }
}
-}
-impl<'a> HCZippedAcyclicIterator<'a> {
- pub(crate) fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self {
- HCZippedAcyclicIterator {
- i1,
- i2,
- seen: IndexSet::new(),
- first_to_expire: Ordering::Equal,
+ #[test]
+ fn heap_stackful_post_order_iter() {
+ let mut wam = MockWAM::new();
+
+ let f_atom = atom!("f");
+ let a_atom = atom!("a");
+ let b_atom = atom!("b");
+
+ wam.machine_st.heap
+ .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 2)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(0))
+ ]
+ ));
+
+ for _ in 0..20 { // 0000 {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 4)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ {
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+ let mut var = heap_loc_as_cell!(0);
+
+ // self-referencing variables are copied with their forwarding
+ // and marking bits set to true. it suffices to check only the
+ // forwarding bit to detect cycles of all kinds, including
+ // unbound/self-referencing variables.
+
+ var.set_forwarding_bit(true);
+ var.set_mark_bit(true);
+
+ assert_eq!(iter.next().unwrap(), var);
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ {
+ // mutually referencing variables.
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ // term is: [a, b]
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(a_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(atom_as_cell!(b_atom));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.pop();
+
+ // now make the list cyclic.
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ // the cycle will be iterated twice before being detected.
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ {
+ let mut iter = stackful_post_order_iter(
+ &mut wam.machine_st.heap,
+ heap_loc_as_cell!(0),
+ );
+
+ // cut the iteration short to check that all cells are
+ // unmarked and unforwarded by the Drop instance of
+ // StackfulPreOrderHeapIter.
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3));
+ assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom));
+ assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0));
+
+ wam.machine_st.heap.clear();
+
+ // first a 'dangling' partial string, later modified to be a
+ // two-part complete string, then a three-part cyclic string
+ // involving an uncompacted list of chars.
+
+ let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1),
+ );
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+
+ let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl);
+ let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(3),
+ );
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
+
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64)));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64)));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
}
+
+ wam.machine_st.heap.clear();
+
+ let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.extend(functor);
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap[4] = list_loc_as_cell!(1);
+
+ {
+ let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ let mut link_back = list_loc_as_cell!(1);
+ link_back.set_forwarding_bit(true);
+
+ assert_eq!(iter.next().unwrap(), link_back);
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+ wam.machine_st.heap.clear();
}
-}
-impl<'a> Iterator for HCZippedAcyclicIterator<'a> {
- type Item = (Addr, Addr);
+ #[test]
+ fn heap_stackless_post_order_iter() {
+ let mut wam = MockWAM::new();
- fn next(&mut self) -> Option<Self::Item> {
- while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) {
- if !self.seen.contains(&(a1.clone(), a2.clone())) {
- self.i1.stack().push(a1.clone());
- self.i2.stack().push(a2.clone());
+ let f_atom = atom!("f");
+ let a_atom = atom!("a");
+ let b_atom = atom!("b");
- self.seen.insert((a1, a2));
+ wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
- break;
- }
+ {
+ let mut iter = stackless_post_order_iter(
+ &mut wam.machine_st.heap,
+ str_loc_as_cell!(0),
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 2)
+ );
+
+ assert_eq!(iter.next(), None);
}
- match (self.i1.next(), self.i2.next()) {
- (Some(v1), Some(v2)) => Some((v1, v2)),
- (Some(_), None) => {
- self.first_to_expire = Ordering::Greater;
- None
- }
- (None, Some(_)) => {
- self.first_to_expire = Ordering::Less;
- None
- }
- _ => None,
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(0))
+ ]
+ ));
+
+ for _ in 0..20 {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 4)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ {
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ {
+ // mutually referencing variables.
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ // term is: [a, b]
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(a_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(atom_as_cell!(b_atom));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.pop();
+
+ // now make the list cyclic.
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ // the cycle will be iterated twice before being detected.
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ // cut the iteration short to check that all cells are
+ // unmarked and unforwarded by the Drop instance of
+ // StacklessPreOrderHeapIter.
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(0)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3));
+ assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom));
+ assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0));
+
+ wam.machine_st.heap.clear();
+
+ // first a 'dangling' partial string, later modified to be a
+ // two-part complete string, then a three-part cyclic string
+ // involving an uncompacted list of chars.
+
+ let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(1),
+ );
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
}
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+
+ let pstr_second_var_cell = put_partial_string(
+ &mut wam.machine_st.heap,
+ "def",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ heap_loc_as_cell!(3),
+ );
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
+
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0)));
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+ let mut pstr_loc_cell = pstr_loc_as_cell!(0);
+
+ pstr_loc_cell.set_forwarding_bit(true);
+
+ // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64)));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1)));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0));
+
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+
+ assert_eq!(iter.next(), None);
+ }
+
+ wam.machine_st.heap.clear();
+
+ let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.extend(functor);
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ empty_list_as_cell!()
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap[4] = list_loc_as_cell!(1);
+
+ {
+ let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(b_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(f_atom, 3)
+ );
+
+ assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
+ );
+
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(1)
+ );
+
+ assert_eq!(iter.next(), None);
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
}
}
diff --git a/src/heap_print.rs b/src/heap_print.rs
index 09af815f..a0231848 100644
--- a/src/heap_print.rs
+++ b/src/heap_print.rs
@@ -1,50 +1,54 @@
-use prolog_parser::ast::*;
-use prolog_parser::{
- alpha_numeric_char, capital_letter_char, clause_name, cut_char, decimal_digit_char,
- graphic_token_char, is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx,
- semicolon_char, sign_char, single_quote_char, small_letter_char, solo_char,
- variable_indicator_char,
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::instructions::*;
+use crate::parser::ast::*;
+use crate::parser::rug::{Integer, Rational};
+use crate::{
+ alpha_numeric_char, capital_letter_char, cut_char, decimal_digit_char, graphic_token_char,
+ is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, semicolon_char,
+ sign_char, single_quote_char, small_letter_char, solo_char, variable_indicator_char,
};
-use crate::clause_types::*;
use crate::forms::*;
use crate::heap_iter::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::*;
-use crate::machine::machine_state::*;
+use crate::machine::machine_state::pstr_loc_and_offset;
+use crate::machine::partial_string::*;
use crate::machine::streams::*;
-use crate::rug::{Integer, Rational};
+use crate::types::*;
+
use ordered_float::OrderedFloat;
-use indexmap::{IndexMap, IndexSet};
+use indexmap::IndexMap;
use std::cell::Cell;
use std::convert::TryFrom;
-use std::iter::{once, FromIterator};
+use std::iter::once;
use std::net::{IpAddr, TcpListener};
use std::ops::{Range, RangeFrom};
use std::rc::Rc;
/* contains the location, name, precision and Specifier of the parent op. */
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
pub(crate) enum DirectedOp {
- Left(ClauseName, SharedOpDesc),
- Right(ClauseName, SharedOpDesc),
+ Left(Atom, OpDesc),
+ Right(Atom, OpDesc),
}
impl DirectedOp {
#[inline]
- fn as_str(&self) -> &str {
+ fn as_atom(&self) -> Atom {
match self {
- &DirectedOp::Left(ref name, _) | &DirectedOp::Right(ref name, _) => name.as_str(),
+ &DirectedOp::Left(name, _) | &DirectedOp::Right(name, _) => name,
}
}
#[inline]
fn is_negative_sign(&self) -> bool {
match self {
- &DirectedOp::Left(ref name, ref cell) | &DirectedOp::Right(ref name, ref cell) => {
- name.as_str() == "-" && is_prefix!(cell.assoc())
+ &DirectedOp::Left(name, cell) | &DirectedOp::Right(name, cell) => {
+ name == atom!("-") && is_prefix!(cell.get_spec() as u32)
}
}
}
@@ -59,29 +63,33 @@ impl DirectedOp {
}
}
-fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool {
+fn needs_bracketing(child_desc: OpDesc, op: &DirectedOp) -> bool {
match op {
- &DirectedOp::Left(ref name, ref cell) => {
+ DirectedOp::Left(name, cell) => {
let (priority, spec) = cell.get();
if name.as_str() == "-" {
- let child_assoc = child_spec.assoc();
+ let child_assoc = child_desc.get_spec();
if is_prefix!(spec) && (is_postfix!(child_assoc) || is_infix!(child_assoc)) {
return true;
}
}
let is_strict_right = is_yfx!(spec) || is_xfx!(spec) || is_fx!(spec);
- child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_right)
+ child_desc.get_prec() > priority
+ || (child_desc.get_prec() == priority && is_strict_right)
}
- &DirectedOp::Right(_, ref cell) => {
+ DirectedOp::Right(_, cell) => {
let (priority, spec) = cell.get();
let is_strict_left = is_xfx!(spec) || is_xfy!(spec) || is_xf!(spec);
- if child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_left) {
+ if child_desc.get_prec() > priority
+ || (child_desc.get_prec() == priority && is_strict_left)
+ {
true
- } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_spec.assoc()) {
- !SharedOpDesc::ptr_eq(&cell, &child_spec) && child_spec.prec() == priority
+ } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_desc.get_spec())
+ {
+ *cell != child_desc && child_desc.get_prec() == priority
} else {
false
}
@@ -89,59 +97,67 @@ fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool {
}
}
-impl<'a> HCPreOrderIterator<'a> {
+impl<'a> StackfulPreOrderHeapIter<'a> {
/*
* descend into the subtree where the iterator is currently parked
* and check that the leftmost leaf is a number, with every node
* encountered on the way an infix or postfix operator, unblocked
* by brackets.
*/
- fn leftmost_leaf_has_property<P>(&self, property_check: P) -> bool
+ fn leftmost_leaf_has_property<P>(&self, op_dir: &OpDir, property_check: P) -> bool
where
- P: Fn(Addr, &Heap) -> bool,
+ P: Fn(HeapCellValue) -> bool,
{
- let mut addr = match self.state_stack.last().cloned() {
- Some(addr) => addr,
+ let mut h = match self.stack_last() {
+ Some(h) => h,
None => return false,
};
- let mut parent_spec = DirectedOp::Left(clause_name!("-"), SharedOpDesc::new(200, FY));
+ let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8));
loop {
- match self.machine_st.store(self.machine_st.deref(addr)) {
- Addr::Str(s) => match &self.machine_st.heap[s] {
- &HeapCellValue::NamedStr(_, ref name, Some(ref spec))
- if is_postfix!(spec.assoc()) || is_infix!(spec.assoc()) =>
- {
- if needs_bracketing(spec, &parent_spec) {
+ // match self.machine_st.store(self.machine_st.deref(addr)) {
+ read_heap_cell!(self.heap[h],
+ (HeapCellValueTag::Str, s) => {
+ read_heap_cell!(self.heap[s],
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ if let Some(spec) = fetch_atom_op_spec(name, None, op_dir) {
+ if is_postfix!(spec.get_spec() as u32) || is_infix!(spec.get_spec() as u32) {
+ if needs_bracketing(spec, &parent_spec) {
+ return false;
+ } else {
+ h = s + 1;
+ parent_spec = DirectedOp::Right(name, spec);
+ continue;
+ }
+ }
+ }
+
return false;
- } else {
- addr = Addr::HeapCell(s + 1);
- parent_spec = DirectedOp::Right(name.clone(), spec.clone());
}
- }
- _ => {
- return false;
- }
- },
- addr => {
- return property_check(addr, &self.machine_st.heap);
+ _ => {
+ return false;
+ }
+ )
}
- }
+ _ => {
+ return property_check(self.heap[h]);
+ }
+ )
}
}
fn immediate_leaf_has_property<P>(&self, property_check: P) -> bool
where
- P: Fn(Addr, &Heap) -> bool,
+ P: Fn(HeapCellValue) -> bool,
{
- let addr = match self.state_stack.last().cloned() {
- Some(addr) => addr,
+ let addr = match self.stack_last() {
+ Some(h) => self.heap[h],
None => return false,
};
- let addr = self.machine_st.store(self.machine_st.deref(addr));
- property_check(addr, &self.machine_st.heap)
+ // let addr = self.machine_st.store(self.machine_st.deref(addr));
+ property_check(addr)
}
}
@@ -168,20 +184,37 @@ fn char_to_string(is_quoted: bool, c: char) -> String {
}
}
+#[derive(Clone, Copy, Debug)]
+enum NumberFocus {
+ Unfocused(Number),
+ Denominator(TypedArenaPtr<Rational>),
+ Numerator(TypedArenaPtr<Rational>),
+}
+
+impl NumberFocus {
+ fn is_negative(&self) -> bool {
+ match self {
+ NumberFocus::Unfocused(n) => n.is_negative(),
+ NumberFocus::Denominator(r) | NumberFocus::Numerator(r) => **r < 0,
+ }
+ }
+}
+
#[derive(Debug, Clone)]
enum TokenOrRedirect {
- Atom(ClauseName),
+ Atom(Atom),
BarAsOp,
- Op(ClauseName, SharedOpDesc),
+ Char(char),
+ Op(Atom, OpDesc),
NumberedVar(String),
CompositeRedirect(usize, DirectedOp),
FunctorRedirect(usize),
- IpAddr(IpAddr),
- Number(Number, Option<DirectedOp>),
+ #[allow(unused)] IpAddr(IpAddr),
+ NumberFocus(NumberFocus, Option<DirectedOp>),
Open,
Close,
Comma,
- RawPtr(*const u8),
+ RawPtr(*const ArenaHeader),
Space,
LeftCurly,
RightCurly,
@@ -190,7 +223,89 @@ enum TokenOrRedirect {
HeadTailSeparator,
}
-pub(crate) trait HCValueOutputter {
+pub(crate) fn requires_space(atom: &str, op: &str) -> bool {
+ match atom.chars().last() {
+ Some(ac) => op
+ .chars()
+ .next()
+ .map(|oc| {
+ if ac == '0' {
+ oc == '\'' || oc == '(' || alpha_numeric_char!(oc)
+ } else if alpha_numeric_char!(ac) {
+ oc == '(' || alpha_numeric_char!(oc)
+ } else if graphic_token_char!(ac) {
+ graphic_token_char!(oc)
+ } else if variable_indicator_char!(ac) {
+ alpha_numeric_char!(oc)
+ } else if capital_letter_char!(ac) {
+ alpha_numeric_char!(oc)
+ } else if sign_char!(ac) {
+ sign_char!(oc) || decimal_digit_char!(oc)
+ } else if single_quote_char!(ac) {
+ single_quote_char!(oc)
+ } else {
+ false
+ }
+ })
+ .unwrap_or(false),
+ _ => false,
+ }
+}
+
+fn non_quoted_graphic_token<Iter: Iterator<Item = char>>(mut iter: Iter, c: char) -> bool {
+ if c == '/' {
+ return match iter.next() {
+ None => true,
+ Some('*') => false, // if we start with comment token, we must quote.
+ Some(c) => {
+ if graphic_token_char!(c) {
+ iter.all(|c| graphic_token_char!(c))
+ } else {
+ false
+ }
+ }
+ };
+ } else if c == '.' {
+ return match iter.next() {
+ None => false,
+ Some(c) => {
+ if graphic_token_char!(c) {
+ iter.all(|c| graphic_token_char!(c))
+ } else {
+ false
+ }
+ }
+ };
+ } else {
+ iter.all(|c| graphic_token_char!(c))
+ }
+}
+
+pub(super) fn non_quoted_token<Iter: Iterator<Item = char>>(mut iter: Iter) -> bool {
+ if let Some(c) = iter.next() {
+ if small_letter_char!(c) {
+ iter.all(|c| alpha_numeric_char!(c))
+ } else if graphic_token_char!(c) {
+ non_quoted_graphic_token(iter, c)
+ } else if semicolon_char!(c) {
+ iter.next().is_none()
+ } else if cut_char!(c) {
+ iter.next().is_none()
+ } else if c == '[' {
+ iter.next() == Some(']') && iter.next().is_none()
+ } else if c == '{' {
+ iter.next() == Some('}') && iter.next().is_none()
+ } else if solo_char!(c) {
+ !(c == '(' || c == ')' || c == '}' || c == ']' || c == ',' || c == '%' || c == '|')
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+}
+
+pub trait HCValueOutputter {
type Output;
fn new() -> Self;
@@ -207,7 +322,7 @@ pub(crate) trait HCValueOutputter {
}
#[derive(Debug)]
-pub(crate) struct PrinterOutputter {
+pub struct PrinterOutputter {
contents: String,
}
@@ -263,7 +378,7 @@ impl HCValueOutputter for PrinterOutputter {
}
fn range_from(&self, index: RangeFrom<usize>) -> &str {
- &self.contents.as_str()[index]
+ &self.contents.as_str().get(index).unwrap_or("")
}
}
@@ -273,11 +388,15 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
}
#[inline]
-fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option<DirectedOp>) -> bool {
+fn negated_op_needs_bracketing(
+ iter: &StackfulPreOrderHeapIter,
+ op_dir: &OpDir,
+ op: &Option<DirectedOp>,
+) -> bool {
if let Some(ref op) = op {
op.is_negative_sign()
- && iter.leftmost_leaf_has_property(|addr, heap| match Number::try_from((addr, heap)) {
- Ok(Number::Fixnum(n)) => n > 0,
+ && iter.leftmost_leaf_has_property(op_dir, |addr| match Number::try_from(addr) {
+ Ok(Number::Fixnum(n)) => n.get_num() > 0,
Ok(Number::Float(f)) => f > OrderedFloat(0f64),
Ok(Number::Integer(n)) => &*n > &0,
Ok(Number::Rational(n)) => &*n > &0,
@@ -288,66 +407,99 @@ fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option<DirectedOp
}
}
-fn numbervar(n: Integer) -> Var {
- static CHAR_CODES: [char; 26] = [
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
- 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- ];
+pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String> {
+ fn numbervar(n: Integer) -> String {
+ static CHAR_CODES: [char; 26] = [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
+ 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ];
- let i = n.mod_u(26) as usize;
- let j = n.div_rem_floor(Integer::from(26));
- let j = <(Integer, Integer)>::from(j).0;
+ let i = n.mod_u(26) as usize;
+ let j = n.div_rem_floor(Integer::from(26));
+ let j = <(Integer, Integer)>::from(j).0;
- if j == 0 {
- CHAR_CODES[i].to_string()
- } else {
- format!("{}{}", CHAR_CODES[i], j)
+ if j == 0 {
+ CHAR_CODES[i].to_string()
+ } else {
+ format!("{}{}", CHAR_CODES[i], j)
+ }
}
-}
-
-impl MachineState {
- pub(crate) fn numbervar(&self, offset: &Integer, addr: Addr) -> Option<Var> {
- let addr = self.store(self.deref(addr));
- match Number::try_from((addr, &self.heap)) {
- Ok(Number::Fixnum(n)) => {
- if n >= 0 {
- Some(numbervar(Integer::from(offset + Integer::from(n))))
- } else {
- None
- }
+ match Number::try_from(addr) {
+ Ok(Number::Fixnum(n)) => {
+ if n.get_num() >= 0 {
+ Some(numbervar(offset + Integer::from(n.get_num())))
+ } else {
+ None
}
- Ok(Number::Integer(n)) => {
- if &*n >= &0 {
- Some(numbervar(Integer::from(offset + &*n)))
- } else {
- None
- }
+ }
+ Ok(Number::Integer(n)) => {
+ if &*n >= &0 {
+ Some(numbervar(Integer::from(offset + &*n)))
+ } else {
+ None
}
- _ => None,
}
+ _ => None,
}
}
-type ReverseHeapVarDict = IndexMap<Addr, Rc<Var>>;
+macro_rules! push_char {
+ ($self:ident, $c:expr) => {{
+ $self.outputter.push_char($c);
+ $self.last_item_idx = $self.outputter.len();
+ }};
+}
+
+macro_rules! append_str {
+ ($self:ident, $s:expr) => {{
+ $self.last_item_idx = $self.outputter.len();
+ $self.outputter.append($s);
+ }};
+}
+
+macro_rules! print_char {
+ ($self:ident, $is_quoted:expr, $c:expr) => {
+ if non_quoted_token(once($c)) {
+ let result = char_to_string(false, $c);
+
+ push_space_if_amb!($self, &result, {
+ append_str!($self, &result);
+ });
+ } else {
+ let mut result = String::new();
+
+ if $self.quoted {
+ result.push('\'');
+ result += &char_to_string($is_quoted, $c);
+ result.push('\'');
+ } else {
+ result += &char_to_string($is_quoted, $c);
+ }
+
+ push_space_if_amb!($self, &result, {
+ append_str!($self, result.as_str());
+ });
+ }
+ };
+}
#[derive(Debug)]
-pub(crate) struct HCPrinter<'a, Outputter> {
+pub struct HCPrinter<'a, Outputter> {
outputter: Outputter,
- machine_st: &'a MachineState,
+ iter: StackfulPreOrderHeapIter<'a>,
+ arena: &'a mut Arena,
op_dir: &'a OpDir,
state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>,
- heap_locs: ReverseHeapVarDict,
last_item_idx: usize,
- cyclic_terms: IndexMap<Addr, usize>,
- non_cyclic_terms: IndexSet<usize>,
- pub(crate) var_names: IndexMap<Addr, Var>,
- pub(crate) numbervars_offset: Integer,
- pub(crate) numbervars: bool,
- pub(crate) quoted: bool,
- pub(crate) ignore_ops: bool,
- pub(crate) max_depth: usize,
+ pub var_names: IndexMap<HeapCellValue, Rc<String>>,
+ pub numbervars_offset: Integer,
+ pub numbervars: bool,
+ pub quoted: bool,
+ pub ignore_ops: bool,
+ pub print_strings_as_strs: bool,
+ pub max_depth: usize,
}
macro_rules! push_space_if_amb {
@@ -361,117 +513,28 @@ macro_rules! push_space_if_amb {
};
}
-pub(crate) fn requires_space(atom: &str, op: &str) -> bool {
- match atom.chars().last() {
- Some(ac) => op
- .chars()
- .next()
- .map(|oc| {
- if ac == '0' {
- oc == '\'' || oc == '(' || alpha_numeric_char!(oc)
- } else if alpha_numeric_char!(ac) {
- oc == '(' || alpha_numeric_char!(oc)
- } else if graphic_token_char!(ac) {
- graphic_token_char!(oc)
- } else if variable_indicator_char!(ac) {
- alpha_numeric_char!(oc)
- } else if capital_letter_char!(ac) {
- alpha_numeric_char!(oc)
- } else if sign_char!(ac) {
- sign_char!(oc) || decimal_digit_char!(oc)
- } else if single_quote_char!(ac) {
- single_quote_char!(oc)
- } else {
- false
- }
- })
- .unwrap_or(false),
- _ => false,
- }
-}
-
-fn non_quoted_graphic_token<Iter: Iterator<Item = char>>(mut iter: Iter, c: char) -> bool {
- if c == '/' {
- return match iter.next() {
- None => true,
- Some('*') => false, // if we start with comment token, we must quote.
- Some(c) => {
- if graphic_token_char!(c) {
- iter.all(|c| graphic_token_char!(c))
- } else {
- false
- }
- }
- };
- } else if c == '.' {
- return match iter.next() {
- None => false,
- Some(c) => {
- if graphic_token_char!(c) {
- iter.all(|c| graphic_token_char!(c))
- } else {
- false
- }
- }
- };
- } else {
- iter.all(|c| graphic_token_char!(c))
- }
-}
-
-pub(super) fn non_quoted_token<Iter: Iterator<Item = char>>(mut iter: Iter) -> bool {
- if let Some(c) = iter.next() {
- if small_letter_char!(c) {
- iter.all(|c| alpha_numeric_char!(c))
- } else if graphic_token_char!(c) {
- non_quoted_graphic_token(iter, c)
- } else if semicolon_char!(c) {
- iter.next().is_none()
- } else if cut_char!(c) {
- iter.next().is_none()
- } else if c == '[' {
- iter.next() == Some(']') && iter.next().is_none()
- } else if c == '{' {
- iter.next() == Some('}') && iter.next().is_none()
- } else if solo_char!(c) {
- !(c == '(' || c == ')' || c == '}' || c == ']' || c == ',' || c == '%' || c == '|')
- } else {
- false
- }
- } else {
- false
- }
-}
-
-#[inline]
-fn functor_location(addr: &Addr) -> Option<usize> {
- Some(match addr {
- &Addr::Lis(l) => l,
- &Addr::Str(s) => s,
- &Addr::PStrLocation(h, _) => h,
- _ => {
- return None;
- }
- })
-}
-
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
- pub(crate) fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self {
+ pub fn new(
+ heap: &'a mut Heap,
+ arena: &'a mut Arena,
+ op_dir: &'a OpDir,
+ output: Outputter,
+ cell: HeapCellValue,
+ ) -> Self {
HCPrinter {
outputter: output,
- machine_st,
+ iter: stackful_preorder_iter(heap, cell),
+ arena,
op_dir,
state_stack: vec![],
- heap_locs: ReverseHeapVarDict::new(),
toplevel_spec: None,
last_item_idx: 0,
numbervars: false,
numbervars_offset: Integer::from(0),
quoted: false,
ignore_ops: false,
- cyclic_terms: IndexMap::new(),
- non_cyclic_terms: IndexSet::new(),
var_names: IndexMap::new(),
+ print_strings_as_strs: false,
max_depth: 0,
}
}
@@ -482,87 +545,82 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
requires_space(tail, atom)
}
- fn enqueue_op(
- &mut self,
- iter: &mut HCPreOrderIterator,
- mut max_depth: usize,
- ct: ClauseType,
- spec: SharedOpDesc,
- ) {
- if is_postfix!(spec.assoc()) {
+ fn enqueue_op(&mut self, mut max_depth: usize, ct: ClauseType, spec: OpDesc) {
+ let name = ct.name();
+
+ if is_postfix!(spec.get_spec()) {
if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
+ self.iter.pop_stack();
- self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ self.state_stack.push(TokenOrRedirect::Op(name, spec));
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
return;
}
- let right_directed_op = DirectedOp::Right(ct.name(), spec.clone());
+ let right_directed_op = DirectedOp::Right(name, spec);
- self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
+ self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
));
- } else if is_prefix!(spec.assoc()) {
- match ct.name().as_str() {
- "-" | "\\" => {
- self.format_prefix_op_with_space(iter, max_depth, ct.name(), spec);
+ } else if is_prefix!(spec.get_spec()) {
+ match name {
+ atom!("-") | atom!("\\") => {
+ self.format_prefix_op_with_space(max_depth, name, spec);
return;
}
_ => {}
};
if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
+ self.iter.pop_stack();
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
- self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
+ self.state_stack.push(TokenOrRedirect::Op(name, spec));
return;
}
- let left_directed_op = DirectedOp::Left(ct.name(), spec.clone());
+ let left_directed_op = DirectedOp::Left(name, spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
left_directed_op,
));
- self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
+
+ self.state_stack.push(TokenOrRedirect::Op(name, spec));
} else {
- match ct.name().as_str() {
+ match name.as_str() {
"|" => {
- self.format_bar_separator_op(iter, max_depth, ct.name(), spec);
+ self.format_bar_separator_op(max_depth, name, spec);
return;
}
_ => {}
};
+ let ellipsis_atom = atom!("...");
+
if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
- iter.stack().pop();
+ self.iter.pop_stack();
+ self.iter.pop_stack();
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
- self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom));
+ self.state_stack.push(TokenOrRedirect::Op(name, spec));
+ self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom));
return;
}
- let left_directed_op = DirectedOp::Left(ct.name(), spec.clone());
- let right_directed_op = DirectedOp::Right(ct.name(), spec.clone());
+ let left_directed_op = DirectedOp::Left(name, spec);
+ let right_directed_op = DirectedOp::Right(name, spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
left_directed_op,
));
- self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
+ self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
@@ -570,21 +628,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
- fn format_struct(
- &mut self,
- iter: &mut HCPreOrderIterator,
- mut max_depth: usize,
- arity: usize,
- name: ClauseName,
- ) -> bool {
+ fn format_struct(&mut self, mut max_depth: usize, arity: usize, name: Atom) -> bool {
if self.check_max_depth(&mut max_depth) {
for _ in 0..arity {
- iter.stack().pop();
+ self.iter.pop_stack();
}
self.state_stack.push(TokenOrRedirect::Close);
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(name));
@@ -608,25 +659,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
true
}
- fn format_prefix_op_with_space(
- &mut self,
- iter: &mut HCPreOrderIterator,
- mut max_depth: usize,
- name: ClauseName,
- spec: SharedOpDesc,
- ) {
+ fn format_prefix_op_with_space(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) {
if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
+ self.iter.pop_stack();
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::Space);
self.state_stack.push(TokenOrRedirect::Atom(name));
return;
}
- let op = DirectedOp::Left(name.clone(), spec);
+ let op = DirectedOp::Left(name, spec);
self.state_stack
.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
@@ -634,46 +678,43 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Atom(name));
}
- fn format_bar_separator_op(
- &mut self,
- iter: &mut HCPreOrderIterator,
- mut max_depth: usize,
- name: ClauseName,
- spec: SharedOpDesc,
- ) {
+ fn format_bar_separator_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) {
if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
+ self.iter.pop_stack();
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ let ellipsis_atom = atom!("...");
+
+ self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom));
self.state_stack.push(TokenOrRedirect::BarAsOp);
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom));
return;
}
- let left_directed_op = DirectedOp::Left(name.clone(), spec.clone());
- let right_directed_op = DirectedOp::Right(name.clone(), spec.clone());
+ let left_directed_op = DirectedOp::Left(name, spec);
+ let right_directed_op = DirectedOp::Right(name, spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
left_directed_op,
));
+
self.state_stack.push(TokenOrRedirect::BarAsOp);
+
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
));
}
- fn format_curly_braces(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) -> bool {
+ fn format_curly_braces(&mut self, mut max_depth: usize) -> bool {
if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
+ self.iter.pop_stack();
+
+ let ellipsis_atom = atom!("...");
self.state_stack.push(TokenOrRedirect::RightCurly);
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom));
self.state_stack.push(TokenOrRedirect::LeftCurly);
return false;
@@ -687,12 +728,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
true
}
- fn format_numbered_vars(&mut self, iter: &mut HCPreOrderIterator) -> bool {
- let addr = iter.stack().last().cloned().unwrap();
+ fn format_numbered_vars(&mut self) -> bool {
+ let h = self.iter.stack_last().unwrap();
// 7.10.4
- if let Some(var) = iter.machine_st().numbervar(&self.numbervars_offset, addr) {
- iter.stack().pop();
+ if let Some(var) = numbervar(&self.numbervars_offset, self.iter.heap[h]) {
+ self.iter.pop_stack();
self.state_stack.push(TokenOrRedirect::NumberedVar(var));
return true;
}
@@ -702,198 +743,134 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn format_clause(
&mut self,
- iter: &mut HCPreOrderIterator,
max_depth: usize,
arity: usize,
ct: ClauseType,
+ op_desc: Option<OpDesc>,
) -> bool {
if self.numbervars && is_numbered_var(&ct, arity) {
- if self.format_numbered_vars(iter) {
+ if self.format_numbered_vars() {
return true;
}
}
- if let Some(spec) = ct.spec() {
- if "." == ct.name().as_str() && is_infix!(spec.assoc()) {
+ let dot_atom = atom!(".");
+ let name = ct.name();
+
+ if let Some(spec) = op_desc {
+ if dot_atom == name && is_infix!(spec.get_spec()) {
if !self.ignore_ops {
- self.push_list(iter, max_depth);
+ self.push_list(max_depth);
return true;
}
}
- if !self.ignore_ops && spec.prec() > 0 {
- self.enqueue_op(iter, max_depth, ct, spec);
+ if !self.ignore_ops && spec.get_prec() > 0 {
+ self.enqueue_op(max_depth, ct, spec);
return true;
}
}
- return match (ct.name().as_str(), arity) {
- ("{}", 1) if !self.ignore_ops => self.format_curly_braces(iter, max_depth),
- _ => self.format_struct(iter, max_depth, arity, ct.name()),
+ return match (name.as_str(), arity) {
+ ("{}", 1) if !self.ignore_ops => self.format_curly_braces(max_depth),
+ _ => self.format_struct(max_depth, arity, name),
};
}
- #[inline]
- fn push_char(&mut self, c: char) {
- self.outputter.push_char(c);
- self.last_item_idx = self.outputter.len();
- }
-
- #[inline]
- fn append_str(&mut self, s: &str) {
- self.last_item_idx = self.outputter.len();
- self.outputter.append(s);
- }
+ fn offset_as_string(&mut self, h: usize) -> Option<String> {
+ let addr = self.iter.heap[h];
- fn offset_as_string(&mut self, iter: &mut HCPreOrderIterator, addr: Addr) -> Option<Var> {
if let Some(var) = self.var_names.get(&addr) {
- if addr.as_var().is_some() {
- return Some(format!("{}", var));
- } else {
- iter.stack().push(addr);
- return None;
- }
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ return Some(format!("{}", var.as_str()));
+ }
+ _ => {
+ self.iter.push_stack(h);
+ return None;
+ }
+ );
}
- match addr {
- Addr::Lis(h) | Addr::Str(h) => Some(format!("{}", h)),
- _ => {
- if let Some(r) = addr.as_var() {
- match r {
- Ref::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)),
- Ref::HeapCell(h) | Ref::AttrVar(h) => Some(format!("_{}", h)),
- }
- } else {
- None
- }
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Lis | HeapCellValueTag::Str, h) => {
+ Some(format!("{}", h))
}
- }
- }
-
- fn record_children_as_non_cyclic(&mut self, addr: &Addr) {
- match addr {
- &Addr::Lis(l) => {
- let c1 = self
- .machine_st
- .store(self.machine_st.deref(Addr::HeapCell(l)));
- let c2 = self
- .machine_st
- .store(self.machine_st.deref(Addr::HeapCell(l + 1)));
-
- if let Some(c) = functor_location(&c1) {
- self.non_cyclic_terms.insert(c);
- }
-
- if let Some(c) = functor_location(&c2) {
- self.non_cyclic_terms.insert(c);
- }
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
+ Some(format!("_{}", h))
}
- &Addr::Str(s) => {
- let arity = match &self.machine_st.heap[s] {
- HeapCellValue::NamedStr(arity, ..) => arity,
- _ => {
- unreachable!()
- }
- };
-
- for i in 1..arity + 1 {
- let c = self
- .machine_st
- .store(self.machine_st.deref(Addr::HeapCell(s + i)));
-
- if let Some(c) = functor_location(&c) {
- self.non_cyclic_terms.insert(c);
- }
- }
+ (HeapCellValueTag::StackVar, h) => {
+ Some(format!("_s_{}", h))
}
- &Addr::PStrLocation(h, _) => {
- let tail = self.machine_st.heap[h + 1].as_addr(h + 1);
- let tail = self.machine_st.store(self.machine_st.deref(tail));
-
- if let Some(c) = functor_location(&tail) {
- self.non_cyclic_terms.insert(c);
- }
+ _ => {
+ None
}
- _ => {}
- }
+ )
}
- fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<Addr> {
- iter.stack().last().cloned().and_then(|addr| {
- let addr = self.machine_st.store(self.machine_st.deref(addr));
+ fn check_for_seen(&mut self) -> Option<HeapCellValue> {
+ if let Some(addr) = self.iter.next() {
+ let is_cyclic = addr.is_forwarded();
- if let Some(var) = self.var_names.get(&addr) {
- self.heap_locs.insert(addr.clone(), Rc::new(var.clone()));
- }
+ let addr = heap_bound_store(
+ self.iter.heap,
+ heap_bound_deref(self.iter.heap, addr),
+ );
+
+ let addr = unmark_cell_bits!(addr);
- match self.heap_locs.get(&addr).cloned() {
- Some(var) if addr.is_ref() => {
- iter.stack().pop();
+ match self.var_names.get(&addr).cloned() {
+ Some(var) if addr.is_var() => {
+ // If addr is an unbound variable and maps to
+ // a name via heap_locs, append the name to
+ // the current output, and return None. None
+ // short-circuits handle_heap_term.
+ // self.iter.pop_stack();
- push_space_if_amb!(self, &var, {
- self.append_str(&var);
+ let var_str = var.as_str();
+
+ push_space_if_amb!(self, var_str, {
+ append_str!(self, var_str);
});
- return None;
+ None
}
var_opt => {
- let offset = match functor_location(&addr) {
- Some(offset) => offset,
- None => {
- return iter.next();
- }
- };
-
- if !self.non_cyclic_terms.contains(&offset) {
- if let Some(reps) = self.cyclic_terms.get(&addr).cloned() {
- if reps > 0 {
- self.cyclic_terms.insert(addr, reps - 1);
- } else {
- match var_opt {
- Some(var) => {
- push_space_if_amb!(self, &var, {
- self.append_str(&var);
- });
-
- iter.stack().pop();
- }
- None => {
- push_space_if_amb!(self, "...", {
- self.append_str("...");
- });
-
- iter.stack().pop();
- self.cyclic_terms.insert(addr, 2);
- }
- }
-
- return None;
+ if is_cyclic && addr.is_compound() {
+ // self-referential variables are marked "cyclic".
+ match var_opt {
+ Some(var) => {
+ // If the term is bound to a named variable,
+ // print the variable's name to output.
+ push_space_if_amb!(self, &var, {
+ append_str!(self, &var);
+ });
}
- } else if self.machine_st.is_cyclic_term(addr.clone()) {
- if var_opt.is_some() {
- self.cyclic_terms.insert(addr, 0);
- } else {
- self.cyclic_terms.insert(addr, 2);
+ None => {
+ // otherwise, contract it to an ellipsis.
+ push_space_if_amb!(self, "...", {
+ append_str!(self, "...");
+ });
}
- } else {
- self.record_children_as_non_cyclic(&addr);
- self.non_cyclic_terms.insert(offset);
}
- } else {
- self.record_children_as_non_cyclic(&addr);
+
+ return None;
}
- iter.next()
+ Some(addr)
}
}
- })
+ } else {
+ while let Some(_) = self.iter.pop_stack() {}
+ None
+ }
}
- fn print_atom(&mut self, atom: &ClauseName) {
+ fn print_atom(&mut self, atom: Atom) {
let result = self.print_op_addendum(atom.as_str());
push_space_if_amb!(self, result.as_str(), {
- self.append_str(&result);
+ append_str!(self, &result);
});
}
@@ -929,110 +906,137 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
};
push_space_if_amb!(self, &result, {
- self.append_str(&result);
+ append_str!(self, &result);
});
}
#[inline]
fn print_ip_addr(&mut self, ip: IpAddr) {
- self.push_char('\'');
- self.append_str(&format!("{}", ip));
- self.push_char('\'');
+ push_char!(self, '\'');
+ append_str!(self, &format!("{}", ip));
+ push_char!(self, '\'');
}
#[inline]
- fn print_raw_ptr(&mut self, ptr: *const u8) {
- self.append_str(&format!("0x{:x}", ptr as usize));
+ fn print_raw_ptr(&mut self, ptr: *const ArenaHeader) {
+ append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize));
}
- fn print_number(&mut self, n: Number, op: &Option<DirectedOp>) {
+ fn print_number(&mut self, n: NumberFocus, op: &Option<DirectedOp>) {
let add_brackets = if let Some(op) = op {
- op.is_negative_sign() && n.is_positive()
+ op.is_negative_sign() && !n.is_negative()
} else {
false
};
if add_brackets {
- self.push_char('(');
+ push_char!(self, '(');
}
match n {
- Number::Float(fl) => {
- if &fl == &OrderedFloat(0f64) {
- push_space_if_amb!(self, "0.0", {
- self.append_str("0.0");
+ NumberFocus::Unfocused(n) => match n {
+ Number::Float(OrderedFloat(mut fl)) => {
+ if OrderedFloat(fl) == -0f64 {
+ fl = 0f64;
+ }
+
+ let output_str = if fl.fract() == 0f64 {
+ if fl.abs() >= 1.0e16 {
+ format!("{:.1e}", fl.trunc())
+ } else {
+ format!("{:.1}", fl.trunc())
+ }
+ } else if 0f64 < fl.fract().abs() && fl.fract().abs() <= 1.0e-16 {
+ format!("{:>1e}", fl)
+ } else {
+ format!("{}", fl)
+ };
+
+ push_space_if_amb!(self, &output_str, {
+ append_str!(self, &output_str);
});
- } else {
- let OrderedFloat(fl) = fl;
- let output_str = format!("{0:<20?}", fl);
+ }
+ Number::Rational(r) => {
+ self.print_rational(r, add_brackets);
+ return;
+ }
+ n => {
+ let output_str = format!("{}", n);
push_space_if_amb!(self, &output_str, {
- self.append_str(&output_str.trim());
+ append_str!(self, &output_str);
});
}
+ },
+ NumberFocus::Denominator(r) => {
+ let output_str = format!("{}", r.denom());
+
+ push_space_if_amb!(self, &output_str, {
+ append_str!(self, &output_str);
+ });
}
- Number::Rational(r) => {
- self.print_rational(&r, add_brackets);
- return;
- }
- n => {
- let output_str = format!("{}", n);
+ NumberFocus::Numerator(r) => {
+ let output_str = format!("{}", r.numer());
push_space_if_amb!(self, &output_str, {
- self.append_str(&output_str);
+ append_str!(self, &output_str);
});
}
}
if add_brackets {
- self.push_char(')');
+ push_char!(self, ')');
}
}
- fn print_rational(&mut self, r: &Rational, add_brackets: bool) {
- match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) {
- Some(OpDirValue(ref spec)) => {
+ fn print_rational(&mut self, r: TypedArenaPtr<Rational>, add_brackets: bool) {
+ match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) {
+ Some(op_desc) => {
if add_brackets {
self.state_stack.push(TokenOrRedirect::Close);
}
- let rdiv_ct = clause_name!("rdiv");
+ let rdiv_ct = atom!("rdiv");
- let left_directed_op = if spec.prec() > 0 {
- Some(DirectedOp::Left(rdiv_ct.clone(), spec.clone()))
+ let left_directed_op = if op_desc.get_prec() > 0 {
+ Some(DirectedOp::Left(rdiv_ct, *op_desc))
} else {
None
};
- let right_directed_op = if spec.prec() > 0 {
- Some(DirectedOp::Right(rdiv_ct.clone(), spec.clone()))
+ let right_directed_op = if op_desc.get_prec() > 0 {
+ Some(DirectedOp::Right(rdiv_ct, *op_desc))
} else {
None
};
- if spec.prec() > 0 {
- self.state_stack.push(TokenOrRedirect::Number(
- Number::from(r.denom()),
+ if op_desc.get_prec() > 0 {
+ self.state_stack.push(TokenOrRedirect::NumberFocus(
+ NumberFocus::Denominator(r),
left_directed_op,
));
self.state_stack
- .push(TokenOrRedirect::Op(rdiv_ct, spec.clone()));
+ .push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
- self.state_stack.push(TokenOrRedirect::Number(
- Number::from(r.numer()),
+ self.state_stack.push(TokenOrRedirect::NumberFocus(
+ NumberFocus::Numerator(r),
right_directed_op,
));
} else {
self.state_stack.push(TokenOrRedirect::Close);
- self.state_stack
- .push(TokenOrRedirect::Number(Number::from(r.denom()), None));
+ self.state_stack.push(TokenOrRedirect::NumberFocus(
+ NumberFocus::Denominator(r),
+ None,
+ ));
self.state_stack.push(TokenOrRedirect::Comma);
- self.state_stack
- .push(TokenOrRedirect::Number(Number::from(r.numer()), None));
+ self.state_stack.push(TokenOrRedirect::NumberFocus(
+ NumberFocus::Numerator(r),
+ None,
+ ));
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(rdiv_ct));
@@ -1046,157 +1050,173 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
- fn print_char(&mut self, is_quoted: bool, c: char) {
- if non_quoted_token(once(c)) {
- let c = char_to_string(false, c);
+ // returns true if max_depth limit is reached and ellipsis is printed.
+ fn print_string_as_functor(&mut self, focus: usize, max_depth: usize) -> bool {
+ let iter = HeapPStrIter::new(self.iter.heap, focus);
- push_space_if_amb!(self, &c, {
- self.append_str(c.as_str());
- });
- } else {
- let mut result = String::new();
+ for (char_count, c) in iter.chars().enumerate() {
+ append_str!(self, "'.'");
+ push_char!(self, '(');
- if self.quoted {
- result.push('\'');
- result += &char_to_string(is_quoted, c);
- result.push('\'');
- } else {
- result += &char_to_string(is_quoted, c);
- }
+ print_char!(self, self.quoted, c);
+ push_char!(self, ',');
- push_space_if_amb!(self, &result, {
- self.append_str(result.as_str());
- });
+ self.state_stack.push(TokenOrRedirect::Close);
+
+ if max_depth >= char_count + 1 {
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
+ return true;
+ }
}
+
+ false
}
- fn print_proper_string(&mut self, buf: String, max_depth: usize) {
- self.push_char('"');
+ fn print_proper_string(&mut self, focus: usize, max_depth: usize) {
+ push_char!(self, '"');
+
+ let iter = HeapPStrIter::new(self.iter.heap, focus);
- let buf = if max_depth == 0 {
- String::from_iter(buf.chars().map(|c| char_to_string(self.quoted, c)))
+ if max_depth == 0 {
+ for c in iter.chars() {
+ for c in char_to_string(self.quoted, c).chars() {
+ push_char!(self, c);
+ }
+ }
} else {
let mut char_count = 0;
- let mut buf = String::from_iter(buf.chars().take(max_depth).map(|c| {
+
+ for c in iter.chars().take(max_depth) {
char_count += 1;
- char_to_string(self.quoted, c)
- }));
+
+ for c in char_to_string(self.quoted, c).chars() {
+ push_char!(self, c);
+ }
+ }
if char_count == max_depth {
- buf += " ...";
+ append_str!(self, " ...");
}
+ }
- buf
- };
+ push_char!(self, '"');
+ }
- self.append_str(&buf);
- self.push_char('"');
+ fn remove_list_children(&mut self, h: usize) {
+ match self.iter.heap[h].get_tag() {
+ HeapCellValueTag::Lis => {
+ self.iter.pop_stack();
+ self.iter.pop_stack();
+ }
+ HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => {
+ self.iter.pop_stack();
+ }
+ HeapCellValueTag::CStr => {
+ }
+ _ => {
+ unreachable!();
+ }
+ }
}
- fn print_list_like(&mut self, iter: &mut HCPreOrderIterator, addr: Addr, mut max_depth: usize) {
- if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
- iter.stack().pop();
+ fn print_list_like(&mut self, mut max_depth: usize) {
+ let focus = self.iter.focus();
+ let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus);
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
- return;
+ if heap_pstr_iter.next().is_some() {
+ while let Some(_) = heap_pstr_iter.next() {}
+ } else {
+ return self.push_list(max_depth);
}
- let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(addr);
-
- let buf = heap_pstr_iter.to_string();
+ let end_h = heap_pstr_iter.focus();
+ let end_cell = heap_pstr_iter.focus;
- if buf.is_empty() {
- self.push_list(iter, max_depth);
+ if self.check_max_depth(&mut max_depth) {
+ self.remove_list_children(focus);
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
return;
}
- iter.stack().pop();
- iter.stack().pop();
-
- let end_addr = heap_pstr_iter.focus();
+ let at_cdr = self.outputter.ends_with("|");
- let at_cdr = self.at_cdr(",");
-
- if !at_cdr && Addr::EmptyList == end_addr {
- if !self.ignore_ops {
- self.print_proper_string(buf, max_depth);
- return;
- }
+ if !at_cdr && !self.ignore_ops && end_cell.is_string_terminator(&self.iter.heap) {
+ self.remove_list_children(focus);
+ return self.print_proper_string(focus, max_depth);
}
- let buf_len = buf.len();
+ if self.ignore_ops {
+ self.at_cdr(",");
+ self.remove_list_children(focus);
- let buf_iter: Box<dyn Iterator<Item = char>> = if self.max_depth == 0 {
- Box::new(buf.chars())
+ if !self.print_string_as_functor(focus, max_depth) {
+ if end_cell == empty_list_as_cell!() {
+ append_str!(self, "[]");
+ } else {
+ self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
+ self.iter.push_stack(end_h);
+ }
+ }
} else {
- Box::new(buf.chars().take(max_depth))
- };
-
- let mut byte_len = 0;
-
- if self.ignore_ops {
- let mut char_count = 0;
+ let value = heap_bound_store(
+ self.iter.heap,
+ heap_bound_deref(self.iter.heap, self.iter.heap[focus]),
+ );
+
+ read_heap_cell!(value,
+ (HeapCellValueTag::Lis) => {
+ return self.push_list(max_depth);
+ }
+ _ => {
+ let switch = Rc::new(Cell::new((!at_cdr, 0)));
+ self.state_stack.push(TokenOrRedirect::CloseList(switch.clone()));
- for c in buf_iter {
- self.append_str("'.'");
- self.push_char('(');
+ let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus);
+ let pstr = cell_as_string!(self.iter.heap[h]);
- self.print_char(self.quoted, c);
- self.push_char(',');
+ let pstr = pstr.as_str_from(offset.get_num() as usize);
- char_count += 1;
- byte_len += c.len_utf8();
- }
+ if max_depth > 0 && pstr.chars().count() + 1 >= max_depth {
+ if value.get_tag() != HeapCellValueTag::CStr {
+ self.iter.pop_stack();
+ }
- for _ in 0..char_count {
- self.state_stack.push(TokenOrRedirect::Close);
- }
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
+ self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
+ } else if end_cell != empty_list_as_cell!() {
+ if value.get_tag() != HeapCellValueTag::CStr {
+ self.iter.pop_stack();
+ self.iter.push_stack(h+1);
+ }
- if self.max_depth > 0 && buf_len > byte_len {
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
- } else {
- self.state_stack
- .push(TokenOrRedirect::FunctorRedirect(max_depth));
- iter.stack().push(end_addr);
- }
- } else {
- let switch = if !at_cdr {
- self.push_char('[');
- true
- } else {
- false
- };
+ self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
+ self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
+ }
- for c in buf_iter {
- self.print_char(self.quoted, c);
- self.push_char(',');
+ let state_stack_len = self.state_stack.len();
- byte_len += c.len_utf8();
- }
+ for (char_count, c) in pstr.chars().enumerate() {
+ if max_depth > 0 && char_count + 1 >= max_depth {
+ break;
+ }
- self.state_stack
- .push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0)))));
+ self.state_stack.push(TokenOrRedirect::Comma);
+ self.state_stack.push(TokenOrRedirect::Char(c));
+ }
- if self.max_depth > 0 && buf_len > byte_len {
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
- } else {
- self.outputter
- .truncate(self.outputter.len() - ','.len_utf8());
- self.state_stack
- .push(TokenOrRedirect::FunctorRedirect(max_depth));
+ self.state_stack[state_stack_len ..].reverse();
- iter.stack().push(end_addr);
- }
+ if let Some(TokenOrRedirect::Comma) = self.state_stack.last() {
+ self.state_stack.pop();
+ }
- self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
+ self.state_stack.push(TokenOrRedirect::OpenList(switch));
+ }
+ );
}
}
- fn check_max_depth(&mut self, max_depth: &mut usize) -> bool {
+ fn check_max_depth(&self, max_depth: &mut usize) -> bool {
if self.max_depth > 0 && *max_depth == 0 {
return true;
}
@@ -1208,17 +1228,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
false
}
- fn push_list(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) {
+ fn push_list(&mut self, mut max_depth: usize) {
if self.check_max_depth(&mut max_depth) {
- iter.stack().pop();
- iter.stack().pop();
+ self.iter.pop_stack();
+ self.iter.pop_stack();
let cell = Rc::new(Cell::new((true, 0)));
- self.state_stack
- .push(TokenOrRedirect::CloseList(cell.clone()));
- self.state_stack
- .push(TokenOrRedirect::Atom(clause_name!("...")));
+ self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));
+ self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::OpenList(cell));
return;
@@ -1226,26 +1244,22 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let cell = Rc::new(Cell::new((true, max_depth)));
- self.state_stack
- .push(TokenOrRedirect::CloseList(cell.clone()));
+ self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));
- self.state_stack
- .push(TokenOrRedirect::FunctorRedirect(max_depth));
+ self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
- self.state_stack
- .push(TokenOrRedirect::FunctorRedirect(max_depth));
+ self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::OpenList(cell));
}
fn handle_op_as_struct(
&mut self,
- name: ClauseName,
+ name: Atom,
arity: usize,
- iter: &mut HCPreOrderIterator,
op: &Option<DirectedOp>,
is_functor_redirect: bool,
- spec: SharedOpDesc,
+ op_desc: OpDesc,
negated_operand: bool,
max_depth: usize,
) {
@@ -1253,20 +1267,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
negated_operand
|| if let Some(ref op) = op {
if self.numbervars && arity == 1 && name.as_str() == "$VAR" {
- !iter.immediate_leaf_has_property(|addr, heap| {
- match heap.index_addr(&addr).as_ref() {
- &HeapCellValue::Integer(ref n) => &**n >= &0,
- &HeapCellValue::Addr(Addr::Fixnum(n)) => n >= 0,
- &HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64),
- &HeapCellValue::Rational(ref r) => &**r >= &0,
+ !self.iter.immediate_leaf_has_property(|addr| {
+ match Number::try_from(addr) {
+ Ok(Number::Integer(n)) => &*n >= &0,
+ Ok(Number::Fixnum(n)) => n.get_num() >= 0,
+ Ok(Number::Float(f)) => f >= OrderedFloat(0f64),
+ Ok(Number::Rational(r)) => &*r >= &0,
_ => false,
}
- }) && needs_bracketing(&spec, op)
+ }) && needs_bracketing(op_desc, op)
} else {
- needs_bracketing(&spec, op)
+ needs_bracketing(op_desc, op)
}
} else {
- is_functor_redirect && spec.prec() >= 1000
+ is_functor_redirect && op_desc.get_prec() >= 1000
}
} else {
false
@@ -1276,44 +1290,46 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Close);
}
- let ct = ClauseType::from(name.clone(), arity, Some(spec));
+ let ct = ClauseType::from(name, arity);
- if self.format_clause(iter, max_depth, arity, ct) {
- if add_brackets {
- self.state_stack.push(TokenOrRedirect::Open);
+ if self.format_clause(max_depth, arity, ct, Some(op_desc)) && add_brackets {
+ self.state_stack.push(TokenOrRedirect::Open);
- if let Some(ref op) = &op {
- if op.is_left() && requires_space(op.as_str(), "(") {
- self.state_stack.push(TokenOrRedirect::Space);
- }
+ if let Some(ref op) = &op {
+ if op.is_left() && requires_space(op.as_atom().as_str(), "(") {
+ self.state_stack.push(TokenOrRedirect::Space);
}
}
}
}
- fn print_tcp_listener(
- &mut self,
- iter: &mut HCPreOrderIterator,
- tcp_listener: &TcpListener,
- max_depth: usize,
- ) {
+ #[allow(dead_code)]
+ fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() {
- (addr.ip(), Number::from(addr.port() as isize))
+ (
+ addr.ip(),
+ Number::arena_from(addr.port() as usize, self.arena),
+ )
} else {
- let disconnected_atom = clause_name!("$disconnected_tcp_listener");
+ let disconnected_atom = atom!("$disconnected_tcp_listener");
self.state_stack
.push(TokenOrRedirect::Atom(disconnected_atom));
return;
};
- if self.format_struct(iter, max_depth, 1, clause_name!("$tcp_listener")) {
+ let tcp_listener_atom = atom!("$tcp_listener");
+
+ if self.format_struct(max_depth, 1, tcp_listener_atom) {
let atom = self.state_stack.pop().unwrap();
self.state_stack.pop();
self.state_stack.pop();
- self.state_stack.push(TokenOrRedirect::Number(port, None));
+ self.state_stack.push(TokenOrRedirect::NumberFocus(
+ NumberFocus::Unfocused(port),
+ None,
+ ));
self.state_stack.push(TokenOrRedirect::Comma);
self.state_stack.push(TokenOrRedirect::IpAddr(ip));
@@ -1322,13 +1338,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
- fn print_stream(&mut self, iter: &mut HCPreOrderIterator, stream: &Stream, max_depth: usize) {
- if let Some(alias) = &stream.options().alias {
+ fn print_stream(&mut self, stream: Stream, max_depth: usize) {
+ if let Some(alias) = stream.options().get_alias() {
self.print_atom(alias);
} else {
- if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) {
- let atom = if stream.is_stdout() || stream.is_stdin() || stream.is_stderr() {
- TokenOrRedirect::Atom(clause_name!("user"))
+ let stream_atom = atom!("$stream");
+
+ if self.format_struct(max_depth, 1, stream_atom) {
+ let atom = if stream.is_stdout() || stream.is_stdin() {
+ TokenOrRedirect::Atom(atom!("user"))
} else {
TokenOrRedirect::RawPtr(stream.as_ptr())
};
@@ -1347,121 +1365,141 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn handle_heap_term(
&mut self,
- iter: &mut HCPreOrderIterator,
op: Option<DirectedOp>,
is_functor_redirect: bool,
max_depth: usize,
) {
- let negated_operand = negated_op_needs_bracketing(iter, &op);
+ let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op);
- let addr = match self.check_for_seen(iter) {
+ let addr = match self.check_for_seen() {
Some(addr) => addr,
None => return,
};
- match self.machine_st.heap.index_addr(&addr).as_ref() {
- &HeapCellValue::NamedStr(arity, ref name, ref spec) => {
- let spec =
- fetch_op_spec_from_existing(name.clone(), arity, spec.clone(), self.op_dir);
-
- if let Some(spec) = spec {
- self.handle_op_as_struct(
- name.clone(),
- arity,
- iter,
- &op,
- is_functor_redirect,
- spec.clone(),
- negated_operand,
- max_depth,
- );
- } else {
- push_space_if_amb!(self, name.as_str(), {
- let ct = ClauseType::from(name.clone(), arity, spec);
- self.format_clause(iter, max_depth, arity, ct);
- });
- }
- }
- &HeapCellValue::Atom(ref atom, ref spec) => {
- if let Some(_) = fetch_atom_op_spec(atom.clone(), spec.clone(), self.op_dir) {
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if name == atom!("[]") && arity == 0 {
+ if !self.at_cdr("") {
+ append_str!(self, "[]");
+ }
+ } else if arity > 0 {
+ if let Some(spec) = fetch_op_spec(name, arity, self.op_dir) {
+ self.handle_op_as_struct(
+ name,
+ arity,
+ &op,
+ is_functor_redirect,
+ spec,
+ negated_operand,
+ max_depth,
+ );
+ } else {
+ push_space_if_amb!(self, name.as_str(), {
+ let ct = ClauseType::from(name, arity);
+ self.format_clause(max_depth, arity, ct, None);
+ });
+ }
+ } else if fetch_op_spec(name, arity, self.op_dir).is_some() {
let mut result = String::new();
if let Some(ref op) = op {
- if self.outputter.ends_with(&format!(" {}", op.as_str())) {
+ if self.outputter.ends_with(&format!(" {}", op.as_atom().as_str())) {
result.push(' ');
}
result.push('(');
}
- result += &self.print_op_addendum(atom.as_str());
+ result += &self.print_op_addendum(name.as_str());
if op.is_some() {
result.push(')');
}
push_space_if_amb!(self, &result, {
- self.append_str(&result);
+ append_str!(self, &result);
});
} else {
- push_space_if_amb!(self, atom.as_str(), {
- self.print_atom(&atom);
+ push_space_if_amb!(self, name.as_str(), {
+ self.print_atom(name);
});
}
}
- &HeapCellValue::Addr(Addr::Char(c)) => {
- self.print_char(self.quoted, c);
- }
- &HeapCellValue::Addr(Addr::CutPoint(b)) => {
- self.append_str(&format!("{}", b));
- }
- &HeapCellValue::Addr(Addr::EmptyList) => {
- if !self.at_cdr("") {
- self.append_str("[]");
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.iter.heap[s])
+ .get_name_and_arity();
+
+ if let Some(spec) = fetch_op_spec(name, arity, self.op_dir) {
+ self.handle_op_as_struct(
+ name,
+ arity,
+ &op,
+ is_functor_redirect,
+ spec,
+ negated_operand,
+ max_depth,
+ );
+ } else {
+ push_space_if_amb!(self, name.as_str(), {
+ let ct = ClauseType::from(name, arity);
+ self.format_clause(max_depth, arity, ct, None);
+ });
}
}
- &HeapCellValue::Addr(Addr::Float(n)) => {
- self.print_number(Number::Float(n), &op);
+ (HeapCellValueTag::Fixnum, n) => {
+ self.print_number(NumberFocus::Unfocused(Number::Fixnum(n)), &op);
}
- &HeapCellValue::Addr(Addr::Fixnum(n)) => {
- self.print_number(Number::Fixnum(n), &op);
+ (HeapCellValueTag::F64, f) => {
+ self.print_number(NumberFocus::Unfocused(Number::Float(**f)), &op);
}
- &HeapCellValue::Addr(Addr::Usize(u)) => {
- self.append_str(&format!("{}", u));
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
+ self.print_list_like(max_depth);
}
- &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
- self.print_list_like(iter, Addr::PStrLocation(h, n), max_depth);
- }
- &HeapCellValue::Addr(Addr::Lis(l)) => {
+ (HeapCellValueTag::Lis) => {
if self.ignore_ops {
- self.format_struct(iter, max_depth, 2, clause_name!("."));
+ let period_atom = atom!(".");
+ self.format_struct(max_depth, 2, period_atom);
} else {
- self.print_list_like(iter, Addr::Lis(l), max_depth);
+ self.print_list_like(max_depth);
}
}
- &HeapCellValue::Addr(addr) => {
- if let Some(offset_str) = self.offset_as_string(iter, addr) {
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ let h = self.iter.focus();
+
+ if let Some(offset_str) = self.offset_as_string(h) {
push_space_if_amb!(self, &offset_str, {
- self.append_str(offset_str.as_str());
+ append_str!(self, offset_str.as_str());
})
}
}
- &HeapCellValue::Integer(ref n) => {
- self.print_number(Number::Integer(n.clone()), &op);
+ (HeapCellValueTag::Char, c) => {
+ print_char!(self, self.quoted, c);
}
- &HeapCellValue::Rational(ref n) => {
- self.print_number(Number::Rational(n.clone()), &op);
- }
- &HeapCellValue::Stream(ref stream) => {
- self.print_stream(iter, stream, max_depth);
- }
- &HeapCellValue::TcpListener(ref tcp_listener) => {
- self.print_tcp_listener(iter, tcp_listener, max_depth);
+ (HeapCellValueTag::Cons, c) => {
+ match_untyped_arena_ptr!(c,
+ (ArenaHeaderTag::F64, f) => {
+ self.print_number(NumberFocus::Unfocused(Number::Float(*f)), &op);
+ }
+ (ArenaHeaderTag::Integer, n) => {
+ self.print_number(NumberFocus::Unfocused(Number::Integer(n)), &op);
+ }
+ (ArenaHeaderTag::Rational, r) => {
+ self.print_number(NumberFocus::Unfocused(Number::Rational(r)), &op);
+ }
+ (ArenaHeaderTag::Stream, stream) => {
+ self.print_stream(stream, max_depth);
+ }
+ (ArenaHeaderTag::OssifiedOpDir, _op_dir) => {
+ append_str!(self, "$ossified_op_dir");
+ }
+ _ => {
+ }
+ );
}
_ => {
unreachable!()
}
- }
+ );
}
fn at_cdr(&mut self, tr: &str) -> bool {
@@ -1469,7 +1507,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if self.outputter.ends_with("|") {
self.outputter.truncate(len - "|".len());
- self.append_str(tr);
+ append_str!(self, tr);
true
} else {
@@ -1477,29 +1515,28 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
- pub(crate) fn print(mut self, addr: Addr) -> Outputter {
- let mut iter = self.machine_st.pre_order_iter(addr);
-
+ pub fn print(mut self) -> Outputter {
loop {
if let Some(loc_data) = self.state_stack.pop() {
match loc_data {
- TokenOrRedirect::Atom(atom) => self.print_atom(&atom),
- TokenOrRedirect::BarAsOp => self.append_str(" | "),
+ TokenOrRedirect::Atom(atom) => self.print_atom(atom),
+ TokenOrRedirect::BarAsOp => append_str!(self, " | "),
+ TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c),
TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()),
- TokenOrRedirect::NumberedVar(num_var) => self.append_str(num_var.as_str()),
+ TokenOrRedirect::NumberedVar(num_var) => append_str!(self, &num_var),
TokenOrRedirect::CompositeRedirect(max_depth, op) => {
- self.handle_heap_term(&mut iter, Some(op), false, max_depth)
+ self.handle_heap_term(Some(op), false, max_depth)
}
TokenOrRedirect::FunctorRedirect(max_depth) => {
- self.handle_heap_term(&mut iter, None, true, max_depth)
+ self.handle_heap_term(None, true, max_depth)
}
- TokenOrRedirect::Close => self.push_char(')'),
+ TokenOrRedirect::Close => push_char!(self, ')'),
TokenOrRedirect::IpAddr(ip) => self.print_ip_addr(ip),
TokenOrRedirect::RawPtr(ptr) => self.print_raw_ptr(ptr),
- TokenOrRedirect::Open => self.push_char('('),
+ TokenOrRedirect::Open => push_char!(self, '('),
TokenOrRedirect::OpenList(delimit) => {
if !self.at_cdr(",") {
- self.push_char('[');
+ push_char!(self, '[');
} else {
let (_, max_depth) = delimit.get();
delimit.set((false, max_depth));
@@ -1507,19 +1544,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
TokenOrRedirect::CloseList(delimit) => {
if delimit.get().0 {
- self.push_char(']');
+ push_char!(self, ']');
}
}
- TokenOrRedirect::HeadTailSeparator => self.append_str("|"),
- TokenOrRedirect::Number(n, op) => self.print_number(n, &op),
- TokenOrRedirect::Comma => self.append_str(","),
- TokenOrRedirect::Space => self.push_char(' '),
- TokenOrRedirect::LeftCurly => self.push_char('{'),
- TokenOrRedirect::RightCurly => self.push_char('}'),
+ TokenOrRedirect::HeadTailSeparator => append_str!(self, "|"),
+ TokenOrRedirect::NumberFocus(n, op) => self.print_number(n, &op),
+ TokenOrRedirect::Comma => append_str!(self, ","),
+ TokenOrRedirect::Space => push_char!(self, ' '),
+ TokenOrRedirect::LeftCurly => push_char!(self, '{'),
+ TokenOrRedirect::RightCurly => push_char!(self, '}'),
}
- } else if !iter.stack().is_empty() {
+ } else if !self.iter.stack_is_empty() {
let spec = self.toplevel_spec.take();
- self.handle_heap_term(&mut iter, spec, false, self.max_depth);
+ self.handle_heap_term(spec, false, self.max_depth);
} else {
break;
}
@@ -1528,3 +1565,273 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.outputter
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::machine::mock_wam::*;
+
+ #[test]
+ fn term_printing_tests() {
+ let mut wam = MockWAM::new();
+
+ let f_atom = atom!("f");
+ let a_atom = atom!("a");
+ let b_atom = atom!("b");
+ let c_atom = atom!("c");
+
+ wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+
+ {
+ let printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0)
+ );
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "f(a,b)");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(0))
+ ]
+ ));
+
+ {
+ let printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0)
+ );
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "f(a,b,a,...)");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ // print L = [L|L].
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+
+ {
+ let printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0)
+ );
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "[...|...]");
+
+ let mut printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0)
+ );
+
+ printer
+ .var_names
+ .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "[L|L]");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(str_loc_as_cell!(5));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.extend(functor);
+
+ {
+ let printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0),
+ );
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)]");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap[4] = list_loc_as_cell!(1);
+
+ {
+ let printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0),
+ );
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|...]");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ {
+ let mut printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0)
+ );
+
+ printer
+ .var_names
+ .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|L]");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ // issue #382
+ wam.machine_st.heap.clear();
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+
+ for idx in 0..3000 {
+ wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1));
+ wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1));
+ }
+
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0)
+ );
+
+ printer.max_depth = 5;
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "[_1,_3,_5,_7,_9,...]");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ put_partial_string(&mut wam.machine_st.heap, "abc", &mut wam.machine_st.atom_tbl);
+
+ {
+ let printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ pstr_loc_as_cell!(0)
+ );
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "[a,b,c|_1]");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.pop();
+
+ wam.machine_st.heap.push(list_loc_as_cell!(2));
+
+ wam.machine_st.heap.push(atom_as_cell!(a_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(4));
+ wam.machine_st.heap.push(atom_as_cell!(b_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(6));
+ wam.machine_st.heap.push(atom_as_cell!(c_atom));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let printer = HCPrinter::new(
+ &mut wam.machine_st.heap,
+ &mut wam.machine_st.arena,
+ &wam.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(0),
+ );
+
+ let output = printer.print();
+
+ assert_eq!(output.result(), "\"abcabc\"");
+ }
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ assert_eq!(
+ &wam.parse_and_print_term("=(X,[a,b,c|X]).").unwrap(),
+ "=(X,[a,b,c|X])"
+ );
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(
+ &wam.parse_and_print_term("[a,b,\"a\",[a,b,c]].").unwrap(),
+ "[a,b,\"a\",\"abc\"]"
+ );
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(
+ &wam.parse_and_print_term("[\"abc\",e,f,[g,e,h,Y,v|[X,Y]]].")
+ .unwrap(),
+ "[\"abc\",e,f,[g,e,h,Y,v,X,Y]]"
+ );
+
+ all_cells_unmarked(&wam.machine_st.heap);
+
+ assert_eq!(&wam.parse_and_print_term("f((a,b)).").unwrap(), "f((a,b))");
+ }
+}
diff --git a/src/indexing.rs b/src/indexing.rs
index a71ab01f..5deccb80 100644
--- a/src/indexing.rs
+++ b/src/indexing.rs
@@ -1,33 +1,21 @@
-use prolog_parser::ast::*;
-use prolog_parser::clause_name;
-use prolog_parser::tabled_rc::*;
+use crate::atom_table::*;
+use crate::parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
-use crate::rug::Integer;
use indexmap::IndexMap;
-
use slice_deque::{sdeq, SliceDeque};
-use std::convert::TryFrom;
+use std::collections::VecDeque;
use std::hash::Hash;
use std::iter::once;
use std::mem;
-use std::rc::Rc;
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum IndexingCodePtr {
- External(usize), // the index points past the indexing instruction prelude.
- DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction.
- Fail,
- Internal(usize), // the index points into the indexing instruction prelude.
-}
#[derive(Debug, Clone, Copy)]
enum OptArgIndexKeyType {
Structure,
- Constant,
+ Literal,
// List,
}
@@ -35,7 +23,7 @@ impl OptArgIndexKey {
#[inline]
fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool {
match (self, key_type) {
- (OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant)
+ (OptArgIndexKey::Literal(..), OptArgIndexKeyType::Literal)
| (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure)
// | (OptArgIndexKey::List(..), OptArgIndexKeyType::List)
=> true,
@@ -45,11 +33,12 @@ impl OptArgIndexKey {
}
#[inline]
-fn search_skeleton_for_first_key_type(
- skeleton: &[ClauseIndexInfo],
+fn search_skeleton_for_first_key_type<'a>(
+ skeleton: &'a [ClauseIndexInfo],
+ retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
key_type: OptArgIndexKeyType,
append_or_prepend: AppendOrPrepend,
-) -> Option<&OptArgIndexKey> {
+) -> Option<&'a OptArgIndexKey> {
if append_or_prepend.is_append() {
for clause_index_info in skeleton.iter().rev() {
if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
@@ -64,11 +53,20 @@ fn search_skeleton_for_first_key_type(
}
}
+ if let Some(retracted_clauses) = retracted_dynamic_clauses {
+ for clause_index_info in retracted_clauses.iter().rev() {
+ if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
+ return Some(&clause_index_info.opt_arg_index_key);
+ }
+ }
+ }
+
None
}
struct IndexingCodeMergingPtr<'a> {
skeleton: &'a mut [ClauseIndexInfo],
+ retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
indexing_code: &'a mut Vec<IndexingLine>,
offset: usize,
append_or_prepend: AppendOrPrepend,
@@ -79,22 +77,22 @@ impl<'a> IndexingCodeMergingPtr<'a> {
#[inline]
fn new(
skeleton: &'a mut [ClauseIndexInfo],
+ retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
indexing_code: &'a mut Vec<IndexingLine>,
append_or_prepend: AppendOrPrepend,
) -> Self {
let is_dynamic = match &indexing_code[0] {
- IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
- match v {
- IndexingCodePtr::External(_) => false,
- IndexingCodePtr::DynamicExternal(_) => true,
- _ => unreachable!()
- }
- }
- _ => unreachable!()
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
+ IndexingCodePtr::External(_) => false,
+ IndexingCodePtr::DynamicExternal(_) => true,
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
};
Self {
skeleton,
+ retracted_dynamic_clauses,
indexing_code,
offset: 0,
append_or_prepend,
@@ -105,15 +103,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) {
let constant_key = search_skeleton_for_first_key_type(
self.skeleton,
- OptArgIndexKeyType::Constant,
+ self.retracted_dynamic_clauses,
+ OptArgIndexKeyType::Literal,
self.append_or_prepend,
);
let mut constants = IndexMap::new();
match constant_key {
- Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => {
- constants.insert(constant.clone(), constant_ptr);
+ Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
+ constants.insert(*constant, constant_ptr);
}
_ => {
if let IndexingCodePtr::DynamicExternal(_) = constant_ptr {
@@ -145,7 +144,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_static_indexed_choice_for_constant(
&mut self,
external: usize,
- constant: Constant,
+ constant: Literal,
index: usize,
) {
let third_level_index = if self.append_or_prepend.is_append() {
@@ -179,7 +178,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_dynamic_indexed_choice_for_constant(
&mut self,
external: usize,
- constant: Constant,
+ constant: Literal,
index: usize,
) {
let third_level_index = if self.append_or_prepend.is_append() {
@@ -232,8 +231,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn index_overlapping_constant(
&mut self,
- orig_constant: &Constant,
- overlapping_constant: Constant,
+ orig_constant: Literal,
+ overlapping_constant: Literal,
index: usize,
) {
loop {
@@ -252,7 +251,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
let mut constants = IndexMap::new();
- constants.insert(orig_constant.clone(), *c);
+ constants.insert(orig_constant, *c);
*c = IndexingCodePtr::Internal(indexing_code_len);
@@ -282,10 +281,18 @@ impl<'a> IndexingCodeMergingPtr<'a> {
);
}
Some(IndexingCodePtr::DynamicExternal(o)) => {
- self.add_dynamic_indexed_choice_for_constant(o, overlapping_constant, index);
+ self.add_dynamic_indexed_choice_for_constant(
+ o,
+ overlapping_constant,
+ index,
+ );
}
Some(IndexingCodePtr::External(o)) => {
- self.add_static_indexed_choice_for_constant(o, overlapping_constant, index);
+ self.add_static_indexed_choice_for_constant(
+ o,
+ overlapping_constant,
+ index,
+ );
}
Some(IndexingCodePtr::Internal(o)) => {
self.offset += o;
@@ -307,7 +314,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}
}
- fn index_constant(&mut self, constant: Constant, index: usize) {
+ fn index_constant(&mut self, constant: Literal, index: usize) {
loop {
let indexing_code_len = self.indexing_code.len();
@@ -338,10 +345,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => {
match constants.get(&constant).cloned() {
None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
- constants.insert(constant, IndexingCodePtr::DynamicExternal(index));
+ constants.insert(
+ constant,
+ IndexingCodePtr::DynamicExternal(index),
+ );
}
None | Some(IndexingCodePtr::Fail) => {
- constants.insert(constant, IndexingCodePtr::External(index));
+ constants.insert(
+ constant,
+ IndexingCodePtr::External(index),
+ );
}
Some(IndexingCodePtr::DynamicExternal(o)) => {
self.add_dynamic_indexed_choice_for_constant(o, constant, index);
@@ -372,6 +385,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) {
let structure_key = search_skeleton_for_first_key_type(
self.skeleton,
+ self.retracted_dynamic_clauses,
OptArgIndexKeyType::Structure,
self.append_or_prepend,
);
@@ -379,8 +393,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
let mut structures = IndexMap::new();
match structure_key {
- Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => {
- structures.insert((name.clone(), *arity), structure_ptr);
+ Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
+ structures.insert((*name, *arity), structure_ptr);
}
_ => {
if let IndexingCodePtr::DynamicExternal(_) = structure_ptr {
@@ -428,8 +442,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
};
let indexing_code_len = self.indexing_code.len();
- self.indexing_code
- .push(IndexingLine::IndexedChoice(third_level_index));
+ self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => {
@@ -599,6 +612,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
pub(crate) fn merge_clause_index(
target_indexing_code: &mut Vec<IndexingLine>,
skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton.
+ retracted_clauses: &Option<Vec<ClauseIndexInfo>>,
new_clause_loc: usize, // the absolute location of the new clause in the code vector.
append_or_prepend: AppendOrPrepend,
) {
@@ -609,27 +623,28 @@ pub(crate) fn merge_clause_index(
let mut merging_ptr = IndexingCodeMergingPtr::new(
skeleton,
+ retracted_clauses,
target_indexing_code,
append_or_prepend,
);
match &opt_arg_index_key {
- OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => {
+ OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
let offset = new_clause_loc - index_loc + 1;
- merging_ptr.index_constant(constant.clone(), offset);
+ merging_ptr.index_constant(*constant, offset);
for overlapping_constant in overlapping_constants {
merging_ptr.offset = 0;
merging_ptr.index_overlapping_constant(
- constant,
- overlapping_constant.clone(),
+ *constant,
+ *overlapping_constant,
offset,
);
}
}
- OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => {
- merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1);
+ OptArgIndexKey::Structure(_, index_loc, name, arity) => {
+ merging_ptr.index_structure((*name, *arity), new_clause_loc - index_loc + 1);
}
OptArgIndexKey::List(_, index_loc) => {
merging_ptr.index_list(new_clause_loc - index_loc + 1);
@@ -650,13 +665,13 @@ pub(crate) fn merge_clause_index(
}
pub(crate) fn remove_constant_indices(
- constant: &Constant,
- overlapping_constants: &[Constant],
+ constant: Literal,
+ overlapping_constants: &[Literal],
indexing_code: &mut Vec<IndexingLine>,
offset: usize,
) {
let mut index = 0;
- let iter = once(constant).chain(overlapping_constants.iter());
+ let iter = once(&constant).chain(overlapping_constants.iter());
match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => {
@@ -688,11 +703,13 @@ pub(crate) fn remove_constant_indices(
)) => {
constants_index = index;
- match constants.get(constant).cloned() {
- Some(IndexingCodePtr::DynamicExternal(_)) |
- Some(IndexingCodePtr::External(_)) |
- Some(IndexingCodePtr::Fail) => {
- constants.remove(constant);
+ let constant = *constant;
+
+ match constants.get(&constant).cloned() {
+ Some(IndexingCodePtr::DynamicExternal(_))
+ | Some(IndexingCodePtr::External(_))
+ | Some(IndexingCodePtr::Fail) => {
+ constants.remove(&constant);
break;
}
Some(IndexingCodePtr::Internal(o)) => {
@@ -704,13 +721,14 @@ pub(crate) fn remove_constant_indices(
}
}
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
- StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
+ StaticCodeIndices::remove_instruction_with_offset(
+ indexed_choice_instrs,
+ offset,
+ );
if indexed_choice_instrs.len() == 1 {
if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
- let ext = IndexingCodePtr::External(
- indexed_choice_instr.offset()
- );
+ let ext = IndexingCodePtr::External(indexed_choice_instr.offset());
match &mut indexing_code[constants_index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
@@ -724,7 +742,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
- constants.insert(constant.clone(), ext);
+ constants.insert(*constant, ext);
}
_ => {
unreachable!()
@@ -736,7 +754,10 @@ pub(crate) fn remove_constant_indices(
break;
}
IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => {
- DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
+ DynamicCodeIndices::remove_instruction_with_offset(
+ indexed_choice_instrs,
+ offset,
+ );
if indexed_choice_instrs.len() == 1 {
if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
@@ -754,7 +775,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
- constants.insert(constant.clone(), ext);
+ constants.insert(*constant, ext);
}
_ => {
unreachable!()
@@ -790,7 +811,7 @@ pub(crate) fn remove_constant_indices(
}
pub(crate) fn remove_structure_index(
- name: &ClauseName,
+ name: Atom,
arity: usize,
indexing_code: &mut Vec<IndexingLine>,
offset: usize,
@@ -825,7 +846,8 @@ pub(crate) fn remove_structure_index(
structures_index = index;
match structures.get(&(name.clone(), arity)).cloned() {
- Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => {
+ Some(IndexingCodePtr::DynamicExternal(_))
+ | Some(IndexingCodePtr::External(_)) => {
structures.remove(&(name.clone(), arity));
break;
}
@@ -1012,27 +1034,14 @@ pub(crate) fn remove_index(
clause_loc: usize,
) {
match opt_arg_index_key {
- OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => {
- remove_constant_indices(
- constant,
- overlapping_constants,
- indexing_code,
- clause_loc,
- );
- }
- OptArgIndexKey::Structure(_, _, ref name, ref arity) => {
- remove_structure_index(
- name,
- *arity,
- indexing_code,
- clause_loc,
- );
+ OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
+ remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
+ }
+ OptArgIndexKey::Structure(_, _, name, arity) => {
+ remove_structure_index(*name, *arity, indexing_code, clause_loc);
}
OptArgIndexKey::List(..) => {
- remove_list_index(
- indexing_code,
- clause_loc,
- );
+ remove_list_index(indexing_code, clause_loc);
}
OptArgIndexKey::None => {
unreachable!()
@@ -1076,49 +1085,52 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
});
}
-pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData<Atom>) -> Vec<Constant> {
+pub(crate) fn constant_key_alternatives(
+ constant: Literal,
+ atom_tbl: &mut AtomTable,
+ // arena: &mut Arena,
+) -> Vec<Literal> {
let mut constants = vec![];
match constant {
- Constant::Atom(ref name, ref op) => {
- if name.is_char() {
- let c = name.as_str().chars().next().unwrap();
- constants.push(Constant::Char(c));
- }
-
- if op.is_some() {
- constants.push(Constant::Atom(name.clone(), None));
+ Literal::Atom(ref name) => {
+ if let Some(c) = name.as_char() {
+ constants.push(Literal::Char(c));
}
}
- Constant::Char(c) => {
- let atom = clause_name!(c.to_string(), atom_tbl);
- constants.push(Constant::Atom(atom, None));
+ Literal::Char(c) => {
+ let atom = atom_tbl.build_with(&c.to_string());
+ constants.push(Literal::Atom(atom));
}
- Constant::Fixnum(ref n) => {
- constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
+ /*
+ Literal::Fixnum(ref n) => {
+ constants.push(Literal::Integer(arena_alloc!(n, arena))); //Rc::new(Integer::from(*n))));
+ /*
if *n >= 0 {
if let Ok(n) = usize::try_from(*n) {
- constants.push(Constant::Usize(n));
+ constants.push(Literal::Usize(n));
}
}
+ */
}
- Constant::Integer(ref n) => {
+ */
+ Literal::Integer(ref n) => {
if let Some(n) = n.to_isize() {
- constants.push(Constant::Fixnum(n));
- }
-
- if let Some(n) = n.to_usize() {
- constants.push(Constant::Usize(n));
+ Fixnum::build_with_checked(n as i64).map(|n| {
+ constants.push(Literal::Fixnum(n));
+ }).unwrap();
}
}
- Constant::Usize(n) => {
- constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
+ /*
+ Literal::Usize(n) => {
+ constants.push(Literal::Integer(Rc::new(Integer::from(*n))));
if let Ok(n) = isize::try_from(*n) {
- constants.push(Constant::Fixnum(n));
+ constants.push(Literal::Fixnum(n));
}
}
+ */
_ => {}
}
@@ -1127,16 +1139,16 @@ pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledDat
#[derive(Debug)]
pub(crate) struct StaticCodeIndices {
- constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>,
- lists: SliceDeque<IndexedChoiceInstruction>,
- structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>,
+ constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>>,
+ lists: VecDeque<IndexedChoiceInstruction>,
+ structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>>,
}
#[derive(Debug)]
pub(crate) struct DynamicCodeIndices {
- constants: IndexMap<Constant, SliceDeque<usize>>,
- lists: SliceDeque<usize>,
- structures: IndexMap<(ClauseName, usize), SliceDeque<usize>>,
+ constants: IndexMap<Literal, VecDeque<usize>>,
+ lists: VecDeque<usize>,
+ structures: IndexMap<(Atom, usize), VecDeque<usize>>,
}
pub(crate) trait Indexer {
@@ -1144,32 +1156,29 @@ pub(crate) trait Indexer {
fn new() -> Self;
- fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<Self::ThirdLevelIndex>>;
- fn lists(&mut self) -> &mut SliceDeque<Self::ThirdLevelIndex>;
- fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<Self::ThirdLevelIndex>>;
+ fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>>;
+ fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
+ fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<Self::ThirdLevelIndex>>;
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
fn second_level_index<IndexKey: Eq + Hash>(
- indices: IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
- prelude: &mut SliceDeque<IndexingLine>,
+ indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr>;
fn switch_on<IndexKey: Eq + Hash>(
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
- index: &mut IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
- prelude: &mut SliceDeque<IndexingLine>,
+ index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr;
fn switch_on_list(
- lists: &mut SliceDeque<Self::ThirdLevelIndex>,
- prelude: &mut SliceDeque<IndexingLine>,
+ lists: &mut VecDeque<Self::ThirdLevelIndex>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr;
- fn remove_instruction_with_offset(
- code: &mut SliceDeque<Self::ThirdLevelIndex>,
- offset: usize,
- );
+ fn remove_instruction_with_offset(code: &mut SliceDeque<Self::ThirdLevelIndex>, offset: usize);
fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
}
@@ -1181,23 +1190,23 @@ impl Indexer for StaticCodeIndices {
fn new() -> Self {
Self {
constants: IndexMap::new(),
- lists: sdeq![],
+ lists: VecDeque::new(),
structures: IndexMap::new(),
}
}
#[inline]
- fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>> {
+ fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>> {
&mut self.constants
}
#[inline]
- fn lists(&mut self) -> &mut SliceDeque<IndexedChoiceInstruction> {
+ fn lists(&mut self) -> &mut VecDeque<IndexedChoiceInstruction> {
&mut self.lists
}
#[inline]
- fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>> {
+ fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>> {
&mut self.structures
}
@@ -1210,18 +1219,18 @@ impl Indexer for StaticCodeIndices {
}
fn second_level_index<IndexKey: Eq + Hash>(
- indices: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
- prelude: &mut SliceDeque<IndexingLine>,
+ indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr> {
let mut index_locs = IndexMap::new();
for (key, mut code) in indices.into_iter() {
if code.len() > 1 {
index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
- cap_choice_seq_with_trust(&mut code);
+ cap_choice_seq_with_trust(code.make_contiguous());
prelude.push_back(IndexingLine::from(code));
} else {
- code.first().map(|i| {
+ code.front().map(|i| {
index_locs.insert(key, IndexingCodePtr::External(i.offset()));
});
}
@@ -1232,8 +1241,8 @@ impl Indexer for StaticCodeIndices {
fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
- index: &mut IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
- prelude: &mut SliceDeque<IndexingLine>,
+ index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
let index = mem::replace(index, IndexMap::new());
let index = Self::second_level_index(index, prelude);
@@ -1253,25 +1262,28 @@ impl Indexer for StaticCodeIndices {
}
fn switch_on_list(
- lists: &mut SliceDeque<IndexedChoiceInstruction>,
- prelude: &mut SliceDeque<IndexingLine>,
+ lists: &mut VecDeque<IndexedChoiceInstruction>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
if lists.len() > 1 {
- cap_choice_seq_with_trust(lists);
- let lists = mem::replace(lists, sdeq![]);
+ cap_choice_seq_with_trust(lists.make_contiguous());
+ let lists = mem::replace(lists, VecDeque::new());
prelude.push_back(IndexingLine::from(lists));
IndexingCodePtr::Internal(1)
} else {
lists
- .first()
+ .front()
.map(|i| IndexingCodePtr::External(i.offset()))
.unwrap_or(IndexingCodePtr::Fail)
}
}
#[inline]
- fn remove_instruction_with_offset(code: &mut SliceDeque<IndexedChoiceInstruction>, offset: usize) {
+ fn remove_instruction_with_offset(
+ code: &mut SliceDeque<IndexedChoiceInstruction>,
+ offset: usize,
+ ) {
for (index, line) in code.iter().enumerate() {
if offset == line.offset() {
code.remove(index);
@@ -1294,23 +1306,23 @@ impl Indexer for DynamicCodeIndices {
fn new() -> Self {
Self {
constants: IndexMap::new(),
- lists: sdeq![],
+ lists: VecDeque::new(),
structures: IndexMap::new(),
}
}
#[inline]
- fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<usize>> {
+ fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>> {
&mut self.constants
}
#[inline]
- fn lists(&mut self) -> &mut SliceDeque<usize> {
+ fn lists(&mut self) -> &mut VecDeque<usize> {
&mut self.lists
}
#[inline]
- fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<usize>> {
+ fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<usize>> {
&mut self.structures
}
@@ -1320,17 +1332,17 @@ impl Indexer for DynamicCodeIndices {
}
fn second_level_index<IndexKey: Eq + Hash>(
- indices: IndexMap<IndexKey, SliceDeque<usize>>,
- prelude: &mut SliceDeque<IndexingLine>,
+ indices: IndexMap<IndexKey, VecDeque<usize>>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr> {
let mut index_locs = IndexMap::new();
for (key, code) in indices.into_iter() {
if code.len() > 1 {
index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
- prelude.push_back(IndexingLine::DynamicIndexedChoice(code));
+ prelude.push_back(IndexingLine::DynamicIndexedChoice(code.into_iter().collect()));
} else {
- code.first().map(|i| {
+ code.front().map(|i| {
index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i));
});
}
@@ -1341,8 +1353,8 @@ impl Indexer for DynamicCodeIndices {
fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
- index: &mut IndexMap<IndexKey, SliceDeque<usize>>,
- prelude: &mut SliceDeque<IndexingLine>,
+ index: &mut IndexMap<IndexKey, VecDeque<usize>>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
let index = mem::replace(index, IndexMap::new());
let index = Self::second_level_index(index, prelude);
@@ -1362,16 +1374,16 @@ impl Indexer for DynamicCodeIndices {
}
fn switch_on_list(
- lists: &mut SliceDeque<usize>,
- prelude: &mut SliceDeque<IndexingLine>,
+ lists: &mut VecDeque<usize>,
+ prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr {
if lists.len() > 1 {
- let lists = mem::replace(lists, sdeq![]);
- prelude.push_back(IndexingLine::DynamicIndexedChoice(lists));
+ let lists = mem::replace(lists, VecDeque::new());
+ prelude.push_back(IndexingLine::DynamicIndexedChoice(lists.into_iter().collect()));
IndexingCodePtr::Internal(1)
} else {
lists
- .first()
+ .front()
.map(|i| IndexingCodePtr::DynamicExternal(*i))
.unwrap_or(IndexingCodePtr::Fail)
}
@@ -1395,19 +1407,13 @@ impl Indexer for DynamicCodeIndices {
#[derive(Debug)]
pub(crate) struct CodeOffsets<I: Indexer> {
- atom_tbl: TabledData<Atom>,
indices: I,
optimal_index: usize,
}
impl<I: Indexer> CodeOffsets<I> {
- pub(crate) fn new(
- atom_tbl: TabledData<Atom>,
- indices: I,
- optimal_index: usize,
- ) -> Self {
+ pub(crate) fn new(indices: I, optimal_index: usize) -> Self {
CodeOffsets {
- atom_tbl,
indices,
optimal_index,
}
@@ -1419,15 +1425,24 @@ impl<I: Indexer> CodeOffsets<I> {
self.indices.lists().push_back(index);
}
- fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec<Constant> {
- let overlapping_constants = constant_key_alternatives(constant, self.atom_tbl.clone());
- let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
+ fn index_constant(
+ &mut self,
+ atom_tbl: &mut AtomTable,
+ constant: Literal,
+ index: usize,
+ ) -> Vec<Literal> {
+ let overlapping_constants = constant_key_alternatives(constant, atom_tbl);
+ let code = self.indices.constants().entry(constant).or_insert(VecDeque::new());
let is_initial_index = code.is_empty();
code.push_back(I::compute_index(is_initial_index, index));
for constant in &overlapping_constants {
- let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
+ let code = self
+ .indices
+ .constants()
+ .entry(*constant)
+ .or_insert(VecDeque::new());
let is_initial_index = code.is_empty();
let index = I::compute_index(is_initial_index, index);
@@ -1438,11 +1453,12 @@ impl<I: Indexer> CodeOffsets<I> {
overlapping_constants
}
- fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize {
- let code = self.indices
+ fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
+ let code = self
+ .indices
.structures()
.entry((name.clone(), arity))
- .or_insert(sdeq![]);
+ .or_insert(VecDeque::new());
let code_len = code.len();
let is_initial_index = code.is_empty();
@@ -1456,28 +1472,25 @@ impl<I: Indexer> CodeOffsets<I> {
optimal_arg: &Term,
index: usize,
clause_index_info: &mut ClauseIndexInfo,
+ atom_tbl: &mut AtomTable,
) {
match optimal_arg {
- &Term::Clause(_, ref name, ref terms, _) => {
+ &Term::Clause(_, name, ref terms) => {
clause_index_info.opt_arg_index_key =
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
self.index_structure(name, terms.len(), index);
}
- &Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => {
+ &Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
- &Term::Constant(_, ref constant) => {
- let overlapping_constants = self.index_constant(constant, index);
-
- clause_index_info.opt_arg_index_key = OptArgIndexKey::Constant(
- self.optimal_index,
- 0,
- constant.clone(),
- overlapping_constants,
- );
+ &Term::Literal(_, constant) => {
+ let overlapping_constants = self.index_constant(atom_tbl, constant, index);
+
+ clause_index_info.opt_arg_index_key =
+ OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
}
_ => {}
}
@@ -1496,7 +1509,7 @@ impl<I: Indexer> CodeOffsets<I> {
return vec![];
}
- let mut prelude = sdeq![];
+ let mut prelude = VecDeque::new();
let mut emitted_switch_on_structure = false;
let mut emitted_switch_on_constant = false;
diff --git a/src/instructions.rs b/src/instructions.rs
deleted file mode 100644
index 90cbeeab..00000000
--- a/src/instructions.rs
+++ /dev/null
@@ -1,847 +0,0 @@
-use prolog_parser::ast::*;
-use prolog_parser::clause_name;
-
-use crate::clause_types::*;
-use crate::forms::*;
-use crate::indexing::IndexingCodePtr;
-use crate::machine::heap::*;
-use crate::machine::machine_errors::MachineStub;
-use crate::machine::machine_indices::*;
-use crate::rug::Integer;
-
-use indexmap::IndexMap;
-
-use slice_deque::SliceDeque;
-
-use std::rc::Rc;
-
-fn reg_type_into_functor(r: RegType) -> MachineStub {
- match 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", [atom("root")]),
- Level::Shallow => functor!("level", [atom("shallow")]),
- Level::Deep => functor!("level", [atom("deep")]),
- }
- }
-}
-
-impl ArithmeticTerm {
- fn into_functor(&self) -> MachineStub {
- match self {
- &ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
- &ArithmeticTerm::Interm(i) => {
- functor!("intermediate", [integer(i)])
- }
- &ArithmeticTerm::Number(ref n) => {
- vec![n.clone().into()]
- }
- }
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum NextOrFail {
- Next(usize),
- Fail(usize),
-}
-
-impl NextOrFail {
- #[inline]
- pub fn is_next(&self) -> bool {
- if let NextOrFail::Next(_) = self {
- true
- } else {
- false
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub(crate) enum Death {
- Finite(usize),
- Infinity,
-}
-
-#[derive(Debug)]
-pub(crate) enum ChoiceInstruction {
- DynamicElse(usize, Death, NextOrFail),
- DynamicInternalElse(usize, Death, NextOrFail),
- DefaultRetryMeElse(usize),
- DefaultTrustMe(usize),
- RetryMeElse(usize),
- TrustMe(usize),
- TryMeElse(usize),
-}
-
-impl ChoiceInstruction {
- pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
- match self {
- &ChoiceInstruction::DynamicElse(birth, death, next_or_fail) => {
- match (death, next_or_fail) {
- (Death::Infinity, NextOrFail::Next(i)) => {
- functor!(
- "dynamic_else",
- [integer(birth), atom("inf"), integer(i)]
- )
- }
- (Death::Infinity, NextOrFail::Fail(i)) => {
- let next_functor = functor!("fail", [integer(i)]);
-
- functor!(
- "dynamic_else",
- [integer(birth), atom("inf"), aux(h, 0)],
- [next_functor]
- )
- }
- (Death::Finite(d), NextOrFail::Fail(i)) => {
- let next_functor = functor!("fail", [integer(i)]);
-
- functor!(
- "dynamic_else",
- [integer(birth), integer(d), aux(h, 0)],
- [next_functor]
- )
- }
- (Death::Finite(d), NextOrFail::Next(i)) => {
- functor!(
- "dynamic_else",
- [integer(birth), integer(d), integer(i)]
- )
- }
- }
- }
- &ChoiceInstruction::DynamicInternalElse(birth, death, next_or_fail) => {
- match (death, next_or_fail) {
- (Death::Infinity, NextOrFail::Next(i)) => {
- functor!(
- "dynamic_internal_else",
- [integer(birth), atom("inf"), integer(i)]
- )
- }
- (Death::Infinity, NextOrFail::Fail(i)) => {
- let next_functor = functor!("fail", [integer(i)]);
-
- functor!(
- "dynamic_internal_else",
- [integer(birth), atom("inf"), aux(h, 0)],
- [next_functor]
- )
- }
- (Death::Finite(d), NextOrFail::Fail(i)) => {
- let next_functor = functor!("fail", [integer(i)]);
-
- functor!(
- "dynamic_internal_else",
- [integer(birth), integer(d), aux(h, 0)],
- [next_functor]
- )
- }
- (Death::Finite(d), NextOrFail::Next(i)) => {
- functor!(
- "dynamic_internal_else",
- [integer(birth), integer(d), integer(i)]
- )
- }
- }
- }
- &ChoiceInstruction::TryMeElse(offset) => {
- functor!("try_me_else", [integer(offset)])
- }
- &ChoiceInstruction::RetryMeElse(offset) => {
- functor!("retry_me_else", [integer(offset)])
- }
- &ChoiceInstruction::TrustMe(offset) => {
- functor!("trust_me", [integer(offset)])
- }
- &ChoiceInstruction::DefaultRetryMeElse(offset) => {
- functor!("default_retry_me_else", [integer(offset)])
- }
- &ChoiceInstruction::DefaultTrustMe(offset) => {
- functor!("default_trust_me", [integer(offset)])
- }
- }
- }
-}
-
-#[derive(Debug)]
-pub(crate) enum CutInstruction {
- Cut(RegType),
- GetLevel(RegType),
- GetLevelAndUnify(RegType),
- NeckCut,
-}
-
-impl CutInstruction {
- pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
- match self {
- &CutInstruction::Cut(r) => {
- let rt_stub = reg_type_into_functor(r);
- functor!("cut", [aux(h, 0)], [rt_stub])
- }
- &CutInstruction::GetLevel(r) => {
- let rt_stub = reg_type_into_functor(r);
- functor!("get_level", [aux(h, 0)], [rt_stub])
- }
- &CutInstruction::GetLevelAndUnify(r) => {
- let rt_stub = reg_type_into_functor(r);
- functor!("get_level_and_unify", [aux(h, 0)], [rt_stub])
- }
- &CutInstruction::NeckCut => {
- functor!("neck_cut")
- }
- }
- }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub(crate) enum IndexedChoiceInstruction {
- Retry(usize),
- Trust(usize),
- Try(usize),
-}
-
-impl IndexedChoiceInstruction {
- pub(crate) fn offset(&self) -> usize {
- match self {
- &IndexedChoiceInstruction::Retry(offset) => offset,
- &IndexedChoiceInstruction::Trust(offset) => offset,
- &IndexedChoiceInstruction::Try(offset) => offset,
- }
- }
-
- pub(crate) fn to_functor(&self) -> MachineStub {
- match self {
- &IndexedChoiceInstruction::Try(offset) => {
- functor!("try", [integer(offset)])
- }
- &IndexedChoiceInstruction::Trust(offset) => {
- functor!("trust", [integer(offset)])
- }
- &IndexedChoiceInstruction::Retry(offset) => {
- functor!("retry", [integer(offset)])
- }
- }
- }
-}
-
-/// A `Line` is an instruction (cf. page 98 of wambook).
-#[derive(Debug)]
-pub(crate) enum IndexingLine {
- Indexing(IndexingInstruction),
- IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
- DynamicIndexedChoice(SliceDeque<usize>),
-}
-
-impl From<IndexingInstruction> for IndexingLine {
- #[inline]
- fn from(instr: IndexingInstruction) -> Self {
- IndexingLine::Indexing(instr)
- }
-}
-
-impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
- #[inline]
- fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
- IndexingLine::IndexedChoice(instrs)
- }
-}
-
-#[derive(Debug)]
-pub(crate) enum Line {
- Arithmetic(ArithmeticInstruction),
- Choice(ChoiceInstruction),
- Control(ControlInstruction),
- Cut(CutInstruction),
- Fact(FactInstruction),
- IndexingCode(Vec<IndexingLine>),
- IndexedChoice(IndexedChoiceInstruction),
- DynamicIndexedChoice(usize),
- Query(QueryInstruction),
-}
-
-impl Line {
- #[inline]
- pub(crate) fn is_head_instr(&self) -> bool {
- match self {
- &Line::Fact(_) => true,
- &Line::Query(_) => true,
- _ => false,
- }
- }
-
- pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
- match self {
- &Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
- &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)),
- &Line::Control(ref control_instr) => functors.push(control_instr.to_functor()),
- &Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
- &Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
- &Line::IndexingCode(ref indexing_instrs) => {
- for indexing_instr in indexing_instrs {
- match indexing_instr {
- IndexingLine::Indexing(indexing_instr) => {
- let section = indexing_instr.to_functor(h);
- h += section.len();
- functors.push(section);
- }
- IndexingLine::IndexedChoice(indexed_choice_instrs) => {
- for indexed_choice_instr in indexed_choice_instrs {
- let section = indexed_choice_instr.to_functor();
- h += section.len();
- functors.push(section);
- }
- }
- IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
- for indexed_choice_instr in indexed_choice_instrs {
- let section = functor!("dynamic", [integer(*indexed_choice_instr)]);
- h += section.len();
- functors.push(section);
- }
- }
- }
- }
- }
- &Line::IndexedChoice(ref indexed_choice_instr) => {
- functors.push(indexed_choice_instr.to_functor())
- }
- &Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
- functors.push(functor!("dynamic", [integer(*indexed_choice_instr)]));
- }
- &Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
- }
- }
-}
-
-#[inline]
-pub(crate) fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec<IndexingLine>> {
- match line {
- Line::IndexingCode(ref mut indexing_code) => Some(indexing_code),
- _ => None,
- }
-}
-
-#[inline]
-pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
- match line {
- Line::IndexingCode(ref indexing_code) => Some(indexing_code),
- _ => None,
- }
-}
-
-#[derive(Debug, Clone)]
-pub(crate) enum ArithmeticInstruction {
- Add(ArithmeticTerm, ArithmeticTerm, usize),
- Sub(ArithmeticTerm, ArithmeticTerm, usize),
- Mul(ArithmeticTerm, ArithmeticTerm, usize),
- Pow(ArithmeticTerm, ArithmeticTerm, usize),
- IntPow(ArithmeticTerm, ArithmeticTerm, usize),
- IDiv(ArithmeticTerm, ArithmeticTerm, usize),
- Max(ArithmeticTerm, ArithmeticTerm, usize),
- Min(ArithmeticTerm, ArithmeticTerm, usize),
- IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize),
- RDiv(ArithmeticTerm, ArithmeticTerm, usize),
- Div(ArithmeticTerm, ArithmeticTerm, usize),
- Shl(ArithmeticTerm, ArithmeticTerm, usize),
- Shr(ArithmeticTerm, ArithmeticTerm, usize),
- Xor(ArithmeticTerm, ArithmeticTerm, usize),
- And(ArithmeticTerm, ArithmeticTerm, usize),
- Or(ArithmeticTerm, ArithmeticTerm, usize),
- Mod(ArithmeticTerm, ArithmeticTerm, usize),
- Rem(ArithmeticTerm, ArithmeticTerm, usize),
- Gcd(ArithmeticTerm, ArithmeticTerm, usize),
- Sign(ArithmeticTerm, usize),
- Cos(ArithmeticTerm, usize),
- Sin(ArithmeticTerm, usize),
- Tan(ArithmeticTerm, usize),
- Log(ArithmeticTerm, usize),
- Exp(ArithmeticTerm, usize),
- ACos(ArithmeticTerm, usize),
- ASin(ArithmeticTerm, usize),
- ATan(ArithmeticTerm, usize),
- ATan2(ArithmeticTerm, ArithmeticTerm, usize),
- Sqrt(ArithmeticTerm, usize),
- Abs(ArithmeticTerm, usize),
- Float(ArithmeticTerm, usize),
- Truncate(ArithmeticTerm, usize),
- Round(ArithmeticTerm, usize),
- Ceiling(ArithmeticTerm, usize),
- Floor(ArithmeticTerm, usize),
- Neg(ArithmeticTerm, usize),
- Plus(ArithmeticTerm, usize),
- BitwiseComplement(ArithmeticTerm, usize),
-}
-
-fn arith_instr_unary_functor(
- h: usize,
- name: &'static str,
- at: &ArithmeticTerm,
- t: usize,
-) -> MachineStub {
- let at_stub = at.into_functor();
-
- functor!(name, [aux(h, 0), integer(t)], [at_stub])
-}
-
-fn arith_instr_bin_functor(
- h: usize,
- name: &'static str,
- at_1: &ArithmeticTerm,
- at_2: &ArithmeticTerm,
- t: usize,
-) -> MachineStub {
- let at_1_stub = at_1.into_functor();
- let at_2_stub = at_2.into_functor();
-
- functor!(
- name,
- [aux(h, 0), aux(h, 1), integer(t)],
- [at_1_stub, at_2_stub]
- )
-}
-
-impl ArithmeticInstruction {
- pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
- match self {
- &ArithmeticInstruction::Add(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "add", at_1, at_2, t)
- }
- &ArithmeticInstruction::Sub(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "sub", at_1, at_2, t)
- }
- &ArithmeticInstruction::Mul(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "mul", at_1, at_2, t)
- }
- &ArithmeticInstruction::IntPow(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "int_pow", at_1, at_2, t)
- }
- &ArithmeticInstruction::Pow(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "pow", at_1, at_2, t)
- }
- &ArithmeticInstruction::IDiv(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "idiv", at_1, at_2, t)
- }
- &ArithmeticInstruction::Max(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "max", at_1, at_2, t)
- }
- &ArithmeticInstruction::Min(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "min", at_1, at_2, t)
- }
- &ArithmeticInstruction::IntFloorDiv(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "int_floor_div", at_1, at_2, t)
- }
- &ArithmeticInstruction::RDiv(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "rdiv", at_1, at_2, t)
- }
- &ArithmeticInstruction::Div(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "div", at_1, at_2, t)
- }
- &ArithmeticInstruction::Shl(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "shl", at_1, at_2, t)
- }
- &ArithmeticInstruction::Shr(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "shr", at_1, at_2, t)
- }
- &ArithmeticInstruction::Xor(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "xor", at_1, at_2, t)
- }
- &ArithmeticInstruction::And(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "and", at_1, at_2, t)
- }
- &ArithmeticInstruction::Or(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "or", at_1, at_2, t)
- }
- &ArithmeticInstruction::Mod(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "mod", at_1, at_2, t)
- }
- &ArithmeticInstruction::Rem(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "rem", at_1, at_2, t)
- }
- &ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => {
- arith_instr_bin_functor(h, "rem", at_1, at_2, t)
- }
- &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::Float(ref at, t) => {
- arith_instr_unary_functor(h, "float", at, t)
- }
- &ArithmeticInstruction::Truncate(ref at, t) => {
- arith_instr_unary_functor(h, "truncate", at, t)
- }
- &ArithmeticInstruction::Round(ref at, t) => {
- arith_instr_unary_functor(h, "round", at, t)
- }
- &ArithmeticInstruction::Ceiling(ref at, t) => {
- arith_instr_unary_functor(h, "ceiling", at, t)
- }
- &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::BitwiseComplement(ref at, t) => {
- arith_instr_unary_functor(h, "\\", at, t)
- }
- }
- }
-}
-
-#[derive(Debug)]
-pub(crate) enum ControlInstruction {
- Allocate(usize), // num_frames.
- // name, arity, perm_vars after threshold, last call, use default call policy.
- CallClause(ClauseType, usize, usize, bool, bool),
- Deallocate,
- JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
- RevJmpBy(usize), // notice the lack of context change as in
- // JmpBy. RevJmpBy is used only to patch extensible
- // predicates together.
- Proceed,
-}
-
-impl ControlInstruction {
- pub(crate) fn perm_vars(&self) -> Option<usize> {
- match self {
- ControlInstruction::CallClause(_, _, num_cells, ..) => Some(*num_cells),
- ControlInstruction::JmpBy(_, _, num_cells, ..) => Some(*num_cells),
- _ => None,
- }
- }
-
- pub(crate) fn to_functor(&self) -> MachineStub {
- match self {
- &ControlInstruction::Allocate(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::JmpBy(_, offset, ..) => {
- functor!("jmp_by", [integer(offset)])
- }
- &ControlInstruction::RevJmpBy(offset) => {
- functor!("rev_jmp_by", [integer(offset)])
- }
- &ControlInstruction::Proceed => {
- functor!("proceed")
- }
- }
- }
-}
-
-/// `IndexingInstruction` cf. page 110 of wambook.
-#[derive(Debug)]
-pub(crate) enum IndexingInstruction {
- // The first index is the optimal argument being indexed.
- SwitchOnTerm(
- usize,
- IndexingCodePtr,
- IndexingCodePtr,
- IndexingCodePtr,
- IndexingCodePtr,
- ),
- SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
- SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
-}
-
-impl IndexingInstruction {
- pub(crate) fn to_functor(&self, mut h: usize) -> MachineStub {
- match self {
- &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
- functor!(
- "switch_on_term",
- [
- integer(arg),
- indexing_code_ptr(h, vars),
- indexing_code_ptr(h, constants),
- indexing_code_ptr(h, lists),
- indexing_code_ptr(h, structures)
- ]
- )
- }
- &IndexingInstruction::SwitchOnConstant(ref constants) => {
- let mut key_value_list_stub = vec![];
- let orig_h = h;
-
- h += 2; // skip the 2-cell "switch_on_constant" functor.
-
- for (c, ptr) in constants.iter() {
- let key_value_pair = functor!(
- ":",
- SharedOpDesc::new(600, XFY),
- [constant(c), indexing_code_ptr(h + 3, *ptr)]
- );
-
- key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
- key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
- key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
- h + 3 + key_value_pair.len(),
- )));
-
- h += key_value_pair.len() + 3;
- key_value_list_stub.extend(key_value_pair.into_iter());
- }
-
- key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
-
- functor!(
- "switch_on_constant",
- [aux(orig_h, 0)],
- [key_value_list_stub]
- )
- }
- &IndexingInstruction::SwitchOnStructure(ref structures) => {
- let mut key_value_list_stub = vec![];
- let orig_h = h;
-
- h += 2; // skip the 2-cell "switch_on_constant" functor.
-
- for ((name, arity), ptr) in structures.iter() {
- let predicate_indicator_stub = functor!(
- "/",
- SharedOpDesc::new(400, YFX),
- [clause_name(name.clone()), integer(*arity)]
- );
-
- let key_value_pair = functor!(
- ":",
- SharedOpDesc::new(600, XFY),
- [aux(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
- [predicate_indicator_stub]
- );
-
- key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
- key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
- key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
- h + 3 + key_value_pair.len(),
- )));
-
- h += key_value_pair.len() + 3;
- key_value_list_stub.extend(key_value_pair.into_iter());
- }
-
- key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
-
- functor!(
- "switch_on_structure",
- [aux(orig_h, 0)],
- [key_value_list_stub]
- )
- }
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub(crate) enum FactInstruction {
- GetConstant(Level, Constant, RegType),
- GetList(Level, RegType),
- GetPartialString(Level, String, RegType, bool),
- GetStructure(ClauseType, usize, RegType),
- GetValue(RegType, usize),
- GetVariable(RegType, usize),
- UnifyConstant(Constant),
- UnifyLocalValue(RegType),
- UnifyVariable(RegType),
- UnifyValue(RegType),
- UnifyVoid(usize),
-}
-
-impl FactInstruction {
- pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
- match self {
- &FactInstruction::GetConstant(lvl, ref c, r) => {
- let lvl_stub = lvl.into_functor();
- let rt_stub = reg_type_into_functor(r);
-
- functor!(
- "get_constant",
- [aux(h, 0), constant(h, c), aux(h, 1)],
- [lvl_stub, rt_stub]
- )
- }
- &FactInstruction::GetList(lvl, r) => {
- let lvl_stub = lvl.into_functor();
- let rt_stub = reg_type_into_functor(r);
-
- 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 rt_stub = reg_type_into_functor(r);
-
- functor!(
- "get_structure",
- [clause_name(ct.name()), integer(arity), aux(h, 0)],
- [rt_stub]
- )
- }
- &FactInstruction::GetValue(r, arg) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("get_value", [aux(h, 0), integer(arg)], [rt_stub])
- }
- &FactInstruction::GetVariable(r, arg) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
- }
- &FactInstruction::UnifyConstant(ref c) => {
- functor!("unify_constant", [constant(h, c)], [])
- }
- &FactInstruction::UnifyLocalValue(r) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("unify_local_value", [aux(h, 0)], [rt_stub])
- }
- &FactInstruction::UnifyVariable(r) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("unify_variable", [aux(h, 0)], [rt_stub])
- }
- &FactInstruction::UnifyValue(r) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("unify_value", [aux(h, 0)], [rt_stub])
- }
- &FactInstruction::UnifyVoid(vars) => {
- functor!("unify_void", [integer(vars)])
- }
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub(crate) 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),
- PutVariable(RegType, usize),
- SetConstant(Constant),
- SetLocalValue(RegType),
- SetVariable(RegType),
- SetValue(RegType),
- SetVoid(usize),
-}
-
-impl QueryInstruction {
- pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
- match self {
- &QueryInstruction::PutUnsafeValue(norm, arg) => {
- functor!("put_unsafe_value", [integer(norm), integer(arg)])
- }
- &QueryInstruction::PutConstant(lvl, ref c, r) => {
- let lvl_stub = lvl.into_functor();
- let rt_stub = reg_type_into_functor(r);
-
- functor!(
- "put_constant",
- [aux(h, 0), constant(h, c), aux(h, 1)],
- [lvl_stub, rt_stub]
- )
- }
- &QueryInstruction::PutList(lvl, r) => {
- let lvl_stub = lvl.into_functor();
- let rt_stub = 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);
-
- 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 rt_stub = reg_type_into_functor(r);
-
- functor!(
- "put_structure",
- [clause_name(ct.name()), integer(arity), aux(h, 0)],
- [rt_stub]
- )
- }
- &QueryInstruction::PutValue(r, arg) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("put_value", [aux(h, 0), integer(arg)], [rt_stub])
- }
- &QueryInstruction::GetVariable(r, arg) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
- }
- &QueryInstruction::PutVariable(r, arg) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub])
- }
- &QueryInstruction::SetConstant(ref c) => {
- functor!("set_constant", [constant(h, c)], [])
- }
- &QueryInstruction::SetLocalValue(r) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("set_local_value", [aux(h, 0)], [rt_stub])
- }
- &QueryInstruction::SetVariable(r) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("set_variable", [aux(h, 0)], [rt_stub])
- }
- &QueryInstruction::SetValue(r) => {
- let rt_stub = reg_type_into_functor(r);
-
- functor!("set_value", [aux(h, 0)], [rt_stub])
- }
- &QueryInstruction::SetVoid(vars) => {
- functor!("set_void", [integer(vars)])
- }
- }
- }
-}
-
-pub(crate) type CompiledFact = Vec<FactInstruction>;
-
-pub(crate) type Code = Vec<Line>;
diff --git a/src/iterators.rs b/src/iterators.rs
index a83c5796..4f255584 100644
--- a/src/iterators.rs
+++ b/src/iterators.rs
@@ -1,9 +1,8 @@
-use prolog_parser::ast::*;
-use prolog_parser::rc_atom;
-
-use crate::clause_types::*;
+use crate::atom_table::*;
use crate::forms::*;
+use crate::instructions::*;
use crate::machine::machine_indices::*;
+use crate::parser::ast::*;
use std::cell::Cell;
use std::collections::VecDeque;
@@ -16,10 +15,10 @@ use std::vec::Vec;
pub(crate) enum TermRef<'a> {
AnonVar(Level),
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>),
+ Literal(Level, &'a Cell<RegType>, &'a Literal),
+ Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
+ PartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
+ Var(Level, &'a Cell<VarReg>, Rc<String>),
}
impl<'a> TermRef<'a> {
@@ -27,7 +26,7 @@ impl<'a> TermRef<'a> {
match self {
TermRef::AnonVar(lvl)
| TermRef::Cons(lvl, ..)
- | TermRef::Constant(lvl, ..)
+ | TermRef::Literal(lvl, ..)
| TermRef::Var(lvl, ..)
| TermRef::Clause(lvl, ..) => lvl,
TermRef::PartialString(lvl, ..) => lvl,
@@ -38,82 +37,31 @@ impl<'a> TermRef<'a> {
#[derive(Debug)]
pub(crate) enum TermIterState<'a> {
AnonVar(Level),
- Constant(Level, &'a Cell<RegType>, &'a Constant),
- Clause(
- Level,
- usize,
- &'a Cell<RegType>,
- ClauseType,
- &'a Vec<Box<Term>>,
- ),
+ Literal(Level, &'a Cell<RegType>, &'a Literal),
+ Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
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));
- }
- Term::Constant(_, Constant::String(tail)) => {
- string += &tail;
- return Some((string, None));
- }
- _ => {
- return None;
- }
- }
+ InitialPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
+ FinalPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
+ Var(Level, &'a Cell<VarReg>, Rc<String>),
}
impl<'a> TermIterState<'a> {
pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
match term {
- &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())
- } else {
- ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default())
- };
-
+ Term::AnonVar => TermIterState::AnonVar(lvl),
+ Term::Clause(cell, name, subterms) => {
+ let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default());
TermIterState::Clause(lvl, 0, cell, ct, subterms)
}
- &Term::Cons(ref cell, ref head, ref tail) => {
+ Term::Cons(cell, head, 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::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
+ Term::PartialString(cell, string_buf, tail) => {
+ TermIterState::InitialPartialString(lvl, cell, *string_buf, tail)
+ }
+ Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()),
}
}
}
@@ -129,11 +77,11 @@ impl<'a> QueryIterator<'a> {
.push(TermIterState::subterm_to_state(lvl, term));
}
- fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
+ fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
let state_stack = terms
.iter()
.rev()
- .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref()))
+ .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
.collect();
QueryIterator { state_stack }
@@ -141,29 +89,19 @@ impl<'a> QueryIterator<'a> {
fn from_term(term: &'a Term) -> Self {
let state = match term {
- &Term::AnonVar => {
+ Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => {
return QueryIterator {
state_stack: vec![],
}
}
- &Term::Clause(ref r, ref name, ref terms, ref fixity) => TermIterState::Clause(
+ Term::Clause(r, name, terms) => TermIterState::Clause(
Level::Root,
0,
r,
- ClauseType::from(name.clone(), terms.len(), fixity.clone()),
+ ClauseType::from(*name, terms.len()),
terms,
),
- &Term::Cons(..) => {
- return QueryIterator {
- state_stack: vec![],
- }
- }
- &Term::Constant(_, _) => {
- return QueryIterator {
- state_stack: vec![],
- }
- }
- &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Root, cell, (*var).clone()),
+ Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
};
QueryIterator {
@@ -173,8 +111,8 @@ impl<'a> QueryIterator<'a> {
fn new(term: &'a QueryTerm) -> Self {
match term {
- &QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms, _) => {
- let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN, terms);
+ &QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => {
+ let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms);
QueryIterator {
state_stack: vec![state],
}
@@ -186,7 +124,7 @@ impl<'a> QueryIterator<'a> {
}
}
&QueryTerm::UnblockedCut(ref cell) => {
- let state = TermIterState::Var(Level::Root, cell, rc_atom!("!"));
+ let state = TermIterState::Var(Level::Root, cell, Rc::new("!".to_string()));
QueryIterator {
state_stack: vec![state],
}
@@ -225,10 +163,10 @@ impl<'a> Iterator for QueryIterator<'a> {
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
if child_num == child_terms.len() {
match ct {
- ClauseType::CallN => {
- self.push_subterm(Level::Shallow, child_terms[0].as_ref())
+ ClauseType::CallN(_) => {
+ self.push_subterm(Level::Shallow, &child_terms[0]);
}
- ClauseType::Named(..) | ClauseType::Op(..) => {
+ ClauseType::Named(..) => {
return match lvl {
Level::Root => None,
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
@@ -247,33 +185,30 @@ impl<'a> Iterator for QueryIterator<'a> {
child_terms,
));
- self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
+ self.push_subterm(lvl.child_level(), &child_terms[child_num]);
}
}
TermIterState::InitialCons(lvl, cell, head, tail) => {
- if let Some((string, tail)) = is_partial_string(head, tail) {
- self.state_stack
- .push(TermIterState::PartialString(lvl, cell, string, tail));
+ self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, 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::InitialPartialString(lvl, cell, string, tail) => {
+ self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
+ if let Some(tail) = tail {
self.push_subterm(lvl.child_level(), tail);
- self.push_subterm(lvl.child_level(), head);
}
}
- TermIterState::PartialString(lvl, cell, string, tail) => {
+ TermIterState::FinalPartialString(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));
}
- TermIterState::Constant(lvl, cell, constant) => {
- return Some(TermRef::Constant(lvl, cell, constant));
+ TermIterState::Literal(lvl, cell, constant) => {
+ return Some(TermRef::Literal(lvl, cell, constant));
}
TermIterState::Var(lvl, cell, var) => {
return Some(TermRef::Var(lvl, cell, var));
@@ -297,10 +232,10 @@ impl<'a> FactIterator<'a> {
.push_back(TermIterState::subterm_to_state(lvl, term));
}
- pub(crate) fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
+ pub(crate) fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
let state_queue = terms
.iter()
- .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref()))
+ .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
.collect();
FactIterator {
@@ -311,23 +246,31 @@ impl<'a> FactIterator<'a> {
fn new(term: &'a Term, iterable_root: bool) -> Self {
let states = match term {
- &Term::AnonVar => {
+ 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());
+ Term::Clause(cell, name, terms) => {
+ let ct = ClauseType::from(*name, terms.len());
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
}
- &Term::Cons(ref cell, ref head, ref tail) => vec![TermIterState::InitialCons(
+ Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
Level::Root,
cell,
head.as_ref(),
tail.as_ref(),
)],
- &Term::Constant(ref cell, ref constant) => {
- vec![TermIterState::Constant(Level::Root, cell, constant)]
+ Term::PartialString(cell, string_buf, tail_opt) => {
+ vec![TermIterState::InitialPartialString(
+ Level::Root,
+ cell,
+ *string_buf,
+ tail_opt,
+ )]
}
- &Term::Var(ref cell, ref var) => {
+ Term::Literal(cell, constant) => {
+ vec![TermIterState::Literal(Level::Root, cell, constant)]
+ }
+ Term::Var(cell, var) => {
vec![TermIterState::Var(Level::Root, cell, var.clone())]
}
};
@@ -359,21 +302,20 @@ 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);
- }
+ self.push_subterm(Level::Deep, head);
+ self.push_subterm(Level::Deep, tail);
- return Some(TermRef::PartialString(lvl, cell, string, tail));
- } else {
- self.push_subterm(Level::Deep, head);
+ return Some(TermRef::Cons(lvl, cell, head, tail));
+ }
+ TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => {
+ if let Some(tail) = tail_opt {
self.push_subterm(Level::Deep, tail);
-
- return Some(TermRef::Cons(lvl, cell, head, tail));
}
+
+ return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt));
}
- TermIterState::Constant(lvl, cell, constant) => {
- return Some(TermRef::Constant(lvl, cell, constant))
+ TermIterState::Literal(lvl, cell, constant) => {
+ return Some(TermRef::Literal(lvl, cell, constant))
}
TermIterState::Var(lvl, cell, var) => {
return Some(TermRef::Var(lvl, cell, var));
@@ -386,17 +328,17 @@ impl<'a> Iterator for FactIterator<'a> {
}
}
-pub(crate) fn post_order_iter(term: &Term) -> QueryIterator {
+pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> {
QueryIterator::from_term(term)
}
-pub(crate) fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator {
+pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> {
FactIterator::new(term, iterable_root)
}
#[derive(Debug)]
pub(crate) enum ChunkedTerm<'a> {
- HeadClause(ClauseName, &'a Vec<Box<Term>>),
+ HeadClause(Atom, &'a Vec<Term>),
BodyTerm(&'a QueryTerm),
}
@@ -407,7 +349,7 @@ pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> Query
impl<'a> ChunkedTerm<'a> {
pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> {
match self {
- &ChunkedTerm::BodyTerm(ref qt) => QueryIterator::new(qt),
+ &ChunkedTerm::BodyTerm(qt) => QueryIterator::new(qt),
&ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms),
}
}
@@ -517,7 +459,7 @@ impl<'a> ChunkedIterator<'a> {
while let Some(term) = item {
match term {
ChunkedTerm::HeadClause(_, terms) => {
- if contains_cut_var(terms.iter().map(|t| t.as_ref())) {
+ if contains_cut_var(terms.iter()) {
self.cut_var_in_head = true;
}
@@ -547,13 +489,16 @@ impl<'a> ChunkedIterator<'a> {
arity = 1;
break;
}
- ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => result.push(term),
+ ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => {
+ self.deep_cut_encountered = true;
+ result.push(term);
+ }
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => {
result.push(term)
}
ChunkedTerm::BodyTerm(&QueryTerm::Clause(
_,
- ClauseType::CallN,
+ ClauseType::CallN(_),
ref subterms,
_,
)) => {
diff --git a/src/lib.rs b/src/lib.rs
index 1fd4a4fb..99c5d9f9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,25 +1,34 @@
-#[cfg(feature = "num-rug-adapter")]
-use num_rug_adapter as rug;
-#[cfg(feature = "rug")]
-use rug;
+#![recursion_limit = "4112"]
#[macro_use]
-mod macros;
+extern crate static_assertions;
+
+#[macro_use]
+pub mod macros;
+#[macro_use]
+pub mod atom_table;
+#[macro_use]
+pub mod arena;
+#[macro_use]
+pub mod parser;
mod allocator;
mod arithmetic;
-mod clause_types;
-mod codegen;
+pub mod codegen;
mod debray_allocator;
mod fixtures;
mod forms;
mod heap_iter;
-mod heap_print;
+pub mod heap_print;
mod indexing;
-mod instructions;
+#[macro_use]
+pub mod instructions {
+ include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
+}
mod iterators;
pub mod machine;
+mod raw_block;
pub mod read;
mod targets;
-mod write;
+pub mod types;
-use machine::*;
+use instructions::instr;
diff --git a/src/lib/arithmetic.pl b/src/lib/arithmetic.pl
index dc9ce077..ee719a18 100644
--- a/src/lib/arithmetic.pl
+++ b/src/lib/arithmetic.pl
@@ -94,12 +94,6 @@ number_to_rational(Eps0, Real0, Fraction) :-
),
!.
-number(X) :-
- ( integer(X)
- ; float(X)
- ; rational(X)
- ).
-
stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :-
Fn1 is A + C,
Fd1 is B + D,
diff --git a/src/lib/atts.pl b/src/lib/atts.pl
index 5906466b..a9369426 100644
--- a/src/lib/atts.pl
+++ b/src/lib/atts.pl
@@ -24,30 +24,42 @@
'$absent_from_list'(Ls, Attr).
'$absent_from_list'(X, Attr) :-
- ( var(X) -> true
- ; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr)
+ ( var(X) ->
+ true
+ ; X = [L|Ls],
+ L \= Attr ->
+ '$absent_from_list'(Ls, Attr)
).
'$get_attr'(V, Attr) :-
- '$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr).
+ '$get_attr_list'(V, Ls),
+ nonvar(Ls),
+ '$get_from_list'(Ls, V, Attr).
'$get_from_list'([L|Ls], V, Attr) :-
nonvar(L),
- ( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr)
- ; L = Attr, '$enqueue_attr_var'(V)
+ ( L \= Attr ->
+ nonvar(Ls),
+ '$get_from_list'(Ls, V, Attr)
+ ; L = Attr,
+ '$enqueue_attr_var'(V)
).
'$put_attr'(V, Attr) :-
- '$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr).
+ '$get_attr_list'(V, Ls),
+ '$add_to_list'(Ls, V, Attr).
'$add_to_list'(Ls, V, Attr) :-
- ( var(Ls) ->
- Ls = [Attr | _], '$enqueue_attr_var'(V)
- ; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr)
+ ( var(Ls) ->
+ Ls = [Attr | _],
+ '$enqueue_attr_var'(V)
+ ; Ls = [_ | Ls0],
+ '$add_to_list'(Ls0, V, Attr)
).
'$del_attr'(Ls0, _, _) :-
- var(Ls0), !.
+ var(Ls0),
+ !.
'$del_attr'(Ls0, V, Attr) :-
Ls0 = [Att | Ls1],
nonvar(Att),
@@ -134,22 +146,22 @@ put_attr(Name, Arity, Module) -->
[(put_atts(V, +Attr) :-
!,
functor(Attr, Head, Arity),
- functor(AttrForm, Head, Arity),
- '$get_attr_list'(V, Ls),
- atts:'$del_attr'(Ls, V, Module:AttrForm),
- atts:'$put_attr'(V, Module:Attr)),
+ functor(AttrForm, Head, Arity),
+ '$get_attr_list'(V, Ls),
+ atts:'$del_attr'(Ls, V, Module:AttrForm),
+ atts:'$put_attr'(V, Module:Attr)),
(put_atts(V, Attr) :-
!,
functor(Attr, Head, Arity),
- functor(AttrForm, Head, Arity),
- '$get_attr_list'(V, Ls),
- atts:'$del_attr'(Ls, V, Module:AttrForm),
- atts:'$put_attr'(V, Module:Attr)),
+ functor(AttrForm, Head, Arity),
+ '$get_attr_list'(V, Ls),
+ atts:'$del_attr'(Ls, V, Module:AttrForm),
+ atts:'$put_attr'(V, Module:Attr)),
(put_atts(V, -Attr) :-
!,
functor(Attr, _, _),
- '$get_attr_list'(V, Ls),
- atts:'$del_attr'(Ls, V, Module:Attr))].
+ '$get_attr_list'(V, Ls),
+ atts:'$del_attr'(Ls, V, Module:Attr))].
get_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity) },
diff --git a/src/lib/between.pl b/src/lib/between.pl
index 5a0d5bab..2711e8e8 100644
--- a/src/lib/between.pl
+++ b/src/lib/between.pl
@@ -12,17 +12,18 @@ between(Lower, Upper, X) :-
( nonvar(X) ->
Lower =< X,
X =< Upper
- ; compare(Ord, Lower, Upper),
- between_(Ord, Lower, Upper, X)
+ ; Lower =< Upper,
+ between_(Lower, Upper, X)
).
-between_(<, Lower0, Upper, X) :-
- ( X = Lower0
- ; Lower1 is Lower0 + 1,
- compare(Ord, Lower1, Upper),
- between_(Ord, Lower1, Upper, X)
- ).
-between_(=, Upper, Upper, Upper).
+between_(Lower, Upper, Lower1) :-
+ Lower < Upper,
+ !,
+ ( Lower1 = Lower
+ ; Lower0 is Lower + 1,
+ between_(Lower0, Upper, Lower1)
+ ).
+between_(Lower, Lower, Lower).
enumerate_nats(I, I).
enumerate_nats(I0, N) :-
diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl
index 00a26238..e21d441e 100644
--- a/src/lib/builtins.pl
+++ b/src/lib/builtins.pl
@@ -1,4 +1,4 @@
-:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
+:- module(builtins, [(=)/2, (\=)/2, (\+)/1, !/0, (',')/2, (->)/2, (;)/2,
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
abolish/1, asserta/1, assertz/1,
@@ -59,65 +59,62 @@ call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G).
call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H).
+% dynamic module resolution.
Module : Predicate :-
- ( atom(Module) ->
- '$module_call'(Module, Predicate)
- ;
- throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
-
-% dynamic module resolution.
-
:(Module, Predicate, A1) :-
- ( atom(Module) -> '$module_call'(A1, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) ->
+ '$module_call'(A1, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2) :-
- ( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) :-
- ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
- ; throw(error(type_error(atom, Module), (:)/2))
+ ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
+ ; throw(error(type_error(atom, Module), (:)/2))
).
% flags.
@@ -205,153 +202,184 @@ repeat.
repeat :- repeat.
+:- meta_predicate ','(0,0).
-:- meta_predicate ','(0, 0).
+:- meta_predicate ;(0,0).
-:- meta_predicate ','(0, +, +).
+:- meta_predicate ->(0,0).
-:- meta_predicate ;(0, 0).
-:- meta_predicate ;(0, 0, +).
+G1 -> G2 :- control_entry_point((G1 -> G2)).
-:- meta_predicate ->(0, 0).
-:- meta_predicate ->(0, 0, +).
+:- non_counted_backtracking staggered_if_then/2.
+staggered_if_then(G1, G2) :-
+ '$get_staggered_cp'(B),
+ call('$call'(G1)),
+ '$set_cp'(B),
+ call('$call'(G2)).
-','(G1, G2) :-
- '$get_b_value'(B),
- ( '$call_with_default_policy'(var(G1)) ->
- throw(error(instantiation_error, (',')/2))
- ; '$call_with_default_policy'(','(G1, G2, B))
- ).
+G1 ; G2 :- control_entry_point((G1 ; G2)).
-';'(G1, G2) :-
- '$get_b_value'(B),
- ( '$call_with_default_policy'(var(G1)) ->
- throw(error(instantiation_error, (';')/2))
- ; '$call_with_default_policy'(';'(G1, G2, B))
- ).
+:- non_counted_backtracking staggered_sc/2.
+staggered_sc(G, _) :- call('$call'(G)).
+staggered_sc(_, G) :- call('$call'(G)).
-G1 -> G2 :-
- '$get_b_value'(B),
- ( '$call_with_default_policy'(var(G1)) ->
- throw(error(instantiation_error, (->)/2))
- ; '$call_with_default_policy'(->(G1, G2, B))
- ).
-
-
-:-non_counted_backtracking call_or_cut/3.
-call_or_cut(G, B, ErrorPI) :-
- ( '$call_with_default_policy'(var(G)) ->
- throw(error(instantiation_error, ErrorPI))
- ; '$call_with_default_policy'(call_or_cut(G, B))
- ).
+!.
+:- non_counted_backtracking set_cp/1.
-:- non_counted_backtracking control_functor/1.
+set_cp(B) :- '$set_cp'(B).
-control_functor(_:G) :- nonvar(G), control_functor(G).
-control_functor(call(_:C)) :- C == !.
-control_functor(!).
-control_functor((_,_)).
-control_functor((_;_)).
-control_functor((_->_)).
+','(G1, G2) :- control_entry_point((G1, G2)).
+:- non_counted_backtracking control_entry_point/1.
-:- non_counted_backtracking call_or_cut/2.
+control_entry_point(G) :-
+ functor(G, Name, Arity),
+ catch(builtins:control_entry_point_(G),
+ dispatch_prep_error,
+ builtins:throw(error(type_error(callable, G), Name/Arity))).
-call_or_cut(G, B) :-
- ( nonvar(G),
- '$call_with_default_policy'(control_functor(G)) ->
- '$call_with_default_policy'(call_or_cut_interp(G, B))
- ; call(G)
- ).
+:- non_counted_backtracking control_entry_point_/1.
-:- non_counted_backtracking call_or_cut_interp/2.
+control_entry_point_(G) :-
+ '$get_cp'(B),
+ dispatch_prep(G,B,Conts),
+ dispatch_call_list(Conts).
-call_or_cut_interp(_ : G, B) :-
- call_or_cut_interp(G, B).
-call_or_cut_interp(call(_ : !), B) :-
- !. % '$set_cp'(B).
-call_or_cut_interp(!, B) :-
- '$set_cp'(B).
-call_or_cut_interp((G1, G2), B) :-
- '$call_with_default_policy'(','(G1, G2, B)).
-call_or_cut_interp((G1 ; G2), B) :-
- '$call_with_default_policy'(';'(G1, G2, B)).
-call_or_cut_interp((G1 -> G2), B) :-
- '$call_with_default_policy'(->(G1, G2, B)).
+:- non_counted_backtracking cont_list_to_goal/2.
-:- non_counted_backtracking (',')/3.
+cont_list_goal([Cont], Cont) :- !.
+cont_list_goal(Conts, builtins:dispatch_call_list(Conts)).
-','(G1, G2, B) :-
- ( nonvar(G1),
- '$call_with_default_policy'(control_functor(G1)) ->
- '$call_with_default_policy'(call_or_cut_interp(G1, B)),
- '$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
- ; call(G1),
- '$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
- ).
-:- non_counted_backtracking (;)/3.
+:- non_counted_backtracking module_qualified_cut/1.
-';'(G1, G2, B) :-
- ( nonvar(G1),
- '$call_with_default_policy'(control_functor(G1)) ->
- '$call_with_default_policy'(';-interp'(G1, G2, B))
- ; call(G1)
- ; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
+module_qualified_cut(Gs) :-
+ ( functor(Gs, call, 1) ->
+ arg(1, Gs, G1)
+ ; Gs = G1
+ ),
+ functor(G1, (:), 2),
+ arg(2, G1, G2),
+ G2 == !.
+
+
+:- non_counted_backtracking dispatch_prep/3.
+
+dispatch_prep(Gs, B, [Cont|Conts]) :-
+ ( callable(Gs) ->
+ ( functor(Gs, ',', 2) ->
+ arg(1, Gs, G1),
+ arg(2, Gs, G2),
+ dispatch_prep(G1, B, IConts1),
+ cont_list_goal(IConts1, Cont),
+ dispatch_prep(G2, B, Conts)
+ ; functor(Gs, ';', 2) ->
+ arg(1, Gs, G1),
+ arg(2, Gs, G2),
+ dispatch_prep(G1, B, IConts0),
+ dispatch_prep(G2, B, IConts1),
+ cont_list_goal(IConts0, Cont0),
+ cont_list_goal(IConts1, Cont1),
+ Cont = builtins:staggered_sc(Cont0, Cont1),
+ Conts = []
+ ; functor(Gs, ->, 2) ->
+ arg(1, Gs, G1),
+ arg(2, Gs, G2),
+ dispatch_prep(G1, B, IConts1),
+ dispatch_prep(G2, B, IConts2),
+ cont_list_goal(IConts1, Cont1),
+ cont_list_goal(IConts2, Cont2),
+ Cont = builtins:staggered_if_then(Cont1, Cont2),
+ Conts = []
+ ; ( Gs == ! ; module_qualified_cut(Gs) ) ->
+ Cont = builtins:set_cp(B),
+ Conts = []
+ ; Cont = Gs,
+ Conts = []
+ )
+ ; var(Gs) ->
+ Cont = Gs,
+ Conts = []
+ ; throw(dispatch_prep_error)
).
-:- non_counted_backtracking ';-interp'/3.
+:- non_counted_backtracking dispatch_call_list/1.
-';-interp'((G1 -> G2), G3, B) :-
+dispatch_call_list([]).
+dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :-
!,
- ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
- '$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
- ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
- ).
-';-interp'(_:(G1 -> G2), G3, B) :-
+ '$call'(G1),
+ '$call'(G2),
+ '$call'(G3),
+ '$call'(G4),
+ '$call'(G5),
+ '$call'(G6),
+ '$call'(G7),
+ '$call'(G8),
+ '$call_with_default_policy'(dispatch_call_list(Gs)).
+dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :-
!,
- ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
- '$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
- ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
- ).
-';-interp'(G1, G2, B) :-
- ( '$call_with_default_policy'(call_or_cut_interp(G1, B))
- ; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
- ).
-
+ '$call'(G1),
+ '$call'(G2),
+ '$call'(G3),
+ '$call'(G4),
+ '$call'(G5),
+ '$call'(G6),
+ '$call'(G7).
+dispatch_call_list([G1,G2,G3,G4,G5,G6]) :-
+ !,
+ '$call'(G1),
+ '$call'(G2),
+ '$call'(G3),
+ '$call'(G4),
+ '$call'(G5),
+ '$call'(G6).
+dispatch_call_list([G1,G2,G3,G4,G5]) :-
+ !,
+ '$call'(G1),
+ '$call'(G2),
+ '$call'(G3),
+ '$call'(G4),
+ '$call'(G5).
+dispatch_call_list([G1,G2,G3,G4]) :-
+ !,
+ '$call'(G1),
+ '$call'(G2),
+ '$call'(G3),
+ '$call'(G4).
+dispatch_call_list([G1,G2,G3]) :-
+ !,
+ '$call'(G1),
+ '$call'(G2),
+ '$call'(G3).
+dispatch_call_list([G1,G2]) :-
+ !,
+ '$call'(G1),
+ '$call'(G2).
+dispatch_call_list([G1]) :-
+ '$call'(G1).
-:- non_counted_backtracking (->)/3.
-
-->(G1, G2, B) :-
- ( nonvar(G1),
- '$call_with_default_policy'(control_functor(G1)) ->
- ( '$call_with_default_policy'(call_or_cut_interp(G1, B)) ->
- '$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
- )
- ; call(G1) ->
- '$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
- ).
% univ.
:- non_counted_backtracking univ_errors/3.
univ_errors(Term, List, N) :-
- '$skip_max_list'(N, -1, List, R),
- ( var(R) ->
- ( var(Term),
- throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
- ; true
- )
+ '$skip_max_list'(N, _, List, R),
+ ( var(R) ->
+ ( var(Term),
+ throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
+ ; true
+ )
; R \== [] ->
throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b)
; List = [H|T] ->
@@ -388,9 +416,10 @@ univ_worker(Term, List, _) :-
!,
'$call_with_default_policy'(List = [Term]).
univ_worker(Term, [Name|Args], N) :-
- var(Term), !,
+ var(Term),
+ !,
'$call_with_default_policy'(Arity is N-1),
- '$call_with_default_policy'(functor(Term, Name, Arity)),
+ '$call_with_default_policy'(functor(Term, Name, Arity)), % Term = {var}, Name = nonvar, Arity = 0.
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)).
univ_worker(Term, List, _) :-
'$call_with_default_policy'(functor(Term, Name, Arity)),
@@ -415,7 +444,7 @@ get_args([Arg|Args], Func, I0, N) :-
:- meta_predicate parse_options_list(?, 0, ?, ?, ?).
parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
- '$skip_max_list'(_, -1, Options, Tail),
+ '$skip_max_list'(_, _, Options, Tail),
( Tail == [] ->
true
; var(Tail) ->
@@ -468,7 +497,7 @@ parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
).
must_be_var_names_list(VarNames) :-
- '$skip_max_list'(_, -1, VarNames, Tail),
+ '$skip_max_list'(_, _, VarNames, Tail),
( Tail == [] ->
must_be_var_names_list_(VarNames, VarNames)
; var(Tail) ->
@@ -565,7 +594,7 @@ can_be_list(List, _) :-
var(List),
!.
can_be_list(List, _) :-
- '$skip_max_list'(_, -1, List, Tail),
+ '$skip_max_list'(_, _, List, Tail),
( var(Tail) ->
true
; Tail == []
@@ -620,9 +649,11 @@ throw(Ball) :-
),
'$unwind_stack'.
+
:- non_counted_backtracking '$iterate_find_all'/4.
+
'$iterate_find_all'(Template, Goal, _, LhOffset) :-
- call(Goal),
+ '$call'(Goal),
'$copy_to_lh'(LhOffset, Template),
'$fail'.
'$iterate_find_all'(_, _, Solutions, LhOffset) :-
@@ -636,7 +667,7 @@ truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
:- meta_predicate findall(?, 0, ?).
findall(Template, Goal, Solutions) :-
- error:can_be(list, Solutions),
+ '$call_with_default_policy'(error:can_be(list, Solutions)),
'$lh_length'(LhLength),
'$call_with_default_policy'(
catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength),
@@ -644,7 +675,6 @@ findall(Template, Goal, Solutions) :-
( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))
).
-
:- non_counted_backtracking '$iterate_find_all_diff'/5.
'$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
@@ -659,8 +689,8 @@ findall(Template, Goal, Solutions) :-
:- meta_predicate findall(?, 0, ?, ?).
findall(Template, Goal, Solutions0, Solutions1) :-
- error:can_be(list, Solutions0),
- error:can_be(list, Solutions1),
+ '$call_with_default_policy'(error:can_be(list, Solutions0)),
+ '$call_with_default_policy'(error:can_be(list, Solutions1)),
'$lh_length'(LhLength),
'$call_with_default_policy'(
catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0,
@@ -679,9 +709,9 @@ set_difference([], _, []) :- !.
set_difference(Xs, [], Xs).
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
- iso_ext:variant(V1, V2),
+ V1 = V2, % \+ \+ (V1 = V2), % (2) % iso_ext:variant(V1, V2), % (1)
!,
- V1 = V2,
+ % V1 = V2, % (3)
group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
group_by_variant(Pairs, _, [], Pairs).
@@ -713,15 +743,15 @@ rightmost_power(Term, FinalTerm, Xs) :-
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :-
( nonvar(Goal),
- ( Goal = _ ^ _
- ; Goal = _ : (_ ^ _)
- ) ->
- rightmost_power(Goal, Goal1, ExistentialVars0),
+ loader:strip_module(Goal, M, Goal1),
+ ( Goal1 = _ ^ _ ) ->
+ rightmost_power(Goal1, Goal2, ExistentialVars0),
term_variables(ExistentialVars0, ExistentialVars),
sort(Witnesses0, Witnesses1),
sort(ExistentialVars, ExistentialVars1),
set_difference(Witnesses1, ExistentialVars1, Witnesses),
- findall(Witnesses-Template, Goal1, PairedSolutions)
+ expand_goal(M:Goal2, M, Goal3),
+ findall(Witnesses-Template, Goal3, PairedSolutions)
; Witnesses = Witnesses0,
findall(Witnesses-Template, Goal, PairedSolutions)
).
@@ -779,11 +809,11 @@ setof(Template, Goal, Solution) :-
( var(H) ->
throw(error(instantiation_error, clause/2))
; callable(H), functor(H, Name, Arity) ->
- ( '$head_is_dynamic'(Module, H) ->
+ ( '$no_such_predicate'(Module, H) ->
+ '$fail'
+ ; '$head_is_dynamic'(Module, H) ->
'$clause_body_is_valid'(B),
Module:'$clause'(H, B)
- ; '$no_such_predicate'(Module, H) ->
- '$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2))
)
@@ -800,12 +830,11 @@ clause(H, B) :-
arg(1, H, Module),
arg(2, H, F),
'$module_clause'(F, B, Module)
+ ; '$no_such_predicate'(user, H) ->
+ '$fail'
; '$head_is_dynamic'(user, H) ->
'$clause_body_is_valid'(B),
'$clause'(H, B)
- ; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if
- %% H is not callable.
- '$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2))
)
@@ -854,13 +883,14 @@ asserta_clause(Head, Body) :-
:- meta_predicate asserta(0).
-asserta(Clause) :-
+asserta(Clause0) :-
+ loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) ->
Head = Clause,
Body = true,
- asserta_clause(Head, Body)
+ module_asserta_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
- asserta_clause(Head, Body)
+ module_asserta_clause(Head, Body, Module)
).
module_assertz_clause(Head, Body, Module) :-
@@ -909,13 +939,14 @@ assertz_clause(Head, Body) :-
:- meta_predicate assertz(0).
-assertz(Clause) :-
+assertz(Clause0) :-
+ loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) ->
Head = Clause,
Body = true,
- assertz_clause(Head, Body)
+ module_assertz_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
- assertz_clause(Head, Body)
+ module_assertz_clause(Head, Body, Module)
).
@@ -999,13 +1030,14 @@ retract_clause(Head, Body) :-
:- meta_predicate retract(0).
retract(Clause0) :-
- strip_module(Clause0, Module, Clause),
- ( Clause = (Head :- Body) ->
- true
- ; Head = Clause,
- Body = true
- ),
- retract_clause(Module:Head, Body).
+ loader:strip_module(Clause0, Module, Clause),
+ ( Clause \= (_ :- _) ->
+ Head = Clause,
+ Body = true,
+ retract_module_clause(Head, Body, Module)
+ ; Clause = (Head :- Body) ->
+ retract_module_clause(Head, Body, Module)
+ ).
:- meta_predicate retractall(0).
@@ -1022,8 +1054,10 @@ module_abolish(Pred, Module) :-
; Pred = Name/Arity ->
( var(Name) ->
throw(error(instantiation_error, abolish/1))
+ ; var(Arity) ->
+ throw(error(instantiation_error, abolish/1))
; integer(Arity) ->
- ( \+ atom(Name) ->
+ (\+ atom(Name) ->
throw(error(type_error(atom, Name), abolish/1))
; Arity < 0 ->
throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
@@ -1075,17 +1109,16 @@ abolish(Pred) :-
; throw(error(type_error(predicate_indicator, Pred), abolish/1))
).
-'$iterate_db_refs'(Ref, Name/Arity) :-
- '$lookup_db_ref'(Ref, Name, Arity).
-'$iterate_db_refs'(Ref, Name/Arity) :-
- '$get_next_db_ref'(Ref, NextRef),
- '$iterate_db_refs'(NextRef, Name/Arity).
-
+'$iterate_db_refs'(Name, Arity, Name/Arity). % :-
+% '$lookup_db_ref'(Ref, Name, Arity).
+'$iterate_db_refs'(RName, RArity, Name/Arity) :-
+ '$get_next_db_ref'(RName, RArity, RRName, RRArity),
+ '$iterate_db_refs'(RRName, RRArity, Name/Arity).
current_predicate(Pred) :-
( var(Pred) ->
- '$get_next_db_ref'(Ref, _),
- '$iterate_db_refs'(Ref, Pred)
+ '$get_next_db_ref'(RN, RA, _, _),
+ '$iterate_db_refs'(RN, RA, Pred)
; Pred \= _/_ ->
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
; Pred = Name/Arity,
@@ -1094,15 +1127,14 @@ current_predicate(Pred) :-
; integer(Arity), Arity < 0
) ->
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
- ; '$get_next_db_ref'(Ref, _),
- '$iterate_db_refs'(Ref, Pred)
+ ; '$get_next_db_ref'(RN, RA, _, _),
+ '$iterate_db_refs'(RN, RA, Pred)
).
-'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
- '$lookup_op_db_ref'(Ref, Priority, Spec, Op).
-'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
- '$get_next_op_db_ref'(Ref, NextRef),
- '$iterate_op_db_refs'(NextRef, Priority, Spec, Op).
+'$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp).
+'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :-
+ '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp),
+ '$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op).
can_be_op_priority(Priority) :- var(Priority).
can_be_op_priority(Priority) :- op_priority(Priority).
@@ -1114,8 +1146,8 @@ current_op(Priority, Spec, Op) :-
( can_be_op_priority(Priority),
can_be_op_specifier(Spec),
error:can_be(atom, Op) ->
- '$get_next_op_db_ref'(Ref, _),
- '$iterate_op_db_refs'(Ref, Priority, Spec, Op)
+ '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op),
+ '$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op)
).
list_of_op_atoms(Var) :-
@@ -1209,7 +1241,7 @@ atom_length(Atom, Length) :-
).
atom_chars(Atom, List) :-
- '$skip_max_list'(_, -1, List, Tail),
+ '$skip_max_list'(_, _, List, Tail),
( ( Tail == [] ; var(Tail) ) ->
true
; throw(error(type_error(list, List), atom_chars/2))
@@ -1227,7 +1259,7 @@ atom_chars(Atom, List) :-
).
atom_codes(Atom, List) :-
- '$skip_max_list'(_, -1, List, Tail),
+ '$skip_max_list'(_, _, List, Tail),
( ( Tail == [] ; var(Tail) ) ->
true
; throw(error(type_error(list, List), atom_codes/2))
@@ -1284,9 +1316,9 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :-
; atom_chars(Atom, AtomChars),
lists:append(BeforeChars, LengthAndAfterChars, AtomChars),
lists:append(LengthChars, AfterChars, LengthAndAfterChars),
- '$skip_max_list'(Before, -1, BeforeChars, []),
- '$skip_max_list'(Length, -1, LengthChars, []),
- '$skip_max_list'(After, -1, AfterChars, []),
+ '$skip_max_list'(Before, _, BeforeChars, []),
+ '$skip_max_list'(Length, _, LengthChars, []),
+ '$skip_max_list'(After, _, AfterChars, []),
atom_chars(Sub_atom, LengthChars)
).
@@ -1481,7 +1513,8 @@ open(SourceSink, Mode, Stream, StreamOptions) :-
atom(SourceSink) ->
atom_chars(SourceSink, SourceSinkString)
; SourceSink = SourceSinkString
- ), '$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
+ ),
+ '$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
)
).
diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl
index 85856810..4ac7df2b 100644
--- a/src/lib/charsio.pl
+++ b/src/lib/charsio.pl
@@ -1,9 +1,9 @@
:- module(charsio, [char_type/2,
chars_utf8bytes/2,
get_single_char/1,
- read_n_chars/3,
+ get_n_chars/3,
read_line_to_chars/3,
- read_term_from_chars/2,
+ read_from_chars/2,
write_term_to_chars/3,
chars_base64/3]).
@@ -113,18 +113,8 @@ get_single_char(C) :-
).
-read_term_from_chars(Chars, Term) :-
- ( var(Chars) ->
- 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
- ;
- type_error(complete_string, Chars, read_term_from_chars/2)
- ),
+read_from_chars(Chars, Term) :-
+ must_be(chars, Chars),
'$read_term_from_chars'(Chars, Term).
@@ -205,7 +195,7 @@ read_line_to_chars(Stream, Cs0, Cs) :-
characters read.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-read_n_chars(Stream, N, Cs) :-
+get_n_chars(Stream, N, Cs) :-
can_be(integer, N),
( var(N) ->
read_to_eof(Stream, Cs),
diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl
index c2b29712..d887c211 100644
--- a/src/lib/clpz.pl
+++ b/src/lib/clpz.pl
@@ -6169,7 +6169,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
get_attr(To, lowlink, L2),
L1 =\= L2 } ->
{ get_attr(To, value, N) },
- [neq_num(V, N)]
+ [clpz:neq_num(V, N)]
; []
),
distinct_goals_(Es, V).
@@ -6690,7 +6690,7 @@ gcc_edge_goal(arc_to(_,_,V,F), Val) -->
get_attr(Val, lowlink, L2),
L1 =\= L2,
get_attr(Val, value, Value) } ->
- [neq_num(V, Value)]
+ [clpz:neq_num(V, Value)]
; []
).
diff --git a/src/lib/crypto.pl b/src/lib/crypto.pl
index efc478ae..63696b5c 100644
--- a/src/lib/crypto.pl
+++ b/src/lib/crypto.pl
@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Written 2020, 2021 by Markus Triska (triska@metalevel.at)
+ Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
Predicates for cryptographic applications.
@@ -46,6 +46,7 @@
:- use_module(library(format)).
:- use_module(library(charsio)).
:- use_module(library(si)).
+:- use_module(library(iso_ext), [partial_string/3]).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hex_bytes(?Hex, ?Bytes) is det.
@@ -594,7 +595,9 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
member(Encoding, [utf8,octet]),
encoding_chars(octet, CipherText0, CipherText1),
maplist(char_code, TagChars, Tag),
- append(CipherText1, TagChars, CipherText),
+ % we append the tag very efficiently, retaining a compact
+ % internal string representation of the ciphertext
+ partial_string(CipherText1, CipherText, TagChars),
( Algorithm = 'chacha20-poly1305' -> true
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
),
diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl
index f4cee25c..488c7a92 100644
--- a/src/lib/dcgs.pl
+++ b/src/lib/dcgs.pl
@@ -1,16 +1,26 @@
:- module(dcgs,
[op(1105, xfy, '|'),
- phrase/2,
- phrase/3,
- seq//1,
- seqq//1,
- ... //0
- ]).
+ phrase/2,
+ phrase/3,
+ seq//1,
+ seqq//1,
+ ... //0
+ ]).
:- use_module(library(error)).
-:- use_module(library(lists), [append/3]).
+:- use_module(library(lists), [append/3, member/2]).
:- use_module(library(loader), [strip_module/3]).
+load_context(GRBody, Module, GRBody0) :-
+ strip_module(GRBody, Module, GRBody0),
+ ( nonvar(Module) ->
+ true
+ ; prolog_load_context(module, Module) ->
+ true
+ ; true
+ ).
+
+
:- meta_predicate phrase(2, ?).
:- meta_predicate phrase(2, ?, ?).
@@ -18,100 +28,44 @@
phrase(GRBody, S0) :-
phrase(GRBody, S0, []).
-
phrase(GRBody, S0, S) :-
- ( var(GRBody) ->
- throw(error(instantiation_error, phrase/3))
- ; strip_module(GRBody, Module, GRBody0),
- dcg_constr(GRBody0) ->
- ( var(Module) ->
- phrase_(GRBody0, S0, S)
- ; phrase_(Module:GRBody0, S0, S)
- )
- ; functor(GRBody, _, _) ->
- call(GRBody, S0, S)
- ; throw(error(type_error(callable, GRBody), phrase/3))
+ load_context(GRBody, Module, GRBody0),
+ ( var(GRBody0) ->
+ instantiation_error(phrase/3)
+ ; dcg_body(GRBody0, S0, S, GRBody1, Module) ->
+ call(GRBody1)
+ ; type_error(callable, GRBody0, phrase/3)
).
-phrase_([], S, S).
-phrase_(!, S, S).
-phrase_(_:[], S, S) :- !.
-phrase_(_:!, S, S) :- !.
-phrase_((A, B), S0, S) :-
- phrase(A, S0, S1), phrase(B, S1, S).
-phrase_(M:(A, B), S0, S) :-
- !,
- phrase(M:A, S0, S1), phrase(M:B, S1, S).
-phrase_((A -> B ; C), S0, S) :-
- !,
- ( phrase(A, S0, S1) ->
- phrase(B, S1, S)
- ; phrase(C, S0, S)
- ).
-phrase_(M:(A -> B ; C), S0, S) :-
- !,
- ( phrase(M:A, S0, S1) ->
- phrase(M:B, S1, S)
- ; phrase(M:C, S0, S)
+
+module_call_qualified(M, Call, Call1) :-
+ ( nonvar(M) -> Call1 = M:Call
+ ; Call = Call1
).
-phrase_((A ; B), S0, S) :-
- ( phrase(A, S0, S) ; phrase(B, S0, S) ).
-phrase_(M:(A ; B), S0, S) :-
- !,
- ( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
-phrase_((A | B), S0, S) :-
- ( phrase(A, S0, S) ; phrase(B, S0, S) ).
-phrase_(M:(A | B), S0, S) :-
- !,
- ( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
-phrase_({G}, S0, S) :-
- ( call(G), S0 = S ).
-phrase_(M:{G}, S0, S) :-
- !,
- ( call(M:G), S0 = S ).
-phrase_(call(G), S0, S) :-
- call(G, S0, S).
-phrase_(M:call(G), S0, S) :-
- !,
- call(M:G, S0, S).
-phrase_((A -> B), S0, S) :-
- phrase((A -> B ; fail), S0, S).
-phrase_(M:(A -> B), S0, S) :-
- !,
- phrase((M:A -> M:B ; fail), S0, S).
-phrase_(phrase(NonTerminal), S0, S) :-
- phrase(NonTerminal, S0, S).
-phrase_(M:phrase(NonTerminal), S0, S) :-
- !,
- phrase(M:NonTerminal, S0, S).
-phrase_([T|Ts], S0, S) :-
- append([T|Ts], S, S0).
-phrase_(_:[T|Ts], S0, S) :-
- append([T|Ts], S, S0).
% The same version of the below two dcg_rule clauses, but with module scoping.
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head),
- dcg_body(GRBody, S0, S1, Goal1),
+ dcg_body(GRBody, S0, S1, Goal1, _),
dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ).
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head),
- dcg_body(GRBody, S0, S, Body).
+ dcg_body(GRBody, S0, S, Body, _).
% This program uses append/3 as defined in the Prolog prologue.
% Expands a DCG rule into a Prolog rule, when no error condition applies.
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head),
- dcg_body(GRBody, S0, S1, Goal1),
+ dcg_body(GRBody, S0, S1, Goal1, _),
dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ).
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head),
- dcg_body(GRBody, S0, S, Body).
+ dcg_body(GRBody, S0, S, Body, _).
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
NonTerminal =.. NonTerminalUniv,
@@ -121,18 +75,20 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
dcg_terminals(Terminals, S0, S, S0 = List) :-
append(Terminals, S, List).
-dcg_body(Var, S0, S, Body) :-
+dcg_body(Var, S0, S, Body, M) :-
var(Var),
- Body = phrase(Var, S0, S).
-dcg_body(GRBody, S0, S, Body) :-
+ module_call_qualified(M, Var, Var1),
+ Body = phrase(Var1, S0, S).
+dcg_body(GRBody, S0, S, Body, M) :-
nonvar(GRBody),
dcg_constr(GRBody),
- dcg_cbody(GRBody, S0, S, Body).
-dcg_body(NonTerminal, S0, S, Goal) :-
+ dcg_cbody(GRBody, S0, S, Body, M).
+dcg_body(NonTerminal, S0, S, Goal1, M) :-
nonvar(NonTerminal),
\+ dcg_constr(NonTerminal),
NonTerminal \= ( _ -> _ ),
NonTerminal \= ( \+ _ ),
+ module_call_qualified(M, Goal, Goal1),
dcg_non_terminal(NonTerminal, S0, S, Goal).
% The following constructs in a grammar rule body
@@ -151,37 +107,40 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
% The principal functor of the first argument indicates
% the construct to be expanded.
-dcg_cbody([], S0, S, S0 = S).
-dcg_cbody([T|Ts], S0, S, Goal) :-
+dcg_cbody([], S0, S, S0 = S, _M).
+dcg_cbody([T|Ts], S0, S, Goal, _M) :-
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),
- dcg_body(GRSecond, S1, S, Second).
-dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
+dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :-
+ dcg_body(GRFirst, S0, S1, First, M),
+ dcg_body(GRSecond, S1, S, Second, M).
+dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :-
\+ subsumes_term(( _ -> _ ), GREither),
- dcg_body(GREither, S0, S, Either),
- dcg_body(GROr, S0, S, Or).
-dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
+ dcg_body(GREither, S0, S, Either, M),
+ dcg_body(GROr, S0, S, Or, M).
+dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :-
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({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)).
-dcg_cbody(!, S0, S, ( !, S0 = S )).
-dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
-dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
- dcg_body(GRIf, S0, S1, If),
- dcg_body(GRThen, S1, S, Then).
+ dcg_cbody(GRCond, S0, S, Cond, M),
+ dcg_body(GRElse, S0, S, Else, M).
+dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :-
+ dcg_body(GREither, S0, S, Either, M),
+ dcg_body(GROr, S0, S, Or, M).
+dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :-
+ module_call_qualified(M, Goal, Goal1).
+dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :-
+ module_call_qualified(M, Cont, Cont1).
+dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :-
+ module_call_qualified(M, Body, Body1).
+dcg_cbody(!, S0, S, ( !, S0 = S ), _M).
+dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :-
+ module_call_qualified(M, GRBody, GRBody1).
+dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :-
+ dcg_body(GRIf, S0, S1, If, M),
+ dcg_body(GRThen, S1, S, Then, M).
user:term_expansion(Term0, Term) :-
nonvar(Term0),
- dcg_rule(Term0, (Head :- Body)),
- Term = (Head :- Body).
+ dcg_rule(Term0, Term).
% Describes a sequence
seq([]) --> [].
@@ -193,3 +152,13 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess).
% Describes an arbitrary number of elements
... --> [] | [_], ... .
+
+user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :-
+ load_context(GRBody, M, GRBody0),
+ nonvar(GRBody0),
+ catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M),
+ error(E, must_be/2),
+ ( GRBody1 = throw(error(E, must_be/2)) )
+ ).
+
+user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
diff --git a/src/lib/error.pl b/src/lib/error.pl
index d5827495..c5af6d7c 100644
--- a/src/lib/error.pl
+++ b/src/lib/error.pl
@@ -80,7 +80,7 @@ character(C) :-
atom_length(C, 1).
ilist(Ls) :-
- '$skip_max_list'(_, -1, Ls, Rs),
+ '$skip_max_list'(_, _, Ls, Rs),
( var(Rs) ->
instantiation_error(must_be/2)
; Rs == []
@@ -124,7 +124,7 @@ can_(list, Term) :- list_or_partial_list(Term).
can_(boolean, Term) :- boolean(Term).
list_or_partial_list(Ls) :-
- '$skip_max_list'(_, -1, Ls, Rs),
+ '$skip_max_list'(_, _, Ls, Rs),
( var(Rs) -> true
; Rs == []
).
diff --git a/src/lib/files.pl b/src/lib/files.pl
index 6989cb46..9ee1c2b9 100644
--- a/src/lib/files.pl
+++ b/src/lib/files.pl
@@ -174,7 +174,7 @@ file_creation_time(File, T) :-
file_time_(File, Which, T) :-
file_must_exist(File, file_time_/3),
'$file_time'(File, Which, T0),
- read_term_from_chars(T0, T).
+ read_from_chars(T0, T).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/lib/format.pl b/src/lib/format.pl
index 3fd28fb6..fd2a9816 100644
--- a/src/lib/format.pl
+++ b/src/lib/format.pl
@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Written 2020, 2021 by Markus Triska (triska@metalevel.at)
+ Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
This library provides the nonterminal format_//2 to describe
@@ -28,6 +28,9 @@
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)
+ ~NU like ~ND, using "_" (underscore) to separate groups of digits
+ ~NL format an integer so that at most N digits appear on a line.
+ If N is 0 or omitted, it defaults to 72.
~Nr where N is an integer between 2 and 36: format the
next argument, which must be an integer, in radix N.
The characters "a" to "z" are used for radices 10 to 36.
@@ -200,14 +203,22 @@ cells([~|Fs0], Args0, Tab, Es, VNs) -->
cells([~|Fs0], Args0, Tab, Es, VNs) -->
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
!,
- { number_chars(Num, NCs),
- phrase(("~",seq(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) },
+ { separate_digits_fractional(Arg, ',', Num, Cs) },
+ cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
+cells([~|Fs0], Args0, Tab, Es, VNs) -->
+ { numeric_argument(Fs0, Num, ['U'|Fs], Args0, [Arg|Args]) },
+ !,
+ { separate_digits_fractional(Arg, '_', Num, Cs) },
+ cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
+cells([~|Fs0], Args0, Tab, Es, VNs) -->
+ { numeric_argument(Fs0, Num0, ['L'|Fs], Args0, [Arg|Args]) },
+ !,
+ { ( Num0 =:= 0 ->
+ Num = 72
+ ; Num = Num0
+ ),
+ phrase(format_("~d", [Arg]), Cs0),
+ phrase(split_lines_width(Cs0, Num), Cs) },
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
cells([~,i|Fs], [_|Args], Tab, Es, VNs) --> !,
cells(Fs, Args, Tab, Es, VNs).
@@ -312,12 +323,30 @@ Cs = [a,b,c], Rest = [~,t,e,s,t].
Cs = [a,b,c], Rest = [].
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+separate_digits_fractional(Arg, Sep, Num, Cs) :-
+ number_chars(Num, NCs),
+ phrase(("~",seq(NCs),"d"), FStr),
+ phrase(format_(FStr, [Arg]), Cs0),
+ phrase(upto_what(Bs0, .), Cs0, Ds),
+ reverse(Bs0, Bs1),
+ phrase(groups_of_three(Bs1,Sep), Bs2),
+ reverse(Bs2, Bs),
+ append(Bs, Ds, Cs).
+
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) --> seq(Ls).
+groups_of_three([A,B,C,D|Rs], Sep) --> !, [A,B,C,Sep], groups_of_three([D|Rs], Sep).
+groups_of_three(Ls, _) --> seq(Ls).
+
+split_lines_width(Cs, Num) -->
+ ( { length(Prefix, Num),
+ append(Prefix, [R|Rs], Cs) } ->
+ seq(Prefix), "_\n",
+ split_lines_width([R|Rs], Num)
+ ; seq(Cs)
+ ).
cell(From, To, Es0) -->
( { Es0 == [] } -> []
diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl
index 378d495a..e614b1f6 100644
--- a/src/lib/iso_ext.pl
+++ b/src/lib/iso_ext.pl
@@ -14,7 +14,7 @@
partial_string_tail/2,
setup_call_cleanup/3,
call_nth/2,
- variant/2,
+% variant/2,
copy_term_nat/2]).
:- use_module(library(error), [can_be/2,
@@ -22,10 +22,7 @@
instantiation_error/1,
type_error/3]).
-
-:- meta_predicate(call_cleanup(0, 0)).
-
-:- meta_predicate(setup_call_cleanup(0, 0, 0)).
+:- use_module(library(lists), [maplist/3]).
:- meta_predicate(forall(0, 0)).
@@ -55,14 +52,17 @@ bb_get(Key, Value) :-
).
-call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
+% setup_call_cleanup.
+:- meta_predicate(call_cleanup(0, 0)).
-% setup_call_cleanup.
+call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
+
+:- meta_predicate(setup_call_cleanup(0, 0, 0)).
setup_call_cleanup(S, G, C) :-
'$get_b_value'(B),
- call(S),
+ '$call'(S),
'$set_cp_by_default'(B),
'$get_current_block'(Bb),
( C = _:CC,
@@ -71,6 +71,8 @@ setup_call_cleanup(S, G, C) :-
; '$call_with_default_policy'(scc_helper(C, G, Bb))
).
+:- meta_predicate(scc_helper(?,0,?)).
+
:- non_counted_backtracking scc_helper/3.
scc_helper(C, G, Bb) :-
'$get_cp'(Cp),
@@ -96,7 +98,8 @@ scc_helper(_, _, _) :-
:- non_counted_backtracking run_cleaners_with_handling/0.
run_cleaners_with_handling :-
- '$get_scc_cleaner'(C), '$get_level'(B),
+ '$get_scc_cleaner'(C),
+ '$get_level'(B),
'$call_with_default_policy'(catch(C, _, true)),
'$set_cp_by_default'(B),
'$call_with_default_policy'(run_cleaners_with_handling).
@@ -134,16 +137,31 @@ handle_ile(B, E, _) :-
:- meta_predicate(call_with_inference_limit(0, ?, ?)).
call_with_inference_limit(G, L, R) :-
+ ( integer(L) ->
+ ( L < 0 ->
+ domain_error(not_less_than_zero, L, call_with_inference_limit/3)
+ ; true
+ )
+ ; var(L) ->
+ instantiation_error(call_with_inference_limit/3)
+ ; type_error(integer, L, call_with_inference_limit/3)
+ ),
'$get_current_block'(Bb),
'$get_b_value'(B),
'$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)),
'$remove_call_policy_check'(B).
+install_inference_counter(B, L, Count0) :-
+ '$install_inference_counter'(B, L, Count0).
+
+:- meta_predicate(call_with_inference_limit(0,?,?,?,?)).
+
:- non_counted_backtracking call_with_inference_limit/5.
+
call_with_inference_limit(G, L, R, Bb, B) :-
'$install_new_block'(NBb),
'$install_inference_counter'(B, L, Count0),
- call(G),
+ '$call'(G),
'$inference_level'(R, B),
'$remove_inference_counter'(B, Count1),
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
@@ -160,14 +178,12 @@ call_with_inference_limit(_, _, R, Bb, B) :-
'$erase_ball',
'$call_with_default_policy'(handle_ile(B, Ball, R)).
-variant(X, Y) :- '$variant'(X, Y).
-
partial_string(String, L, L0) :-
( String == [] ->
L = L0
; catch(atom_chars(Atom, String),
- error(E, _),
- throw(error(E, partial_string/3))),
+ error(E, _),
+ throw(error(E, partial_string/3))),
'$create_partial_string'(Atom, L, L0)
).
diff --git a/src/lib/lists.pl b/src/lib/lists.pl
index 20631588..964280d7 100644
--- a/src/lib/lists.pl
+++ b/src/lib/lists.pl
@@ -3,7 +3,7 @@
maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
sum_list/2, transpose/2, list_to_set/2, list_max/2,
- list_min/2, permutation/2]).
+ list_min/2, permutation/2]).
/* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe
Copyright (c) 2018-2021, Mark Thom
@@ -50,24 +50,20 @@
:- meta_predicate foldl(3, ?, ?, ?).
:- meta_predicate foldl(4, ?, ?, ?, ?).
-
-length(Xs, N) :-
- var(N),
- !,
- '$skip_max_list'(M, -1, Xs, Xs0),
- ( Xs0 == [] -> N = M
- ; var(Xs0) -> length_addendum(Xs0, N, M)).
-length(Xs, N) :-
- integer(N),
- N >= 0, !,
- '$skip_max_list'(M, N, Xs, Xs0),
- ( Xs0 == [] -> N = M
- ; var(Xs0) -> R is N-M, length_rundown(Xs0, R)).
+length(Xs0, N) :-
+ '$skip_max_list'(M, N, Xs0,Xs),
+ !,
+ ( Xs == [] -> N = M
+ ; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2))
+ ; nonvar(N) -> R is N-M, length_rundown(Xs, R)
+ ; N == Xs -> throw(error(resource_error(finite_memory),length/2))
+ ; length_addendum(Xs, N, M)
+ ).
length(_, N) :-
- integer(N), !,
- domain_error(not_less_than_zero, N, length/2).
+ integer(N), !,
+ domain_error(not_less_than_zero, N, length/2).
length(_, N) :-
- type_error(integer, N, length/2).
+ type_error(integer, N, length/2).
length_addendum([], N, N).
length_addendum([_|Xs], N, M) :-
@@ -285,8 +281,8 @@ list_min_(N, Min0, Min) :-
% or partial list.
permutation(Xs, Ys) :-
- '$skip_max_list'(Xlen, -1, Xs, XTail),
- '$skip_max_list'(Ylen, -1, Ys, YTail),
+ '$skip_max_list'(Xlen, _, Xs, XTail),
+ '$skip_max_list'(Ylen, _, Ys, YTail),
( XTail == [], YTail == [] % both proper lists
-> Xlen == Ylen
; var(XTail), YTail == [] % partial, proper
diff --git a/src/lib/ordsets.pl b/src/lib/ordsets.pl
index ff080962..b5886d38 100644
--- a/src/lib/ordsets.pl
+++ b/src/lib/ordsets.pl
@@ -89,7 +89,7 @@ because the order it relies on may have been changed.
% setof/3.
is_ordset(Term) :-
- '$skip_max_list'(_, -1, Term, Tail), Tail == [], %% is_list(Term),
+ '$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term),
is_ordset2(Term).
is_ordset2([]).
diff --git a/src/lib/pio.pl b/src/lib/pio.pl
index 38849a4b..db609aa6 100644
--- a/src/lib/pio.pl
+++ b/src/lib/pio.pl
@@ -21,7 +21,7 @@
:- use_module(library(freeze)).
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]).
:- use_module(library(lists), [member/2, maplist/2]).
-:- use_module(library(charsio), [read_n_chars/3]).
+:- use_module(library(charsio), [get_n_chars/3]).
:- meta_predicate(phrase_from_file(2, ?)).
:- meta_predicate(phrase_from_file(2, ?, ?)).
@@ -62,7 +62,7 @@ reader_step(Stream, Pos, Xs0) :-
set_stream_position(Stream, Pos),
( at_end_of_stream(Stream)
-> Xs0 = []
- ; read_n_chars(Stream, 4096, Cs),
+ ; get_n_chars(Stream, 4096, Cs),
partial_string(Cs, Xs0, Xs),
stream_to_lazy_list(Stream, Xs)
).
diff --git a/src/lib/random.pl b/src/lib/random.pl
index 2fb21279..d678aff2 100644
--- a/src/lib/random.pl
+++ b/src/lib/random.pl
@@ -22,11 +22,11 @@ random(R) :-
random_integer(Lower, Upper, R) :-
var(R),
( (var(Lower) ; var(Upper)) ->
- instantiation_error(random_integer/3)
+ instantiation_error(random_integer/3)
; \+ integer(Lower) ->
- domain_error(integer, Lower, random_integer/3)
+ type_error(integer, Lower, random_integer/3)
; \+ integer(Upper) ->
- domain_error(integer, Upper, random_integer/3)
+ type_error(integer, Upper, random_integer/3)
; Upper > Lower,
random(R0),
R is floor((Upper - Lower) * R0 + Lower)
diff --git a/src/lib/reif.pl b/src/lib/reif.pl
index a1d31419..c0e14989 100644
--- a/src/lib/reif.pl
+++ b/src/lib/reif.pl
@@ -79,5 +79,6 @@ tmember(P_2, [X|Xs]) :-
:- meta_predicate(tmember_t(2, ?, ?)).
+tmember_t(_P_2, [], false).
tmember_t(P_2, [X|Xs], T) :-
if_( call(P_2, X), T = true, tmember_t(P_2, Xs, T) ).
diff --git a/src/lib/serialization/abnf.pl b/src/lib/serialization/abnf.pl
index d5c1c31b..037e7aa0 100644
--- a/src/lib/serialization/abnf.pl
+++ b/src/lib/serialization/abnf.pl
@@ -9,26 +9,26 @@
syntaxes. The DCGs are presented in the order they appear in the RFC.
While some DCGs below use `char_type/2`, the most common ones are defined
manually in order to take advantage of Prolog's first-argument indexing.
-
+
BSD 3-Clause License
-
+
Copyright (c) 2021, Aram Panasenco
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
-
+
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
diff --git a/src/lib/serialization/json.pl b/src/lib/serialization/json.pl
index e1bebe11..dac27882 100644
--- a/src/lib/serialization/json.pl
+++ b/src/lib/serialization/json.pl
@@ -1,29 +1,29 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu)
Part of Scryer Prolog.
-
+
`json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl)
or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html).
-
+
BSD 3-Clause License
-
+
Copyright (c) 2021, Aram Panasenco
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
-
+
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -44,7 +44,7 @@
:- use_module(library(dif)).
:- use_module(library(lists)).
-/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
+/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */
json_chars(Internal) --> json_element(Internal).
diff --git a/src/lib/sgml.pl b/src/lib/sgml.pl
index 507da1c6..0289278e 100644
--- a/src/lib/sgml.pl
+++ b/src/lib/sgml.pl
@@ -58,6 +58,7 @@
:- use_module(library(error)).
:- use_module(library(dcgs)).
:- use_module(library(pio)).
+:- use_module(library(charsio)).
load_html(Source, Es, Options) :-
load_structure_(Source, Es, Options, html).
@@ -75,15 +76,8 @@ load_structure_(file(Fs), [E], Options, What) :-
load_(What, Cs, E, Options).
load_structure_(stream(Stream), [E], Options, What) :-
must_be(list, Options),
- read_to_end(Stream, Cs),
+ get_n_chars(Stream, _, Cs),
load_(What, Cs, E, Options).
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
-
-read_to_end(Stream, Cs) :-
- '$get_n_chars'(Stream, 4096, Cs0),
- ( Cs0 = [] -> Cs = []
- ; partial_string(Cs0, Cs, Rest),
- read_to_end(Stream, Rest)
- ).
diff --git a/src/lib/tabling/trie.pl b/src/lib/tabling/trie.pl
index cd855b92..2460f70f 100644
--- a/src/lib/tabling/trie.pl
+++ b/src/lib/tabling/trie.pl
@@ -41,6 +41,8 @@
trie_get_all_values/2 % +Trie, -Value
]).
+:- use_module(library(format)).
+
:- use_module(library(assoc)).
:- use_module(library(atts)).
:- use_module(library(lists)).
diff --git a/src/lib/time.pl b/src/lib/time.pl
index 56e31fae..5da5bb59 100644
--- a/src/lib/time.pl
+++ b/src/lib/time.pl
@@ -49,11 +49,11 @@
:- use_module(library(error)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
-:- use_module(library(charsio), [read_term_from_chars/2]).
+:- use_module(library(charsio), [read_from_chars/2]).
current_time(T) :-
'$current_time'(T0),
- read_term_from_chars(T0, T).
+ read_from_chars(T0, T).
format_time([], _) --> [].
format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T).
diff --git a/src/lib/ugraphs.pl b/src/lib/ugraphs.pl
new file mode 100644
index 00000000..159f4c00
--- /dev/null
+++ b/src/lib/ugraphs.pl
@@ -0,0 +1,630 @@
+/* Author: R.A.O'Keefe, Vitor Santos Costa, Jan Wielemaker
+ E-mail: J.Wielemaker@vu.nl
+ WWW: http://www.swi-prolog.org
+ Copyright (c) 1984-2021, VU University Amsterdam
+ CWI, Amsterdam
+ SWI-Prolog Solutions .b.v
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+:- module(ugraphs,
+ [ add_edges/3, % +Graph, +Edges, -NewGraph
+ add_vertices/3, % +Graph, +Vertices, -NewGraph
+ complement/2, % +Graph, -NewGraph
+ compose/3, % +LeftGraph, +RightGraph, -NewGraph
+ del_edges/3, % +Graph, +Edges, -NewGraph
+ del_vertices/3, % +Graph, +Vertices, -NewGraph
+ edges/2, % +Graph, -Edges
+ neighbors/3, % +Vertex, +Graph, -Vertices
+ neighbours/3, % +Vertex, +Graph, -Vertices
+ reachable/3, % +Vertex, +Graph, -Vertices
+ top_sort/2, % +Graph, -Sort
+ top_sort/3, % +Graph, -Sort0, -Sort
+ transitive_closure/2, % +Graph, -Closure
+ transpose_ugraph/2, % +Graph, -NewGraph
+ vertices/2, % +Graph, -Vertices
+ vertices_edges_to_ugraph/3, % +Vertices, +Edges, -Graph
+ ugraph_union/3, % +Graph1, +Graph2, -Graph
+ connect_ugraph/3 % +Graph1, -Start, -Graph
+ ]).
+
+/** <module> Graph manipulation library
+
+The S-representation of a graph is a list of (vertex-neighbours) pairs,
+where the pairs are in standard order (as produced by keysort) and the
+neighbours of each vertex are also in standard order (as produced by
+sort). This form is convenient for many calculations.
+
+A new UGraph from raw data can be created using
+vertices_edges_to_ugraph/3.
+
+Adapted to support some of the functionality of the SICStus ugraphs
+library by Vitor Santos Costa.
+
+Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker.
+
+@author R.A.O'Keefe
+@author Vitor Santos Costa
+@author Jan Wielemaker
+@license BSD-2 or Artistic 2.0
+*/
+
+:- use_module(library(lists)).
+:- use_module(library(pairs)).
+:- use_module(library(ordsets)).
+
+%! vertices(+Graph, -Vertices)
+%
+% Unify Vertices with all vertices appearing in Graph. Example:
+%
+% ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
+% L = [1, 2, 3, 4, 5]
+
+vertices([], []) :- !.
+vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
+ vertices(Graph, Vertices).
+
+
+%! vertices_edges_to_ugraph(+Vertices, +Edges, -UGraph) is det.
+%
+% Create a UGraph from Vertices and edges. Given a graph with a
+% set of Vertices and a set of Edges, Graph must unify with the
+% corresponding S-representation. Note that the vertices without
+% edges will appear in Vertices but not in Edges. Moreover, it is
+% sufficient for a vertice to appear in Edges.
+%
+% ==
+% ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L).
+% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]]
+% ==
+%
+% In this case all vertices are defined implicitly. The next
+% example shows three unconnected vertices:
+%
+% ==
+% ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L).
+% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]]
+% ==
+
+vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
+ sort(Edges, EdgeSet),
+ p_to_s_vertices(EdgeSet, IVertexBag),
+ append(Vertices, IVertexBag, VertexBag),
+ sort(VertexBag, VertexSet),
+ p_to_s_group(VertexSet, EdgeSet, Graph).
+
+
+%! add_vertices(+Graph, +Vertices, -NewGraph)
+%
+% Unify NewGraph with a new graph obtained by adding the list of
+% Vertices to Graph. Example:
+%
+% ```
+% ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG).
+% NG = [0-[], 1-[3,5], 2-[], 9-[]]
+% ```
+
+% replace with real msort/2 when available
+msort_(List, Sorted) :-
+ pairs_keys(Pairs, List),
+ keysort(Pairs, SortedPairs),
+ pairs_keys(SortedPairs, Sorted).
+
+add_vertices(Graph, Vertices, NewGraph) :-
+ % msort/2 not available in Scryer Prolog yet: msort(Vertices, V1),
+ msort_(Vertices, V1),
+ add_vertices_to_s_graph(V1, Graph, NewGraph).
+
+add_vertices_to_s_graph(L, [], NL) :-
+ !,
+ add_empty_vertices(L, NL).
+add_vertices_to_s_graph([], L, L) :- !.
+add_vertices_to_s_graph([V1|VL], [V-Edges|G], NGL) :-
+ compare(Res, V1, V),
+ add_vertices_to_s_graph(Res, V1, VL, V, Edges, G, NGL).
+
+add_vertices_to_s_graph(=, _, VL, V, Edges, G, [V-Edges|NGL]) :-
+ add_vertices_to_s_graph(VL, G, NGL).
+add_vertices_to_s_graph(<, V1, VL, V, Edges, G, [V1-[]|NGL]) :-
+ add_vertices_to_s_graph(VL, [V-Edges|G], NGL).
+add_vertices_to_s_graph(>, V1, VL, V, Edges, G, [V-Edges|NGL]) :-
+ add_vertices_to_s_graph([V1|VL], G, NGL).
+
+add_empty_vertices([], []).
+add_empty_vertices([V|G], [V-[]|NG]) :-
+ add_empty_vertices(G, NG).
+
+%! del_vertices(+Graph, +Vertices, -NewGraph) is det.
+%
+% Unify NewGraph with a new graph obtained by deleting the list of
+% Vertices and all the edges that start from or go to a vertex in
+% Vertices to the Graph. Example:
+%
+% ==
+% ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]],
+% [2,1],
+% NL).
+% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]]
+% ==
+%
+% @compat Upto 5.6.48 the argument order was (+Vertices, +Graph,
+% -NewGraph). Both YAP and SWI-Prolog have changed the argument
+% order for compatibility with recent SICStus as well as
+% consistency with del_edges/3.
+
+del_vertices(Graph, Vertices, NewGraph) :-
+ sort(Vertices, V1), % JW: was msort
+ ( V1 = []
+ -> Graph = NewGraph
+ ; del_vertices(Graph, V1, V1, NewGraph)
+ ).
+
+del_vertices(G, [], V1, NG) :-
+ !,
+ del_remaining_edges_for_vertices(G, V1, NG).
+del_vertices([], _, _, []).
+del_vertices([V-Edges|G], [V0|Vs], V1, NG) :-
+ compare(Res, V, V0),
+ split_on_del_vertices(Res, V,Edges, [V0|Vs], NVs, V1, NG, NGr),
+ del_vertices(G, NVs, V1, NGr).
+
+del_remaining_edges_for_vertices([], _, []).
+del_remaining_edges_for_vertices([V0-Edges|G], V1, [V0-NEdges|NG]) :-
+ ord_subtract(Edges, V1, NEdges),
+ del_remaining_edges_for_vertices(G, V1, NG).
+
+split_on_del_vertices(<, V, Edges, Vs, Vs, V1, [V-NEdges|NG], NG) :-
+ ord_subtract(Edges, V1, NEdges).
+split_on_del_vertices(>, V, Edges, [_|Vs], Vs, V1, [V-NEdges|NG], NG) :-
+ ord_subtract(Edges, V1, NEdges).
+split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG).
+
+%! add_edges(+Graph, +Edges, -NewGraph)
+%
+% Unify NewGraph with a new graph obtained by adding the list of Edges
+% to Graph. Example:
+%
+% ```
+% ?- add_edges([1-[3,5],2-[4],3-[],4-[5],
+% 5-[],6-[],7-[],8-[]],
+% [1-6,2-3,3-2,5-7,3-2,4-5],
+% NL).
+% NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5],
+% 5-[7], 6-[], 7-[], 8-[]]
+% ```
+
+add_edges(Graph, Edges, NewGraph) :-
+ p_to_s_graph(Edges, G1),
+ ugraph_union(Graph, G1, NewGraph).
+
+%! ugraph_union(+Graph1, +Graph2, -NewGraph)
+%
+% NewGraph is the union of Graph1 and Graph2. Example:
+%
+% ```
+% ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
+% L = [1-[2], 2-[3,4], 3-[1,2,4]]
+% ```
+
+ugraph_union(Set1, [], Set1) :- !.
+ugraph_union([], Set2, Set2) :- !.
+ugraph_union([Head1-E1|Tail1], [Head2-E2|Tail2], Union) :-
+ compare(Order, Head1, Head2),
+ ugraph_union(Order, Head1-E1, Tail1, Head2-E2, Tail2, Union).
+
+ugraph_union(=, Head-E1, Tail1, _-E2, Tail2, [Head-Es|Union]) :-
+ ord_union(E1, E2, Es),
+ ugraph_union(Tail1, Tail2, Union).
+ugraph_union(<, Head1, Tail1, Head2, Tail2, [Head1|Union]) :-
+ ugraph_union(Tail1, [Head2|Tail2], Union).
+ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :-
+ ugraph_union([Head1|Tail1], Tail2, Union).
+
+%! del_edges(+Graph, +Edges, -NewGraph)
+%
+% Unify NewGraph with a new graph obtained by removing the list of
+% Edges from Graph. Notice that no vertices are deleted. Example:
+%
+% ```
+% ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]],
+% [1-6,2-3,3-2,5-7,3-2,4-5,1-3],
+% NL).
+% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]]
+% ```
+
+del_edges(Graph, Edges, NewGraph) :-
+ p_to_s_graph(Edges, G1),
+ graph_subtract(Graph, G1, NewGraph).
+
+%! graph_subtract(+Set1, +Set2, ?Difference)
+%
+% Is based on ord_subtract
+
+graph_subtract(Set1, [], Set1) :- !.
+graph_subtract([], _, []).
+graph_subtract([Head1-E1|Tail1], [Head2-E2|Tail2], Difference) :-
+ compare(Order, Head1, Head2),
+ graph_subtract(Order, Head1-E1, Tail1, Head2-E2, Tail2, Difference).
+
+graph_subtract(=, H-E1, Tail1, _-E2, Tail2, [H-E|Difference]) :-
+ ord_subtract(E1,E2,E),
+ graph_subtract(Tail1, Tail2, Difference).
+graph_subtract(<, Head1, Tail1, Head2, Tail2, [Head1|Difference]) :-
+ graph_subtract(Tail1, [Head2|Tail2], Difference).
+graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :-
+ graph_subtract([Head1|Tail1], Tail2, Difference).
+
+%! edges(+Graph, -Edges)
+%
+% Unify Edges with all edges appearing in Graph. Example:
+%
+% ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
+% L = [1-3, 1-5, 2-4, 4-5]
+
+edges(Graph, Edges) :-
+ s_to_p_graph(Graph, Edges).
+
+p_to_s_graph(P_Graph, S_Graph) :-
+ sort(P_Graph, EdgeSet),
+ p_to_s_vertices(EdgeSet, VertexBag),
+ sort(VertexBag, VertexSet),
+ p_to_s_group(VertexSet, EdgeSet, S_Graph).
+
+
+p_to_s_vertices([], []).
+p_to_s_vertices([A-Z|Edges], [A,Z|Vertices]) :-
+ p_to_s_vertices(Edges, Vertices).
+
+
+p_to_s_group([], _, []).
+p_to_s_group([Vertex|Vertices], EdgeSet, [Vertex-Neibs|G]) :-
+ p_to_s_group(EdgeSet, Vertex, Neibs, RestEdges),
+ p_to_s_group(Vertices, RestEdges, G).
+
+
+p_to_s_group([V1-X|Edges], V2, [X|Neibs], RestEdges) :- V1 == V2,
+ !,
+ p_to_s_group(Edges, V2, Neibs, RestEdges).
+p_to_s_group(Edges, _, [], Edges).
+
+
+
+s_to_p_graph([], []) :- !.
+s_to_p_graph([Vertex-Neibs|G], P_Graph) :-
+ s_to_p_graph(Neibs, Vertex, P_Graph, Rest_P_Graph),
+ s_to_p_graph(G, Rest_P_Graph).
+
+
+s_to_p_graph([], _, P_Graph, P_Graph) :- !.
+s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :-
+ s_to_p_graph(Neibs, Vertex, P, Rest_P).
+
+%! transitive_closure(+Graph, -Closure)
+%
+% Generate the graph Closure as the transitive closure of Graph.
+% Example:
+%
+% ```
+% ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L).
+% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]]
+% ```
+
+transitive_closure(Graph, Closure) :-
+ warshall(Graph, Graph, Closure).
+
+warshall([], Closure, Closure) :- !.
+warshall([V-_|G], E, Closure) :-
+ memberchk(V-Y, E), % Y := E(v)
+ warshall(E, V, Y, NewE),
+ warshall(G, NewE, Closure).
+
+
+warshall([X-Neibs|G], V, Y, [X-NewNeibs|NewG]) :-
+ memberchk(V, Neibs),
+ !,
+ ord_union(Neibs, Y, NewNeibs),
+ warshall(G, V, Y, NewG).
+warshall([X-Neibs|G], V, Y, [X-Neibs|NewG]) :-
+ !,
+ warshall(G, V, Y, NewG).
+warshall([], _, _, []).
+
+%! transpose_ugraph(Graph, NewGraph) is det.
+%
+% Unify NewGraph with a new graph obtained from Graph by replacing
+% all edges of the form V1-V2 by edges of the form V2-V1. The cost
+% is O(|V|*log(|V|)). Notice that an undirected graph is its own
+% transpose. Example:
+%
+% ==
+% ?- transpose([1-[3,5],2-[4],3-[],4-[5],
+% 5-[],6-[],7-[],8-[]], NL).
+% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]]
+% ==
+%
+% @compat This predicate used to be known as transpose/2.
+% Following SICStus 4, we reserve transpose/2 for matrix
+% transposition and renamed ugraph transposition to
+% transpose_ugraph/2.
+
+transpose_ugraph(Graph, NewGraph) :-
+ edges(Graph, Edges),
+ vertices(Graph, Vertices),
+ flip_edges(Edges, TransposedEdges),
+ vertices_edges_to_ugraph(Vertices, TransposedEdges, NewGraph).
+
+flip_edges([], []).
+flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :-
+ flip_edges(Pairs, Flipped).
+
+%! compose(+LeftGraph, +RightGraph, -NewGraph)
+%
+% Compose NewGraph by connecting the _drains_ of LeftGraph to the
+% _sources_ of RightGraph. Example:
+%
+% ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
+% L = [1-[4], 2-[1,2,4], 3-[]]
+
+compose(G1, G2, Composition) :-
+ vertices(G1, V1),
+ vertices(G2, V2),
+ ord_union(V1, V2, V),
+ compose(V, G1, G2, Composition).
+
+compose([], _, _, []) :- !.
+compose([Vertex|Vertices], [Vertex-Neibs|G1], G2,
+ [Vertex-Comp|Composition]) :-
+ !,
+ compose1(Neibs, G2, [], Comp),
+ compose(Vertices, G1, G2, Composition).
+compose([Vertex|Vertices], G1, G2, [Vertex-[]|Composition]) :-
+ compose(Vertices, G1, G2, Composition).
+
+
+compose1([V1|Vs1], [V2-N2|G2], SoFar, Comp) :-
+ compare(Rel, V1, V2),
+ !,
+ compose1(Rel, V1, Vs1, V2, N2, G2, SoFar, Comp).
+compose1(_, _, Comp, Comp).
+
+
+compose1(<, _, Vs1, V2, N2, G2, SoFar, Comp) :-
+ !,
+ compose1(Vs1, [V2-N2|G2], SoFar, Comp).
+compose1(>, V1, Vs1, _, _, G2, SoFar, Comp) :-
+ !,
+ compose1([V1|Vs1], G2, SoFar, Comp).
+compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :-
+ ord_union(N2, SoFar, Next),
+ compose1(Vs1, G2, Next, Comp).
+
+%! top_sort(+Graph, -Sorted) is semidet.
+%! top_sort(+Graph, -Sorted, ?Tail) is semidet.
+%
+% Sorted is a topological sorted list of nodes in Graph. A
+% toplogical sort is possible if the graph is connected and
+% acyclic. In the example we show how topological sorting works
+% for a linear graph:
+%
+% ==
+% ?- top_sort([1-[2], 2-[3], 3-[]], L).
+% L = [1, 2, 3]
+% ==
+%
+% The predicate top_sort/3 is a difference list version of
+% top_sort/2.
+
+top_sort(Graph, Sorted) :-
+ vertices_and_zeros(Graph, Vertices, Counts0),
+ count_edges(Graph, Vertices, Counts0, Counts1),
+ select_zeros(Counts1, Vertices, Zeros),
+ top_sort(Zeros, Sorted, Graph, Vertices, Counts1).
+
+top_sort(Graph, Sorted0, Sorted) :-
+ vertices_and_zeros(Graph, Vertices, Counts0),
+ count_edges(Graph, Vertices, Counts0, Counts1),
+ select_zeros(Counts1, Vertices, Zeros),
+ top_sort(Zeros, Sorted, Sorted0, Graph, Vertices, Counts1).
+
+
+vertices_and_zeros([], [], []) :- !.
+vertices_and_zeros([Vertex-_|Graph], [Vertex|Vertices], [0|Zeros]) :-
+ vertices_and_zeros(Graph, Vertices, Zeros).
+
+
+count_edges([], _, Counts, Counts) :- !.
+count_edges([_-Neibs|Graph], Vertices, Counts0, Counts2) :-
+ incr_list(Neibs, Vertices, Counts0, Counts1),
+ count_edges(Graph, Vertices, Counts1, Counts2).
+
+
+incr_list([], _, Counts, Counts) :- !.
+incr_list([V1|Neibs], [V2|Vertices], [M|Counts0], [N|Counts1]) :-
+ V1 == V2,
+ !,
+ N is M+1,
+ incr_list(Neibs, Vertices, Counts0, Counts1).
+incr_list(Neibs, [_|Vertices], [N|Counts0], [N|Counts1]) :-
+ incr_list(Neibs, Vertices, Counts0, Counts1).
+
+
+select_zeros([], [], []) :- !.
+select_zeros([0|Counts], [Vertex|Vertices], [Vertex|Zeros]) :-
+ !,
+ select_zeros(Counts, Vertices, Zeros).
+select_zeros([_|Counts], [_|Vertices], Zeros) :-
+ select_zeros(Counts, Vertices, Zeros).
+
+
+
+top_sort([], [], Graph, _, Counts) :-
+ !,
+ vertices_and_zeros(Graph, _, Counts).
+top_sort([Zero|Zeros], [Zero|Sorted], Graph, Vertices, Counts1) :-
+ graph_memberchk(Zero-Neibs, Graph),
+ decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
+ top_sort(NewZeros, Sorted, Graph, Vertices, Counts2).
+
+top_sort([], Sorted0, Sorted0, Graph, _, Counts) :-
+ !,
+ vertices_and_zeros(Graph, _, Counts).
+top_sort([Zero|Zeros], [Zero|Sorted], Sorted0, Graph, Vertices, Counts1) :-
+ graph_memberchk(Zero-Neibs, Graph),
+ decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
+ top_sort(NewZeros, Sorted, Sorted0, Graph, Vertices, Counts2).
+
+graph_memberchk(Element1-Edges, [Element2-Edges2|_]) :-
+ Element1 == Element2,
+ !,
+ Edges = Edges2.
+graph_memberchk(Element, [_|Rest]) :-
+ graph_memberchk(Element, Rest).
+
+
+decr_list([], _, Counts, Counts, Zeros, Zeros) :- !.
+decr_list([V1|Neibs], [V2|Vertices], [1|Counts1], [0|Counts2], Zi, Zo) :-
+ V1 == V2,
+ !,
+ decr_list(Neibs, Vertices, Counts1, Counts2, [V2|Zi], Zo).
+decr_list([V1|Neibs], [V2|Vertices], [N|Counts1], [M|Counts2], Zi, Zo) :-
+ V1 == V2,
+ !,
+ M is N-1,
+ decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
+decr_list(Neibs, [_|Vertices], [N|Counts1], [N|Counts2], Zi, Zo) :-
+ decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
+
+
+%! neighbors(+Vertex, +Graph, -Neigbours) is det.
+%! neighbours(+Vertex, +Graph, -Neigbours) is det.
+%
+% Neigbours is a sorted list of the neighbours of Vertex in Graph.
+% Example:
+%
+% ```
+% ?- neighbours(4,[1-[3,5],2-[4],3-[],
+% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
+% NL = [1,2,7,5]
+% ```
+
+neighbors(Vertex, Graph, Neig) :-
+ neighbours(Vertex, Graph, Neig).
+
+neighbours(V,[V0-Neig|_],Neig) :-
+ V == V0,
+ !.
+neighbours(V,[_|G],Neig) :-
+ neighbours(V,G,Neig).
+
+
+%! connect_ugraph(+UGraphIn, -Start, -UGraphOut) is det.
+%
+% Adds Start as an additional vertex that is connected to all vertices
+% in UGraphIn. This can be used to create an topological sort for a
+% not connected graph. Start is before any vertex in UGraphIn in the
+% standard order of terms. No vertex in UGraphIn can be a variable.
+%
+% Can be used to order a not-connected graph as follows:
+%
+% ```
+% top_sort_unconnected(Graph, Vertices) :-
+% ( top_sort(Graph, Vertices)
+% -> true
+% ; connect_ugraph(Graph, Start, Connected),
+% top_sort(Connected, Ordered0),
+% Ordered0 = [Start|Vertices]
+% ).
+% ```
+
+connect_ugraph([], 0, []) :- !.
+connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
+ vertices(Graph, Vertices),
+ Vertices = [First|_],
+ before(First, Start).
+
+%! before(+Term, -Before) is det.
+%
+% Unify Before to a term that comes before Term in the standard
+% order of terms.
+%
+% @error instantiation_error if Term is unbound.
+
+before(X, _) :-
+ var(X),
+ !,
+ instantiation_error(X).
+before(Number, Start) :-
+ number(Number),
+ !,
+ Start is Number - 1.
+before(_, 0).
+
+
+%! complement(+UGraphIn, -UGraphOut)
+%
+% UGraphOut is a ugraph with an edge between all vertices that are
+% _not_ connected in UGraphIn and all edges from UGraphIn removed.
+% Example:
+%
+% ```
+% ?- complement([1-[3,5],2-[4],3-[],
+% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
+% NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8],
+% 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8],
+% 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]]
+% ```
+%
+% @tbd Simple two-step algorithm. You could be smarter, I suppose.
+
+complement(G, NG) :-
+ vertices(G,Vs),
+ complement(G,Vs,NG).
+
+complement([], _, []).
+complement([V-Ns|G], Vs, [V-INs|NG]) :-
+ ord_add_element(Ns,V,Ns1),
+ ord_subtract(Vs,Ns1,INs),
+ complement(G, Vs, NG).
+
+%! reachable(+Vertex, +UGraph, -Vertices)
+%
+% True when Vertices is an ordered set of vertices reachable in
+% UGraph, including Vertex. Example:
+%
+% ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V).
+% V = [1, 3, 5]
+
+reachable(N, G, Rs) :-
+ reachable([N], G, [N], Rs).
+
+reachable([], _, Rs, Rs).
+reachable([N|Ns], G, Rs0, RsF) :-
+ neighbours(N, G, Nei),
+ ord_union(Rs0, Nei, Rs1, D),
+ append(Ns, D, Nsi),
+ reachable(Nsi, G, Rs1, RsF).
diff --git a/src/lib/uuid.pl b/src/lib/uuid.pl
index affa3b68..3f89db4b 100644
--- a/src/lib/uuid.pl
+++ b/src/lib/uuid.pl
@@ -4,9 +4,9 @@
This library provides reasoning about UUID (only version 4 right now).
There are three predicates:
* uuidv4/1, to generate a new UUIDv4
- * uuidv4_string/1, to generate a new UUIDv4 in string hex representation
+ * uuidv4_string/1, to generate a new UUIDv4 in string hex representation
* uuid_string/2, to converte between UUID list of bytes and UUID hex representation
-
+
Examples:
?- uuidv4(X).
X = [42,147,248,242,117,196,79,2,129,159|...].
@@ -30,7 +30,7 @@
:- use_module(library(dcgs)).
:- use_module(library(lists)).
-/*
+/*
An UUID is made of 16 bytes, composed of 5 sections:
time_low - 4
time_mid - 2
diff --git a/src/loader.pl b/src/loader.pl
index 531730cc..3d3e8bd2 100644
--- a/src/loader.pl
+++ b/src/loader.pl
@@ -1,4 +1,3 @@
-
:- module(loader, [consult/1,
expand_goal/3,
expand_term/2,
@@ -90,18 +89,22 @@ unload_evacuable(Evacuable) :-
run_initialization_goals(Module) :-
( predicate_property(Module:'$initialization_goals'(_), dynamic) ->
+ % FIXME: failing here. also, see add_module.
findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals),
abolish(Module:'$initialization_goals'/1),
- ( maplist(Module:call, Goals) ->
- true
- ; %% initialization goals can fail without thwarting the load.
- write('Warning: initialization/1 failed for: '),
- writeq(maplist(Module:call, Goals)),
- nl
- )
+ maplist(loader:success_or_warning, Goals)
; true
).
+success_or_warning(Goal) :-
+ ( call(Goal) ->
+ true
+ ; %% initialization goals can fail without thwarting the load.
+ write('Warning: initialization/1 failed for: '),
+ writeq(Goal),
+ nl
+ ).
+
run_initialization_goals :-
prolog_load_context(module, Module),
run_initialization_goals(user),
@@ -258,8 +261,8 @@ expand_term_goals(Terms0, Terms) :-
Terms = (Module:Head2 :- Body1)
; type_error(atom, Module, load/1)
)
- ; prolog_load_context(module, Target),
- module_expanded_head_variables(Head1, HeadVars),
+ ; module_expanded_head_variables(Head1, HeadVars),
+ prolog_load_context(module, Target),
expand_goal(Body0, Target, Body1, HeadVars),
Terms = (Head1 :- Body1)
)
@@ -316,6 +319,7 @@ compile_dispatch(user:goal_expansion(Term, Terms), Evacuable) :-
compile_dispatch((user:goal_expansion(Term, Terms) :- Body), Evacuable) :-
'$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable).
+
remove_module(Module, Evacuable) :-
( nonvar(Module),
Module = library(ModuleName),
@@ -508,7 +512,8 @@ open_file(Path, Stream) :-
; catch(open(Path, read, Stream),
error(existence_error(source_sink, _), _),
( atom_concat(Path, '.pl', ExtendedPath),
- open(ExtendedPath, read, Stream) )
+ open(ExtendedPath, read, Stream)
+ )
)
).
@@ -540,15 +545,15 @@ use_module(Module, Exports, Evacuable) :-
check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
- '$cpp_meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
+ '$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
check_predicate_property(built_in, _, Name, Arity, built_in) :-
- '$cpp_built_in_property'(Name, Arity).
+ '$built_in_property'(Name, Arity).
check_predicate_property(dynamic, Module, Name, Arity, dynamic) :-
- '$cpp_dynamic_property'(Module, Name, Arity).
+ '$dynamic_property'(Module, Name, Arity).
check_predicate_property(multifile, Module, Name, Arity, multifile) :-
- '$cpp_multifile_property'(Module, Name, Arity).
+ '$multifile_property'(Module, Name, Arity).
check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :-
- '$cpp_discontiguous_property'(Module, Name, Arity).
+ '$discontiguous_property'(Module, Name, Arity).
@@ -573,15 +578,13 @@ predicate_property(Callable, Property) :-
atom(Module),
nonvar(Callable0) ->
functor(Callable0, Name, Arity),
- ( atom(Name),
- Name \== [] ->
+ ( atom(Name) ->
extract_predicate_property(Property, PropertyType),
check_predicate_property(PropertyType, Module, Name, Arity, Property)
; type_error(callable, Callable0, predicate_property/2)
)
; functor(Callable, Name, Arity),
- ( atom(Name),
- Name \== [] ->
+ ( atom(Name) ->
extract_predicate_property(Property, PropertyType),
load_context(Module),
check_predicate_property(PropertyType, Module, Name, Arity, Property)
@@ -624,11 +627,16 @@ expand_subgoal(UnexpandedGoals, MS, Module, ExpandedGoals, HeadVars) :-
).
-expand_module_name(ESG0, M, ESG) :-
+expand_module_name(ESG0, MS, M, ESG) :-
( var(ESG0) ->
ESG = M:ESG0
; ESG0 = _:_ ->
ESG = ESG0
+ ; functor(ESG0, F, A0),
+ A is A0 + MS,
+ functor(EESG0, F, A),
+ predicate_property(EESG0, built_in) ->
+ ESG = ESG0
; ESG = M:ESG0
).
@@ -641,7 +649,7 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars
pairs:same_key(SG, HeadVars, [_|_], _) ->
expand_subgoal(SG, MS, M, ESG, HeadVars)
; expand_subgoal(SG, MS, M, ESG0, HeadVars),
- expand_module_name(ESG0, M, ESG)
+ expand_module_name(ESG0, MS, M, ESG)
),
expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars)
; ESG = SG,
@@ -656,14 +664,17 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
( GoalFunctor == (:),
SubGoals = [M, SubGoal] ->
expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars),
- ExpandedGoals = M:ExpandedSubGoal
+ expand_module_name(ExpandedSubGoal, 0, M, ExpandedGoals)
; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars),
ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
).
expand_goal(UnexpandedGoals, Module, ExpandedGoals) :-
- expand_goal(UnexpandedGoals, Module, ExpandedGoals, []),
+ % if a goal isn't callable, defer to call/N to report the error.
+ catch('$call'(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, [])),
+ error(type_error(callable, _), _),
+ '$call'(UnexpandedGoals = ExpandedGoals)),
!.
expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars) :-
@@ -705,33 +716,30 @@ expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :-
)
).
-thread_goals(Goals0, Goals1, Functor) :-
+thread_goals(Goals0, Goals1, Hole, Functor) :-
( var(Goals0) ->
- Goals0 = Goals1
- ; ( Goals0 = [G | Gs] ->
- ( Gs = [] ->
- Goals1 = G
- ; Goals1 =.. [Functor, G, Goals2],
- thread_goals(Gs, Goals2, Functor)
- )
- ; Goals1 = Goals0
+ Goals1 =.. [Functor, Goals0, Hole]
+ ; Goals0 = [G | Gs] ->
+ ( Gs == [] ->
+ Goals1 =.. [Functor, G, Hole]
+ ; Goals1 =.. [Functor, G, Goals2],
+ thread_goals(Gs, Goals2, Hole, Functor)
)
+ ; Goals1 =.. [Functor, Goals0, Hole]
).
-thread_goals(Goals0, Goals1, Hole, Functor) :-
+thread_goals(Goals0, Goals1, Functor) :-
( var(Goals0) ->
- Goals1 =.. [Functor, Goals0, Hole]
- ; ( Goals0 = [G | Gs] ->
- ( Gs == [] ->
- Goals1 =.. [Functor, G, Hole]
- ; Goals1 =.. [Functor, G, Goals2],
- thread_goals(Gs, Goals2, Hole, Functor)
- )
- ; Goals1 =.. [Functor, Goals0, Hole]
+ Goals0 = Goals1
+ ; Goals0 = [G | Gs] ->
+ ( Gs = [] ->
+ Goals1 = G
+ ; Goals1 =.. [Functor, G, Goals2],
+ thread_goals(Gs, Goals2, Functor)
)
+ ; Goals1 = Goals0
).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% call/{1-64} with dynamic goal expansion.
@@ -773,12 +781,14 @@ call_clause('$call'(G), G0) :-
instantiation_error(call/1)
; G = M:G1,
!,
+ callable(G1),
functor(G1, F, _),
atom(F),
atom(M),
F \== [],
G0 = M:G1
; !,
+ callable(G),
functor(G, F, _),
atom(F),
F \== [],
@@ -788,6 +798,7 @@ call_clause('$call'(G), G0) :-
call_clause(G, G0) :-
strip_module(G, M, G1),
+ callable(G1),
functor(G1, F, _),
atom(F),
F \== [],
@@ -818,6 +829,7 @@ call_clause('$call'(G1), Args, N, G0) :-
F \== [],
append(As, Args, As1),
G3 =.. [F | As1],
+ callable(G3),
G0 = M:G3
; !,
G1 =.. [F | As],
@@ -826,6 +838,7 @@ call_clause('$call'(G1), Args, N, G0) :-
load_context(M),
append(As, Args, As1),
G2 =.. [F | As1],
+ callable(G2),
G0 = M:G2
).
@@ -840,6 +853,7 @@ call_clause(G, Args, _, G0) :-
),
append(As, Args, As1),
G2 =.. [F | As1],
+ callable(G2),
expand_goal(call(M:G2), M, call(G0)).
diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs
index 4e3f832a..2541f0a1 100644
--- a/src/machine/arithmetic_ops.rs
+++ b/src/machine/arithmetic_ops.rs
@@ -1,37 +1,97 @@
use divrem::*;
-use prolog_parser::ast::*;
-use prolog_parser::clause_name;
-
+use crate::arena::*;
use crate::arithmetic::*;
-use crate::clause_types::*;
+use crate::atom_table::*;
use crate::forms::*;
+use crate::heap_iter::*;
use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
-use crate::rug::{Integer, Rational};
+use crate::parser::ast::*;
+use crate::parser::rug::{Integer, Rational};
+use crate::types::*;
+
+use crate::fixnum;
+
use ordered_float::*;
use std::cmp;
use std::convert::TryFrom;
use std::f64;
use std::mem;
-use std::rc::Rc;
#[macro_export]
macro_rules! try_numeric_result {
- ($s: ident, $e: expr, $caller: expr) => {
+ ($e: expr, $stub_gen: expr) => {
match $e {
Ok(val) => Ok(val),
- Err(e) => {
- let caller_copy = $caller.iter().map(|v| v.context_free_clone()).collect();
+ Err(e) => Err(Box::new(move |machine_st: &mut MachineState| {
+ let stub = $stub_gen();
+ let evaluation_error = machine_st.evaluation_error(e);
+
+ machine_st.error_form(evaluation_error, stub)
+ }) as Box<dyn Fn(&mut MachineState) -> MachineStub>),
+ }
+ };
+}
- Err($s.error_form(MachineError::evaluation_error(e), caller_copy))
+macro_rules! drop_iter_on_err {
+ ($self:expr, $iter: expr, $result: expr) => {
+ match $result {
+ Ok(val) => val,
+ Err(stub_gen) => {
+ std::mem::drop($iter);
+ return Err(stub_gen($self));
}
}
};
}
+fn zero_divisor_eval_error(
+ stub_gen: impl Fn() -> FunctorStub + 'static,
+) -> MachineStubGen {
+ Box::new(move |machine_st| {
+ let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor);
+ let stub = stub_gen();
+
+ machine_st.error_form(eval_error, stub)
+ })
+}
+
+fn undefined_eval_error(
+ stub_gen: impl Fn() -> FunctorStub + 'static,
+) -> MachineStubGen {
+ Box::new(move |machine_st| {
+ let eval_error = machine_st.evaluation_error(EvalError::Undefined);
+ let stub = stub_gen();
+
+ machine_st.error_form(eval_error, stub)
+ })
+}
+
+fn numerical_type_error(
+ valid_type: ValidType,
+ n: Number,
+ stub_gen: impl Fn() -> FunctorStub + 'static,
+) -> MachineStubGen {
+ Box::new(move |machine_st| {
+ let type_error = machine_st.type_error(valid_type, n);
+ let stub = stub_gen();
+
+ machine_st.error_form(type_error, stub)
+ })
+}
+
+pub(crate) fn sign(n: Number) -> Number {
+ if n.is_positive() {
+ Number::Fixnum(Fixnum::build_with(1))
+ } else if n.is_negative() {
+ Number::Fixnum(Fixnum::build_with(-1))
+ } else {
+ Number::Fixnum(Fixnum::build_with(0))
+ }
+}
+
fn isize_gcd(n1: isize, n2: isize) -> Option<isize> {
if n1 == 0 {
return n2.checked_abs().map(|n| n as isize);
@@ -80,935 +140,1293 @@ fn isize_gcd(n1: isize, n2: isize) -> Option<isize> {
Some(n1 << shift as isize)
}
-impl MachineState {
- pub(crate) fn get_number(&mut self, at: &ArithmeticTerm) -> Result<Number, MachineStub> {
- match at {
- &ArithmeticTerm::Reg(r) => self.arith_eval_by_metacall(r),
- &ArithmeticTerm::Interm(i) => {
- Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(0)))
- }
- &ArithmeticTerm::Number(ref n) => Ok(n.clone()),
+pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number, EvalError> {
+ match (lhs, rhs) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(
+ if let Some(result) = n1.get_num().checked_add(n2.get_num()) {
+ fixnum!(Number, result, arena)
+ } else {
+ Number::arena_from(
+ Integer::from(n1.get_num()) + Integer::from(n2.get_num()),
+ arena,
+ )
+ },
+ ),
+ (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => {
+ Ok(Number::arena_from(
+ Integer::from(n1.get_num()) + &*n2,
+ arena,
+ ))
+ }
+ (Number::Fixnum(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Fixnum(n1)) => {
+ Ok(Number::arena_from(
+ Rational::from(n1.get_num()) + &*n2,
+ arena,
+ ))
+ }
+ (Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
+ | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
+ Ok(Number::Float(add_f(float_fn_to_f(n1.get_num())?, n2)?))
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1) + &*n2, arena)) // 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::arena_from(Rational::from(&*n1) + &*n2, arena))
+ }
+ (Number::Rational(n1), Number::Float(OrderedFloat(n2)))
+ | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
+ Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
+ }
+ (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
+ Ok(Number::Float(add_f(f1, f2)?))
+ }
+ (Number::Rational(r1), Number::Rational(r2)) => {
+ Ok(Number::arena_from(Rational::from(&*r1) + &*r2, arena))
}
}
+}
- pub(super) fn rational_from_number(&self, n: Number) -> Result<Rc<Rational>, MachineError> {
- match n {
- Number::Fixnum(n) => Ok(Rc::new(Rational::from(n))),
- Number::Rational(r) => Ok(r),
- Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) {
- Some(r) => Ok(Rc::new(r)),
- None => Err(MachineError::instantiation_error()),
- },
- Number::Integer(n) => Ok(Rc::new(Rational::from(&*n))),
+pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number {
+ match n {
+ Number::Fixnum(n) => {
+ if let Some(n) = n.get_num().checked_neg() {
+ fixnum!(Number, n, arena)
+ } else {
+ Number::arena_from(-Integer::from(n.get_num()), arena)
+ }
}
+ Number::Integer(n) => Number::arena_from(-Integer::from(&*n), arena),
+ Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
+ Number::Rational(r) => Number::arena_from(-Rational::from(&*r), arena),
}
+}
- pub(crate) fn get_rational(
- &mut self,
- at: &ArithmeticTerm,
- caller: MachineStub,
- ) -> Result<(Rc<Rational>, MachineStub), MachineStub> {
- let n = self.get_number(at)?;
-
- match self.rational_from_number(n) {
- Ok(r) => Ok((r, caller)),
- Err(e) => Err(self.error_form(e, caller)),
- }
- }
-
- pub(crate) fn arith_eval_by_metacall(&self, r: RegType) -> Result<Number, MachineStub> {
- let caller = MachineError::functor_stub(clause_name!("is"), 2);
- let mut interms: Vec<Number> = Vec::with_capacity(64);
-
- for addr in self.post_order_iter(self[r]) {
- match self.heap.index_addr(&addr).as_ref() {
- &HeapCellValue::NamedStr(2, ref name, _) => {
- let a2 = interms.pop().unwrap();
- let a1 = interms.pop().unwrap();
-
- match name.as_str() {
- "+" => interms.push(try_numeric_result!(self, a1 + a2, caller)?),
- "-" => interms.push(try_numeric_result!(self, a1 - a2, caller)?),
- "*" => interms.push(try_numeric_result!(self, a1 * a2, caller)?),
- "/" => interms.push(self.div(a1, a2)?),
- "**" => interms.push(self.pow(a1, a2, "is")?),
- "^" => interms.push(self.int_pow(a1, a2)?),
- "max" => interms.push(self.max(a1, a2)?),
- "min" => interms.push(self.min(a1, a2)?),
- "rdiv" => {
- let r1 = self.rational_from_number(a1);
- let r2 =
- r1.and_then(|r1| self.rational_from_number(a2).map(|r2| (r1, r2)));
-
- match r2 {
- Ok((r1, r2)) => {
- let result = Number::Rational(Rc::new(self.rdiv(r1, r2)?));
- interms.push(result);
- }
- Err(e) => {
- return Err(self.error_form(e, caller));
- }
- }
- }
- "//" => interms.push(self.idiv(a1, a2)?),
- "div" => interms.push(self.int_floor_div(a1, a2)?),
- ">>" => interms.push(self.shr(a1, a2)?),
- "<<" => interms.push(self.shl(a1, a2)?),
- "/\\" => interms.push(self.and(a1, a2)?),
- "\\/" => interms.push(self.or(a1, a2)?),
- "xor" => interms.push(self.xor(a1, a2)?),
- "mod" => interms.push(self.modulus(a1, a2)?),
- "rem" => interms.push(self.remainder(a1, a2)?),
- "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))),
- "gcd" => interms.push(self.gcd(a1, a2)?),
- _ => {
- let evaluable_stub = MachineError::functor_stub(name.clone(), 2);
-
- return Err(self.error_form(
- MachineError::type_error(
- self.heap.h(),
- ValidType::Evaluable,
- evaluable_stub,
- ),
- caller,
- ));
- }
- }
- }
- &HeapCellValue::NamedStr(1, ref name, _) => {
- let a1 = interms.pop().unwrap();
-
- match name.as_str() {
- "-" => interms.push(-a1),
- "+" => interms.push(a1),
- "cos" => interms.push(Number::Float(OrderedFloat(self.cos(a1)?))),
- "sin" => interms.push(Number::Float(OrderedFloat(self.sin(a1)?))),
- "tan" => interms.push(Number::Float(OrderedFloat(self.tan(a1)?))),
- "sqrt" => interms.push(Number::Float(OrderedFloat(self.sqrt(a1)?))),
- "log" => interms.push(Number::Float(OrderedFloat(self.log(a1)?))),
- "exp" => interms.push(Number::Float(OrderedFloat(self.exp(a1)?))),
- "acos" => interms.push(Number::Float(OrderedFloat(self.acos(a1)?))),
- "asin" => interms.push(Number::Float(OrderedFloat(self.asin(a1)?))),
- "atan" => interms.push(Number::Float(OrderedFloat(self.atan(a1)?))),
- "abs" => interms.push(a1.abs()),
- "float" => interms.push(Number::Float(OrderedFloat(self.float(a1)?))),
- "truncate" => interms.push(self.truncate(a1)),
- "round" => interms.push(self.round(a1)?),
- "ceiling" => interms.push(self.ceiling(a1)),
- "floor" => interms.push(self.floor(a1)),
- "\\" => interms.push(self.bitwise_complement(a1)?),
- "sign" => interms.push(self.sign(a1)),
- _ => {
- let evaluable_stub = MachineError::functor_stub(name.clone(), 1);
-
- return Err(self.error_form(
- MachineError::type_error(
- self.heap.h(),
- ValidType::Evaluable,
- evaluable_stub,
- ),
- caller,
- ));
- }
- }
- }
- &HeapCellValue::Addr(Addr::Fixnum(n)) => {
- interms.push(Number::Fixnum(n));
- }
- &HeapCellValue::Addr(Addr::Float(n)) => interms.push(Number::Float(n)),
- &HeapCellValue::Integer(ref n) => interms.push(Number::Integer(n.clone())),
- &HeapCellValue::Addr(Addr::Usize(n)) => {
- interms.push(Number::Integer(Rc::new(Integer::from(n))));
- }
- &HeapCellValue::Rational(ref n) => interms.push(Number::Rational(n.clone())),
- &HeapCellValue::Atom(ref name, _) if name.as_str() == "pi" => {
- interms.push(Number::Float(OrderedFloat(f64::consts::PI)))
- }
- &HeapCellValue::Atom(ref name, _) if name.as_str() == "e" => {
- interms.push(Number::Float(OrderedFloat(f64::consts::E)))
- }
- &HeapCellValue::Atom(ref name, _) if name.as_str() == "epsilon" => {
- interms.push(Number::Float(OrderedFloat(f64::EPSILON)))
- }
- &HeapCellValue::NamedStr(arity, ref name, _) => {
- let evaluable_stub = MachineError::functor_stub(name.clone(), arity);
-
- return Err(self.error_form(
- MachineError::type_error(
- self.heap.h(),
- ValidType::Evaluable,
- evaluable_stub,
- ),
- caller,
- ));
- }
- &HeapCellValue::Atom(ref name, _) => {
- let evaluable_stub = MachineError::functor_stub(name.clone(), 0);
-
- return Err(self.error_form(
- MachineError::type_error(
- self.heap.h(),
- ValidType::Evaluable,
- evaluable_stub,
- ),
- caller,
- ));
- }
- &HeapCellValue::Addr(addr) if addr.is_ref() => {
- return Err(self.error_form(MachineError::instantiation_error(), caller));
- }
- val => {
- return Err(self.type_error(
- ValidType::Number,
- val.context_free_clone(),
- clause_name!("is"),
- 2,
- ));
- }
+pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
+ match n {
+ Number::Fixnum(n) => {
+ if let Some(n) = n.get_num().checked_abs() {
+ fixnum!(Number, n, arena)
+ } else {
+ Number::arena_from(Integer::from(n.get_num()).abs(), arena)
}
}
-
- Ok(interms.pop().unwrap())
+ Number::Integer(n) => Number::arena_from(Integer::from(n.abs_ref()), arena),
+ Number::Float(f) => Number::Float(f.abs()),
+ Number::Rational(r) => Number::arena_from(Rational::from(r.abs_ref()), arena),
}
+}
+
+#[inline]
+pub(crate) fn sub(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number, EvalError> {
+ let neg_result = neg(rhs, arena);
+ add(lhs, neg_result, arena)
+}
- pub(crate) fn rdiv(&self, r1: Rc<Rational>, r2: Rc<Rational>) -> Result<Rational, MachineStub> {
- if &*r2 == &0 {
- let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2);
- Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Rational::from(&*r1 / &*r2))
+pub(crate) fn mul(lhs: Number, rhs: Number, arena: &mut Arena) -> Result<Number, EvalError> {
+ match (lhs, rhs) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(
+ if let Some(result) = n1.get_num().checked_mul(n2.get_num()) {
+ fixnum!(Number, result, arena)
+ } else {
+ Number::arena_from(
+ Integer::from(n1.get_num()) * Integer::from(n2.get_num()),
+ arena,
+ )
+ },
+ ),
+ (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => {
+ Ok(Number::arena_from(
+ Integer::from(n1.get_num()) * &*n2,
+ arena,
+ ))
+ }
+ (Number::Fixnum(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Fixnum(n1)) => {
+ Ok(Number::arena_from(
+ Rational::from(n1.get_num()) * &*n2,
+ arena,
+ ))
+ }
+ (Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
+ | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
+ Ok(Number::Float(mul_f(float_fn_to_f(n1.get_num())?, n2)?))
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1) * &*n2, arena)) // 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::arena_from(Rational::from(&*n1) * &*n2, arena))
+ }
+ (Number::Rational(n1), Number::Float(OrderedFloat(n2)))
+ | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
+ Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?))
+ }
+ (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
+ Ok(Number::Float(mul_f(f1, f2)?))
+ }
+ (Number::Rational(r1), Number::Rational(r2)) => {
+ Ok(Number::arena_from(Rational::from(&*r1) * &*r2, arena))
}
}
+}
- pub(crate) fn int_floor_div(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(div)"), 2);
- let modulus = self.modulus(n1.clone(), n2.clone())?;
+pub(crate) fn div(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
+ let stub_gen = || functor_stub(atom!("/"), 2);
- self.idiv(try_numeric_result!(self, n1 - modulus, stub)?, n2)
+ if n2.is_zero() {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ try_numeric_result!(n1 / n2, stub_gen)
}
+}
- pub(crate) fn idiv(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n2 == 0 {
- let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
+pub(crate) fn float_pow(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
+ let f1 = result_f(&n1, rnd_f);
+ let f2 = result_f(&n2, rnd_f);
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- if let Some(result) = n1.checked_div(n2) {
- Ok(Number::from(result))
- } else {
- let n1 = Integer::from(n1);
- let n2 = Integer::from(n2);
+ let stub_gen = || {
+ let pow_atom = atom!("**");
+ functor_stub(pow_atom, 2)
+ };
+
+ let f1 = try_numeric_result!(f1, stub_gen)?;
+ let f2 = try_numeric_result!(f2, stub_gen)?;
- Ok(Number::from(n1 / n2))
+ let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f);
+
+ Ok(Number::Float(OrderedFloat(try_numeric_result!(
+ result, stub_gen
+ )?)))
+}
+
+pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ if n1.is_zero() && n2.is_negative() {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
+
+ return Err(undefined_eval_error(stub_gen));
+ }
+
+ let stub_gen = || {
+ let caret_atom = atom!("^");
+ functor_stub(caret_atom, 2)
+ };
+
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n1_i = n1.get_num();
+ let n2_i = n2.get_num();
+
+ if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && n2_i < 0 {
+ let n = Number::Fixnum(n1);
+ Err(numerical_type_error(ValidType::Float, n, stub_gen))
+ } else {
+ if let Ok(n2_u) = u32::try_from(n2_i) {
+ if let Some(result) = n1_i.checked_pow(n2_u) {
+ return Ok(Number::arena_from(result, arena));
}
}
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 == &0 {
- let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(Integer::from(n1) / &*n2))
- }
- }
- (Number::Integer(n2), Number::Fixnum(n1)) => {
- if n1 == 0 {
- let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
+ let n1 = Integer::from(n1_i);
+ let n2 = Integer::from(n2_i);
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(&*n2 / Integer::from(n1)))
- }
+ Ok(Number::arena_from(binary_pow(n1, &n2), arena))
}
- (Number::Integer(n1), Number::Integer(n2)) => {
- if &*n2 == &0 {
- let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
-
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(
- <(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0,
- ))
- }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1_i = n1.get_num();
+
+ if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && &*n2 < &0 {
+ let n = Number::Fixnum(n1);
+ Err(numerical_type_error(ValidType::Float, n, stub_gen))
+ } else {
+ let n1 = Integer::from(n1_i);
+ Ok(Number::arena_from(binary_pow(n1, &*n2), arena))
}
- (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => {
- let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
-
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- ))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
+
+ if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2_i < 0 {
+ let n = Number::Integer(n1);
+ Err(numerical_type_error(ValidType::Float, n, stub_gen))
+ } else {
+ let n2 = Integer::from(n2_i);
+ Ok(Number::arena_from(binary_pow((*n1).clone(), &n2), arena))
}
- (n1, _) => {
- let stub = MachineError::functor_stub(clause_name!("(//)"), 2);
-
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- ))
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 {
+ let n = Number::Integer(n1);
+ Err(numerical_type_error(ValidType::Float, n, stub_gen))
+ } else {
+ Ok(Number::arena_from(binary_pow((*n1).clone(), &*n2), arena))
}
}
- }
+ (n1, Number::Integer(n2)) => {
+ let f1 = float(n1)?;
+ let f2 = float(Number::Integer(n2))?;
- pub(crate) fn div(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(/)"), 2);
-
- if n2.is_zero() {
- Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- try_numeric_result!(self, n1 / n2, stub)
+ unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2))
+ .map(|f| Number::Float(OrderedFloat(f)))
}
- }
+ (n1, n2) => {
+ let f2 = float(n2)?;
- pub(crate) fn atan2(&self, n1: Number, n2: Number) -> Result<f64, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
+ if n1.is_negative() && f2 != f2.floor() {
+ return Err(undefined_eval_error(stub_gen));
+ }
- if n1.is_zero() && n2.is_zero() {
- Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub))
- } else {
- let f1 = self.float(n1)?;
- let f2 = self.float(n2)?;
+ let f1 = float(n1)?;
- self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2))
+ unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2))
+ .map(|f| Number::Float(OrderedFloat(f)))
}
}
+}
- pub(crate) fn int_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- if n1.is_zero() && n2.is_negative() {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
- return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
- }
+pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result<Number, MachineStubGen> {
+ if n2.is_negative() && n1.is_zero() {
+ let stub_gen = move || functor_stub(culprit, 2);
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if !(n1 == 1 || n1 == 0 || n1 == -1) && n2 < 0 {
- let n = Number::from(n1);
- let stub = MachineError::functor_stub(clause_name!("^"), 2);
+ return Err(undefined_eval_error(stub_gen));
+ }
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Float, n),
- stub,
- ))
- } else {
- if let Ok(n2) = u32::try_from(n2) {
- if let Some(result) = n1.checked_pow(n2) {
- return Ok(Number::from(result));
- }
- }
+ float_pow(n1, n2)
+}
- let n1 = Integer::from(n1);
- let n2 = Integer::from(n2);
+#[inline]
+pub(crate) fn float(n: Number) -> Result<f64, MachineStubGen> {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
- Ok(Number::from(binary_pow(n1, &n2)))
- }
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if !(n1 == 1 || n1 == 0 || n1 == -1) && &*n2 < &0 {
- let n = Number::from(n1);
- let stub = MachineError::functor_stub(clause_name!("^"), 2);
+ try_numeric_result!(result_f(&n, rnd_f), stub_gen)
+}
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Float, n),
- stub,
- ))
- } else {
- let n1 = Integer::from(n1);
- Ok(Number::from(binary_pow(n1, n2.as_ref())))
- }
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2 < 0 {
- let n = Number::Integer(n1);
- let stub = MachineError::functor_stub(clause_name!("^"), 2);
+#[inline]
+pub(crate) fn unary_float_fn_template<FloatFn>(
+ n1: Number,
+ f: FloatFn,
+) -> Result<f64, MachineStubGen>
+where
+ FloatFn: Fn(f64) -> f64,
+{
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Float, n),
- stub,
- ))
- } else {
- let n2 = Integer::from(n2);
- Ok(Number::from(binary_pow(n1.as_ref().clone(), &n2)))
- }
- }
- (Number::Integer(n1), Number::Integer(n2)) => {
- if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 {
- let n = Number::Integer(n1);
- let stub = MachineError::functor_stub(clause_name!("^"), 2);
+ let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
+ let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f);
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Float, n),
- stub,
- ))
- } else {
- Ok(Number::from(binary_pow(n1.as_ref().clone(), n2.as_ref())))
- }
- }
- (n1, Number::Integer(n2)) => {
- let f1 = self.float(n1)?;
- let f2 = self.float(Number::Integer(n2))?;
+ try_numeric_result!(f1, stub_gen)
+}
- self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2))
- .map(|f| Number::Float(OrderedFloat(f)))
+pub(crate) fn max(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ if n1.get_num() > n2.get_num() {
+ Ok(Number::Fixnum(n1))
+ } else {
+ Ok(Number::Fixnum(n2))
+ }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ if &*n2 > &n1.get_num() {
+ Ok(Number::Integer(n2))
+ } else {
+ Ok(Number::Fixnum(n1))
}
- (n1, n2) => {
- let f2 = self.float(n2)?;
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => {
+ if &*n1 > &n2.get_num() {
+ Ok(Number::Integer(n1))
+ } else {
+ Ok(Number::Fixnum(n2))
+ }
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ if n1 > n2 {
+ Ok(Number::Integer(n1))
+ } else {
+ Ok(Number::Integer(n2))
+ }
+ }
+ (n1, n2) => {
+ let stub_gen = || {
+ let max_atom = atom!("max");
+ functor_stub(max_atom, 2)
+ };
- if n1.is_negative() && f2 != f2.floor() {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
- return Err(
- self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)
- );
- }
+ let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
+ let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?;
- let f1 = self.float(n1)?;
- self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2))
- .map(|f| Number::Float(OrderedFloat(f)))
- }
+ Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2))))
}
}
+}
- pub(crate) fn gcd(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if let Some(result) = isize_gcd(n1, n2) {
- Ok(Number::Fixnum(result))
- } else {
- Ok(Number::from(Integer::from(n1).gcd(&Integer::from(n2))))
- }
+pub(crate) fn min(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ if n1.get_num() < n2.get_num() {
+ Ok(Number::Fixnum(n1))
+ } else {
+ Ok(Number::Fixnum(n2))
}
- (Number::Fixnum(n1), Number::Integer(n2))
- | (Number::Integer(n2), Number::Fixnum(n1)) => {
- let n1 = Integer::from(n1);
- Ok(Number::from(Integer::from(n2.gcd_ref(&n1))))
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ if &*n2 < &n1.get_num() {
+ Ok(Number::Integer(n2))
+ } else {
+ Ok(Number::Fixnum(n1))
}
- (Number::Integer(n1), Number::Integer(n2)) => {
- Ok(Number::from(Integer::from(n1.gcd_ref(&n2))))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => {
+ if &*n1 < &n2.get_num() {
+ Ok(Number::Integer(n1))
+ } else {
+ Ok(Number::Fixnum(n2))
}
- (Number::Float(f), _) | (_, Number::Float(f)) => {
- let n = Number::Float(f);
- let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
-
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n),
- stub,
- ))
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ if n1 < n2 {
+ Ok(Number::Integer(n1))
+ } else {
+ Ok(Number::Integer(n2))
}
- (Number::Rational(r), _) | (_, Number::Rational(r)) => {
- let n = Number::Rational(r);
- let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
+ }
+ (n1, n2) => {
+ let stub_gen = || {
+ let min_atom = atom!("min");
+ functor_stub(min_atom, 2)
+ };
- Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n),
- stub,
- ))
- }
+ let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
+ let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?;
+
+ Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2))))
}
}
+}
- pub(crate) fn float_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let f1 = result_f(&n1, rnd_f);
- let f2 = result_f(&n2, rnd_f);
-
- let stub = MachineError::functor_stub(clause_name!("(**)"), 2);
+pub fn rational_from_number(
+ n: Number,
+ stub_gen: impl Fn() -> FunctorStub + 'static,
+ arena: &mut Arena,
+) -> Result<TypedArenaPtr<Rational>, MachineStubGen> {
+ match n {
+ Number::Fixnum(n) => Ok(arena_alloc!(Rational::from(n.get_num()), arena)),
+ Number::Rational(r) => Ok(r),
+ Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) {
+ Some(r) => Ok(arena_alloc!(r, arena)),
+ None => Err(Box::new(move |machine_st| {
+ let instantiation_error = machine_st.instantiation_error();
+ let stub = stub_gen();
+
+ machine_st.error_form(instantiation_error, stub)
+ })),
+ },
+ Number::Integer(n) => Ok(arena_alloc!(Rational::from(&*n), arena)),
+ }
+}
- let f1 = try_numeric_result!(self, f1, stub)?;
- let f2 = try_numeric_result!(self, f2, stub)?;
+pub(crate) fn rdiv(
+ r1: TypedArenaPtr<Rational>,
+ r2: TypedArenaPtr<Rational>,
+) -> Result<Rational, MachineStubGen> {
+ if &*r2 == &0 {
+ let stub_gen = || {
+ let rdiv_atom = atom!("rdiv");
+ functor_stub(rdiv_atom, 2)
+ };
+
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Rational::from(&*r1 / &*r2))
+ }
+}
- let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f);
+pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let idiv_atom = atom!("//");
+ functor_stub(idiv_atom, 2)
+ };
- Ok(Number::Float(OrderedFloat(try_numeric_result!(
- self, result, stub
- )?)))
- }
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ if n2.get_num() == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ if let Some(result) = n1.get_num().checked_div(n2.get_num()) {
+ Ok(Number::arena_from(result, arena))
+ } else {
+ let n1 = Integer::from(n1.get_num());
+ let n2 = Integer::from(n2.get_num());
- pub(crate) fn pow(
- &self,
- n1: Number,
- n2: Number,
- culprit: &'static str,
- ) -> Result<Number, MachineStub> {
- if n2.is_negative() && n1.is_zero() {
- let stub = MachineError::functor_stub(clause_name!(culprit), 2);
- return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
+ Ok(Number::arena_from(n1 / n2, arena))
+ }
+ }
}
-
- self.float_pow(n1, n2)
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Number::arena_from(Integer::from(n1) / &*n2, arena))
+ }
+ }
+ (Number::Integer(n2), Number::Fixnum(n1)) => {
+ if n1.get_num() == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Number::arena_from(&*n2 / Integer::from(n1), arena))
+ }
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Number::arena_from(
+ <(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0,
+ arena,
+ ))
+ }
+ }
+ (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn unary_float_fn_template<FloatFn>(
- &self,
- n1: Number,
- f: FloatFn,
- ) -> Result<f64, MachineStub>
- where
- FloatFn: Fn(f64) -> f64,
- {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
+pub(crate) fn int_floor_div(
+ n1: Number,
+ n2: Number,
+ arena: &mut Arena,
+) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let div_atom = atom!("div");
+ functor_stub(div_atom, 2)
+ };
- let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
- let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f);
+ let modulus = modulus(n1, n2, arena)?;
+ let n1 = try_numeric_result!(sub(n1, modulus, arena), stub_gen)?;
- try_numeric_result!(self, f1, stub)
- }
+ idiv(n1, n2, arena)
+}
- #[inline]
- pub(crate) fn sin(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.sin())
- }
+pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let shr_atom = atom!(">>");
+ functor_stub(shr_atom, 2)
+ };
- #[inline]
- pub(crate) fn cos(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.cos())
- }
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n1_i = n1.get_num();
+ let n2_i = n2.get_num();
- #[inline]
- pub(crate) fn tan(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.tan())
- }
+ let n1 = Integer::from(n1_i);
- #[inline]
- pub(crate) fn log(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.log(f64::consts::E))
- }
+ if let Ok(n2) = u32::try_from(n2_i) {
+ return Ok(Number::arena_from(n1 >> n2, arena));
+ } else {
+ return Ok(Number::arena_from(n1 >> u32::max_value(), arena));
+ }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
- #[inline]
- pub(crate) fn exp(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.exp())
+ match n2.to_u32() {
+ Some(n2) => Ok(Number::arena_from(n1 >> n2, arena)),
+ _ => Ok(Number::arena_from(n1 >> u32::max_value(), arena)),
+ }
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) {
+ Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
+ _ => Ok(Number::arena_from(
+ Integer::from(&*n1 >> u32::max_value()),
+ arena,
+ )),
+ },
+ (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
+ Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
+ _ => Ok(Number::arena_from(
+ Integer::from(&*n1 >> u32::max_value()),
+ arena,
+ )),
+ },
+ (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn asin(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.asin())
- }
+pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let shl_atom = atom!(">>");
+ functor_stub(shl_atom, 2)
+ };
- #[inline]
- pub(crate) fn acos(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.acos())
- }
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n1_i = n1.get_num();
+ let n2_i = n2.get_num();
- #[inline]
- pub(crate) fn atan(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.atan())
- }
+ let n1 = Integer::from(n1_i);
- #[inline]
- pub(crate) fn sqrt(&self, n1: Number) -> Result<f64, MachineStub> {
- if n1.is_negative() {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
- return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
+ if let Ok(n2) = u32::try_from(n2_i) {
+ return Ok(Number::arena_from(n1 << n2, arena));
+ } else {
+ return Ok(Number::arena_from(n1 << u32::max_value(), arena));
+ }
}
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
- self.unary_float_fn_template(n1, |f| f.sqrt())
+ match n2.to_u32() {
+ Some(n2) => Ok(Number::arena_from(n1 << n2, arena)),
+ _ => Ok(Number::arena_from(n1 << u32::max_value(), arena)),
+ }
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) {
+ Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
+ _ => Ok(Number::arena_from(
+ Integer::from(&*n1 << u32::max_value()),
+ arena,
+ )),
+ },
+ (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
+ Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
+ _ => Ok(Number::arena_from(
+ Integer::from(&*n1 << u32::max_value()),
+ arena,
+ )),
+ },
+ (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn float(&self, n: Number) -> Result<f64, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
- try_numeric_result!(self, result_f(&n, rnd_f), stub)
- }
+pub(crate) fn and(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let and_atom = atom!("/\\");
+ functor_stub(and_atom, 2)
+ };
- #[inline]
- pub(crate) fn floor(&self, n1: Number) -> Number {
- rnd_i(&n1).to_owned()
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ Ok(Number::arena_from(n1.get_num() & n2.get_num(), arena))
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 & &*n2, arena))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from(
+ &*n1 & Integer::from(n2.get_num()),
+ arena,
+ )),
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1 & &*n2), arena))
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn ceiling(&self, n1: Number) -> Number {
- -self.floor(-n1)
- }
+pub(crate) fn or(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let or_atom = atom!("\\/");
+ functor_stub(or_atom, 2)
+ };
- #[inline]
- pub(crate) fn truncate(&self, n: Number) -> Number {
- if n.is_negative() {
- -self.floor(n.abs())
- } else {
- self.floor(n)
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ Ok(Number::arena_from(n1.get_num() | n2.get_num(), arena))
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 | &*n2, arena))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from(
+ &*n1 | Integer::from(n2.get_num()),
+ arena,
+ )),
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1 | &*n2), arena))
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
}
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- pub(crate) fn round(&self, n: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
-
- let result = n + Number::Float(OrderedFloat(0.5f64));
- let result = try_numeric_result!(self, result, stub)?;
+pub(crate) fn xor(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let xor_atom = atom!("xor");
+ functor_stub(xor_atom, 2)
+ };
- Ok(self.floor(result))
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ Ok(Number::arena_from(n1.get_num() ^ n2.get_num(), arena))
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 ^ &*n2, arena))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from(
+ &*n1 ^ Integer::from(n2.get_num()),
+ arena,
+ )),
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1 ^ &*n2), arena))
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ _ => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
}
+}
- pub(crate) fn shr(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(>>)"), 2);
+pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let mod_atom = atom!("mod");
+ functor_stub(mod_atom, 2)
+ };
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- let n1 = Integer::from(n1);
+ match (x, y) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
- if let Ok(n2) = u32::try_from(n2) {
- return Ok(Number::from(n1 >> n2));
- } else {
- return Ok(Number::from(n1 >> u32::max_value()));
- }
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1_i = n1.get_num();
+ Ok(Number::arena_from(n1_i.rem_floor(n2_i), arena))
}
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
-
- match n2.to_u32() {
- Some(n2) => Ok(Number::from(n1 >> n2)),
- _ => Ok(Number::from(n1 >> u32::max_value())),
- }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(
+ <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1,
+ arena,
+ ))
}
- (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) {
- Ok(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))),
- _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))),
- },
- (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
- Some(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))),
- _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))),
- },
- (Number::Integer(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
}
+ (Number::Integer(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
+
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n2 = Integer::from(n2_i);
+ Ok(Number::arena_from(
+ <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1,
+ arena,
+ ))
+ }
+ }
+ (Number::Integer(x), Number::Integer(y)) => {
+ if &*y == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Number::arena_from(
+ <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1,
+ arena,
+ ))
+ }
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- pub(crate) fn shl(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(<<)"), 2);
+pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let rem_atom = atom!("rem");
+ functor_stub(rem_atom, 2)
+ };
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- let n1 = Integer::from(n1);
+ match (x, y) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
- if let Ok(n2) = u32::try_from(n2) {
- return Ok(Number::from(n1 << n2));
- } else {
- return Ok(Number::from(n1 << u32::max_value()));
- }
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1_i = n1.get_num();
+ Ok(Number::arena_from(n1_i % n2_i, arena))
}
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
-
- match n2.to_u32() {
- Some(n2) => Ok(Number::from(n1 << n2)),
- _ => Ok(Number::from(n1 << u32::max_value())),
- }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 % &*n2, arena))
}
- (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) {
- Ok(n2) => Ok(Number::from(Integer::from(&*n1 << n2))),
- _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))),
- },
- (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
- Some(n2) => Ok(Number::from(Integer::from(&*n1 << n2))),
- _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))),
- },
- (Number::Integer(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
}
+ (Number::Integer(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
+
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n2 = Integer::from(n2_i);
+ Ok(Number::arena_from(&*n1 % n2, arena))
+ }
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Number::arena_from(Integer::from(&*n1 % &*n2), arena))
+ }
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- pub(crate) fn bitwise_complement(&self, n1: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(\\)"), 2);
+pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let gcd_atom = atom!("gcd");
+ functor_stub(gcd_atom, 2)
+ };
- match n1 {
- Number::Fixnum(n) => Ok(Number::Fixnum(!n)),
- Number::Integer(n1) => Ok(Number::from(Integer::from(!&*n1))),
- _ => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n1_i = n1.get_num() as isize;
+ let n2_i = n2.get_num() as isize;
+
+ if let Some(result) = isize_gcd(n1_i, n2_i) {
+ Ok(Number::arena_from(result, arena))
+ } else {
+ Ok(Number::arena_from(
+ Integer::from(n1_i).gcd(&Integer::from(n2_i)),
+ arena,
+ ))
+ }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(Integer::from(n2.gcd_ref(&n1)), arena))
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(n1.gcd_ref(&n2)), arena))
+ }
+ (Number::Float(f), _) | (_, Number::Float(f)) => {
+ let n = Number::Float(f);
+ Err(numerical_type_error(ValidType::Integer, n, stub_gen))
+ }
+ (Number::Rational(r), _) | (_, Number::Rational(r)) => {
+ let n = Number::Rational(r);
+ Err(numerical_type_error(ValidType::Integer, n, stub_gen))
}
}
+}
- pub(crate) fn xor(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(xor)"), 2);
+pub(crate) fn atan2(n1: Number, n2: Number) -> Result<f64, MachineStubGen> {
+ if n1.is_zero() && n2.is_zero() {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 ^ n2)),
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
- Ok(Number::from(n1 ^ &*n2))
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 ^ Integer::from(n2))),
- (Number::Integer(n1), Number::Integer(n2)) => {
- Ok(Number::from(Integer::from(&*n1 ^ &*n2)))
- }
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
+ Err(undefined_eval_error(stub_gen))
+ } else {
+ let f1 = float(n1)?;
+ let f2 = float(n2)?;
+
+ unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2))
}
+}
- pub(crate) fn and(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2);
+#[inline]
+pub(crate) fn sin(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.sin())
+}
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 & n2)),
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
- Ok(Number::from(n1 & &*n2))
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 & Integer::from(n2))),
- (Number::Integer(n1), Number::Integer(n2)) => {
- Ok(Number::from(Integer::from(&*n1 & &*n2)))
- }
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
+#[inline]
+pub(crate) fn cos(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.cos())
+}
+
+#[inline]
+pub(crate) fn tan(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.tan())
+}
+
+#[inline]
+pub(crate) fn log(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.log(f64::consts::E))
+}
+
+#[inline]
+pub(crate) fn exp(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.exp())
+}
+
+#[inline]
+pub(crate) fn asin(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.asin())
+}
+
+#[inline]
+pub(crate) fn acos(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.acos())
+}
+
+#[inline]
+pub(crate) fn atan(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.atan())
+}
+
+#[inline]
+pub(crate) fn sqrt(n1: Number) -> Result<f64, MachineStubGen> {
+ if n1.is_negative() {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
+
+ return Err(undefined_eval_error(stub_gen));
}
- pub(crate) fn or(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2);
+ unary_float_fn_template(n1, |f| f.sqrt())
+}
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 | n2)),
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
- Ok(Number::from(n1 | &*n2))
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 | Integer::from(n2))),
- (Number::Integer(n1), Number::Integer(n2)) => {
- Ok(Number::from(Integer::from(&*n1 | &*n2)))
- }
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
+#[inline]
+pub(crate) fn floor(n1: Number, arena: &mut Arena) -> Number {
+ rnd_i(&n1, arena)
+}
+
+#[inline]
+pub(crate) fn ceiling(n1: Number, arena: &mut Arena) -> Number {
+ let n1 = neg(n1, arena);
+ let n1 = floor(n1, arena);
+
+ neg(n1, arena)
+}
+
+#[inline]
+pub(crate) fn truncate(n: Number, arena: &mut Arena) -> Number {
+ if n.is_negative() {
+ let n = abs(n, arena);
+ let n = floor(n, arena);
+
+ neg(n, arena)
+ } else {
+ floor(n, arena)
+ }
+}
+
+pub(crate) fn round(n: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
+
+ let result = add(n, Number::Float(OrderedFloat(0.5f64)), arena);
+ let result = try_numeric_result!(result, stub_gen)?;
+
+ Ok(floor(result, arena))
+}
+
+pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ match n1 {
+ Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))),
+ Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)),
+ _ => {
+ let stub_gen = || {
+ let bitwise_atom = atom!("\\");
+ functor_stub(bitwise_atom, 2)
+ };
+
+ Err(numerical_type_error(ValidType::Integer, n1, stub_gen))
}
}
+}
- pub(crate) fn modulus(&self, x: Number, y: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(mod)"), 2);
+impl MachineState {
+ #[inline]
+ pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result<Number, MachineStub> {
+ match at {
+ &ArithmeticTerm::Reg(r) => {
+ let value = self.store(self.deref(self[r]));
- match (x, y) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n2 == 0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(n1.rem_floor(n2)))
+ match Number::try_from(value) {
+ Ok(n) => Ok(n),
+ Err(_) => self.arith_eval_by_metacall(value),
}
}
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 == &0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- let n1 = Integer::from(n1);
- Ok(Number::from(
- <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1,
- ))
- }
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if n2 == 0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- let n2 = Integer::from(n2);
- Ok(Number::from(
- <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1,
- ))
- }
- }
- (Number::Integer(x), Number::Integer(y)) => {
- if &*y == &0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(
- <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1,
- ))
- }
+ &ArithmeticTerm::Interm(i) => {
+ Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(Fixnum::build_with(0))))
}
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
+ &ArithmeticTerm::Number(n) => Ok(n),
}
}
- pub(crate) fn remainder(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(rem)"), 2);
+ pub fn get_rational(
+ &mut self,
+ at: &ArithmeticTerm,
+ caller: impl Fn() -> FunctorStub + 'static,
+ ) -> Result<TypedArenaPtr<Rational>, MachineStub> {
+ let n = self.get_number(at)?;
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n2 == 0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(n1 % n2))
- }
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 == &0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- let n1 = Integer::from(n1);
- Ok(Number::from(n1 % &*n2))
- }
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if n2 == 0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- let n2 = Integer::from(n2);
- Ok(Number::from(&*n1 % n2))
- }
- }
- (Number::Integer(n1), Number::Integer(n2)) => {
- if &*n2 == &0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(Integer::from(&*n1 % &*n2)))
- }
- }
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
+ match rational_from_number(n, caller, &mut self.arena) {
+ Ok(r) => Ok(r),
+ Err(e_gen) => Err(e_gen(self))
}
}
- pub(crate) fn max(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n1 > n2 {
- Ok(Number::Fixnum(n1))
- } else {
- Ok(Number::Fixnum(n2))
- }
+ pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result<Number, MachineStub> {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+ let mut iter = stackless_post_order_iter(&mut self.heap, value);
+
+ while let Some(value) = iter.next() {
+ if value.is_forwarded() {
+ let (name, arity) = read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ (name, arity)
+ }
+ (HeapCellValueTag::Lis | HeapCellValueTag::PStr) => {
+ (atom!("."), 2)
+ }
+ _ => {
+ unreachable!()
+ }
+ );
+
+ std::mem::drop(iter);
+
+ let evaluable_error = self.evaluable_error(name, arity);
+ let stub = stub_gen();
+
+ return Err(self.error_form(evaluable_error, stub));
}
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 > &n1 {
- Ok(Number::Integer(n2))
- } else {
- Ok(Number::Fixnum(n1))
- }
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if &*n1 > &n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Fixnum(n2))
- }
- }
- (Number::Integer(n1), Number::Integer(n2)) => {
- if n1 > n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Integer(n2))
- }
- }
- (n1, n2) => {
- let stub = MachineError::functor_stub(clause_name!("max"), 2);
- let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
- let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?;
+ read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 2 {
+ let a1 = self.interms.pop().unwrap();
+ let a2 = self.interms.pop().unwrap();
+
+ match name {
+ atom!("+") => self.interms.push(drop_iter_on_err!(
+ self,
+ iter,
+ try_numeric_result!(add(a1, a2, &mut self.arena), stub_gen)
+ )),
+ atom!("-") => self.interms.push(drop_iter_on_err!(
+ self,
+ iter,
+ try_numeric_result!(sub(a1, a2, &mut self.arena), stub_gen)
+ )),
+ atom!("*") => self.interms.push(drop_iter_on_err!(
+ self,
+ iter,
+ try_numeric_result!(mul(a1, a2, &mut self.arena), stub_gen)
+ )),
+ atom!("/") => self.interms.push(
+ drop_iter_on_err!(self, iter, div(a1, a2))
+ ),
+ atom!("**") => self.interms.push(
+ drop_iter_on_err!(self, iter, pow(a1, a2, atom!("is")))
+ ),
+ atom!("^") => self.interms.push(
+ drop_iter_on_err!(self, iter, int_pow(a1, a2, &mut self.arena))
+ ),
+ atom!("max") => self.interms.push(
+ drop_iter_on_err!(self, iter, max(a1, a2))
+ ),
+ atom!("min") => self.interms.push(
+ drop_iter_on_err!(self, iter, min(a1, a2))
+ ),
+ atom!("rdiv") => {
+ let r1 = drop_iter_on_err!(
+ self,
+ iter,
+ rational_from_number(a1, stub_gen, &mut self.arena)
+ );
+
+ let r2 = drop_iter_on_err!(
+ self,
+ iter,
+ rational_from_number(a2, stub_gen, &mut self.arena)
+ );
+
+ let result = arena_alloc!(
+ drop_iter_on_err!(self, iter, rdiv(r1, r2)),
+ self.arena
+ );
+
+ self.interms.push(Number::Rational(result));
+ }
+ atom!("//") => self.interms.push(
+ drop_iter_on_err!(self, iter, idiv(a1, a2, &mut self.arena))
+ ),
+ atom!("div") => self.interms.push(
+ drop_iter_on_err!(self, iter, int_floor_div(a1, a2, &mut self.arena))
+ ),
+ atom!(">>") => self.interms.push(
+ drop_iter_on_err!(self, iter, shr(a1, a2, &mut self.arena))
+ ),
+ atom!("<<") => self.interms.push(
+ drop_iter_on_err!(self, iter, shl(a1, a2, &mut self.arena))
+ ),
+ atom!("/\\") => self.interms.push(
+ drop_iter_on_err!(self, iter, and(a1, a2, &mut self.arena))
+ ),
+ atom!("\\/") => self.interms.push(
+ drop_iter_on_err!(self, iter, or(a1, a2, &mut self.arena))
+ ),
+ atom!("xor") => self.interms.push(
+ drop_iter_on_err!(self, iter, xor(a1, a2, &mut self.arena))
+ ),
+ atom!("mod") => self.interms.push(
+ drop_iter_on_err!(self, iter, modulus(a1, a2, &mut self.arena))
+ ),
+ atom!("rem") => self.interms.push(
+ drop_iter_on_err!(self, iter, remainder(a1, a2, &mut self.arena))
+ ),
+ atom!("atan2") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, atan2(a1, a2))
+ ))),
+ atom!("gcd") => self.interms.push(
+ drop_iter_on_err!(self, iter, gcd(a1, a2, &mut self.arena))
+ ),
+ _ => {
+ let evaluable_stub = functor_stub(name, 2);
+ let stub = stub_gen();
+
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(ValidType::Evaluable, evaluable_stub);
+ return Err(self.error_form(type_error, stub));
+ }
+ }
- Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2))))
- }
- }
- }
+ continue;
+ } else if arity == 1 {
+ let a1 = self.interms.pop().unwrap();
+
+ match name {
+ atom!("-") => self.interms.push(neg(a1, &mut self.arena)),
+ atom!("+") => self.interms.push(a1),
+ atom!("cos") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, cos(a1))
+ ))),
+ atom!("sin") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, sin(a1))
+ ))),
+ atom!("tan") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, tan(a1))
+ ))),
+ atom!("sqrt") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, sqrt(a1))
+ ))),
+ atom!("log") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, log(a1))
+ ))),
+ atom!("exp") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, exp(a1))
+ ))),
+ atom!("acos") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, acos(a1))
+ ))),
+ atom!("asin") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, asin(a1))
+ ))),
+ atom!("atan") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, atan(a1))
+ ))),
+ atom!("abs") => self.interms.push(abs(a1, &mut self.arena)),
+ atom!("float") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, float(a1))
+ ))),
+ atom!("truncate") => self.interms.push(truncate(a1, &mut self.arena)),
+ atom!("round") => self.interms.push(drop_iter_on_err!(self, iter, round(a1, &mut self.arena))),
+ atom!("ceiling") => self.interms.push(ceiling(a1, &mut self.arena)),
+ atom!("floor") => self.interms.push(floor(a1, &mut self.arena)),
+ atom!("\\") => self.interms.push(
+ drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena))
+ ),
+ atom!("sign") => self.interms.push(sign(a1)),
+ _ => {
+ let evaluable_stub = functor_stub(name, 1);
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(
+ ValidType::Evaluable,
+ evaluable_stub,
+ );
- pub(crate) fn min(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n1 < n2 {
- Ok(Number::Fixnum(n1))
- } else {
- Ok(Number::Fixnum(n2))
+ let stub = stub_gen();
+ return Err(self.error_form(type_error, stub));
+ }
+ }
+
+ continue;
+ } else if arity == 0 {
+ match name {
+ atom!("pi") => {
+ self.interms.push(Number::Float(OrderedFloat(f64::consts::PI)));
+ continue;
+ }
+ atom!("e") => {
+ self.interms.push(Number::Float(OrderedFloat(f64::consts::E)));
+ continue;
+ }
+ atom!("epsilon") => {
+ self.interms.push(Number::Float(OrderedFloat(f64::EPSILON)));
+ continue;
+ }
+ _ => {
+ }
+ }
+ }
+
+ std::mem::drop(iter);
+
+ let evaluable_error = self.evaluable_error(name, arity);
+ let stub = stub_gen();
+
+ return Err(self.error_form(evaluable_error, stub));
}
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 < &n1 {
- Ok(Number::Integer(n2))
- } else {
- Ok(Number::Fixnum(n1))
+ (HeapCellValueTag::Fixnum, n) => {
+ self.interms.push(Number::Fixnum(n));
}
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if &*n1 < &n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Fixnum(n2))
+ (HeapCellValueTag::F64, fl) => {
+ self.interms.push(Number::Float(**fl));
}
- }
- (Number::Integer(n1), Number::Integer(n2)) => {
- if n1 < n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Integer(n2))
+ (HeapCellValueTag::Cons, ptr) => {
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Integer, n) => {
+ self.interms.push(Number::Integer(n));
+ }
+ (ArenaHeaderTag::Rational, r) => {
+ self.interms.push(Number::Rational(r));
+ }
+ (ArenaHeaderTag::F64, fl) => {
+ self.interms.push(Number::Float(*fl));
+ }
+ _ => {
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(ValidType::Evaluable, value);
+ let stub = stub_gen();
+
+ return Err(self.error_form(type_error, stub));
+ }
+ )
}
- }
- (n1, n2) => {
- let stub = MachineError::functor_stub(clause_name!("max"), 2);
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => {
+ std::mem::drop(iter);
- let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
- let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?;
+ let instantiation_error = self.instantiation_error();
+ let stub = stub_gen();
- Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2))))
- }
+ return Err(self.error_form(instantiation_error, stub));
+ }
+ _ => {
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(ValidType::Evaluable, value);
+ let stub = stub_gen();
+
+ return Err(self.error_form(type_error, stub));
+ }
+ )
}
+
+ Ok(self.interms.pop().unwrap())
}
+}
- pub(crate) fn sign(&self, n: Number) -> Number {
- if n.is_positive() {
- Number::from(1)
- } else if n.is_negative() {
- Number::from(-1)
- } else {
- Number::from(0)
- }
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::machine::mock_wam::*;
+
+ #[test]
+ fn arith_eval_by_metacall_tests() {
+ let mut wam = MachineState::new();
+ let mut op_dir = default_op_dir();
+
+ op_dir.insert(
+ (atom!("+"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::Pre),
+ OpDesc::build_with(200, FY as u8),
+ );
+ op_dir.insert(
+ (atom!("*"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("/"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+
+ let term_write_result =
+ parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
+
+ assert_eq!(
+ wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+ Ok(Number::Fixnum(Fixnum::build_with(8))),
+ );
+
+ wam.heap.clear();
+
+ let term_write_result =
+ parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
+
+ assert_eq!(
+ wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+ Ok(Number::Fixnum(Fixnum::build_with(19))),
+ );
+
+ wam.heap.clear();
+
+ let term_write_result =
+ parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
+
+ assert_eq!(
+ wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+ Ok(Number::Fixnum(Fixnum::build_with(-1)))
+ );
}
}
diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs
index f39a2ac8..f74d3981 100644
--- a/src/machine/attributed_variables.rs
+++ b/src/machine/attributed_variables.rs
@@ -1,20 +1,23 @@
use crate::heap_iter::*;
use crate::machine::*;
-use prolog_parser::temp_v;
+use crate::parser::ast::*;
+use crate::temp_v;
+use crate::types::*;
use indexmap::IndexSet;
use std::cmp::Ordering;
use std::vec::IntoIter;
-pub(super) type Bindings = Vec<(usize, Addr)>;
+pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)]
pub(super) struct AttrVarInitializer {
pub(super) attr_var_queue: Vec<usize>,
pub(super) bindings: Bindings,
- pub(super) cp: LocalCodePtr,
- pub(super) instigating_p: LocalCodePtr,
+ pub(super) p: usize,
+ pub(super) cp: usize,
+ // pub(super) instigating_p: usize,
pub(super) verify_attrs_loc: usize,
}
@@ -23,8 +26,8 @@ impl AttrVarInitializer {
AttrVarInitializer {
attr_var_queue: vec![],
bindings: vec![],
- instigating_p: LocalCodePtr::default(),
- cp: LocalCodePtr::default(),
+ p: 0,
+ cp: 0,
verify_attrs_loc,
}
}
@@ -37,44 +40,39 @@ impl AttrVarInitializer {
}
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: HeapCellValue) {
if self.attr_var_init.bindings.is_empty() {
- self.attr_var_init.instigating_p = self.p.local();
+ // save self.p and self.cp and ensure that the next
+ // instruction is InstallVerifyAttrInterrupt.
- if self.last_call {
- self.attr_var_init.cp = self.cp;
- } else {
- self.attr_var_init.cp = self.p.local() + 1;
- }
+ self.attr_var_init.p = self.p;
+ self.attr_var_init.cp = self.cp;
- self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
+ self.p = INSTALL_VERIFY_ATTR_INTERRUPT - 1;
+ self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
}
self.attr_var_init.bindings.push((h, addr));
}
- fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) {
+ fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) {
let iter = self
.attr_var_init
.bindings
.iter()
- .map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
+ .map(|(ref h, _)| attr_var_as_cell!(*h));
- let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
+ let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
- let iter = self
- .attr_var_init
- .bindings
- .drain(0..)
- .map(|(_, addr)| HeapCellValue::Addr(addr));
+ let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
- let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
+ let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
(var_list_addr, value_list_addr)
}
fn verify_attributes(&mut self) {
for (h, _) in &self.attr_var_init.bindings {
- self.heap[*h] = HeapCellValue::Addr(Addr::AttrVar(*h));
+ self.heap[*h] = attr_var_as_cell!(*h);
}
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists();
@@ -83,69 +81,104 @@ impl MachineState {
self[temp_v!(2)] = value_list_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))) {
- Addr::AttrVar(h) => Some(Addr::AttrVar(h)),
- _ => None,
- })
- .collect();
-
- attr_vars
- .sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less));
-
- self.term_dedup(&mut attr_vars);
+ pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
+ let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() {
+ vec![]
+ } else {
+ self.attr_var_init.attr_var_queue[b..]
+ .iter()
+ .filter_map(|h| {
+ read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))),
+ (HeapCellValueTag::AttrVar, h) => {
+ Some(attr_var_as_cell!(h))
+ }
+ _ => {
+ None
+ }
+ )
+ })
+ .collect()
+ };
+
+ attr_vars.sort_unstable_by(|a1, a2| {
+ compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less)
+ });
+
+ attr_vars.dedup();
attr_vars.into_iter()
}
- pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
- self.allocate(self.num_of_args + 2);
+ pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) {
+ self.allocate(arity + 3);
let e = self.e;
- self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
+ let and_frame = self.stack.index_and_frame_mut(e);
- for i in 1..self.num_of_args + 1 {
- self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
+ for i in 1..arity + 1 {
+ and_frame[i] = self.registers[i];
}
- self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0);
- self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args);
+ and_frame[arity + 1] =
+ fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
+ and_frame[arity + 2] =
+ fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
+ and_frame[arity + 3] =
+ fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
self.verify_attributes();
- self.num_of_args = 2;
+ self.num_of_args = 3;
self.b0 = self.b;
- self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+ self.p = p;
}
- pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> {
+ pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
let mut seen_set = IndexSet::new();
let mut seen_vars = vec![];
- let mut iter = self.acyclic_pre_order_iter(addr);
-
- while let Some(addr) = iter.next() {
- if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() {
- if seen_set.contains(h) {
- continue;
- }
-
- seen_vars.push(addr);
- seen_set.insert(*h);
-
- let mut l = h + 1;
- let mut list_elements = vec![];
-
- while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) {
- list_elements.push(self.heap[elem].as_addr(elem));
- l = elem + 1;
+ let mut iter = stackful_preorder_iter(&mut self.heap, cell);
+
+ while let Some(value) = iter.next() {
+ read_heap_cell!(value,
+ (HeapCellValueTag::AttrVar, h) => {
+ if seen_set.contains(&h) {
+ continue;
+ }
+
+ let value = unmark_cell_bits!(value);
+
+ seen_vars.push(value);
+ seen_set.insert(h);
+
+ let mut l = h + 1;
+ // let mut list_elements = vec![];
+ // let iter_stack_len = iter.stack_len();
+
+ loop {
+ read_heap_cell!(iter.heap[l],
+ (HeapCellValueTag::Lis) => {
+ iter.push_stack(l);
+ // l = elem + 1;
+ break;
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
+ if h == l {
+ break;
+ } else {
+ l = h;
+ }
+ }
+ _ => {
+ break;
+ }
+ )
+ }
+
+ // iter.stack_slice_from(iter_stack_len ..).reverse();
}
-
- for element in list_elements.into_iter().rev() {
- iter.stack().push(element);
+ _ => {
}
- }
+ );
}
seen_vars
diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs
deleted file mode 100644
index bb21462e..00000000
--- a/src/machine/code_repo.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-use crate::clause_types::*;
-use crate::instructions::*;
-use crate::machine::machine_indices::*;
-
-#[derive(Debug)]
-pub(crate) struct CodeRepo {
- pub(super) code: Code,
-}
-
-impl CodeRepo {
- #[inline]
- pub(super) fn new() -> Self {
- CodeRepo { code: Code::new() }
- }
-
- #[inline]
- pub(super) fn lookup_local_instr<'a>(&'a self, p: LocalCodePtr) -> RefOrOwned<'a, Line> {
- match p {
- LocalCodePtr::Halt => {
- // exit with the interrupt exit code.
- std::process::exit(1);
- }
- LocalCodePtr::DirEntry(p) => RefOrOwned::Borrowed(&self.code[p as usize]),
- LocalCodePtr::IndexingBuf(p, o, i) => match &self.code[p] {
- &Line::IndexingCode(ref indexing_lines) => match &indexing_lines[o] {
- &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
- RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
- }
- &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
- RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[i]))
- }
- _ => {
- unreachable!()
- }
- },
- _ => {
- unreachable!()
- }
- },
- }
- }
-
- pub(super) fn lookup_instr<'a>(
- &'a self,
- last_call: bool,
- p: &CodePtr,
- ) -> Option<RefOrOwned<'a, Line>> {
- match p {
- &CodePtr::Local(local) => {
- return Some(self.lookup_local_instr(local));
- }
- &CodePtr::REPL(..) => None,
- &CodePtr::BuiltInClause(ref built_in, _) => {
- let call_clause = call_clause!(
- ClauseType::BuiltIn(built_in.clone()),
- built_in.arity(),
- 0,
- last_call
- );
-
- Some(RefOrOwned::Owned(call_clause))
- }
- &CodePtr::CallN(arity, _, last_call) => {
- let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
-
- Some(RefOrOwned::Owned(call_clause))
- }
- &CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])),
- }
- }
-
- pub(super) fn find_living_dynamic_else(
- &self,
- mut p: usize,
- cc: usize,
- ) -> Option<(usize, usize)> {
- loop {
- match &self.code[p] {
- &Line::Choice(ChoiceInstruction::DynamicElse(
- birth,
- death,
- NextOrFail::Next(i),
- )) => {
- if birth < cc && Death::Finite(cc) <= death {
- return Some((p, i));
- } else if i > 0 {
- p += i;
- } else {
- return None;
- }
- }
- &Line::Choice(ChoiceInstruction::DynamicElse(
- birth,
- death,
- NextOrFail::Fail(_),
- )) => {
- if birth < cc && Death::Finite(cc) <= death {
- return Some((p, 0));
- } else {
- return None;
- }
- }
- &Line::Choice(ChoiceInstruction::DynamicInternalElse(
- birth,
- death,
- NextOrFail::Next(i),
- )) => {
- if birth < cc && Death::Finite(cc) <= death {
- return Some((p, i));
- } else if i > 0 {
- p += i;
- } else {
- return None;
- }
- }
- &Line::Choice(ChoiceInstruction::DynamicInternalElse(
- birth,
- death,
- NextOrFail::Fail(_),
- )) => {
- if birth < cc && Death::Finite(cc) <= death {
- return Some((p, 0));
- } else {
- return None;
- }
- }
- &Line::Control(ControlInstruction::RevJmpBy(i)) => {
- p -= i;
- }
- _ => {
- unreachable!();
- }
- }
- }
- }
-
- pub(super) fn find_living_dynamic(
- &self,
- p: LocalCodePtr,
- cc: usize,
- ) -> Option<(usize, usize, usize, bool)> {
- let (p, oi, mut ii) = match p {
- LocalCodePtr::IndexingBuf(p, oi, ii) => (p, oi, ii),
- _ => unreachable!(),
- };
-
- let indexed_choice_instrs = match &self.code[p] {
- Line::IndexingCode(ref indexing_code) => match &indexing_code[oi] {
- IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
- indexed_choice_instrs
- }
- _ => unreachable!(),
- },
- _ => unreachable!(),
- };
-
- loop {
- match &indexed_choice_instrs.get(ii) {
- Some(&offset) => match &self.code[p + offset - 1] {
- &Line::Choice(ChoiceInstruction::DynamicInternalElse(
- birth,
- death,
- next_or_fail,
- )) => {
- if birth < cc && Death::Finite(cc) <= death {
- return Some((offset, oi, ii, next_or_fail.is_next()));
- } else {
- ii += 1;
- }
- }
- _ => unreachable!(),
- },
- None => return None,
- }
- }
- }
-}
diff --git a/src/machine/code_walker.rs b/src/machine/code_walker.rs
index fe63347f..fcda8710 100644
--- a/src/machine/code_walker.rs
+++ b/src/machine/code_walker.rs
@@ -2,45 +2,47 @@ use crate::instructions::*;
use indexmap::IndexSet;
-fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
+fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> bool {
match line {
- &Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => {
+ &Instruction::TryMeElse(offset) if offset > 0 => {
stack.push(index + offset);
}
- &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset))
- | &Line::Choice(ChoiceInstruction::RetryMeElse(offset))
+ &Instruction::DefaultRetryMeElse(offset) |
+ &Instruction::RetryMeElse(offset)
if offset > 0 =>
{
stack.push(index + offset);
}
- &Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
+ &Instruction::DynamicElse(_, _, NextOrFail::Next(offset))
if offset > 0 =>
{
stack.push(index + offset);
}
- &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
+ &Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))
if offset > 0 =>
{
stack.push(index + offset);
}
- &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
+ &Instruction::JmpByCall(_, offset, _) => {
stack.push(index + offset);
}
- &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
+ &Instruction::JmpByExecute(_, offset, _) => {
stack.push(index + offset);
return true;
}
- &Line::Control(ControlInstruction::Proceed)
- | &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
+ &Instruction::Proceed => {
return true;
}
- &Line::Control(ControlInstruction::RevJmpBy(offset)) => {
+ &Instruction::RevJmpBy(offset) => {
if offset > 0 {
stack.push(index - offset);
} else {
return true;
}
}
+ instr if instr.is_execute() => {
+ return true;
+ }
_ => {}
};
@@ -51,7 +53,7 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
* begin in code at the offset p. Each instruction is passed to the
* walker function.
*/
-pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line)) {
+pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) {
let mut stack = vec![p];
let mut visited_indices = IndexSet::new();
diff --git a/src/machine/compile.rs b/src/machine/compile.rs
index ef99df34..157f16ae 100644
--- a/src/machine/compile.rs
+++ b/src/machine/compile.rs
@@ -1,18 +1,22 @@
-use prolog_parser::clause_name;
-
+use crate::atom_table::*;
use crate::codegen::*;
use crate::debray_allocator::*;
-use crate::indexing::{merge_clause_index, remove_index, IndexingCodePtr};
+use crate::forms::*;
+use crate::indexing::{merge_clause_index, remove_index};
+use crate::instructions::*;
use crate::machine::load_state::*;
use crate::machine::loader::*;
+use crate::machine::machine_errors::*;
use crate::machine::preprocessor::*;
use crate::machine::term_stream::*;
use crate::machine::*;
+use crate::parser::ast::*;
use slice_deque::{sdeq, SliceDeque};
use std::cell::Cell;
use std::collections::VecDeque;
+use std::mem;
use std::ops::Range;
struct StandaloneCompileResult {
@@ -25,17 +29,21 @@ pub(super) fn bootstrapping_compile(
wam: &mut Machine,
listing_src: ListingSource,
) -> Result<(), SessionError> {
- let stream = &mut parsing_stream(stream)?;
- let term_stream = BootstrappingTermStream::from_prolog_stream(
+ let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st();
+
+ let term_stream = BootstrappingTermStream::from_char_reader(
stream,
- wam.machine_st.atom_tbl.clone(),
- wam.machine_st.flags,
+ machine_st,
listing_src,
);
- let loader = Loader::new(term_stream, wam);
- loader.load()?;
+ let payload = BootstrappingLoadState(
+ LoadStatePayload::new(wam_prelude.code.len(), term_stream)
+ );
+
+ let loader: Loader<'_, BootstrappingLoadState> = Loader { payload, wam_prelude };
+ loader.load()?;
Ok(())
}
@@ -57,7 +65,7 @@ pub(super) fn compile_appendix(
mut queue: VecDeque<TopLevel>,
jmp_by_locs: Vec<usize>,
non_counted_bt: bool,
- atom_tbl: TabledData<Atom>,
+ atom_tbl: &mut AtomTable,
) -> Result<(), CompilationError> {
let mut jmp_by_locs = VecDeque::from(jmp_by_locs);
@@ -65,7 +73,8 @@ pub(super) fn compile_appendix(
let code_len = code.len();
match &mut code[jmp_by_offset] {
- &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => {
+ &mut Instruction::JmpByCall(_, ref mut offset, ..) |
+ &mut Instruction::JmpByExecute(_, ref mut offset, ..) => {
*offset = code_len - jmp_by_offset;
}
_ => {
@@ -80,7 +89,7 @@ pub(super) fn compile_appendix(
non_counted_bt,
};
- let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
+ let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl, settings);
let tl = queue.pop_front().unwrap();
let decl_code = compile_relation(&mut cg, &tl)?;
@@ -136,20 +145,20 @@ fn derelictize_try_me_else(
retraction_info: &mut RetractionInfo,
) -> Option<usize> {
match &mut code[index] {
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(0))) => None,
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) => {
+ Instruction::DynamicElse(_, _, NextOrFail::Next(0)) => None,
+ Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o));
Some(mem::replace(o, 0))
}
- Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(0))) => None,
- Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) => {
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Next(0)) => None,
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o)) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o));
Some(mem::replace(o, 0))
}
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_)))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => None,
- Line::Choice(ChoiceInstruction::TryMeElse(0)) => None,
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+ Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) |
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => None,
+ Instruction::TryMeElse(0) => None,
+ Instruction::TryMeElse(ref mut o) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o));
Some(mem::replace(o, 0))
}
@@ -164,6 +173,7 @@ fn merge_indices(
target_index_loc: usize,
index_range: Range<usize>,
skeleton: &mut [ClauseIndexInfo],
+ retracted_dynamic_clauses: &Option<Vec<ClauseIndexInfo>>,
retraction_info: &mut RetractionInfo,
) {
for clause_index in index_range {
@@ -174,7 +184,7 @@ fn merge_indices(
let clause_loc =
find_inner_choice_instr(code, skeleton[clause_index].clause_start, index_loc);
- let target_indexing_line = to_indexing_line_mut(&mut code[target_index_loc]).unwrap();
+ let target_indexing_line = code[target_index_loc].to_indexing_line_mut().unwrap();
skeleton[clause_index]
.opt_arg_index_key
@@ -183,6 +193,7 @@ fn merge_indices(
merge_clause_index(
target_indexing_line,
&mut skeleton[0..clause_index + 1],
+ retracted_dynamic_clauses,
clause_loc,
AppendOrPrepend::Append,
);
@@ -200,8 +211,8 @@ fn merge_indices(
fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize {
loop {
match &code[index] {
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(i)))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(i)))
+ Instruction::DynamicElse(_, _, NextOrFail::Next(i)) |
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Next(i))
if *i > 0 =>
{
index += i;
@@ -216,28 +227,29 @@ fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize {
fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> usize {
loop {
match &code[index] {
- Line::Choice(ChoiceInstruction::TryMeElse(o))
- | Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+ Instruction::TryMeElse(o) |
+ Instruction::RetryMeElse(o) => {
if *o > 0 {
return index;
} else {
index = index_loc;
}
}
- &Line::Choice(ChoiceInstruction::DynamicElse(_, _, next_or_fail)) => match next_or_fail
- {
- NextOrFail::Next(i) => {
- if i == 0 {
+ &Instruction::DynamicElse(_, _, next_or_fail) => {
+ match next_or_fail {
+ NextOrFail::Next(i) => {
+ if i == 0 {
+ index = index_loc;
+ } else {
+ return index;
+ }
+ }
+ NextOrFail::Fail(_) => {
index = index_loc;
- } else {
- return index;
}
}
- NextOrFail::Fail(_) => {
- index = index_loc;
- }
- },
- &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, next_or_fail)) => {
+ }
+ &Instruction::DynamicInternalElse(_, _, next_or_fail) => {
match next_or_fail {
NextOrFail::Next(i) => {
if i == 0 {
@@ -251,20 +263,20 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u
}
}
}
- Line::Choice(ChoiceInstruction::TrustMe(_)) => {
+ Instruction::TrustMe(_) => {
return index;
}
- Line::IndexingCode(indexing_code) => match &indexing_code[0] {
+ Instruction::IndexingCode(indexing_code) => match &indexing_code[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
IndexingCodePtr::External(v) => {
index += v;
}
IndexingCodePtr::DynamicExternal(v) => match &code[index + v] {
- &Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ &Instruction::DynamicInternalElse(
_,
_,
NextOrFail::Next(0),
- )) => {
+ ) => {
return index + v;
}
_ => {
@@ -277,7 +289,7 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u
unreachable!();
}
},
- Line::Control(ControlInstruction::RevJmpBy(offset)) => {
+ Instruction::RevJmpBy(offset) => {
index -= offset;
}
_ => {
@@ -300,9 +312,7 @@ fn remove_index_from_subsequence(
) {
if let Some(index_loc) = opt_arg_index_key.switch_on_term_loc() {
let clause_start = find_inner_choice_instr(code, clause_start, index_loc);
-
- let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
-
+ let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
let offset = clause_start - index_loc + 1;
remove_index(opt_arg_index_key, target_indexing_line, offset);
@@ -341,7 +351,7 @@ fn merge_indexed_subsequences(
);
match &mut code[inner_try_me_else_loc] {
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+ Instruction::TryMeElse(ref mut o) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
inner_try_me_else_loc,
*o,
@@ -349,15 +359,15 @@ fn merge_indexed_subsequences(
match *o {
0 => {
- code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(0));
+ code[inner_try_me_else_loc] = Instruction::TrustMe(0);
}
o => match &code[inner_try_me_else_loc + o] {
- Line::Control(ControlInstruction::RevJmpBy(0)) => {
- code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(o));
+ Instruction::RevJmpBy(0) => {
+ code[inner_try_me_else_loc] = Instruction::TrustMe(o);
}
_ => {
code[inner_try_me_else_loc] =
- Line::Choice(ChoiceInstruction::RetryMeElse(o));
+ Instruction::RetryMeElse(o);
}
},
}
@@ -393,7 +403,7 @@ fn merge_indexed_subsequences(
);
}
None => match &mut code[outer_threaded_choice_instr_loc] {
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+ Instruction::TryMeElse(ref mut o) => {
retraction_info
.push_record(RetractionRecord::ModifiedTryMeElse(inner_trust_me_loc, *o));
@@ -422,13 +432,24 @@ fn delete_from_skeleton(
skeleton.core.clause_assert_margin -= 1;
}
- retraction_info.push_record(RetractionRecord::RemovedSkeletonClause(
- compilation_target,
- key,
- target_pos,
- clause_index_info,
- clause_clause_loc,
- ));
+ if skeleton.core.is_dynamic {
+ skeleton.core.add_retracted_dynamic_clause_info(clause_index_info);
+
+ retraction_info.push_record(RetractionRecord::RemovedDynamicSkeletonClause(
+ compilation_target,
+ key,
+ target_pos,
+ clause_clause_loc,
+ ));
+ } else {
+ retraction_info.push_record(RetractionRecord::RemovedSkeletonClause(
+ compilation_target,
+ key,
+ target_pos,
+ clause_index_info,
+ clause_clause_loc,
+ ));
+ }
clause_clause_loc
}
@@ -440,60 +461,55 @@ fn blunt_leading_choice_instr(
) -> usize {
loop {
match &mut code[instr_loc] {
- Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+ Instruction::RetryMeElse(o) => {
retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse(instr_loc, *o));
-
- code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(*o));
-
+ code[instr_loc] = Instruction::TryMeElse(*o);
return instr_loc;
}
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(_)))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(_))) => {
+ Instruction::DynamicElse(_, _, NextOrFail::Next(_)) |
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Next(_)) => {
return instr_loc;
}
- &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o))) => {
+ &mut Instruction::DynamicElse(b, d, NextOrFail::Fail(o)) => {
retraction_info.push_record(RetractionRecord::AppendedNextOrFail(
instr_loc,
NextOrFail::Fail(o),
));
- code[instr_loc] =
- Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(0)));
-
+ code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(0));
return instr_loc;
}
- &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ &mut Instruction::DynamicInternalElse(
b,
d,
NextOrFail::Fail(o),
- )) => {
+ ) => {
retraction_info.push_record(RetractionRecord::AppendedNextOrFail(
instr_loc,
NextOrFail::Fail(o),
));
- code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ code[instr_loc] = Instruction::DynamicInternalElse(
b,
d,
NextOrFail::Next(0),
- ));
+ );
return instr_loc;
}
- Line::Choice(ChoiceInstruction::TrustMe(o)) => {
- retraction_info
- .push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false));
+ Instruction::TrustMe(o) => {
+ retraction_info.push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false));
- code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0));
+ code[instr_loc] = Instruction::TryMeElse(0);
return instr_loc + 1;
}
- Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+ Instruction::TryMeElse(0) => {
return instr_loc + 1;
}
- Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
+ Instruction::TryMeElse(o) => {
instr_loc += *o;
}
- Line::Control(ControlInstruction::RevJmpBy(o)) => {
+ Instruction::RevJmpBy(o) => {
instr_loc -= *o;
}
_ => {
@@ -509,7 +525,7 @@ fn set_switch_var_offset_to_choice_instr(
offset: usize,
retraction_info: &mut RetractionInfo,
) {
- let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+ let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
let v = match &target_indexing_line[0] {
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
@@ -522,9 +538,9 @@ fn set_switch_var_offset_to_choice_instr(
};
match &code[index_loc + v] {
- Line::Choice(ChoiceInstruction::TryMeElse(_))
- | Line::Choice(ChoiceInstruction::DynamicElse(..))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {}
+ Instruction::TryMeElse(_) |
+ Instruction::DynamicElse(..) |
+ Instruction::DynamicInternalElse(..) => {}
_ => {
set_switch_var_offset(code, index_loc, offset, retraction_info);
}
@@ -538,7 +554,7 @@ fn set_switch_var_offset(
offset: usize,
retraction_info: &mut RetractionInfo,
) {
- let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+ let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
let old_v = match &mut target_indexing_line[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => match *v {
@@ -564,73 +580,67 @@ fn internalize_choice_instr_at(
retraction_info: &mut RetractionInfo,
) {
match &mut code[instr_loc] {
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_)))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => {}
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0))) => {
+ Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) |
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => {
+ }
+ Instruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0)) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0));
*o = NextOrFail::Fail(0);
}
- &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o))) => {
+ &mut Instruction::DynamicElse(b, d, NextOrFail::Next(o)) => {
retraction_info.push_record(RetractionRecord::AppendedNextOrFail(
instr_loc,
NextOrFail::Next(o),
));
match &mut code[instr_loc + o] {
- Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
- code[instr_loc] =
- Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o)));
+ Instruction::RevJmpBy(p) if *p == 0 => {
+ code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Fail(o));
}
_ => {
- code[instr_loc] =
- Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o)));
+ code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(o));
}
}
}
- Line::Choice(ChoiceInstruction::DynamicInternalElse(
- _,
- _,
- ref mut o @ NextOrFail::Next(0),
- )) => {
+ Instruction::DynamicInternalElse(_, _, ref mut o @ NextOrFail::Next(0)) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0));
*o = NextOrFail::Fail(0);
}
- &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(o))) => {
+ &mut Instruction::DynamicInternalElse(b, d, NextOrFail::Next(o)) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, o));
match &mut code[instr_loc + o] {
- Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
- code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ Instruction::RevJmpBy(p) if *p == 0 => {
+ code[instr_loc] = Instruction::DynamicInternalElse(
b,
d,
NextOrFail::Fail(o),
- ));
+ );
}
_ => {
- code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ code[instr_loc] = Instruction::DynamicInternalElse(
b,
d,
NextOrFail::Next(o),
- ));
+ );
}
}
}
- Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+ Instruction::TryMeElse(0) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0));
-
- code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0));
+ code[instr_loc] = Instruction::TrustMe(0);
}
- Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
+ Instruction::TryMeElse(o) => {
let o = *o;
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, o));
match &mut code[instr_loc + o] {
- Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
- code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(o));
+ Instruction::RevJmpBy(p) if *p == 0 => {
+ code[instr_loc] = Instruction::TrustMe(o);
}
_ => {
- code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o));
+ code[instr_loc] = Instruction::RetryMeElse(o);
}
}
}
@@ -648,8 +658,7 @@ fn thread_choice_instr_at_to(
) {
loop {
match &mut code[instr_loc] {
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
- | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
+ Instruction::TryMeElse(ref mut o) | Instruction::RetryMeElse(ref mut o)
if target_loc >= instr_loc =>
{
retraction_info.push_record(RetractionRecord::ReplacedChoiceOffset(instr_loc, *o));
@@ -657,82 +666,80 @@ fn thread_choice_instr_at_to(
*o = target_loc - instr_loc;
return;
}
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)) |
+ Instruction::DynamicInternalElse(
_,
_,
NextOrFail::Next(ref mut o),
- )) if target_loc >= instr_loc => {
+ ) if target_loc >= instr_loc => {
retraction_info
.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, *o));
*o = target_loc - instr_loc;
return;
}
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(o)))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(o))) => {
+ Instruction::DynamicElse(_, _, NextOrFail::Next(o)) |
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Next(o)) => {
instr_loc += *o;
}
- Line::Choice(ChoiceInstruction::TryMeElse(o))
- | Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+ Instruction::TryMeElse(o)
+ | Instruction::RetryMeElse(o) => {
instr_loc += *o;
}
- Line::Control(ControlInstruction::RevJmpBy(ref mut o)) if instr_loc >= target_loc => {
+ Instruction::RevJmpBy(ref mut o) if instr_loc >= target_loc => {
retraction_info.push_record(RetractionRecord::ModifiedRevJmpBy(instr_loc, *o));
*o = instr_loc - target_loc;
return;
}
- &mut Line::Control(ControlInstruction::RevJmpBy(o)) => {
+ &mut Instruction::RevJmpBy(o) => {
instr_loc -= o;
}
- &mut Line::Choice(ChoiceInstruction::DynamicElse(birth, death, ref mut fail))
+ &mut Instruction::DynamicElse(birth, death, ref mut fail)
if target_loc >= instr_loc =>
{
retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail));
- code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicElse(
+ code[instr_loc] = instr!("dynamic_else",
birth,
death,
- NextOrFail::Next(target_loc - instr_loc),
- ));
+ NextOrFail::Next(target_loc - instr_loc)
+ );
return;
}
- Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(o))) if *o > 0 => {
+ Instruction::DynamicElse(_, _, NextOrFail::Fail(o)) if *o > 0 => {
instr_loc += *o;
}
- &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ &mut Instruction::DynamicInternalElse(
birth,
death,
ref mut fail,
- )) if target_loc >= instr_loc => {
+ ) if target_loc >= instr_loc => {
retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail));
- code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ code[instr_loc] = instr!("dynamic_internal_else",
birth,
death,
- NextOrFail::Next(target_loc - instr_loc),
- ));
+ NextOrFail::Next(target_loc - instr_loc)
+ );
return;
}
- Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(o)))
+ Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(o))
if *o > 0 =>
{
instr_loc += *o;
}
- Line::Choice(ChoiceInstruction::TrustMe(ref mut o)) if target_loc >= instr_loc => {
+ Instruction::TrustMe(ref mut o) if target_loc >= instr_loc => {
retraction_info.push_record(
RetractionRecord::AppendedTrustMe(instr_loc, *o, false),
//choice_instr.is_default()),
);
- code[instr_loc] =
- Line::Choice(ChoiceInstruction::RetryMeElse(target_loc - instr_loc));
-
+ code[instr_loc] = instr!("retry_me_else", target_loc - instr_loc);
return;
}
- Line::Choice(ChoiceInstruction::TrustMe(o)) if *o > 0 => {
+ Instruction::TrustMe(o) if *o > 0 => {
instr_loc += *o;
}
_ => {
@@ -749,7 +756,7 @@ fn remove_non_leading_clause(
retraction_info: &mut RetractionInfo,
) -> Option<IndexPtr> {
match &mut code[non_indexed_choice_instr_loc] {
- Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => {
+ Instruction::RetryMeElse(ref mut o) => {
let o = *o;
thread_choice_instr_at_to(
@@ -761,19 +768,19 @@ fn remove_non_leading_clause(
None
}
- Line::Choice(ChoiceInstruction::TrustMe(_)) => {
+ Instruction::TrustMe(_) => {
match &mut code[preceding_choice_instr_loc] {
- Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+ Instruction::RetryMeElse(o) => {
retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse(
preceding_choice_instr_loc,
*o,
));
- code[preceding_choice_instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0));
+ code[preceding_choice_instr_loc] = Instruction::TrustMe(0);
None
}
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+ Instruction::TryMeElse(ref mut o) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
preceding_choice_instr_loc,
*o,
@@ -804,8 +811,8 @@ fn finalize_retract(
retraction_info: &mut RetractionInfo,
) -> usize {
let clause_clause_loc = delete_from_skeleton(
- compilation_target.clone(),
- key.clone(),
+ compilation_target,
+ key,
skeleton,
target_pos,
retraction_info,
@@ -830,7 +837,7 @@ fn remove_leading_unindexed_clause(
retraction_info: &mut RetractionInfo,
) -> Option<IndexPtr> {
match &mut code[non_indexed_choice_instr_loc] {
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+ Instruction::TryMeElse(ref mut o) => {
if *o > 0 {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
non_indexed_choice_instr_loc,
@@ -858,7 +865,7 @@ fn remove_leading_unindexed_clause(
fn find_dynamic_outer_choice_instr(code: &Code, index_loc: usize) -> usize {
match &code[index_loc] {
- Line::IndexingCode(indexing_code) => match &indexing_code[0] {
+ Instruction::IndexingCode(indexing_code) => match &indexing_code[0] {
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
_,
IndexingCodePtr::DynamicExternal(v),
@@ -920,7 +927,7 @@ fn prepend_compiled_clause(
retraction_info.push_record(RetractionRecord::SkeletonClauseStartReplaced(
compilation_target,
- key.clone(),
+ key,
1,
skeleton.clauses[1].clause_start,
));
@@ -931,22 +938,16 @@ fn prepend_compiled_clause(
let inner_thread_rev_offset =
3 + prepend_queue.len() + clause_loc - skeleton.clauses[1].clause_start;
- prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
- inner_thread_rev_offset,
- )));
+ prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
- prepend_queue.push_front(Line::Choice(
- settings.internal_try_me_else(prepend_queue.len()),
- ));
+ prepend_queue.push_front(settings.internal_try_me_else(prepend_queue.len()));
// prepend_queue is now:
// | TryMeElse N_2
// | (clause_code)
// +N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1)
- prepend_queue.push_front(Line::Control(ControlInstruction::RevJmpBy(
- 1 + clause_loc - index_loc,
- )));
+ prepend_queue.push_front(Instruction::RevJmpBy(1 + clause_loc - index_loc));
let outer_thread_choice_offset = // outer_thread_choice_loc WAS index_loc - 1..
match derelictize_try_me_else(code, outer_thread_choice_loc, retraction_info) {
@@ -958,7 +959,7 @@ fn prepend_compiled_clause(
next_subseq_offset;
prepend_queue.push_back(
- Line::Control(ControlInstruction::RevJmpBy(outer_thread_rev_offset))
+ Instruction::RevJmpBy(outer_thread_rev_offset)
);
prepend_queue.len()
@@ -974,17 +975,13 @@ fn prepend_compiled_clause(
// awaiting the addition of unindexed
// clauses.
- prepend_queue.push_back(
- Line::Control(ControlInstruction::RevJmpBy(0)),
- );
+ prepend_queue.push_back(Instruction::RevJmpBy(0));
0
}
};
- prepend_queue.push_front(Line::Choice(
- settings.try_me_else(outer_thread_choice_offset),
- ));
+ prepend_queue.push_front(settings.try_me_else(outer_thread_choice_offset));
// prepend_queue is now:
// | TryMeElse N_3
@@ -994,11 +991,12 @@ fn prepend_compiled_clause(
// N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1)
// N_3 | RevJmpBy (TryMeElse(N_1) at index_loc - 1 or TrustMe if N_1 == 0)
- let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+ let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
merge_clause_index(
target_indexing_line,
&mut skeleton.clauses,
+ &skeleton.core.retracted_dynamic_clauses,
clause_loc + 2, // == skeleton.clauses[0].clause_start
AppendOrPrepend::Prepend,
);
@@ -1039,19 +1037,19 @@ fn prepend_compiled_clause(
// this is a stub for chaining inner-threaded choice
// instructions.
- prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(0)));
+ prepend_queue.push_back(Instruction::RevJmpBy(0));
let prepend_queue_len = prepend_queue.len();
match &mut prepend_queue[1] {
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) if *o == 0 => {
+ Instruction::TryMeElse(ref mut o) if *o == 0 => {
*o = prepend_queue_len - 2;
}
- Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ Instruction::DynamicInternalElse(
_,
_,
ref mut o @ NextOrFail::Next(0),
- )) => {
+ ) => {
*o = NextOrFail::Fail(prepend_queue_len - 2);
}
_ => {
@@ -1059,11 +1057,8 @@ fn prepend_compiled_clause(
}
}
- prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
- inner_thread_rev_offset,
- )));
-
- prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len())));
+ prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
+ prepend_queue.push_front(settings.try_me_else(prepend_queue.len()));
// prepend_queue is now:
// | TryMeElse(N_2)
@@ -1093,11 +1088,8 @@ fn prepend_compiled_clause(
let inner_thread_rev_offset =
1 + prepend_queue.len() + clause_loc - old_clause_start;
- prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
- inner_thread_rev_offset,
- )));
-
- prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len())));
+ prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
+ prepend_queue.push_front(settings.try_me_else(prepend_queue.len()));
// prepend_queue is now:
// | TryMeElse(N_2)
@@ -1121,11 +1113,8 @@ fn prepend_compiled_clause(
let inner_thread_rev_offset =
1 + prepend_queue.len() + clause_loc - old_clause_start;
- prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
- inner_thread_rev_offset,
- )));
-
- prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len())));
+ prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
+ prepend_queue.push_front(settings.try_me_else(prepend_queue.len()));
// prepend_queue is now:
// | TryMeElse(N_2)
@@ -1184,8 +1173,7 @@ fn append_compiled_clause(
.switch_on_term_loc()
{
Some(index_loc) if lower_bound_arg_num == target_arg_num => {
- code.push(Line::Choice(settings.internal_trust_me()));
-
+ code.push(settings.internal_trust_me());
code.extend(clause_code.drain(3..)); // skip the indexing code
// set skeleton[target_pos].opt_arg_index_key to
@@ -1197,11 +1185,12 @@ fn append_compiled_clause(
skeleton.clauses[target_pos].clause_start,
));
- let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+ let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
merge_clause_index(
target_indexing_line,
&mut skeleton.clauses[lower_bound..],
+ &skeleton.core.retracted_dynamic_clauses,
clause_loc,
AppendOrPrepend::Append,
);
@@ -1230,7 +1219,7 @@ fn append_compiled_clause(
target_pos_clause_start // skeleton.clauses[target_pos - 1].clause_start
}
_ => {
- code.push(Line::Choice(settings.trust_me()));
+ code.push(settings.trust_me());
skeleton.clauses[target_pos].opt_arg_index_key += clause_loc;
code.extend(clause_code.drain(1..));
@@ -1306,12 +1295,12 @@ fn mergeable_indexed_subsequences(
fn print_overwrite_warning(
compilation_target: &CompilationTarget,
code_ptr: IndexPtr,
- key: &PredicateKey,
+ key: PredicateKey,
is_dynamic: bool,
) {
- if let CompilationTarget::Module(ref module_name) = compilation_target {
- match module_name.as_str() {
- "builtins" | "loader" => return,
+ if let CompilationTarget::Module(module_name) = compilation_target {
+ match module_name {
+ atom!("builtins") | atom!("loader") => return,
_ => {}
}
}
@@ -1322,21 +1311,20 @@ fn print_overwrite_warning(
_ => {}
}
- println!("Warning: overwriting {}/{}", key.0, key.1);
+ println!("Warning: overwriting {}/{}", key.0.as_str(), key.1);
}
-impl<'a> LoadState<'a> {
- pub(super) fn listing_src_file_name(&self) -> Option<ClauseName> {
- if let Some(load_context) = self.wam.load_contexts.last() {
+impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
+ pub(super) fn listing_src_file_name(&mut self) -> Option<Atom> {
+ if let Some(load_context) = self.wam_prelude.load_contexts.last() {
if !load_context.path.is_file() {
return None;
}
if let Some(path_str) = load_context.path.to_str() {
if !path_str.is_empty() {
- return Some(clause_name!(
- path_str.to_string(),
- self.wam.machine_st.atom_tbl
+ return Some(LS::machine_st(&mut self.payload).atom_tbl.build_with(
+ path_str
));
}
}
@@ -1349,14 +1337,17 @@ impl<'a> LoadState<'a> {
&mut self,
term: Term,
settings: CodeGenSettings,
- atom_tbl: TabledData<Atom>,
) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new();
- let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
let queue = preprocessor.parse_queue(self)?;
+ let mut cg = CodeGenerator::<DebrayAllocator>::new(
+ &mut LS::machine_st(&mut self.payload).atom_tbl,
+ settings,
+ );
+
let mut clause_code = cg.compile_predicate(&vec![clause])?;
compile_appendix(
@@ -1364,7 +1355,7 @@ impl<'a> LoadState<'a> {
queue,
cg.jmp_by_locs,
settings.non_counted_bt,
- atom_tbl,
+ cg.atom_tbl,
)?;
Ok(StandaloneCompileResult {
@@ -1376,17 +1367,15 @@ impl<'a> LoadState<'a> {
fn compile(
&mut self,
key: PredicateKey,
- predicates: &mut PredicateQueue,
+ mut predicates: PredicateQueue,
settings: CodeGenSettings,
) -> Result<CodeIndex, SessionError> {
- let code_index =
- self.get_or_insert_code_index(key.clone(), predicates.compilation_target.clone());
+ let code_index = self.get_or_insert_code_index(key, predicates.compilation_target);
- let code_len = self.wam.code_repo.code.len();
- let mut code_ptr = code_len;
+ LS::err_on_builtin_overwrite(self, key)?;
- let mut cg =
- CodeGenerator::<DebrayAllocator>::new(self.wam.machine_st.atom_tbl.clone(), settings);
+ let code_len = self.wam_prelude.code.len();
+ let mut code_ptr = code_len;
let mut clauses = vec![];
let mut preprocessor = Preprocessor::new();
@@ -1396,6 +1385,12 @@ impl<'a> LoadState<'a> {
}
let queue = preprocessor.parse_queue(self)?;
+
+ let mut cg = CodeGenerator::<DebrayAllocator>::new(
+ &mut LS::machine_st(&mut self.payload).atom_tbl,
+ settings,
+ );
+
let mut code = cg.compile_predicate(&clauses)?;
compile_appendix(
@@ -1403,7 +1398,7 @@ impl<'a> LoadState<'a> {
queue,
cg.jmp_by_locs,
settings.non_counted_bt,
- self.wam.machine_st.atom_tbl.clone(),
+ cg.atom_tbl,
)?;
if settings.is_extensible {
@@ -1417,41 +1412,45 @@ impl<'a> LoadState<'a> {
}
match &mut code[0] {
- Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+ Instruction::TryMeElse(0) => {
code_ptr += 1;
}
_ => {}
}
match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&predicates.compilation_target, &key)
{
Some(skeleton) => {
- self.retraction_info
- .push_record(RetractionRecord::SkeletonClauseTruncateBack(
- predicates.compilation_target.clone(),
- key.clone(),
- skeleton.clauses.len(),
- ));
+ let skeleton_clause_len = skeleton.clauses.len();
skeleton.clauses.extend(cg.skeleton.clauses.into_iter());
skeleton
.core
.clause_clause_locs
.extend_from_slice(&clause_clause_locs[0..]);
+
+ self.payload.retraction_info
+ .push_record(RetractionRecord::SkeletonClauseTruncateBack(
+ predicates.compilation_target,
+ key,
+ skeleton_clause_len,
+ ));
}
None => {
cg.skeleton
- .core
- .clause_clause_locs
- .extend_from_slice(&clause_clause_locs[0..]);
+ .core
+ .clause_clause_locs
+ .extend_from_slice(&clause_clause_locs[0..]);
+
+ let skeleton = cg.skeleton;
self.add_extensible_predicate(
- key.clone(),
- cg.skeleton,
- predicates.compilation_target.clone(),
+ key,
+ skeleton,
+ predicates.compilation_target,
);
}
};
@@ -1466,7 +1465,7 @@ impl<'a> LoadState<'a> {
print_overwrite_warning(
&predicates.compilation_target,
code_index.get(),
- &key,
+ key,
settings.is_dynamic(),
);
@@ -1477,14 +1476,14 @@ impl<'a> LoadState<'a> {
};
set_code_index(
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
&predicates.compilation_target,
key,
&code_index,
index_ptr,
);
- self.wam.code_repo.code.extend(code.into_iter());
+ self.wam_prelude.code.extend(code.into_iter());
Ok(code_index)
}
@@ -1494,18 +1493,22 @@ impl<'a> LoadState<'a> {
key: &PredicateKey,
clause_clause_locs: SliceDeque<usize>,
) {
- match self.wam.indices.get_local_predicate_skeleton_mut(
- self.compilation_target.clone(),
- compilation_target.clone(),
- self.listing_src_file_name(),
- key.clone(),
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
+ self.payload.compilation_target,
+ *compilation_target,
+ listing_src_file_name,
+ *key,
) {
Some(skeleton) => {
- self.retraction_info.push_record(
+ let payload_compilation_target = self.payload.compilation_target;
+
+ self.payload.retraction_info.push_record(
RetractionRecord::SkeletonLocalClauseTruncateBack(
- self.compilation_target.clone(),
- compilation_target.clone(),
- key.clone(),
+ payload_compilation_target,
+ *compilation_target,
+ *key,
skeleton.clause_clause_locs.len(),
),
);
@@ -1519,8 +1522,8 @@ impl<'a> LoadState<'a> {
skeleton.clause_clause_locs = clause_clause_locs;
self.add_local_extensible_predicate(
- compilation_target.clone(),
- key.clone(),
+ *compilation_target,
+ *key,
skeleton,
);
}
@@ -1533,18 +1536,22 @@ impl<'a> LoadState<'a> {
key: &PredicateKey,
code_len: usize,
) {
- match self.wam.indices.get_local_predicate_skeleton_mut(
- self.compilation_target.clone(),
- compilation_target.clone(),
- self.listing_src_file_name(),
- key.clone(),
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
+ self.payload.compilation_target,
+ *compilation_target,
+ listing_src_file_name,
+ *key,
) {
Some(skeleton) => {
- self.retraction_info.push_record(
+ let payload_compilation_target = self.payload.compilation_target;
+
+ self.payload.retraction_info.push_record(
RetractionRecord::SkeletonLocalClauseClausePopFront(
- self.compilation_target.clone(),
- compilation_target.clone(),
- key.clone(),
+ payload_compilation_target,
+ *compilation_target,
+ *key,
),
);
@@ -1555,8 +1562,8 @@ impl<'a> LoadState<'a> {
skeleton.clause_clause_locs.push_front(code_len);
self.add_local_extensible_predicate(
- compilation_target.clone(),
- key.clone(),
+ *compilation_target,
+ *key,
skeleton,
);
}
@@ -1569,18 +1576,22 @@ impl<'a> LoadState<'a> {
key: &PredicateKey,
code_len: usize,
) {
- match self.wam.indices.get_local_predicate_skeleton_mut(
- self.compilation_target.clone(),
- compilation_target.clone(),
- self.listing_src_file_name(),
- key.clone(),
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
+ self.payload.compilation_target,
+ *compilation_target,
+ listing_src_file_name,
+ *key,
) {
Some(skeleton) => {
- self.retraction_info.push_record(
+ let payload_compilation_target = self.payload.compilation_target;
+
+ self.payload.retraction_info.push_record(
RetractionRecord::SkeletonLocalClauseClausePopBack(
- self.compilation_target.clone(),
- compilation_target.clone(),
- key.clone(),
+ payload_compilation_target,
+ *compilation_target,
+ *key,
),
);
@@ -1591,8 +1602,8 @@ impl<'a> LoadState<'a> {
skeleton.clause_clause_locs.push_back(code_len);
self.add_local_extensible_predicate(
- compilation_target.clone(),
- key.clone(),
+ *compilation_target,
+ *key,
skeleton,
);
}
@@ -1608,13 +1619,13 @@ impl<'a> LoadState<'a> {
append_or_prepend: AppendOrPrepend,
) -> Result<CodeIndex, SessionError> {
let settings = match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
Some(skeleton) if !skeleton.clauses.is_empty() => CodeGenSettings {
global_clock_tick: if skeleton.core.is_dynamic {
- Some(self.wam.machine_st.global_clock)
+ Some(LS::machine_st(&mut self.payload).global_clock)
} else {
None
},
@@ -1625,7 +1636,7 @@ impl<'a> LoadState<'a> {
let settings = CodeGenSettings {
global_clock_tick: if let Some(skeleton) = skeleton_opt {
if skeleton.core.is_dynamic {
- Some(self.wam.machine_st.global_clock)
+ Some(LS::machine_st(&mut self.payload).global_clock)
} else {
None
}
@@ -1639,21 +1650,19 @@ impl<'a> LoadState<'a> {
let mut predicate_queue = predicate_queue![clause];
predicate_queue.compilation_target = compilation_target;
- return self.compile(key, &mut predicate_queue, settings);
+ return self.compile(key, predicate_queue, settings);
}
};
- let atom_tbl = self.wam.machine_st.atom_tbl.clone();
-
let StandaloneCompileResult {
clause_code,
mut standalone_skeleton,
- } = self.compile_standalone_clause(clause, settings, atom_tbl)?;
+ } = self.compile_standalone_clause(clause, settings)?;
- let code_len = self.wam.code_repo.code.len();
+ let code_len = self.wam_prelude.code.len();
let skeleton = match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
@@ -1668,28 +1677,30 @@ impl<'a> LoadState<'a> {
skeleton.core.clause_clause_locs.push_back(code_len);
- self.retraction_info
+ self.payload.retraction_info
.push_record(RetractionRecord::SkeletonClausePopBack(
- compilation_target.clone(),
- key.clone(),
+ compilation_target,
+ key,
));
+ let global_clock = LS::machine_st(&mut self.payload).global_clock;
+
let result = append_compiled_clause(
- &mut self.wam.code_repo.code,
+ &mut self.wam_prelude.code,
clause_code,
skeleton,
- &mut self.retraction_info,
- self.wam.machine_st.global_clock,
+ &mut self.payload.retraction_info,
+ global_clock,
);
self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len);
let code_index =
- self.get_or_insert_code_index(key.clone(), compilation_target.clone());
+ self.get_or_insert_code_index(key, compilation_target);
if let Some(new_code_ptr) = result {
set_code_index(
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
&compilation_target,
key,
&code_index,
@@ -1706,29 +1717,31 @@ impl<'a> LoadState<'a> {
skeleton.core.clause_clause_locs.push_front(code_len);
skeleton.core.clause_assert_margin += 1;
- self.retraction_info
+ self.payload.retraction_info
.push_record(RetractionRecord::SkeletonClausePopFront(
- compilation_target.clone(),
- key.clone(),
+ compilation_target,
+ key,
));
+ let global_clock = LS::machine_st(&mut self.payload).global_clock;
+
let new_code_ptr = prepend_compiled_clause(
- &mut self.wam.code_repo.code,
- compilation_target.clone(),
- key.clone(),
+ &mut self.wam_prelude.code,
+ compilation_target,
+ key,
clause_code,
skeleton,
- &mut self.retraction_info,
- self.wam.machine_st.global_clock,
+ &mut self.payload.retraction_info,
+ global_clock,
);
self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len);
let code_index =
- self.get_or_insert_code_index(key.clone(), compilation_target.clone());
+ self.get_or_insert_code_index(key, compilation_target);
set_code_index(
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
&compilation_target,
key,
&code_index,
@@ -1742,9 +1755,9 @@ impl<'a> LoadState<'a> {
pub(super) fn retract_dynamic_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
let skeleton = match self
- .wam
+ .wam_prelude
.indices
- .get_predicate_skeleton_mut(&self.compilation_target, &key)
+ .get_predicate_skeleton_mut(&self.payload.compilation_target, &key)
{
Some(skeleton) => skeleton,
None => {
@@ -1756,53 +1769,50 @@ impl<'a> LoadState<'a> {
.opt_arg_index_key
.switch_on_term_loc()
{
- Some(index_loc) => find_inner_choice_instr(
- &self.wam.code_repo.code,
- skeleton.clauses[target_pos].clause_start,
- index_loc,
- ),
+ Some(index_loc) => {
+ find_inner_choice_instr(
+ &self.wam_prelude.code,
+ skeleton.clauses[target_pos].clause_start,
+ index_loc,
+ )
+ }
None => skeleton.clauses[target_pos].clause_start,
};
- match &mut self.wam.code_repo.code[clause_loc] {
- Line::Choice(ChoiceInstruction::DynamicElse(_, ref mut d, _))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, ref mut d, _)) => {
- *d = Death::Finite(self.wam.machine_st.global_clock);
+ match &mut self.wam_prelude.code[clause_loc] {
+ Instruction::DynamicElse(_, ref mut d, _) |
+ Instruction::DynamicInternalElse(_, ref mut d, _) => {
+ *d = Death::Finite(LS::machine_st(&mut self.payload).global_clock);
}
_ => unreachable!(),
}
delete_from_skeleton(
- self.compilation_target.clone(),
+ self.payload.compilation_target,
key,
skeleton,
target_pos,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
)
}
pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
- let code_index =
- self.get_or_insert_code_index(key.clone(), self.compilation_target.clone());
+ let payload_compilation_target = self.payload.compilation_target;
+ let code_index = self.get_or_insert_code_index(key, payload_compilation_target);
- let skeleton = match self
- .wam
+ let skeleton = self
+ .wam_prelude
.indices
- .get_predicate_skeleton_mut(&self.compilation_target, &key)
- {
- Some(skeleton) => skeleton,
- None => {
- unreachable!();
- }
- };
+ .get_predicate_skeleton_mut(&payload_compilation_target, &key)
+ .unwrap();
- let code = &mut self.wam.code_repo.code;
+ let code = &mut self.wam_prelude.code;
let lower_bound = lower_bound_of_target_clause(skeleton, target_pos);
let lower_bound_is_unindexed = !skeleton.clauses[lower_bound].opt_arg_index_key.is_some();
if target_pos == 0 || (lower_bound + 1 == target_pos && lower_bound_is_unindexed) {
- // the clause preceding target_pos, if there is one, is of key type
- // OptArgIndexKey::None.
+ // the clause preceding target_pos, if there is one, is of
+ // key type OptArgIndexKey::None.
match skeleton.clauses[target_pos]
.opt_arg_index_key
.switch_on_term_loc()
@@ -1818,13 +1828,13 @@ impl<'a> LoadState<'a> {
code,
&skeleton.clauses[target_pos].opt_arg_index_key,
inner_clause_start,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
match derelictize_try_me_else(
code,
inner_clause_start,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
) {
Some(offset) => {
let instr_loc = find_inner_choice_instr(
@@ -1836,20 +1846,20 @@ impl<'a> LoadState<'a> {
let clause_loc = blunt_leading_choice_instr(
code,
instr_loc,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
set_switch_var_offset(
code,
index_loc,
clause_loc - index_loc,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
- self.retraction_info.push_record(
+ self.payload.retraction_info.push_record(
RetractionRecord::SkeletonClauseStartReplaced(
- self.compilation_target.clone(),
- key.clone(),
+ payload_compilation_target,
+ key,
target_pos + 1,
skeleton.clauses[target_pos + 1].clause_start,
),
@@ -1866,12 +1876,12 @@ impl<'a> LoadState<'a> {
return finalize_retract(
key,
- self.compilation_target.clone(),
+ payload_compilation_target,
skeleton,
code_index,
target_pos,
index_ptr_opt,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
}
None => {
@@ -1883,24 +1893,24 @@ impl<'a> LoadState<'a> {
code,
preceding_choice_instr_loc,
skeleton.clauses[target_pos].clause_start - 2,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
)
} else {
remove_leading_unindexed_clause(
code,
skeleton.clauses[target_pos].clause_start - 2,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
)
};
return finalize_retract(
key,
- self.compilation_target.clone(),
+ payload_compilation_target,
skeleton,
code_index,
target_pos,
index_ptr_opt,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
}
}
@@ -1931,14 +1941,12 @@ impl<'a> LoadState<'a> {
Some(later_indexing_loc) if later_indexing_loc < target_indexing_loc => {
let target_indexing_line = mem::replace(
&mut code[target_indexing_loc],
- Line::Control(ControlInstruction::RevJmpBy(
- target_indexing_loc - later_indexing_loc,
- )),
+ Instruction::RevJmpBy(target_indexing_loc - later_indexing_loc),
);
match target_indexing_line {
- Line::IndexingCode(indexing_code) => {
- self.retraction_info.push_record(
+ Instruction::IndexingCode(indexing_code) => {
+ self.payload.retraction_info.push_record(
RetractionRecord::ReplacedIndexingLine(
target_indexing_loc,
indexing_code,
@@ -1953,7 +1961,7 @@ impl<'a> LoadState<'a> {
skeleton,
lower_bound,
target_pos + 1,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
merge_indices(
@@ -1961,14 +1969,15 @@ impl<'a> LoadState<'a> {
later_indexing_loc,
0..target_pos - lower_bound,
&mut skeleton.clauses[lower_bound..],
- &mut self.retraction_info,
+ &skeleton.core.retracted_dynamic_clauses,
+ &mut self.payload.retraction_info,
);
set_switch_var_offset(
code,
later_indexing_loc,
lower_bound_clause_start - later_indexing_loc,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
}
_ => {
@@ -1977,7 +1986,7 @@ impl<'a> LoadState<'a> {
skeleton,
lower_bound,
target_pos + 1,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
merge_indices(
@@ -1985,14 +1994,15 @@ impl<'a> LoadState<'a> {
target_indexing_loc,
target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound,
&mut skeleton.clauses[lower_bound..],
- &mut self.retraction_info,
+ &skeleton.core.retracted_dynamic_clauses,
+ &mut self.payload.retraction_info,
);
set_switch_var_offset_to_choice_instr(
code,
target_indexing_loc,
lower_bound_clause_start - target_indexing_loc,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
}
};
@@ -2005,7 +2015,7 @@ impl<'a> LoadState<'a> {
code,
&skeleton.clauses[target_pos].opt_arg_index_key,
skeleton.clauses[target_pos].clause_start,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
);
match skeleton.clauses[target_pos]
@@ -2013,29 +2023,91 @@ impl<'a> LoadState<'a> {
.switch_on_term_loc()
{
Some(index_loc) => {
- let preceding_choice_instr_loc = find_inner_choice_instr(
+ let clause_start = find_inner_choice_instr(
code,
- skeleton.clauses[target_pos - 1].clause_start,
+ skeleton.clauses[target_pos].clause_start,
index_loc,
);
- remove_non_leading_clause(
- code,
- preceding_choice_instr_loc,
- skeleton.clauses[target_pos].clause_start,
- &mut self.retraction_info,
- );
+ let lower_bound_clause_start = skeleton.clauses[lower_bound].clause_start;
+ let preceding_choice_instr_loc;
+
+ match &mut code[clause_start] {
+ Instruction::TryMeElse(0) => {
+ preceding_choice_instr_loc = if skeleton.clauses[lower_bound]
+ .opt_arg_index_key
+ .is_some()
+ {
+ lower_bound_clause_start - 2
+ } else {
+ lower_bound_clause_start
+ };
+
+ remove_non_leading_clause(
+ code,
+ preceding_choice_instr_loc,
+ skeleton.clauses[target_pos].clause_start - 2,
+ &mut self.payload.retraction_info,
+ );
+ }
+ Instruction::TryMeElse(_) => {
+ let new_target_loc = blunt_leading_choice_instr(
+ code,
+ clause_start,
+ &mut self.payload.retraction_info,
+ );
+
+ derelictize_try_me_else(
+ code,
+ clause_start,
+ &mut self.payload.retraction_info,
+ );
- match &mut code[preceding_choice_instr_loc] {
- Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
set_switch_var_offset(
code,
index_loc,
- preceding_choice_instr_loc + 1 - index_loc,
- &mut self.retraction_info,
+ new_target_loc - index_loc,
+ &mut self.payload.retraction_info,
+ );
+
+ self.payload.retraction_info.push_record(
+ RetractionRecord::SkeletonClauseStartReplaced(
+ payload_compilation_target,
+ key,
+ target_pos + 1,
+ skeleton.clauses[target_pos + 1].clause_start,
+ ),
+ );
+
+ skeleton.clauses[target_pos + 1].clause_start =
+ skeleton.clauses[target_pos].clause_start;
+ }
+ _ => {
+ preceding_choice_instr_loc = find_inner_choice_instr(
+ code,
+ skeleton.clauses[target_pos - 1].clause_start,
+ index_loc,
+ );
+
+ remove_non_leading_clause(
+ code,
+ preceding_choice_instr_loc,
+ skeleton.clauses[target_pos].clause_start,
+ &mut self.payload.retraction_info,
);
+
+ match &mut code[preceding_choice_instr_loc] {
+ Instruction::TryMeElse(0) => {
+ set_switch_var_offset(
+ code,
+ index_loc,
+ preceding_choice_instr_loc + 1 - index_loc,
+ &mut self.payload.retraction_info,
+ );
+ }
+ _ => {}
+ }
}
- _ => {}
}
None
@@ -2052,7 +2124,7 @@ impl<'a> LoadState<'a> {
code,
preceding_choice_instr_loc,
skeleton.clauses[target_pos].clause_start,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
)
}
}
@@ -2060,7 +2132,7 @@ impl<'a> LoadState<'a> {
remove_leading_unindexed_clause(
code,
skeleton.clauses[target_pos].clause_start,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
)
}
}
@@ -2068,17 +2140,17 @@ impl<'a> LoadState<'a> {
finalize_retract(
key,
- self.compilation_target.clone(),
+ payload_compilation_target,
skeleton,
code_index,
target_pos,
index_ptr_opt,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
)
}
}
-impl<'a, TS: TermStream> Loader<'a, TS> {
+impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
pub(super) fn compile_clause_clauses<ClauseIter: Iterator<Item = (Term, Term)>>(
&mut self,
key: PredicateKey,
@@ -2089,24 +2161,23 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
let clause_predicates = clause_clauses.map(|(head, body)| {
Term::Clause(
Cell::default(),
- clause_name!("$clause"),
- vec![Box::new(head), Box::new(body)],
- None,
+ atom!("$clause"),
+ vec![head, body],
)
});
let clause_clause_compilation_target = match compilation_target {
- CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")),
- _ => compilation_target.clone(),
+ CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
+ _ => compilation_target,
};
let mut num_clause_predicates = 0;
for clause_term in clause_predicates {
- self.load_state.incremental_compile_clause(
- (clause_name!("$clause"), 2),
+ self.incremental_compile_clause(
+ (atom!("$clause"), 2),
clause_term,
- clause_clause_compilation_target.clone(),
+ clause_clause_compilation_target,
false, // non_counted_bt is false.
append_or_prepend,
)?;
@@ -2115,8 +2186,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
let locs_vec: Vec<_> = match self
- .load_state
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
@@ -2136,9 +2206,9 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
};
- match self.load_state.wam.indices.get_predicate_skeleton_mut(
+ match self.wam_prelude.indices.get_predicate_skeleton_mut(
&clause_clause_compilation_target,
- &(clause_name!("$clause"), 2),
+ &(atom!("$clause"), 2),
) {
Some(skeleton) if append_or_prepend.is_append() => {
for _ in 0..num_clause_predicates {
@@ -2158,8 +2228,31 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
skeleton.core.clause_clause_locs.push_front(loc);
}
}
+ None if append_or_prepend.is_append() => {
+ let mut skeleton = PredicateSkeleton::new();
+
+ for loc in locs_vec {
+ skeleton.core.clause_clause_locs.push_back(loc);
+ }
+
+ self.add_extensible_predicate(
+ (atom!("$clause"), 2),
+ skeleton,
+ clause_clause_compilation_target,
+ );
+ }
None => {
- unreachable!();
+ let mut skeleton = PredicateSkeleton::new();
+
+ for loc in locs_vec.into_iter().rev() {
+ skeleton.core.clause_clause_locs.push_back(loc);
+ }
+
+ self.add_extensible_predicate(
+ (atom!("$clause"), 2),
+ skeleton,
+ clause_clause_compilation_target,
+ );
}
}
@@ -2168,6 +2261,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> {
let key = self
+ .payload
.predicates
.first()
.and_then(|cl| {
@@ -2176,23 +2270,24 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
})
.ok_or(SessionError::NamelessEntry)?;
+ let listing_src_file_name = self.listing_src_file_name();
+ let payload_compilation_target = self.payload.compilation_target;
+
let mut predicate_info = self
- .load_state
- .wam
+ .wam_prelude
.indices
- .get_predicate_skeleton(&self.predicates.compilation_target, &key)
+ .get_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
.map(|skeleton| skeleton.predicate_info())
.unwrap_or_default();
let local_predicate_info = self
- .load_state
- .wam
+ .wam_prelude
.indices
.get_local_predicate_skeleton(
- self.load_state.compilation_target.clone(),
- self.predicates.compilation_target.clone(),
- self.load_state.listing_src_file_name(),
- key.clone(),
+ payload_compilation_target,
+ self.payload.predicates.compilation_target,
+ listing_src_file_name,
+ key,
)
.map(|skeleton| skeleton.predicate_info())
.unwrap_or_default();
@@ -2202,54 +2297,55 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
let do_incremental_compile =
- if self.load_state.compilation_target == self.predicates.compilation_target {
+ if payload_compilation_target == self.payload.predicates.compilation_target {
predicate_info.compile_incrementally()
} else {
local_predicate_info.is_multifile && predicate_info.compile_incrementally()
};
- let predicates_len = self.predicates.len();
- let non_counted_bt = self.non_counted_bt_preds.contains(&key);
+ let predicates_len = self.payload.predicates.len();
+ let non_counted_bt = self.payload.non_counted_bt_preds.contains(&key);
if do_incremental_compile {
- for term in self.predicates.predicates.drain(0..) {
- self.load_state.incremental_compile_clause(
- key.clone(),
+ let predicates = self.payload.predicates.take();
+
+ for term in predicates.predicates {
+ self.incremental_compile_clause(
+ key,
term,
- self.predicates.compilation_target.clone(),
+ payload_compilation_target,
non_counted_bt,
AppendOrPrepend::Append,
)?;
}
} else {
- if self.load_state.compilation_target != self.predicates.compilation_target {
+ if payload_compilation_target != self.payload.predicates.compilation_target {
if !local_predicate_info.is_extensible {
if predicate_info.is_multifile {
println!(
"Warning: overwriting multifile predicate {}:{}/{} because \
it was not locally declared multifile.",
- self.predicates.compilation_target, key.0, key.1
+ self.payload.predicates.compilation_target, key.0.as_str(), key.1
);
}
if let Some(skeleton) = self
- .load_state
- .wam
+ .wam_prelude
.indices
- .remove_predicate_skeleton(&self.predicates.compilation_target, &key)
+ .remove_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
{
if predicate_info.is_dynamic {
let clause_clause_compilation_target =
- match &self.predicates.compilation_target {
+ match self.payload.predicates.compilation_target {
CompilationTarget::User => {
- CompilationTarget::Module(clause_name!("builtins"))
+ CompilationTarget::Module(atom!("builtins"))
}
- module => module.clone(),
+ module => module,
};
- self.load_state.retract_local_clauses_by_locs(
+ self.retract_local_clauses_by_locs(
clause_clause_compilation_target,
- (clause_name!("$clause"), 2),
+ (atom!("$clause"), 2),
(0..skeleton.clauses.len()).map(Some).collect(),
false, // the builtin M:'$clause'/2 is never dynamic.
);
@@ -2257,10 +2353,10 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
predicate_info.is_dynamic = false;
}
- self.load_state.retraction_info.push_record(
+ self.payload.retraction_info.push_record(
RetractionRecord::RemovedSkeleton(
- self.predicates.compilation_target.clone(),
- key.clone(),
+ payload_compilation_target,
+ key,
skeleton,
),
);
@@ -2270,7 +2366,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
let settings = CodeGenSettings {
global_clock_tick: if predicate_info.is_dynamic {
- Some(self.load_state.wam.machine_st.global_clock)
+ Some(LS::machine_st(&mut self.payload).global_clock)
} else {
None
},
@@ -2278,20 +2374,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
non_counted_bt,
};
- let code_index =
- self.load_state
- .compile(key.clone(), &mut self.predicates, settings)?;
+ let predicates = self.payload.predicates.take();
+ let code_index = self.compile(key, predicates, settings)?;
- if let Some(filename) = self.load_state.listing_src_file_name() {
- match self.load_state.wam.indices.modules.get_mut(&filename) {
+ if let Some(filename) = self.listing_src_file_name() {
+ match self.wam_prelude.indices.modules.get_mut(&filename) {
Some(ref mut module) => {
let index_ptr = code_index.get();
- let code_index = module.code_dir.entry(key.clone()).or_insert(code_index);
+ let code_index = module.code_dir.entry(key).or_insert(code_index);
set_code_index(
- &mut self.load_state.retraction_info,
+ &mut self.payload.retraction_info,
&CompilationTarget::Module(filename),
- key.clone(),
+ key,
&code_index,
index_ptr,
);
@@ -2302,13 +2397,16 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
if predicate_info.is_dynamic {
- self.load_state.wam.machine_st.global_clock += 1;
+ LS::machine_st(&mut self.payload).global_clock += 1;
- let clauses_vec: Vec<_> = self.clause_clauses.drain(0..predicates_len).collect();
+ let clause_clauses_len = self.payload.clause_clauses.len();
+ let clauses_vec: Vec<_> = self.payload
+ .clause_clauses.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
+ .collect();
self.compile_clause_clauses(
key,
- self.predicates.compilation_target.clone(),
+ payload_compilation_target,
clauses_vec.into_iter(),
AppendOrPrepend::Append,
)?;
diff --git a/src/machine/copier.rs b/src/machine/copier.rs
index fdd52c96..fd016fd6 100644
--- a/src/machine/copier.rs
+++ b/src/machine/copier.rs
@@ -1,5 +1,6 @@
-use crate::machine::machine_indices::*;
+use crate::atom_table::*;
use crate::machine::stack::*;
+use crate::types::*;
use std::mem;
use std::ops::IndexMut;
@@ -7,20 +8,24 @@ use std::ops::IndexMut;
type Trail = Vec<(Ref, HeapCellValue)>;
#[derive(Debug, Clone, Copy)]
-pub(crate) enum AttrVarPolicy {
+pub enum AttrVarPolicy {
DeepCopy,
StripAttributes,
}
-pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
- fn deref(&self, val: Addr) -> Addr;
- fn push(&mut self, val: HeapCellValue);
+pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
+ fn store(&self, value: HeapCellValue) -> HeapCellValue;
+ fn deref(&self, value: HeapCellValue) -> HeapCellValue;
+ fn push(&mut self, value: HeapCellValue);
fn stack(&mut self) -> &mut Stack;
- fn store(&self, val: Addr) -> Addr;
fn threshold(&self) -> usize;
}
-pub(crate) fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
+pub(crate) fn copy_term<T: CopierTarget>(
+ target: T,
+ addr: HeapCellValue,
+ attr_var_policy: AttrVarPolicy,
+) {
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
copy_term_state.copy_term_impl(addr);
}
@@ -47,50 +52,51 @@ impl<T: CopierTarget> CopyTermState<T> {
#[inline]
fn value_at_scan(&mut self) -> &mut HeapCellValue {
- let scan = self.scan;
- &mut self.target[scan]
+ &mut self.target[self.scan]
}
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
- let trail_item = mem::replace(
- &mut self.target[addr],
- HeapCellValue::Addr(Addr::Lis(threshold)),
- );
-
- self.trail.push((Ref::HeapCell(addr), trail_item));
+ let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
+ self.trail.push((Ref::heap_cell(addr), trail_item));
}
fn copy_list(&mut self, addr: usize) {
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;
+ read_heap_cell!(self.target[addr + offset],
+ (HeapCellValueTag::Lis, h) => {
+ if h >= self.old_h {
+ *self.value_at_scan() = list_loc_as_cell!(h);
+ self.scan += 1;
- return;
+ return;
+ }
}
- }
+ _ => {
+ }
+ )
}
let threshold = self.target.threshold();
- *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
+ *self.value_at_scan() = list_loc_as_cell!(threshold);
for i in 0..2 {
- let hcv = self.target[addr + i].context_free_clone();
+ let hcv = self.target[addr + i];
self.target.push(hcv);
}
let cdr = self
.target
- .store(self.target.deref(Addr::HeapCell(addr + 1)));
+ .store(self.target.deref(heap_loc_as_cell!(addr + 1)));
- if !cdr.is_ref() {
+ if !cdr.is_var() {
self.trail_list_cell(addr + 1, threshold);
} else {
- let car = self.target.store(self.target.deref(Addr::HeapCell(addr)));
+ let car = self
+ .target
+ .store(self.target.deref(heap_loc_as_cell!(addr)));
- if !car.is_ref() {
+ if !car.is_var() {
self.trail_list_cell(addr, threshold);
}
}
@@ -98,187 +104,190 @@ impl<T: CopierTarget> CopyTermState<T> {
self.scan += 1;
}
- fn copy_partial_string(&mut self, addr: usize, n: usize) {
- 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));
+ fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
+ read_heap_cell!(self.target[pstr_loc],
+ (HeapCellValueTag::PStrLoc, h) => {
+ debug_assert!(h >= self.old_h);
+
+ *self.value_at_scan() = match scan_tag {
+ HeapCellValueTag::PStrLoc => {
+ pstr_loc_as_cell!(h)
+ }
+ tag => {
+ debug_assert_eq!(tag, HeapCellValueTag::PStrOffset);
+ pstr_offset_as_cell!(h)
+ }
+ };
+
+ self.scan += 1;
+ return;
+ }
+ (HeapCellValueTag::Var, h) => {
+ debug_assert!(h >= self.old_h);
+ debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
+
+ *self.value_at_scan() = pstr_offset_as_cell!(h);
self.scan += 1;
return;
}
- }
+ _ => {}
+ );
let threshold = self.target.threshold();
- *self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
+ let replacement = read_heap_cell!(self.target[pstr_loc],
+ (HeapCellValueTag::CStr) => {
+ debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
- self.scan += 1;
+ *self.value_at_scan() = pstr_offset_as_cell!(threshold);
+ self.target.push(self.target[pstr_loc]);
- let (pstr, has_tail) = match &self.target[addr] {
- &HeapCellValue::PartialString(ref pstr, has_tail) => {
- (pstr.clone_from_offset(0), has_tail)
+ heap_loc_as_cell!(threshold)
}
_ => {
- unreachable!()
- }
- };
-
- self.target
- .push(HeapCellValue::PartialString(pstr, has_tail));
+ *self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc {
+ pstr_loc_as_cell!(threshold)
+ } else {
+ debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
+ pstr_offset_as_cell!(threshold)
+ };
- let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
+ self.target.push(self.target[pstr_loc]);
+ self.target.push(self.target[pstr_loc + 1]);
- let trail_item = mem::replace(&mut self.target[addr], replacement);
+ pstr_loc_as_cell!(threshold)
+ }
+ );
- self.trail.push((Ref::HeapCell(addr), trail_item));
+ self.scan += 1;
- if has_tail {
- let tail_addr = self.target[addr + 1].as_addr(addr + 1);
- self.target.push(HeapCellValue::Addr(tail_addr));
- }
+ let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
+ self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
}
- fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
- match addr {
- Addr::HeapCell(h) => {
- self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
- self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
+ fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Var, h) => {
+ self.target[frontier] = heap_loc_as_cell!(frontier);
+ self.target[h] = heap_loc_as_cell!(frontier);
- self.trail
- .push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
+ self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h)));
}
- 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)),
- ));
+ (HeapCellValueTag::StackVar, s) => {
+ self.target[frontier] = heap_loc_as_cell!(frontier);
+ self.target.stack()[s] = heap_loc_as_cell!(frontier);
+
+ self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
}
- Addr::AttrVar(h) => {
+ (HeapCellValueTag::AttrVar, h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.threshold()
} else {
frontier
};
- self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
- self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
+ self.target[frontier] = heap_loc_as_cell!(threshold);
+ self.target[h] = heap_loc_as_cell!(threshold);
- self.trail
- .push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h))));
+ self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
- self.target
- .push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
+ self.target.push(attr_var_as_cell!(threshold));
- let list_val = self.target[h + 1].context_free_clone();
+ let list_val = self.target[h + 1];
self.target.push(list_val);
}
}
_ => {
unreachable!()
}
- }
+ );
}
- fn copy_var(&mut self, addr: Addr) {
- let rd = self.target.store(self.target.deref(addr));
+ fn copy_var(&mut self, addr: HeapCellValue) {
+ let rd = self.target.deref(addr);
+ let ra = self.target.store(rd);
- match rd {
- Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
- *self.value_at_scan() = HeapCellValue::Addr(rd);
- self.scan += 1;
- }
- _ if addr == rd => {
- self.reinstantiate_var(addr, self.scan);
- self.scan += 1;
- }
- _ => {
- *self.value_at_scan() = HeapCellValue::Addr(rd);
+ read_heap_cell!(ra,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h >= self.old_h {
+ *self.value_at_scan() = ra;
+ self.scan += 1;
+
+ return;
+ }
}
+ _ => {}
+ );
+
+ if rd == ra {
+ self.reinstantiate_var(ra, self.scan);
+ self.scan += 1;
+ } else {
+ *self.value_at_scan() = ra;
}
}
fn copy_structure(&mut self, addr: usize) {
- match self.target[addr].context_free_clone() {
- HeapCellValue::NamedStr(arity, name, fixity) => {
+ read_heap_cell!(self.target[addr],
+ (HeapCellValueTag::Atom, (name, arity)) => {
let threshold = self.target.threshold();
- *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
+ *self.value_at_scan() = str_loc_as_cell!(threshold);
let trail_item = mem::replace(
&mut self.target[addr],
- HeapCellValue::Addr(Addr::Str(threshold)),
+ str_loc_as_cell!(threshold),
);
- self.trail.push((Ref::HeapCell(addr), trail_item));
-
- self.target
- .push(HeapCellValue::NamedStr(arity, name, fixity));
+ self.trail.push((Ref::heap_cell(addr), trail_item));
+ self.target.push(atom_as_cell!(name, arity));
for i in 0..arity {
- let hcv = self.target[addr + 1 + i].context_free_clone();
+ let hcv = self.target[addr + 1 + i];
self.target.push(hcv);
}
}
- HeapCellValue::Addr(Addr::Str(addr)) => {
- *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
+ (HeapCellValueTag::Str, h) => {
+ *self.value_at_scan() = str_loc_as_cell!(h);
}
_ => {
unreachable!()
}
- }
+ );
self.scan += 1;
}
- fn copy_term_impl(&mut self, addr: Addr) {
+ fn copy_term_impl(&mut self, addr: HeapCellValue) {
self.scan = self.target.threshold();
- self.target.push(HeapCellValue::Addr(addr));
+ self.target.push(addr);
while self.scan < self.target.threshold() {
- match self.value_at_scan() {
- &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;
- } else {
- self.copy_list(h);
- }
- }
- 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(addr, n);
- }
- Addr::Stream(h) => {
- *self.value_at_scan() = self.target[h].context_free_clone();
- }
- _ => {
+ let addr = *self.value_at_scan();
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Lis, h) => {
+ if h >= self.old_h {
self.scan += 1;
+ } else {
+ self.copy_list(h);
}
- },
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
+ self.copy_var(addr);
+ }
+ (HeapCellValueTag::Str, h) => {
+ self.copy_structure(h);
+ }
+ (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
+ self.copy_partial_string(addr.get_tag(), pstr_loc);
+ }
_ => {
self.scan += 1;
}
- }
+ );
}
self.unwind_trail();
@@ -286,12 +295,117 @@ impl<T: CopierTarget> CopyTermState<T> {
fn unwind_trail(&mut self) {
for (r, value) in self.trail.drain(0..) {
- match r {
- Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
- Ref::StackCell(fr, sc) => {
- self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0)
- }
+ let index = r.get_value() as usize;
+
+ match r.get_tag() {
+ RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value,
+ RefTag::StackCell => self.target.stack()[index] = value,
}
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::machine::mock_wam::*;
+
+ #[test]
+ fn copier_tests() {
+ let mut wam = MockWAM::new();
+
+ let f_atom = atom!("f");
+ let a_atom = atom!("a");
+ let b_atom = atom!("b");
+
+ wam.machine_st.heap
+ .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+
+ assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
+ assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
+
+ {
+ let wam = TermCopyingMockWAM { wam: &mut wam };
+ copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
+ }
+
+ // check that the original heap state is still intact.
+ assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
+ assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
+
+ assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(4));
+ assert_eq!(wam.machine_st.heap[4], atom_as_cell!(f_atom, 2));
+ assert_eq!(wam.machine_st.heap[5], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[6], atom_as_cell!(b_atom));
+
+ wam.machine_st.heap.clear();
+
+ let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+
+ let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl);
+ let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
+
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
+
+ {
+ let wam = TermCopyingMockWAM { wam: &mut wam };
+ copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
+ }
+
+ print_heap_terms(wam.machine_st.heap[6..].iter(), 6);
+
+ assert_eq!(wam.machine_st.heap[0], pstr_cell);
+ assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2));
+ assert_eq!(wam.machine_st.heap[2], pstr_second_cell);
+ assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4));
+ assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
+ assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(0i64)));
+
+ assert_eq!(wam.machine_st.heap[7], pstr_cell);
+ assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9));
+ assert_eq!(wam.machine_st.heap[9], pstr_second_cell);
+ assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11));
+ assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7));
+ assert_eq!(wam.machine_st.heap[12], fixnum_as_cell!(Fixnum::build_with(0i64)));
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(0))
+ ]
+ ));
+
+ {
+ let wam = TermCopyingMockWAM { wam: &mut wam };
+ copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
+ }
+
+ assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
+ assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
+ assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0));
+
+ assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6));
+ assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4));
+ assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[8], atom_as_cell!(b_atom));
+ assert_eq!(wam.machine_st.heap[9], atom_as_cell!(a_atom));
+ assert_eq!(wam.machine_st.heap[10], str_loc_as_cell!(6));
+ }
+}
diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs
new file mode 100644
index 00000000..830eedb7
--- /dev/null
+++ b/src/machine/dispatch.rs
@@ -0,0 +1,4886 @@
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::instructions::*;
+use crate::machine::*;
+use crate::machine::arithmetic_ops::*;
+use crate::machine::machine_errors::*;
+use crate::machine::machine_state::*;
+use crate::types::*;
+
+use crate::try_numeric_result;
+
+macro_rules! step_or_fail {
+ ($self:expr, $step_e:expr) => {
+ if $self.machine_st.fail {
+ $self.machine_st.backtrack();
+ } else {
+ $step_e;
+ }
+ };
+}
+
+macro_rules! try_or_throw {
+ ($s:expr, $e:expr) => {{
+ match $e {
+ Ok(val) => val,
+ Err(msg) => {
+ $s.throw_exception(msg);
+ $s.backtrack();
+ continue;
+ }
+ }
+ }};
+}
+
+macro_rules! try_or_throw_gen {
+ ($s:expr, $e:expr) => {{
+ match $e {
+ Ok(val) => val,
+ Err(msg_fn) => {
+ let e = msg_fn($s);
+ $s.throw_exception(e);
+ $s.backtrack();
+ continue;
+ }
+ }
+ }};
+}
+
+static INSTRUCTIONS_PER_INTERRUPT_POLL: usize = 256;
+
+impl MachineState {
+ #[inline(always)]
+ fn compare(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("compare"), 3);
+
+ let a1 = self.store(self.deref(self.registers[1]));
+ let a2 = self.registers[2];
+ let a3 = self.registers[3];
+
+ read_heap_cell!(a1,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[s])
+ .get_name_and_arity();
+
+ match name {
+ atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
+ }
+ _ => {
+ let err = self.domain_error(DomainErrorType::Order, a1);
+ return Err(self.error_form(err, stub_gen()));
+ }
+ }
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+ }
+ _ => {
+ let err = self.type_error(ValidType::Atom, a1);
+ return Err(self.error_form(err, stub_gen()));
+ }
+ );
+
+ let atom = match compare_term_test!(self, a2, a3) {
+ Some(Ordering::Greater) => {
+ atom!(">")
+ }
+ Some(Ordering::Equal) => {
+ atom!("=")
+ }
+ None | Some(Ordering::Less) => {
+ atom!("<")
+ }
+ };
+
+ self.unify_atom(atom, a1);
+ Ok(())
+ }
+
+ pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) {
+ let old_h = self.heap.len();
+
+ let a1 = self.registers[1];
+ let a2 = self.registers[2];
+
+ copy_term(CopyTerm::new(self), a1, attr_var_policy);
+
+ unify_fn!(*self, heap_loc_as_cell!(old_h), a2);
+ }
+
+ fn sort(&mut self) -> CallResult {
+ self.check_sort_errors()?;
+
+ let stub_gen = || functor_stub(atom!("sort"), 2);
+ let mut list = self.try_from_list(self.registers[1], stub_gen)?;
+
+ list.sort_unstable_by(|v1, v2| {
+ compare_term_test!(self, *v1, *v2).unwrap_or(Ordering::Less)
+ });
+
+ list.dedup_by(|v1, v2| {
+ compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal)
+ });
+
+ let heap_addr = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.heap, list.into_iter())
+ );
+
+ let target_addr = self.registers[2];
+
+ unify_fn!(*self, target_addr, heap_addr);
+ Ok(())
+ }
+
+ fn keysort(&mut self) -> CallResult {
+ self.check_keysort_errors()?;
+
+ let stub_gen = || functor_stub(atom!("keysort"), 2);
+ let list = self.try_from_list(self.registers[1], stub_gen)?;
+
+ let mut key_pairs = Vec::with_capacity(list.len());
+
+ for val in list {
+ let key = self.project_onto_key(val)?;
+ key_pairs.push((key, val));
+ }
+
+ key_pairs.sort_by(|a1, a2| {
+ compare_term_test!(self, a1.0, a2.0).unwrap_or(Ordering::Less)
+ });
+
+ let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
+ let heap_addr = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.heap, key_pairs)
+ );
+
+ let target_addr = self.registers[2];
+
+ unify_fn!(*self, target_addr, heap_addr);
+ Ok(())
+ }
+
+ fn is(&mut self, r: RegType, at: ArithmeticTerm) -> CallResult {
+ let n1 = self.store(self.deref(self[r]));
+
+ match self.get_number(&at)? {
+ Number::Fixnum(n) => self.unify_fixnum(n, n1),
+ Number::Float(n) => {
+ // TODO: argghh.. allocate floats to their own area.
+ let n = arena_alloc!(n, &mut self.arena);
+ self.unify_f64(n, n1)
+ }
+ Number::Integer(n) => self.unify_big_int(n, n1),
+ Number::Rational(n) => self.unify_rational(n, n1),
+ }
+
+ Ok(())
+ }
+}
+
+impl Machine {
+ fn read(&mut self) -> CallResult {
+ let stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("read"),
+ 2,
+ )?;
+
+ match self.machine_st.read(stream, &self.indices.op_dir) {
+ Ok(offset) => {
+ let value = self.machine_st.registers[2];
+ unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc));
+ }
+ Err(ParserError::UnexpectedEOF) => {
+ let value = self.machine_st.registers[2];
+ self.machine_st.unify_atom(atom!("end_of_file"), value);
+ }
+ Err(e) => {
+ let stub = functor_stub(atom!("read"), 2);
+ let err = self.machine_st.syntax_error(e);
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
+ };
+
+ Ok(())
+ }
+
+ pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> {
+ loop {
+ match &self.code[p] {
+ &Instruction::DynamicElse(
+ birth,
+ death,
+ NextOrFail::Next(i),
+ ) => {
+ if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+ return Some((p, i));
+ } else if i > 0 {
+ p += i;
+ } else {
+ return None;
+ }
+ }
+ &Instruction::DynamicElse(
+ birth,
+ death,
+ NextOrFail::Fail(_),
+ ) => {
+ if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+ return Some((p, 0));
+ } else {
+ return None;
+ }
+ }
+ &Instruction::DynamicInternalElse(
+ birth,
+ death,
+ NextOrFail::Next(i),
+ ) => {
+ if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+ return Some((p, i));
+ } else if i > 0 {
+ p += i;
+ } else {
+ return None;
+ }
+ }
+ &Instruction::DynamicInternalElse(
+ birth,
+ death,
+ NextOrFail::Fail(_),
+ ) => {
+ if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+ return Some((p, 0));
+ } else {
+ return None;
+ }
+ }
+ &Instruction::RevJmpBy(i) => {
+ p -= i;
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+ }
+ }
+
+ pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> {
+ let p = self.machine_st.p;
+
+ let indexed_choice_instrs = match &self.code[p] {
+ Instruction::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] {
+ IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
+ indexed_choice_instrs
+ }
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
+ };
+
+ loop {
+ match &indexed_choice_instrs.get(ii as usize) {
+ Some(&offset) => match &self.code[p + offset - 1] {
+ &Instruction::DynamicInternalElse(
+ birth,
+ death,
+ next_or_fail,
+ ) => {
+ if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+ return Some((offset, oi, ii, next_or_fail.is_next()));
+ } else {
+ ii += 1;
+ }
+ }
+ _ => unreachable!(),
+ },
+ None => return None,
+ }
+ }
+ }
+
+ #[inline(always)]
+ fn execute_switch_on_term(&mut self) {
+ #[inline(always)]
+ fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool {
+ match &machine.code[p] {
+ Instruction::DynamicInternalElse(..) => {
+ machine.machine_st.dynamic_mode = FirstOrNext::First;
+ return true;
+ }
+ _ => {}
+ }
+
+ match &machine.code[p - 1] {
+ &Instruction::DynamicInternalElse(birth, death, _) => {
+ if birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ _ => {}
+ }
+
+ true
+ }
+
+ let indexing_lines = self.code[self.machine_st.p].to_indexing_line_mut().unwrap();
+
+ let mut index = 0;
+ let addr = match &indexing_lines[0] {
+ &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[arg]))
+ }
+ _ => {
+ unreachable!()
+ }
+ };
+
+ loop {
+ match &indexing_lines[index] {
+ &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
+ let offset = read_heap_cell!(addr,
+ (HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar |
+ HeapCellValueTag::AttrVar) => {
+ v
+ }
+ (HeapCellValueTag::PStrLoc |
+ HeapCellValueTag::Lis |
+ HeapCellValueTag::CStr) => {
+ l
+ }
+ (HeapCellValueTag::Fixnum |
+ HeapCellValueTag::Char |
+ HeapCellValueTag::F64) => {
+ c
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ // if arity == 0 { c } else { s }
+ debug_assert!(arity == 0);
+ c
+ }
+ (HeapCellValueTag::Str) => {
+ s
+ }
+ (HeapCellValueTag::Cons, ptr) => {
+ match ptr.get_tag() {
+ ArenaHeaderTag::Rational | ArenaHeaderTag::Integer |
+ ArenaHeaderTag::F64 => {
+ c
+ }
+ _ => {
+ IndexingCodePtr::Fail
+ }
+ }
+ }
+ _ => {
+ unreachable!();
+ }
+ );
+
+ match offset {
+ IndexingCodePtr::Fail => {
+ self.machine_st.fail = true;
+ break;
+ }
+ IndexingCodePtr::DynamicExternal(o) => {
+ // either points directly to a
+ // DynamicInternalElse, or just ahead of
+ // one. Or neither!
+ let p = self.machine_st.p;
+
+ if !dynamic_external_of_clause_is_valid(self, p + o) {
+ self.machine_st.fail = true;
+ } else {
+ self.machine_st.p += o;
+ }
+
+ break;
+ }
+ IndexingCodePtr::External(o) => {
+ self.machine_st.p += o;
+ break;
+ }
+ IndexingCodePtr::Internal(o) => {
+ index += o;
+ }
+ }
+ }
+ &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
+ let lit = read_heap_cell!(addr,
+ (HeapCellValueTag::Char, c) => {
+ Literal::Char(c)
+ }
+ (HeapCellValueTag::Fixnum, n) => {
+ Literal::Fixnum(n)
+ }
+ (HeapCellValueTag::F64, f) => {
+ Literal::Float(f)
+ }
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ debug_assert_eq!(arity, 0);
+ Literal::Atom(atom)
+ }
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Rational, r) => {
+ Literal::Rational(r)
+ }
+ (ArenaHeaderTag::F64, f) => {
+ Literal::Float(F64Ptr(f))
+ }
+ (ArenaHeaderTag::Integer, n) => {
+ Literal::Integer(n)
+ }
+ _ => {
+ unreachable!()
+ }
+ )
+ }
+ _ => {
+ unreachable!()
+ }
+ );
+
+ let offset = match hm.get(&lit) {
+ Some(offset) => *offset,
+ _ => IndexingCodePtr::Fail,
+ };
+
+ match offset {
+ IndexingCodePtr::Fail => {
+ self.machine_st.fail = true;
+ break;
+ }
+ IndexingCodePtr::DynamicExternal(o) => {
+ // either points directly to a
+ // DynamicInternalElse, or just ahead of
+ // one. Or neither!
+ let p = self.machine_st.p;
+
+ if !dynamic_external_of_clause_is_valid(self, p + o) {
+ self.machine_st.fail = true;
+ } else {
+ self.machine_st.p += o;
+ }
+
+ break;
+ }
+ IndexingCodePtr::External(o) => {
+ self.machine_st.p += o;
+ break;
+ }
+ IndexingCodePtr::Internal(o) => {
+ index += o;
+ }
+ }
+ }
+ &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
+ let offset = read_heap_cell!(addr,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ match hm.get(&(name, arity)) {
+ Some(offset) => *offset,
+ None => IndexingCodePtr::Fail,
+ }
+ }
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_name_and_arity();
+
+ match hm.get(&(name, arity)) {
+ Some(offset) => *offset,
+ None => IndexingCodePtr::Fail,
+ }
+ }
+ _ => {
+ IndexingCodePtr::Fail
+ }
+ );
+
+ match offset {
+ IndexingCodePtr::Fail => {
+ self.machine_st.fail = true;
+ break;
+ }
+ IndexingCodePtr::DynamicExternal(o) => {
+ let p = self.machine_st.p;
+
+ if !dynamic_external_of_clause_is_valid(self, p + o) {
+ self.machine_st.fail = true;
+ } else {
+ self.machine_st.p += o;
+ }
+
+ break;
+ }
+ IndexingCodePtr::External(o) => {
+ self.machine_st.p += o;
+ break;
+ }
+ IndexingCodePtr::Internal(o) => {
+ index += o;
+ }
+ }
+ }
+ &IndexingLine::IndexedChoice(_) => {
+ self.machine_st.oip = index as u32;
+ self.machine_st.iip = 0;
+
+ break;
+ }
+ &IndexingLine::DynamicIndexedChoice(_) => {
+ self.machine_st.dynamic_mode = FirstOrNext::First;
+
+ self.machine_st.oip = index as u32;
+ self.machine_st.iip = 0;
+
+ break;
+ }
+ }
+ }
+ }
+
+ #[inline(always)]
+ pub(super) fn dispatch_loop(&mut self) {
+ 'outer: loop {
+ for _ in 0 .. INSTRUCTIONS_PER_INTERRUPT_POLL {
+ match &self.code[self.machine_st.p] {
+ &Instruction::BreakFromDispatchLoop => {
+ break 'outer;
+ }
+ &Instruction::InstallVerifyAttr => {
+ self.machine_st.p = self.machine_st.attr_var_init.p;
+
+ if self.code[self.machine_st.p].is_execute() {
+ self.machine_st.p = self.machine_st.attr_var_init.cp;
+ } else {
+ self.machine_st.p += 1;
+ self.machine_st.cp = self.machine_st.attr_var_init.cp;
+ }
+
+ let mut p = self.machine_st.p;
+
+ while self.code[p].is_head_instr() {
+ p += 1;
+ }
+
+ let instr = std::mem::replace(
+ &mut self.code[p],
+ Instruction::VerifyAttrInterrupt,
+ );
+
+ self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr;
+ self.machine_st.attr_var_init.cp = p;
+ }
+ &Instruction::VerifyAttrInterrupt => {
+ let (_, arity) = self.code[VERIFY_ATTR_INTERRUPT_LOC].to_name_and_arity();
+ let arity = std::cmp::max(arity, self.machine_st.num_of_args);
+ self.run_verify_attr_interrupt(arity);
+ }
+ &Instruction::Add(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Sub(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
+ );
+ self.machine_st.p += 1;
+ }
+ &Instruction::Mul(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Max(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ max(n1, n2)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Min(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ min(n1, n2)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::IntPow(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ int_pow(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Gcd(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ gcd(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Pow(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ pow(n1, n2, atom!("**"))
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::RDiv(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
+
+ let r1 = try_or_throw!(self.machine_st, self.machine_st.get_rational(a1, stub_gen));
+ let r2 = try_or_throw!(self.machine_st, self.machine_st.get_rational(a2, stub_gen));
+
+ self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
+ try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
+ self.machine_st.arena
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::IntFloorDiv(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ int_floor_div(n1, n2, &mut self.machine_st.arena)
+ );
+ self.machine_st.p += 1;
+ }
+ &Instruction::IDiv(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ idiv(n1, n2, &mut self.machine_st.arena)
+ );
+ self.machine_st.p += 1;
+ }
+ &Instruction::Abs(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = abs(n1, &mut self.machine_st.arena);
+ self.machine_st.p += 1;
+ }
+ &Instruction::Sign(ref a1, t) => {
+ let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = sign(n);
+ self.machine_st.p += 1;
+ }
+ &Instruction::Neg(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena);
+ self.machine_st.p += 1;
+ }
+ &Instruction::BitwiseComplement(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ bitwise_complement(n1, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Div(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ div(n1, n2)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Shr(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ shr(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Shl(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ shl(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Xor(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ xor(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::And(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ and(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Or(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ or(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Mod(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ modulus(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Rem(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ remainder(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Cos(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, cos(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Sin(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, sin(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Tan(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, tan(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Sqrt(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, sqrt(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Log(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, log(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Exp(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, exp(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::ACos(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, acos(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::ASin(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, asin(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::ATan(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, atan(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::ATan2(ref a1, ref a2, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, atan2(n1, n2))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Float(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, float(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Truncate(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = truncate(n1, &mut self.machine_st.arena);
+ self.machine_st.p += 1;
+ }
+ &Instruction::Round(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] =
+ try_or_throw_gen!(&mut self.machine_st, round(n1, &mut self.machine_st.arena));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Ceiling(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = ceiling(n1, &mut self.machine_st.arena);
+ self.machine_st.p += 1;
+ }
+ &Instruction::Floor(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = floor(n1, &mut self.machine_st.arena);
+ self.machine_st.p += 1;
+ }
+ &Instruction::Plus(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = n1;
+ self.machine_st.p += 1;
+ }
+ &Instruction::DynamicElse(..) => {
+ if let FirstOrNext::First = self.machine_st.dynamic_mode {
+ self.machine_st.cc = self.machine_st.global_clock;
+ }
+
+ let p = self.machine_st.p;
+
+ match self.find_living_dynamic_else(p) {
+ Some((p, next_i)) => {
+ self.machine_st.p = p;
+ self.machine_st.oip = 0;
+ self.machine_st.iip = 0;
+
+ match self.machine_st.dynamic_mode {
+ FirstOrNext::First if next_i == 0 => {
+ self.machine_st.p += 1;
+ }
+ FirstOrNext::First => {
+ self.machine_st.cc = self.machine_st.global_clock;
+
+ match self.find_living_dynamic_else(p + next_i) {
+ Some(_) => {
+ self.machine_st.registers[self.machine_st.num_of_args + 1] =
+ fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+ self.machine_st.num_of_args += 1;
+ self.machine_st.try_me_else(next_i);
+ self.machine_st.num_of_args -= 1;
+ }
+ None => {
+ self.machine_st.p += 1;
+ }
+ }
+ }
+ FirstOrNext::Next => {
+ let n = self.machine_st
+ .stack
+ .index_or_frame(self.machine_st.b)
+ .prelude
+ .univ_prelude
+ .num_cells;
+
+ self.machine_st.cc = cell_as_fixnum!(
+ self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
+ ).get_num() as usize;
+
+ if next_i > 0 {
+ match self.find_living_dynamic_else(p + next_i) {
+ Some(_) => {
+ self.retry_me_else(next_i);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ None => {
+ self.trust_me();
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ } else {
+ self.trust_me();
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ }
+ }
+ None => {
+ self.machine_st.fail = true;
+ }
+ }
+
+ self.machine_st.dynamic_mode = FirstOrNext::Next;
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DynamicInternalElse(..) => {
+ let p = self.machine_st.p;
+
+ match self.find_living_dynamic_else(p) {
+ Some((p, next_i)) => {
+ self.machine_st.p = p;
+ self.machine_st.oip = 0;
+ self.machine_st.iip = 0;
+
+ match self.machine_st.dynamic_mode {
+ FirstOrNext::First if next_i == 0 => {
+ self.machine_st.p += 1;
+ }
+ FirstOrNext::First => {
+ match self.find_living_dynamic_else(p + next_i) {
+ Some(_) => {
+ self.machine_st.registers[self.machine_st.num_of_args + 1] =
+ fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+ self.machine_st.num_of_args += 1;
+ self.machine_st.try_me_else(next_i);
+ self.machine_st.num_of_args -= 1;
+ }
+ None => {
+ self.machine_st.p += 1;
+ }
+ }
+ }
+ FirstOrNext::Next => {
+ let n = self.machine_st
+ .stack
+ .index_or_frame(self.machine_st.b)
+ .prelude
+ .univ_prelude
+ .num_cells;
+
+ self.machine_st.cc = cell_as_fixnum!(
+ self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
+ ).get_num() as usize;
+
+ if next_i > 0 {
+ match self.find_living_dynamic_else(p + next_i) {
+ Some(_) => {
+ self.retry_me_else(next_i);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ None => {
+ self.trust_me();
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ } else {
+ self.trust_me();
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ }
+ }
+ None => {
+ self.machine_st.fail = true;
+ }
+ }
+
+ self.machine_st.dynamic_mode = FirstOrNext::Next;
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::TryMeElse(offset) => {
+ self.machine_st.try_me_else(offset);
+ }
+ &Instruction::DefaultRetryMeElse(offset) => {
+ self.retry_me_else(offset);
+ }
+ &Instruction::DefaultTrustMe(_) => {
+ self.trust_me();
+ }
+ &Instruction::RetryMeElse(offset) => {
+ self.retry_me_else(offset);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ &Instruction::TrustMe(_) => {
+ self.trust_me();
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ &Instruction::NeckCut => {
+ let b = self.machine_st.b;
+ let b0 = self.machine_st.b0;
+
+ if b > b0 {
+ self.machine_st.b = b0;
+
+ if b > self.machine_st.e {
+ self.machine_st.stack.truncate(b);
+ }
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetLevel(r) => {
+ let b0 = self.machine_st.b0;
+
+ self.machine_st[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64));
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetLevelAndUnify(r) => {
+ // let b0 = self.machine_st[perm_v!(1)];
+ let b0 = cell_as_fixnum!(
+ self.machine_st.stack[stack_loc!(AndFrame, self.machine_st.e, 1)]
+ );
+ let a = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ // unify_fn!(&mut self.machine_st, a, b0);
+ self.machine_st.unify_fixnum(b0, a);
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::Cut(r) => {
+ let value = self.machine_st[r];
+ self.machine_st.cut_body(value);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ continue;
+ }
+
+ if (self.machine_st.run_cleaners_fn)(self) {
+ continue;
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Allocate(num_cells) => {
+ self.machine_st.allocate(num_cells);
+ }
+ &Instruction::DefaultCallAcyclicTerm(_) => {
+ let addr = self.machine_st.registers[1];
+
+ if self.machine_st.is_cyclic_term(addr) {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::DefaultExecuteAcyclicTerm(_) => {
+ let addr = self.machine_st.registers[1];
+
+ if self.machine_st.is_cyclic_term(addr) {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallArg(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_arg());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteArg(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_arg());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::DefaultCallCompare(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.compare());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteCompare(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.compare());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::DefaultCallTermGreaterThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DefaultExecuteTermGreaterThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DefaultCallTermLessThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DefaultExecuteTermLessThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DefaultCallTermGreaterThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Greater | Ordering::Equal) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultExecuteTermGreaterThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Greater | Ordering::Equal) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultCallTermLessThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Less | Ordering::Equal) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultExecuteTermLessThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Less | Ordering::Equal) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultCallRead(_) => {
+ try_or_throw!(self.machine_st, self.read());
+
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteRead(_) => {
+ try_or_throw!(self.machine_st, self.read());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallCopyTerm(_) => {
+ self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteCopyTerm(_) => {
+ self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallTermEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if self.machine_st.eq_test(a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::DefaultExecuteTermEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if self.machine_st.eq_test(a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallGround(_) => {
+ if self.machine_st.ground_test() {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::DefaultExecuteGround(_) => {
+ if self.machine_st.ground_test() {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallFunctor(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteFunctor(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallTermNotEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::DefaultExecuteTermNotEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallSort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.sort());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteSort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.sort());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::DefaultCallKeySort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteKeySort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::DefaultCallIs(r, at, _) => {
+ try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteIs(r, at, _) => {
+ try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallAcyclicTerm(_) => {
+ let addr = self.machine_st.registers[1];
+
+ if self.machine_st.is_cyclic_term(addr) {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteAcyclicTerm(_) => {
+ let addr = self.machine_st.registers[1];
+
+ if self.machine_st.is_cyclic_term(addr) {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallArg(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_arg());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteArg(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_arg());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallCompare(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.compare());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteCompare(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.compare());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallTermGreaterThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::ExecuteTermGreaterThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::CallTermLessThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::ExecuteTermLessThan(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::CallTermGreaterThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Greater | Ordering::Equal) => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteTermGreaterThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Greater | Ordering::Equal) => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallTermLessThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Less | Ordering::Equal) => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteTermLessThanOrEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ match compare_term_test!(self.machine_st, a1, a2) {
+ Some(Ordering::Less | Ordering::Equal) => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallRead(_) => {
+ try_or_throw!(self.machine_st, self.read());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteRead(_) => {
+ try_or_throw!(self.machine_st, self.read());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallCopyTerm(_) => {
+ self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteCopyTerm(_) => {
+ self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallTermEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if self.machine_st.eq_test(a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteTermEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if self.machine_st.eq_test(a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallGround(_) => {
+ if self.machine_st.ground_test() {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteGround(_) => {
+ if self.machine_st.ground_test() {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallFunctor(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteFunctor(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallTermNotEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteTermNotEqual(_) => {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
+
+ if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallSort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.sort());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteSort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.sort());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallKeySort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteKeySort(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallIs(r, at, _) => {
+ try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteIs(r, at, _) => {
+ try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallN(arity, _) => {
+ let pred = self.machine_st.registers[1];
+
+ for i in 2..arity + 1 {
+ self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+ }
+
+ self.machine_st.registers[arity] = pred;
+
+ try_or_throw!(
+ self.machine_st,
+ self.call_n(atom!("user"), arity)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ &Instruction::ExecuteN(arity, _) => {
+ let pred = self.machine_st.registers[1];
+
+ for i in 2..arity + 1 {
+ self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+ }
+
+ self.machine_st.registers[arity] = pred;
+
+ try_or_throw!(
+ self.machine_st,
+ self.execute_n(atom!("user"), arity)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ &Instruction::DefaultCallN(arity, _) => {
+ let pred = self.machine_st.registers[1];
+
+ for i in 2..arity + 1 {
+ self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+ }
+
+ self.machine_st.registers[arity] = pred;
+
+ try_or_throw!(
+ self.machine_st,
+ self.call_n(atom!("user"), arity)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DefaultExecuteN(arity, _) => {
+ let pred = self.machine_st.registers[1];
+
+ for i in 2..arity + 1 {
+ self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+ }
+
+ self.machine_st.registers[arity] = pred;
+
+ try_or_throw!(
+ self.machine_st,
+ self.execute_n(atom!("user"), arity)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::CallNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less | Ordering::Equal => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less | Ordering::Equal => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallNumberEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteNumberEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallNumberNotEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ self.machine_st.backtrack();
+ }
+ _ => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ }
+ &Instruction::ExecuteNumberNotEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ self.machine_st.backtrack();
+ }
+ _ => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ }
+ &Instruction::CallNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater | Ordering::Equal => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater | Ordering::Equal => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallNumberGreaterThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteNumberGreaterThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallNumberLessThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteNumberLessThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less => {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultCallNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less | Ordering::Equal => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultExecuteNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less | Ordering::Equal => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultCallNumberNotEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ self.machine_st.backtrack();
+ }
+ _ => {
+ self.machine_st.p += 1;
+ }
+ }
+ }
+ &Instruction::DefaultExecuteNumberNotEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ self.machine_st.backtrack();
+ }
+ _ => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ }
+ &Instruction::DefaultCallNumberEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultExecuteNumberEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Equal => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultCallNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater | Ordering::Equal => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater | Ordering::Equal => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultCallNumberGreaterThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultExecuteNumberGreaterThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Greater => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultCallNumberLessThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::DefaultExecuteNumberLessThan(ref at_1, ref at_2, _) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+ let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+ match n1.cmp(&n2) {
+ Ordering::Less => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ //
+ &Instruction::CallIsAtom(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity == 0 {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ (HeapCellValueTag::Char) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::ExecuteIsAtom(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity == 0 {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ (HeapCellValueTag::Char) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::CallIsAtomic(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
+ HeapCellValueTag::Cons) => {
+ self.machine_st.p += 1;
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity == 0 {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::ExecuteIsAtomic(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
+ HeapCellValueTag::Cons) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity == 0 {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::CallIsCompound(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Str | HeapCellValueTag::Lis |
+ HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+ self.machine_st.p += 1;
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity > 0 {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::ExecuteIsCompound(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Str | HeapCellValueTag::Lis |
+ HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity > 0 {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::CallIsInteger(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match Number::try_from(d) {
+ Ok(Number::Fixnum(_) | Number::Integer(_)) => {
+ self.machine_st.p += 1;
+ }
+ Ok(Number::Rational(n)) => {
+ if n.denom() == &1 {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteIsInteger(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match Number::try_from(d) {
+ Ok(Number::Fixnum(_) | Number::Integer(_)) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ Ok(Number::Rational(n)) => {
+ if n.denom() == &1 {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallIsNumber(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match Number::try_from(d) {
+ Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
+ self.machine_st.p += 1;
+ }
+ Ok(Number::Rational(n)) => {
+ if n.denom() == &1 {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteIsNumber(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match Number::try_from(d) {
+ Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ Ok(Number::Rational(n)) => {
+ if n.denom() == &1 {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallIsRational(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Cons, ptr) => {
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Rational, _r) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::ExecuteIsRational(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ read_heap_cell!(d,
+ (HeapCellValueTag::Cons, ptr) => {
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Rational, _r) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ &Instruction::CallIsFloat(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match Number::try_from(d) {
+ Ok(Number::Float(_)) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteIsFloat(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match Number::try_from(d) {
+ Ok(Number::Float(_)) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallIsNonVar(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match d.get_tag() {
+ HeapCellValueTag::AttrVar |
+ HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar => {
+ self.machine_st.backtrack();
+ }
+ _ => {
+ self.machine_st.p += 1;
+ }
+ }
+ }
+ &Instruction::ExecuteIsNonVar(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match d.get_tag() {
+ HeapCellValueTag::AttrVar |
+ HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar => {
+ self.machine_st.backtrack();
+ }
+ _ => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ }
+ &Instruction::CallIsVar(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match d.get_tag() {
+ HeapCellValueTag::AttrVar |
+ HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::ExecuteIsVar(r, _) => {
+ let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+ match d.get_tag() {
+ HeapCellValueTag::AttrVar |
+ HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ &Instruction::CallNamed(arity, name, ref idx, _) => {
+ let idx = idx.get();
+
+ try_or_throw!(
+ self.machine_st,
+ self.try_call(name, arity, idx)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ &Instruction::ExecuteNamed(arity, name, ref idx, _) => {
+ let idx = idx.get();
+
+ try_or_throw!(
+ self.machine_st,
+ self.try_execute(name, arity, idx)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ &Instruction::DefaultCallNamed(arity, name, ref idx, _) => {
+ let idx = idx.get();
+
+ try_or_throw!(
+ self.machine_st,
+ self.try_call(name, arity, idx)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DefaultExecuteNamed(arity, name, ref idx, _) => {
+ let idx = idx.get();
+
+ try_or_throw!(
+ self.machine_st,
+ self.try_execute(name, arity, idx)
+ );
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::Deallocate => {
+ self.machine_st.deallocate()
+ }
+ &Instruction::JmpByCall(arity, offset, _) => {
+ self.machine_st.num_of_args = arity;
+ self.machine_st.b0 = self.machine_st.b;
+ self.machine_st.cp = self.machine_st.p + 1;
+ self.machine_st.p += offset;
+ }
+ &Instruction::JmpByExecute(arity, offset, _) => {
+ self.machine_st.num_of_args = arity;
+ self.machine_st.b0 = self.machine_st.b;
+ self.machine_st.p += offset;
+ }
+ &Instruction::RevJmpBy(offset) => {
+ self.machine_st.p -= offset;
+ }
+ &Instruction::Proceed => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::GetConstant(_, c, reg) => {
+ let value = self.machine_st.deref(self.machine_st[reg]);
+ self.machine_st.write_literal_to_var(value, c);
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::GetList(_, reg) => {
+ let deref_v = self.machine_st.deref(self.machine_st[reg]);
+ let store_v = self.machine_st.store(deref_v);
+
+ read_heap_cell!(store_v,
+ (HeapCellValueTag::PStrLoc, h) => {
+ let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h);
+
+ self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize);
+ self.machine_st.s_offset = 0;
+ self.machine_st.mode = MachineMode::Read;
+ }
+ (HeapCellValueTag::CStr) => {
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.push(store_v);
+
+ self.machine_st.s = HeapPtr::PStrChar(h, 0);
+ self.machine_st.s_offset = 0;
+ self.machine_st.mode = MachineMode::Read;
+ }
+ (HeapCellValueTag::Lis, l) => {
+ self.machine_st.s = HeapPtr::HeapCell(l);
+ self.machine_st.s_offset = 0;
+ self.machine_st.mode = MachineMode::Read;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(list_loc_as_cell!(h+1));
+ self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+
+ self.machine_st.mode = MachineMode::Write;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ continue;
+ }
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetPartialString(_, string, reg, has_tail) => {
+ let deref_v = self.machine_st.deref(self.machine_st[reg]);
+ let store_v = self.machine_st.store(deref_v);
+
+ read_heap_cell!(store_v,
+ (HeapCellValueTag::Str | HeapCellValueTag::Lis |
+ HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar |
+ HeapCellValueTag::StackVar | HeapCellValueTag::Var |
+ HeapCellValueTag::CStr) => {
+ self.machine_st.match_partial_string(store_v, string, has_tail);
+ }
+ _ => {
+ self.machine_st.backtrack();
+ continue;
+ }
+ );
+
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::GetStructure(name, arity, reg) => {
+ let deref_v = self.machine_st.deref(self.machine_st[reg]);
+ let store_v = self.machine_st.store(deref_v);
+
+ read_heap_cell!(store_v,
+ (HeapCellValueTag::Str, a) => {
+ read_heap_cell!(self.machine_st.heap[a],
+ (HeapCellValueTag::Atom, (result_name, result_arity)) => {
+ if arity == result_arity && name == result_name {
+ self.machine_st.s = HeapPtr::HeapCell(a + 1);
+ self.machine_st.s_offset = 0;
+ self.machine_st.mode = MachineMode::Read;
+ } else {
+ self.machine_st.backtrack();
+ continue;
+ }
+ }
+ _ => {
+ unreachable!();
+ }
+ );
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(str_loc_as_cell!(h+1));
+ self.machine_st.heap.push(atom_as_cell!(name, arity));
+
+ self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+ self.machine_st.mode = MachineMode::Write;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ continue;
+ }
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetVariable(norm, arg) => {
+ self.machine_st[norm] = self.machine_st.registers[arg];
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetValue(norm, arg) => {
+ let norm_addr = self.machine_st[norm];
+ let reg_addr = self.machine_st.registers[arg];
+
+ unify_fn!(&mut self.machine_st, norm_addr, reg_addr);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ continue;
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::UnifyConstant(v) => {
+ match self.machine_st.mode {
+ MachineMode::Read => {
+ let addr = self.machine_st.read_s();
+
+ self.machine_st.write_literal_to_var(addr, v);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ continue;
+ } else {
+ self.machine_st.s_offset += 1;
+ }
+ }
+ MachineMode::Write => {
+ self.machine_st.heap.push(v);
+ }
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::UnifyLocalValue(reg) => {
+ match self.machine_st.mode {
+ MachineMode::Read => {
+ let reg_addr = self.machine_st[reg];
+ let value = self.machine_st.read_s();
+
+ unify_fn!(&mut self.machine_st, reg_addr, value);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ continue;
+ } else {
+ self.machine_st.s_offset += 1;
+ }
+ }
+ MachineMode::Write => {
+ let value = self.machine_st.store(self.machine_st.deref(self.machine_st[reg]));
+ let h = self.machine_st.heap.len();
+
+ read_heap_cell!(value,
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
+ let value = self.machine_st.heap[hc];
+
+ self.machine_st.heap.push(value);
+ self.machine_st.s_offset += 1;
+ }
+ _ => {
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ (self.machine_st.bind_fn)(
+ &mut self.machine_st,
+ Ref::heap_cell(h),
+ value,
+ );
+ }
+ );
+ }
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::UnifyVariable(reg) => {
+ match self.machine_st.mode {
+ MachineMode::Read => {
+ self.machine_st[reg] = self.machine_st.read_s();
+ self.machine_st.s_offset += 1;
+ }
+ MachineMode::Write => {
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ self.machine_st[reg] = heap_loc_as_cell!(h);
+ }
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::UnifyValue(reg) => {
+ match self.machine_st.mode {
+ MachineMode::Read => {
+ let reg_addr = self.machine_st[reg];
+ let value = self.machine_st.read_s();
+
+ unify_fn!(&mut self.machine_st, reg_addr, value);
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ continue;
+ } else {
+ self.machine_st.s_offset += 1;
+ }
+ }
+ MachineMode::Write => {
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+
+ let addr = self.machine_st.store(self.machine_st[reg]);
+ (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+
+ // the former code of this match arm was:
+
+ // let addr = self.machine_st.store(self.machine_st[reg]);
+ // self.machine_st.heap.push(HeapCellValue::Addr(addr));
+
+ // the old code didn't perform the occurs
+ // check when enabled and so it was changed to
+ // the above, which is only slightly less
+ // efficient when the occurs_check is disabled.
+ }
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::UnifyVoid(n) => {
+ match self.machine_st.mode {
+ MachineMode::Read => {
+ self.machine_st.s_offset += n;
+ }
+ MachineMode::Write => {
+ let h = self.machine_st.heap.len();
+
+ for i in h..h + n {
+ self.machine_st.heap.push(heap_loc_as_cell!(i));
+ }
+ }
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::IndexingCode(ref indexing_lines) => {
+ match &indexing_lines[self.machine_st.oip as usize] {
+ IndexingLine::Indexing(_) => {
+ self.execute_switch_on_term();
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ IndexingLine::IndexedChoice(ref indexed_choice) => {
+ match &indexed_choice[self.machine_st.iip as usize] {
+ &IndexedChoiceInstruction::Try(offset) => {
+ self.machine_st.indexed_try(offset);
+ }
+ &IndexedChoiceInstruction::Retry(l) => {
+ self.retry(l);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ &IndexedChoiceInstruction::Trust(l) => {
+ self.trust(l);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ }
+ IndexingLine::DynamicIndexedChoice(_) => {
+ let p = self.machine_st.p;
+
+ match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) {
+ Some((offset, oi, ii, is_next_clause)) => {
+ self.machine_st.p = p;
+ self.machine_st.oip = oi;
+ self.machine_st.iip = ii;
+
+ match self.machine_st.dynamic_mode {
+ FirstOrNext::First if !is_next_clause => {
+ self.machine_st.p = p + offset;
+ }
+ FirstOrNext::First => {
+ // there's a leading DynamicElse that sets self.machine_st.cc.
+ // self.machine_st.cc = self.machine_st.global_clock;
+
+ // see that there is a following dynamic_else
+ // clause so we avoid generating a choice
+ // point in case there isn't.
+ match self.find_living_dynamic(oi, ii + 1) {
+ Some(_) => {
+ self.machine_st.registers[self.machine_st.num_of_args + 1] =
+ fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+ self.machine_st.num_of_args += 1;
+ self.machine_st.indexed_try(offset);
+ self.machine_st.num_of_args -= 1;
+ }
+ None => {
+ self.machine_st.p = p + offset;
+ self.machine_st.oip = 0;
+ self.machine_st.iip = 0;
+ }
+ }
+ }
+ FirstOrNext::Next => {
+ let b = self.machine_st.b;
+ let n = self.machine_st
+ .stack
+ .index_or_frame(b)
+ .prelude
+ .univ_prelude
+ .num_cells;
+
+ self.machine_st.cc = cell_as_fixnum!(
+ self.machine_st.stack[stack_loc!(OrFrame, b, n-1)]
+ ).get_num() as usize;
+
+ if is_next_clause {
+ match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip + 1) {
+ // if we're executing the last instruction
+ // of the internal block pointed to by
+ // self.machine_st.iip, we want trust, not retry.
+ // this is true iff ii + 1 < len.
+ Some(_) => {
+ self.retry(offset);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ _ => {
+ self.trust(offset);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ } else {
+ self.trust(offset);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ }
+ }
+ }
+ None => {
+ self.machine_st.fail = true;
+ }
+ }
+
+ self.machine_st.dynamic_mode = FirstOrNext::Next;
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ }
+ &Instruction::PutConstant(_, c, reg) => {
+ self.machine_st[reg] = c;
+ self.machine_st.p += 1;
+ }
+ &Instruction::PutList(_, reg) => {
+ self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len());
+ self.machine_st.p += 1;
+ }
+ &Instruction::PutPartialString(_, string, reg, has_tail) => {
+ let pstr_addr = if has_tail {
+ if string != atom!("") {
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.push(string_as_pstr_cell!(string));
+
+ // the tail will be pushed by the next
+ // instruction, so don't push one here.
+
+ pstr_loc_as_cell!(h)
+ } else {
+ empty_list_as_cell!()
+ }
+ } else {
+ string_as_cstr_cell!(string)
+ };
+
+ self.machine_st[reg] = pstr_addr;
+ self.machine_st.p += 1;
+ }
+ &Instruction::PutStructure(name, arity, reg) => {
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(atom_as_cell!(name, arity));
+ self.machine_st[reg] = str_loc_as_cell!(h);
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::PutUnsafeValue(n, arg) => {
+ let s = stack_loc!(AndFrame, self.machine_st.e, n);
+ let addr = self.machine_st.store(self.machine_st.deref(stack_loc_as_cell!(s)));
+
+ if addr.is_protected(self.machine_st.e) {
+ self.machine_st.registers[arg] = addr;
+ } else {
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+
+ self.machine_st.registers[arg] = heap_loc_as_cell!(h);
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::PutValue(norm, arg) => {
+ self.machine_st.registers[arg] = self.machine_st[norm];
+ self.machine_st.p += 1;
+ }
+ &Instruction::PutVariable(norm, arg) => {
+ match norm {
+ RegType::Perm(n) => {
+ self.machine_st[norm] = stack_loc_as_cell!(AndFrame, self.machine_st.e, n);
+ self.machine_st.registers[arg] = self.machine_st[norm];
+ }
+ RegType::Temp(_) => {
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+
+ self.machine_st[norm] = heap_loc_as_cell!(h);
+ self.machine_st.registers[arg] = heap_loc_as_cell!(h);
+ }
+ };
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::SetConstant(c) => {
+ self.machine_st.heap.push(c);
+ self.machine_st.p += 1;
+ }
+ &Instruction::SetLocalValue(reg) => {
+ let addr = self.machine_st.deref(self.machine_st[reg]);
+ let stored_v = self.machine_st.store(addr);
+
+ if stored_v.is_stack_var() {
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), stored_v);
+ } else {
+ self.machine_st.heap.push(stored_v);
+ }
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::SetVariable(reg) => {
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ self.machine_st[reg] = heap_loc_as_cell!(h);
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::SetValue(reg) => {
+ let heap_val = self.machine_st.store(self.machine_st[reg]);
+ self.machine_st.heap.push(heap_val);
+ self.machine_st.p += 1;
+ }
+ &Instruction::SetVoid(n) => {
+ let h = self.machine_st.heap.len();
+
+ for i in h..h + n {
+ self.machine_st.heap.push(heap_loc_as_cell!(i));
+ }
+
+ self.machine_st.p += 1;
+ }
+ //
+ &Instruction::CallAtomChars(_) => {
+ self.atom_chars();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteAtomChars(_) => {
+ self.atom_chars();
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallAtomCodes(_) => {
+ try_or_throw!(self.machine_st, self.atom_codes());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteAtomCodes(_) => {
+ try_or_throw!(self.machine_st, self.atom_codes());
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallAtomLength(_) => {
+ self.atom_length();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteAtomLength(_) => {
+ self.atom_length();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallBindFromRegister(_) => {
+ self.bind_from_register();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteBindFromRegister(_) => {
+ self.bind_from_register();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallContinuation(_) => {
+ try_or_throw!(self.machine_st, self.call_continuation(false));
+ }
+ &Instruction::ExecuteContinuation(_) => {
+ try_or_throw!(self.machine_st, self.call_continuation(true));
+ }
+ &Instruction::CallCharCode(_) => {
+ try_or_throw!(self.machine_st, self.char_code());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCharCode(_) => {
+ try_or_throw!(self.machine_st, self.char_code());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCharType(_) => {
+ self.char_type();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCharType(_) => {
+ self.char_type();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCharsToNumber(_) => {
+ try_or_throw!(self.machine_st, self.chars_to_number());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCharsToNumber(_) => {
+ try_or_throw!(self.machine_st, self.chars_to_number());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCodesToNumber(_) => {
+ try_or_throw!(self.machine_st, self.codes_to_number());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCodesToNumber(_) => {
+ try_or_throw!(self.machine_st, self.codes_to_number());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCopyTermWithoutAttrVars(_) => {
+ self.copy_term_without_attr_vars();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCopyTermWithoutAttrVars(_) => {
+ self.copy_term_without_attr_vars();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCheckCutPoint(_) => {
+ self.check_cut_point();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCheckCutPoint(_) => {
+ self.check_cut_point();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallClose(_) => {
+ try_or_throw!(self.machine_st, self.close());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteClose(_) => {
+ try_or_throw!(self.machine_st, self.close());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallCopyToLiftedHeap(_) => {
+ self.copy_to_lifted_heap();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteCopyToLiftedHeap(_) => {
+ self.copy_to_lifted_heap();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallCreatePartialString(_) => {
+ self.create_partial_string();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCreatePartialString(_) => {
+ self.create_partial_string();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCurrentHostname(_) => {
+ self.current_hostname();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCurrentHostname(_) => {
+ self.current_hostname();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCurrentInput(_) => {
+ try_or_throw!(self.machine_st, self.current_input());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCurrentInput(_) => {
+ try_or_throw!(self.machine_st, self.current_input());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCurrentOutput(_) => {
+ try_or_throw!(self.machine_st, self.current_output());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCurrentOutput(_) => {
+ try_or_throw!(self.machine_st, self.current_output());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDirectoryFiles(_) => {
+ try_or_throw!(self.machine_st, self.directory_files());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDirectoryFiles(_) => {
+ try_or_throw!(self.machine_st, self.directory_files());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallFileSize(_) => {
+ self.file_size();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteFileSize(_) => {
+ self.file_size();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallFileExists(_) => {
+ self.file_exists();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteFileExists(_) => {
+ self.file_exists();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDirectoryExists(_) => {
+ self.directory_exists();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDirectoryExists(_) => {
+ self.directory_exists();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDirectorySeparator(_) => {
+ self.directory_separator();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDirectorySeparator(_) => {
+ self.directory_separator();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallMakeDirectory(_) => {
+ self.make_directory();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteMakeDirectory(_) => {
+ self.make_directory();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallMakeDirectoryPath(_) => {
+ self.make_directory_path();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteMakeDirectoryPath(_) => {
+ self.make_directory_path();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDeleteFile(_) => {
+ self.delete_file();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDeleteFile(_) => {
+ self.delete_file();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallRenameFile(_) => {
+ self.rename_file();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteRenameFile(_) => {
+ self.rename_file();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallWorkingDirectory(_) => {
+ try_or_throw!(self.machine_st, self.working_directory());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteWorkingDirectory(_) => {
+ try_or_throw!(self.machine_st, self.working_directory());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDeleteDirectory(_) => {
+ self.delete_directory();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDeleteDirectory(_) => {
+ self.delete_directory();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPathCanonical(_) => {
+ try_or_throw!(self.machine_st, self.path_canonical());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePathCanonical(_) => {
+ try_or_throw!(self.machine_st, self.path_canonical());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallFileTime(_) => {
+ self.file_time();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteFileTime(_) => {
+ self.file_time();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDeleteAttribute(_) => {
+ self.delete_attribute();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteDeleteAttribute(_) => {
+ self.delete_attribute();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallDeleteHeadAttribute(_) => {
+ self.delete_head_attribute();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteDeleteHeadAttribute(_) => {
+ self.delete_head_attribute();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallDynamicModuleResolution(arity, _) => {
+ let (module_name, key) = try_or_throw!(
+ self.machine_st,
+ self.dynamic_module_resolution(arity - 2)
+ );
+
+ try_or_throw!(self.machine_st, self.call_clause(module_name, key));
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::ExecuteDynamicModuleResolution(arity, _) => {
+ let (module_name, key) = try_or_throw!(
+ self.machine_st,
+ self.dynamic_module_resolution(arity - 2)
+ );
+
+ try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::CallEnqueueAttributedVar(_) => {
+ self.enqueue_attributed_var();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteEnqueueAttributedVar(_) => {
+ self.enqueue_attributed_var();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallFetchGlobalVar(_) => {
+ self.fetch_global_var();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteFetchGlobalVar(_) => {
+ self.fetch_global_var();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallFirstStream(_) => {
+ self.first_stream();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteFirstStream(_) => {
+ self.first_stream();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallFlushOutput(_) => {
+ try_or_throw!(self.machine_st, self.flush_output());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteFlushOutput(_) => {
+ try_or_throw!(self.machine_st, self.flush_output());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallGetByte(_) => {
+ try_or_throw!(self.machine_st, self.get_byte());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetByte(_) => {
+ try_or_throw!(self.machine_st, self.get_byte());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetChar(_) => {
+ try_or_throw!(self.machine_st, self.get_char());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetChar(_) => {
+ try_or_throw!(self.machine_st, self.get_char());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetNChars(_) => {
+ try_or_throw!(self.machine_st, self.get_n_chars());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetNChars(_) => {
+ try_or_throw!(self.machine_st, self.get_n_chars());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetCode(_) => {
+ try_or_throw!(self.machine_st, self.get_code());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetCode(_) => {
+ try_or_throw!(self.machine_st, self.get_code());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetSingleChar(_) => {
+ try_or_throw!(self.machine_st, self.get_single_char());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetSingleChar(_) => {
+ try_or_throw!(self.machine_st, self.get_single_char());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallResetAttrVarState(_) => {
+ self.reset_attr_var_state();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteResetAttrVarState(_) => {
+ self.reset_attr_var_state();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff(_) => {
+ self.truncate_if_no_lifted_heap_growth_diff();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff(_) => {
+ self.truncate_if_no_lifted_heap_growth_diff();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallTruncateIfNoLiftedHeapGrowth(_) => {
+ self.truncate_if_no_lifted_heap_growth();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth(_) => {
+ self.truncate_if_no_lifted_heap_growth();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetAttributedVariableList(_) => {
+ self.get_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetAttributedVariableList(_) => {
+ self.get_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetAttrVarQueueDelimiter(_) => {
+ self.get_attr_var_queue_delimiter();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetAttrVarQueueDelimiter(_) => {
+ self.get_attr_var_queue_delimiter();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetAttrVarQueueBeyond(_) => {
+ self.get_attr_var_queue_beyond();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetAttrVarQueueBeyond(_) => {
+ self.get_attr_var_queue_beyond();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetBValue(_) => {
+ self.get_b_value();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetBValue(_) => {
+ self.get_b_value();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetContinuationChunk(_) => {
+ self.get_continuation_chunk();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetContinuationChunk(_) => {
+ self.get_continuation_chunk();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetNextDBRef(_) => {
+ self.get_next_db_ref();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetNextDBRef(_) => {
+ self.get_next_db_ref();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetNextOpDBRef(_) => {
+ self.get_next_op_db_ref();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetNextOpDBRef(_) => {
+ self.get_next_op_db_ref();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallIsPartialString(_) => {
+ self.is_partial_string();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteIsPartialString(_) => {
+ self.is_partial_string();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallHalt(_) => {
+ self.halt();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteHalt(_) => {
+ self.halt();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallGetLiftedHeapFromOffset(_) => {
+ self.get_lifted_heap_from_offset();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetLiftedHeapFromOffset(_) => {
+ self.get_lifted_heap_from_offset();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetLiftedHeapFromOffsetDiff(_) => {
+ self.get_lifted_heap_from_offset_diff();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetLiftedHeapFromOffsetDiff(_) => {
+ self.get_lifted_heap_from_offset_diff();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetSCCCleaner(_) => {
+ self.get_scc_cleaner();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetSCCCleaner(_) => {
+ self.get_scc_cleaner();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallHeadIsDynamic(_) => {
+ self.head_is_dynamic();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteHeadIsDynamic(_) => {
+ self.head_is_dynamic();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallInstallSCCCleaner(_) => {
+ self.install_scc_cleaner();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteInstallSCCCleaner(_) => {
+ self.install_scc_cleaner();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallInstallInferenceCounter(_) => {
+ try_or_throw!(self.machine_st, self.install_inference_counter());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteInstallInferenceCounter(_) => {
+ try_or_throw!(self.machine_st, self.install_inference_counter());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLiftedHeapLength(_) => {
+ self.lifted_heap_length();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLiftedHeapLength(_) => {
+ self.lifted_heap_length();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadLibraryAsStream(_) => {
+ try_or_throw!(self.machine_st, self.load_library_as_stream());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadLibraryAsStream(_) => {
+ try_or_throw!(self.machine_st, self.load_library_as_stream());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallModuleExists(_) => {
+ self.module_exists();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteModuleExists(_) => {
+ self.module_exists();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallNextEP(_) => {
+ self.next_ep();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteNextEP(_) => {
+ self.next_ep();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallNoSuchPredicate(_) => {
+ try_or_throw!(self.machine_st, self.no_such_predicate());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteNoSuchPredicate(_) => {
+ try_or_throw!(self.machine_st, self.no_such_predicate());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallNumberToChars(_) => {
+ self.number_to_chars();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteNumberToChars(_) => {
+ self.number_to_chars();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallNumberToCodes(_) => {
+ self.number_to_codes();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteNumberToCodes(_) => {
+ self.number_to_codes();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallOpDeclaration(_) => {
+ try_or_throw!(self.machine_st, self.op_declaration());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteOpDeclaration(_) => {
+ try_or_throw!(self.machine_st, self.op_declaration());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallOpen(_) => {
+ try_or_throw!(self.machine_st, self.open());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteOpen(_) => {
+ try_or_throw!(self.machine_st, self.open());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSetStreamOptions(_) => {
+ try_or_throw!(self.machine_st, self.set_stream_options());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetStreamOptions(_) => {
+ try_or_throw!(self.machine_st, self.set_stream_options());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallNextStream(_) => {
+ self.next_stream();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteNextStream(_) => {
+ self.next_stream();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPartialStringTail(_) => {
+ self.partial_string_tail();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePartialStringTail(_) => {
+ self.partial_string_tail();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPeekByte(_) => {
+ try_or_throw!(self.machine_st, self.peek_byte());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePeekByte(_) => {
+ try_or_throw!(self.machine_st, self.peek_byte());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPeekChar(_) => {
+ try_or_throw!(self.machine_st, self.peek_char());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePeekChar(_) => {
+ try_or_throw!(self.machine_st, self.peek_char());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPeekCode(_) => {
+ try_or_throw!(self.machine_st, self.peek_code());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePeekCode(_) => {
+ try_or_throw!(self.machine_st, self.peek_code());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPointsToContinuationResetMarker(_) => {
+ self.points_to_continuation_reset_marker();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePointsToContinuationResetMarker(_) => {
+ self.points_to_continuation_reset_marker();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPutByte(_) => {
+ try_or_throw!(self.machine_st, self.put_byte());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePutByte(_) => {
+ try_or_throw!(self.machine_st, self.put_byte());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallPutChar(_) => {
+ try_or_throw!(self.machine_st, self.put_char());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePutChar(_) => {
+ try_or_throw!(self.machine_st, self.put_char());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallPutChars(_) => {
+ try_or_throw!(self.machine_st, self.put_chars());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePutChars(_) => {
+ try_or_throw!(self.machine_st, self.put_chars());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPutCode(_) => {
+ try_or_throw!(self.machine_st, self.put_code());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePutCode(_) => {
+ try_or_throw!(self.machine_st, self.put_code());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallReadQueryTerm(_) => {
+ try_or_throw!(self.machine_st, self.read_query_term());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteReadQueryTerm(_) => {
+ try_or_throw!(self.machine_st, self.read_query_term());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallReadTerm(_) => {
+ try_or_throw!(self.machine_st, self.read_term());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteReadTerm(_) => {
+ try_or_throw!(self.machine_st, self.read_term());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallRedoAttrVarBinding(_) => {
+ self.redo_attr_var_binding();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteRedoAttrVarBinding(_) => {
+ self.redo_attr_var_binding();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallRemoveCallPolicyCheck(_) => {
+ self.remove_call_policy_check();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteRemoveCallPolicyCheck(_) => {
+ self.remove_call_policy_check();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallRemoveInferenceCounter(_) => {
+ self.remove_inference_counter();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteRemoveInferenceCounter(_) => {
+ self.remove_inference_counter();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallResetContinuationMarker(_) => {
+ self.reset_continuation_marker();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteResetContinuationMarker(_) => {
+ self.reset_continuation_marker();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallRestoreCutPolicy(_) => {
+ self.restore_cut_policy();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteRestoreCutPolicy(_) => {
+ self.restore_cut_policy();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallSetCutPoint(r, _) => {
+ if !self.set_cut_point(r) {
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ }
+ &Instruction::ExecuteSetCutPoint(r, _) => {
+ let cp = self.machine_st.cp;
+
+ if !self.set_cut_point(r) {
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ } else {
+ // run_cleaners in set_cut_point calls call_by_index.
+ // replace the effect of call_by_index with that
+ // of execute_by_index here.
+
+ self.machine_st.cp = cp;
+ }
+ }
+ &Instruction::CallSetInput(_) => {
+ try_or_throw!(self.machine_st, self.set_input());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetInput(_) => {
+ try_or_throw!(self.machine_st, self.set_input());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallSetOutput(_) => {
+ try_or_throw!(self.machine_st, self.set_output());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetOutput(_) => {
+ try_or_throw!(self.machine_st, self.set_output());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallStoreBacktrackableGlobalVar(_) => {
+ self.store_backtrackable_global_var();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteStoreBacktrackableGlobalVar(_) => {
+ self.store_backtrackable_global_var();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallStoreGlobalVar(_) => {
+ self.store_global_var();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteStoreGlobalVar(_) => {
+ self.store_global_var();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallStreamProperty(_) => {
+ try_or_throw!(self.machine_st, self.stream_property());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteStreamProperty(_) => {
+ try_or_throw!(self.machine_st, self.stream_property());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSetStreamPosition(_) => {
+ try_or_throw!(self.machine_st, self.set_stream_position());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSetStreamPosition(_) => {
+ try_or_throw!(self.machine_st, self.set_stream_position());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallInferenceLevel(_) => {
+ self.inference_level();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteInferenceLevel(_) => {
+ self.inference_level();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCleanUpBlock(_) => {
+ self.clean_up_block();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteCleanUpBlock(_) => {
+ self.clean_up_block();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallEraseBall(_) => {
+ self.erase_ball();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteEraseBall(_) => {
+ self.erase_ball();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => {
+ self.machine_st.backtrack();
+ }
+ &Instruction::CallGetBall(_) => {
+ self.get_ball();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetBall(_) => {
+ self.get_ball();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetCurrentBlock(_) => {
+ self.get_current_block();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetCurrentBlock(_) => {
+ self.get_current_block();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetCutPoint(_) => {
+ self.get_cut_point();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetCutPoint(_) => {
+ self.get_cut_point();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetStaggeredCutPoint(_) => {
+ self.get_staggered_cut_point();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetStaggeredCutPoint(_) => {
+ self.get_staggered_cut_point();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetDoubleQuotes(_) => {
+ self.get_double_quotes();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetDoubleQuotes(_) => {
+ self.get_double_quotes();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallInstallNewBlock(_) => {
+ self.machine_st.install_new_block(self.machine_st.registers[1]);
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteInstallNewBlock(_) => {
+ self.machine_st.install_new_block(self.machine_st.registers[1]);
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallMaybe(_) => {
+ self.maybe();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteMaybe(_) => {
+ self.maybe();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCpuNow(_) => {
+ self.cpu_now();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCpuNow(_) => {
+ self.cpu_now();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCurrentTime(_) => {
+ self.current_time();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCurrentTime(_) => {
+ self.current_time();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallQuotedToken(_) => {
+ self.quoted_token();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteQuotedToken(_) => {
+ self.quoted_token();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallReadTermFromChars(_) => {
+ try_or_throw!(self.machine_st, self.read_term_from_chars());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteReadTermFromChars(_) => {
+ try_or_throw!(self.machine_st, self.read_term_from_chars());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallResetBlock(_) => {
+ self.reset_block();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteResetBlock(_) => {
+ self.reset_block();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallReturnFromVerifyAttr(_) |
+ &Instruction::ExecuteReturnFromVerifyAttr(_) => {
+ self.return_from_verify_attr();
+ }
+ &Instruction::CallSetBall(_) => {
+ self.set_ball();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetBall(_) => {
+ self.set_ball();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallSetCutPointByDefault(r, _) => {
+ self.set_cut_point_by_default(r);
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSetCutPointByDefault(r, _) => {
+ self.set_cut_point_by_default(r);
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSetDoubleQuotes(_) => {
+ self.set_double_quotes();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSetDoubleQuotes(_) => {
+ self.set_double_quotes();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSetSeed(_) => {
+ self.set_seed();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSetSeed(_) => {
+ self.set_seed();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSkipMaxList(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.skip_max_list());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSkipMaxList(_) => {
+ try_or_throw!(self.machine_st, self.machine_st.skip_max_list());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSleep(_) => {
+ self.sleep();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSleep(_) => {
+ self.sleep();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallSocketClientOpen(_) => {
+ try_or_throw!(self.machine_st, self.socket_client_open());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSocketClientOpen(_) => {
+ try_or_throw!(self.machine_st, self.socket_client_open());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSocketServerOpen(_) => {
+ try_or_throw!(self.machine_st, self.socket_server_open());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSocketServerOpen(_) => {
+ try_or_throw!(self.machine_st, self.socket_server_open());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSocketServerAccept(_) => {
+ try_or_throw!(self.machine_st, self.socket_server_accept());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSocketServerAccept(_) => {
+ try_or_throw!(self.machine_st, self.socket_server_accept());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSocketServerClose(_) => {
+ try_or_throw!(self.machine_st, self.socket_server_close());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSocketServerClose(_) => {
+ try_or_throw!(self.machine_st, self.socket_server_close());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallTLSAcceptClient(_) => {
+ try_or_throw!(self.machine_st, self.tls_accept_client());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteTLSAcceptClient(_) => {
+ try_or_throw!(self.machine_st, self.tls_accept_client());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallTLSClientConnect(_) => {
+ try_or_throw!(self.machine_st, self.tls_client_connect());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteTLSClientConnect(_) => {
+ try_or_throw!(self.machine_st, self.tls_client_connect());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSucceed(_) => {
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSucceed(_) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallTermAttributedVariables(_) => {
+ self.term_attributed_variables();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteTermAttributedVariables(_) => {
+ self.term_attributed_variables();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallTermVariables(_) => {
+ self.term_variables();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteTermVariables(_) => {
+ self.term_variables();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallTermVariablesUnderMaxDepth(_) => {
+ self.term_variables_under_max_depth();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteTermVariablesUnderMaxDepth(_) => {
+ self.term_variables_under_max_depth();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallTruncateLiftedHeapTo(_) => {
+ self.truncate_lifted_heap_to();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteTruncateLiftedHeapTo(_) => {
+ self.truncate_lifted_heap_to();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallUnifyWithOccursCheck(_) => {
+ self.unify_with_occurs_check();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteUnifyWithOccursCheck(_) => {
+ self.unify_with_occurs_check();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallUnwindEnvironments(_) => {
+ if !self.unwind_environments() {
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteUnwindEnvironments(_) => {
+ if !self.unwind_environments() {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallUnwindStack(_) | &Instruction::ExecuteUnwindStack(_) => {
+ self.machine_st.unwind_stack();
+ self.machine_st.backtrack();
+ }
+ &Instruction::CallWAMInstructions(_) => {
+ try_or_throw!(self.machine_st, self.wam_instructions());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteWAMInstructions(_) => {
+ try_or_throw!(self.machine_st, self.wam_instructions());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallWriteTerm(_) => {
+ try_or_throw!(self.machine_st, self.write_term());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteWriteTerm(_) => {
+ try_or_throw!(self.machine_st, self.write_term());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallWriteTermToChars(_) => {
+ try_or_throw!(self.machine_st, self.write_term_to_chars());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteWriteTermToChars(_) => {
+ try_or_throw!(self.machine_st, self.write_term_to_chars());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallScryerPrologVersion(_) => {
+ self.scryer_prolog_version();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteScryerPrologVersion(_) => {
+ self.scryer_prolog_version();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCryptoRandomByte(_) => {
+ self.crypto_random_byte();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCryptoRandomByte(_) => {
+ self.crypto_random_byte();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCryptoDataHash(_) => {
+ self.crypto_data_hash();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCryptoDataHash(_) => {
+ self.crypto_data_hash();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCryptoDataHKDF(_) => {
+ self.crypto_data_hkdf();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCryptoDataHKDF(_) => {
+ self.crypto_data_hkdf();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCryptoPasswordHash(_) => {
+ self.crypto_password_hash();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCryptoPasswordHash(_) => {
+ self.crypto_password_hash();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCryptoDataEncrypt(_) => {
+ self.crypto_data_encrypt();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCryptoDataEncrypt(_) => {
+ self.crypto_data_encrypt();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCryptoDataDecrypt(_) => {
+ self.crypto_data_decrypt();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCryptoDataDecrypt(_) => {
+ self.crypto_data_decrypt();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCryptoCurveScalarMult(_) => {
+ self.crypto_curve_scalar_mult();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCryptoCurveScalarMult(_) => {
+ self.crypto_curve_scalar_mult();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallEd25519Sign(_) => {
+ self.ed25519_sign();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteEd25519Sign(_) => {
+ self.ed25519_sign();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallEd25519Verify(_) => {
+ self.ed25519_verify();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteEd25519Verify(_) => {
+ self.ed25519_verify();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallEd25519NewKeyPair(_) => {
+ self.ed25519_new_key_pair();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteEd25519NewKeyPair(_) => {
+ self.ed25519_new_key_pair();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallEd25519KeyPairPublicKey(_) => {
+ self.ed25519_key_pair_public_key();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteEd25519KeyPairPublicKey(_) => {
+ self.ed25519_key_pair_public_key();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCurve25519ScalarMult(_) => {
+ self.curve25519_scalar_mult();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCurve25519ScalarMult(_) => {
+ self.curve25519_scalar_mult();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallFirstNonOctet(_) => {
+ self.first_non_octet();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteFirstNonOctet(_) => {
+ self.first_non_octet();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadHTML(_) => {
+ self.load_html();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadHTML(_) => {
+ self.load_html();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadXML(_) => {
+ self.load_xml();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadXML(_) => {
+ self.load_xml();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallGetEnv(_) => {
+ self.get_env();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetEnv(_) => {
+ self.get_env();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSetEnv(_) => {
+ self.set_env();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetEnv(_) => {
+ self.set_env();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallUnsetEnv(_) => {
+ self.unset_env();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteUnsetEnv(_) => {
+ self.unset_env();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallShell(_) => {
+ self.shell();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteShell(_) => {
+ self.shell();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPID(_) => {
+ self.pid();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePID(_) => {
+ self.pid();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCharsBase64(_) => {
+ try_or_throw!(self.machine_st, self.chars_base64());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCharsBase64(_) => {
+ try_or_throw!(self.machine_st, self.chars_base64());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDevourWhitespace(_) => {
+ try_or_throw!(self.machine_st, self.devour_whitespace());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDevourWhitespace(_) => {
+ try_or_throw!(self.machine_st, self.devour_whitespace());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallIsSTOEnabled(_) => {
+ self.is_sto_enabled();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteIsSTOEnabled(_) => {
+ self.is_sto_enabled();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallSetSTOAsUnify(_) => {
+ self.set_sto_as_unify();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetSTOAsUnify(_) => {
+ self.set_sto_as_unify();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallSetNSTOAsUnify(_) => {
+ self.set_nsto_as_unify();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetNSTOAsUnify(_) => {
+ self.set_nsto_as_unify();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallSetSTOWithErrorAsUnify(_) => {
+ self.set_sto_with_error_as_unify();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteSetSTOWithErrorAsUnify(_) => {
+ self.set_sto_with_error_as_unify();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallHomeDirectory(_) => {
+ self.home_directory();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteHomeDirectory(_) => {
+ self.home_directory();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDebugHook(_) => {
+ self.debug_hook();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteDebugHook(_) => {
+ self.debug_hook();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallPopCount(_) => {
+ self.pop_count();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePopCount(_) => {
+ self.pop_count();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallAddDiscontiguousPredicate(_) => {
+ try_or_throw!(self.machine_st, self.add_discontiguous_predicate());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAddDiscontiguousPredicate(_) => {
+ try_or_throw!(self.machine_st, self.add_discontiguous_predicate());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAddDynamicPredicate(_) => {
+ try_or_throw!(self.machine_st, self.add_dynamic_predicate());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAddDynamicPredicate(_) => {
+ try_or_throw!(self.machine_st, self.add_dynamic_predicate());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAddMultifilePredicate(_) => {
+ try_or_throw!(self.machine_st, self.add_multifile_predicate());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAddMultifilePredicate(_) => {
+ try_or_throw!(self.machine_st, self.add_multifile_predicate());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAddGoalExpansionClause(_) => {
+ try_or_throw!(self.machine_st, self.add_goal_expansion_clause());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAddGoalExpansionClause(_) => {
+ try_or_throw!(self.machine_st, self.add_goal_expansion_clause());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAddTermExpansionClause(_) => {
+ try_or_throw!(self.machine_st, self.add_term_expansion_clause());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAddTermExpansionClause(_) => {
+ try_or_throw!(self.machine_st, self.add_term_expansion_clause());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAddInSituFilenameModule(_) => {
+ try_or_throw!(self.machine_st, self.add_in_situ_filename_module());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAddInSituFilenameModule(_) => {
+ try_or_throw!(self.machine_st, self.add_in_situ_filename_module());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallClauseToEvacuable(_) => {
+ try_or_throw!(self.machine_st, self.clause_to_evacuable());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteClauseToEvacuable(_) => {
+ try_or_throw!(self.machine_st, self.clause_to_evacuable());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallScopedClauseToEvacuable(_) => {
+ try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteScopedClauseToEvacuable(_) => {
+ try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallConcludeLoad(_) => {
+ try_or_throw!(self.machine_st, self.conclude_load());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteConcludeLoad(_) => {
+ try_or_throw!(self.machine_st, self.conclude_load());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallDeclareModule(_) => {
+ try_or_throw!(self.machine_st, self.declare_module());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteDeclareModule(_) => {
+ try_or_throw!(self.machine_st, self.declare_module());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallLoadCompiledLibrary(_) => {
+ try_or_throw!(self.machine_st, self.load_compiled_library());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadCompiledLibrary(_) => {
+ try_or_throw!(self.machine_st, self.load_compiled_library());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadContextSource(_) => {
+ self.load_context_source();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadContextSource(_) => {
+ self.load_context_source();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadContextFile(_) => {
+ self.load_context_file();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadContextFile(_) => {
+ self.load_context_file();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadContextDirectory(_) => {
+ self.load_context_directory();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadContextDirectory(_) => {
+ self.load_context_directory();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadContextModule(_) => {
+ self.load_context_module();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadContextModule(_) => {
+ self.load_context_module();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadContextStream(_) => {
+ self.load_context_stream();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadContextStream(_) => {
+ self.load_context_stream();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPopLoadContext(_) => {
+ self.pop_load_context();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePopLoadContext(_) => {
+ self.pop_load_context();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallPopLoadStatePayload(_) => {
+ self.pop_load_state_payload();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePopLoadStatePayload(_) => {
+ self.pop_load_state_payload();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallPushLoadContext(_) => {
+ try_or_throw!(self.machine_st, self.push_load_context());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePushLoadContext(_) => {
+ try_or_throw!(self.machine_st, self.push_load_context());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallPushLoadStatePayload(_) => {
+ self.push_load_state_payload();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePushLoadStatePayload(_) => {
+ self.push_load_state_payload();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallUseModule(_) => {
+ try_or_throw!(self.machine_st, self.use_module());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteUseModule(_) => {
+ try_or_throw!(self.machine_st, self.use_module());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallBuiltInProperty(_) => {
+ self.builtin_property();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteBuiltInProperty(_) => {
+ self.builtin_property();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallMetaPredicateProperty(_) => {
+ self.meta_predicate_property();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteMetaPredicateProperty(_) => {
+ self.meta_predicate_property();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallMultifileProperty(_) => {
+ self.multifile_property();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteMultifileProperty(_) => {
+ self.multifile_property();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDiscontiguousProperty(_) => {
+ self.discontiguous_property();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDiscontiguousProperty(_) => {
+ self.discontiguous_property();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDynamicProperty(_) => {
+ self.dynamic_property();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDynamicProperty(_) => {
+ self.dynamic_property();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallAbolishClause(_) => {
+ try_or_throw!(self.machine_st, self.abolish_clause());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAbolishClause(_) => {
+ try_or_throw!(self.machine_st, self.abolish_clause());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAsserta(_) => {
+ try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Prepend));
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAsserta(_) => {
+ try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Prepend));
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAssertz(_) => {
+ try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Append));
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAssertz(_) => {
+ try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Append));
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallRetract(_) => {
+ try_or_throw!(self.machine_st, self.retract_clause());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteRetract(_) => {
+ try_or_throw!(self.machine_st, self.retract_clause());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallIsConsistentWithTermQueue(_) => {
+ try_or_throw!(self.machine_st, self.is_consistent_with_term_queue());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteIsConsistentWithTermQueue(_) => {
+ try_or_throw!(self.machine_st, self.is_consistent_with_term_queue());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::CallFlushTermQueue(_) => {
+ try_or_throw!(self.machine_st, self.flush_term_queue());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteFlushTermQueue(_) => {
+ try_or_throw!(self.machine_st, self.flush_term_queue());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallRemoveModuleExports(_) => {
+ try_or_throw!(self.machine_st, self.remove_module_exports());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteRemoveModuleExports(_) => {
+ try_or_throw!(self.machine_st, self.remove_module_exports());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallAddNonCountedBacktracking(_) => {
+ try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteAddNonCountedBacktracking(_) => {
+ try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ }
+
+ let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
+
+ match INTERRUPT.compare_exchange(
+ interrupted,
+ false,
+ std::sync::atomic::Ordering::Relaxed,
+ std::sync::atomic::Ordering::Relaxed,
+ ) {
+ Ok(interruption) => {
+ if interruption {
+ self.machine_st.throw_interrupt_exception();
+ self.machine_st.backtrack();
+ }
+ }
+ Err(_) => unreachable!(),
+ }
+ }
+ }
+}
diff --git a/src/machine/gc.rs b/src/machine/gc.rs
new file mode 100644
index 00000000..1f9c80dc
--- /dev/null
+++ b/src/machine/gc.rs
@@ -0,0 +1,1100 @@
+use crate::atom_table::*;
+use crate::machine::heap::*;
+use crate::types::*;
+
+use core::marker::PhantomData;
+
+pub(crate) trait UnmarkPolicy {
+ fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool;
+ fn mark(heap: &mut [HeapCellValue], current: usize);
+ fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
+ where
+ Self: Sized;
+}
+
+pub(crate) struct IteratorUMP;
+
+impl UnmarkPolicy for IteratorUMP {
+ #[inline(always)]
+ fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool {
+ heap[current].set_mark_bit(false);
+ false
+ }
+
+ #[inline(always)]
+ fn mark(_heap: &mut [HeapCellValue], _current: usize) {}
+
+ #[inline(always)]
+ fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
+ iter.forward_var()
+ }
+}
+
+struct MarkerUMP {}
+
+impl UnmarkPolicy for MarkerUMP {
+ #[inline(always)]
+ fn unmark(_heap: &mut [HeapCellValue], _current: usize) -> bool { true }
+
+ #[inline(always)]
+ fn mark(heap: &mut [HeapCellValue], current: usize) {
+ heap[current].set_mark_bit(true);
+ }
+
+ #[inline(always)]
+ fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
+ if iter.heap[iter.current + 1].get_mark_bit() {
+ return iter.forward_var();
+ }
+
+ let temp = iter.heap[iter.current].get_value();
+
+ iter.heap[iter.current].set_value(iter.next);
+ iter.current += 1;
+
+ iter.next = iter.heap[iter.current].get_value();
+
+ iter.heap[iter.current].set_value(temp);
+ iter.heap[iter.current].set_mark_bit(true);
+
+ None
+ }
+}
+
+#[derive(Debug)]
+pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
+ pub(crate) heap: &'a mut Vec<HeapCellValue>,
+ orig_heap_len: usize,
+ start: usize,
+ current: usize,
+ next: usize,
+ _marker: PhantomData<UMP>,
+}
+
+impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
+ fn drop(&mut self) {
+ if self.current == self.start {
+ self.heap.truncate(self.orig_heap_len);
+ return;
+ }
+
+ while !self.backward() {}
+
+ self.heap.truncate(self.orig_heap_len);
+ }
+}
+
+impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
+ pub(crate) fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
+ let orig_heap_len = heap.len();
+ let start = orig_heap_len + 1;
+
+ heap.push(cell);
+ heap.push(heap_loc_as_cell!(orig_heap_len));
+
+ heap[start].set_mark_bit(true);
+ let next = heap[start].get_value();
+
+ Self {
+ heap,
+ orig_heap_len,
+ start,
+ current: start,
+ next,
+ _marker: PhantomData,
+ }
+ }
+
+ fn backward_and_return(&mut self) -> Option<HeapCellValue> {
+ let current = self.current;
+
+ if self.backward() {
+ self.heap[self.current].set_forwarding_bit(true);
+ self.heap[self.current].set_mark_bit(true);
+ }
+
+ Some(self.heap[current])
+ }
+
+ fn forward_var(&mut self) -> Option<HeapCellValue> {
+ if self.heap[self.next].get_mark_bit() {
+ return self.backward_and_return();
+ }
+
+ self.heap[self.current].set_forwarding_bit(true);
+
+ if self.heap[self.next].get_forwarding_bit() == Some(true) {
+ return self.backward_and_return();
+ }
+
+ let temp = self.heap[self.next].get_value();
+
+ self.heap[self.next].set_value(self.current);
+ self.current = self.next;
+ self.next = temp;
+
+ None
+ }
+
+ fn forward(&mut self) -> Option<HeapCellValue> {
+ loop {
+ if self.heap[self.current].get_forwarding_bit() != Some(true) {
+ match self.heap[self.current].get_tag() {
+ HeapCellValueTag::AttrVar => {
+ if let Some(cell) = UMP::forward_attr_var(self) { return Some(cell); }
+ }
+ HeapCellValueTag::Var => {
+ if let Some(cell) = self.forward_var() { return Some(cell); }
+ }
+ HeapCellValueTag::Str => {
+ if self.heap[self.next + 1].get_mark_bit() {
+ return self.backward_and_return();
+ }
+
+ let h = self.next;
+ let cell = self.heap[h];
+
+ self.heap[h].set_forwarding_bit(true);
+ self.heap[self.current].set_forwarding_bit(true);
+
+ let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
+
+ for cell in &mut self.heap[h + 1 .. h + arity + 1] {
+ cell.set_mark_bit(true);
+ }
+
+ let last_cell_loc = h + arity;
+
+ self.next = self.heap[last_cell_loc].get_value();
+ self.heap[last_cell_loc].set_value(self.current);
+ self.current = last_cell_loc;
+
+ return Some(cell);
+ }
+ HeapCellValueTag::Lis => {
+ if self.heap[self.next + 1].get_mark_bit() {
+ return self.backward_and_return();
+ }
+
+ self.heap[self.current].set_forwarding_bit(true);
+ self.heap[self.next+1].set_mark_bit(true);
+
+ let last_cell_loc = self.next + 1;
+
+ self.next = self.heap[last_cell_loc].get_value();
+ self.heap[last_cell_loc].set_value(self.current);
+ self.current = last_cell_loc;
+
+ return Some(list_loc_as_cell!(last_cell_loc - 1));
+ }
+ HeapCellValueTag::PStrLoc => {
+ let h = self.next;
+ let cell = self.heap[h];
+
+ self.heap[self.current].set_forwarding_bit(true);
+
+ if self.heap[h+1].get_mark_bit() {
+ return self.backward_and_return();
+ }
+
+ if self.heap[h].get_tag() == HeapCellValueTag::PStr {
+ self.heap[h+1].set_mark_bit(true);
+
+ self.next = self.heap[h+1].get_value();
+ self.heap[h+1].set_value(self.current);
+ self.heap[h].set_forwarding_bit(true);
+
+ self.current = h+1;
+ } else {
+ debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset);
+
+ self.next = self.heap[h].get_value();
+ self.heap[h].set_value(self.current);
+ self.current = h;
+
+ if self.heap[h].get_forwarding_bit() == Some(true) {
+ continue;
+ }
+ }
+
+ return Some(cell);
+ }
+ HeapCellValueTag::PStrOffset => {
+ let h = self.next;
+
+ UMP::mark(self.heap, self.current+1);
+
+ if self.heap[h].get_tag() == HeapCellValueTag::PStr {
+ if self.heap[h+1].get_mark_bit() {
+ return self.backward_and_return();
+ }
+
+ self.heap[h+1].set_mark_bit(true);
+ self.heap[self.current].set_forwarding_bit(true);
+
+ self.next = self.heap[h+1].get_value();
+ self.heap[h+1].set_value(self.current);
+ self.current = h+1;
+ } else {
+ debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr);
+
+ self.next = self.heap[h].get_value();
+ self.heap[h].set_value(self.current);
+ self.current = h;
+ }
+ }
+ HeapCellValueTag::StackVar => {
+ let cell = self.heap[self.current];
+ self.heap[self.current].set_forwarding_bit(true);
+ return Some(cell);
+ }
+ _ => {
+ if self.heap[self.current].get_mark_bit() {
+ let current = self.current;
+
+ if self.backward() {
+ return None;
+ }
+
+ return Some(self.heap[current]);
+ }
+
+ return self.backward_and_return();
+ }
+ }
+ } else {
+ if self.backward() {
+ return None;
+ }
+ }
+ }
+ }
+
+ fn backward(&mut self) -> bool {
+ while !self.heap[self.current].get_mark_bit() {
+ let temp = self.heap[self.current].get_value();
+
+ UMP::mark(self.heap, self.current);
+
+ self.heap[self.current].set_forwarding_bit(false);
+ self.heap[self.current].set_value(self.next);
+
+ self.next = self.current;
+ self.current = temp;
+ }
+
+ self.heap[self.current].set_forwarding_bit(false);
+
+ let unmark_is_no_op = UMP::unmark(self.heap, self.current);
+
+ if self.current == self.start {
+ return true;
+ }
+
+ if unmark_is_no_op { // if true, the marker is running.
+ let cell = self.heap[self.current];
+
+ // a cyclic root must be handled specially when marking.
+ if self.next >= self.orig_heap_len && cell.is_ref() {
+ debug_assert!(cell.get_tag() != HeapCellValueTag::PStrOffset);
+
+ self.heap[self.current].set_mark_bit(false);
+ let prev_current = self.heap[self.current].get_value();
+
+ if !self.heap[prev_current].is_forwarded() {
+ return self.backward();
+ }
+ }
+ }
+
+ self.current -= 1;
+
+ let temp = self.heap[self.current+1].get_value();
+
+ self.heap[self.current+1].set_value(self.next);
+ self.next = self.heap[self.current].get_value();
+ self.heap[self.current].set_value(temp);
+
+ false
+ }
+}
+
+impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> {
+ type Item = HeapCellValue;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.forward()
+ }
+}
+
+pub fn mark_cells(heap: &mut Heap, cell: HeapCellValue) {
+ let mut iter = StacklessPreOrderHeapIter::<MarkerUMP>::new(heap, cell);
+ while let Some(_) = iter.forward() {}
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::machine::mock_wam::*;
+
+ #[test]
+ fn heap_marking_tests() {
+ let mut wam = MockWAM::new();
+
+ let f_atom = atom!("f");
+ let a_atom = atom!("a");
+ let b_atom = atom!("b");
+
+ wam.machine_st
+ .heap
+ .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+
+ mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom));
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(0))
+ ]
+ ));
+
+ mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(0));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ // make the structure doubly cyclic.
+ wam.machine_st.heap[2] = str_loc_as_cell!(0);
+
+ mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
+
+ wam.machine_st.heap.extend(functor!(
+ f_atom,
+ [
+ atom(a_atom),
+ atom(b_atom),
+ atom(a_atom),
+ cell(str_loc_as_cell!(1))
+ ]
+ ));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(f_atom, 4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), str_loc_as_cell!(1));
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(0));
+
+ wam.machine_st.heap.clear();
+
+ // term is: [a, b]
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(a_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(atom_as_cell!(b_atom));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!());
+
+ wam.machine_st.heap.pop();
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ // now make the list cyclic.
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), heap_loc_as_cell!(0));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ // make the list doubly cyclic.
+ wam.machine_st.heap[3] = heap_loc_as_cell!(0);
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ // term is: [a, <stream ptr>]
+ let stream = Stream::from_static_string("test", &mut wam.machine_st.arena);
+ let stream_cell =
+ HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons));
+
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(a_atom));
+ wam.machine_st.heap.push(list_loc_as_cell!(3));
+ wam.machine_st.heap.push(stream_cell);
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), stream_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!());
+
+ wam.machine_st.heap.clear();
+
+ // now a cycle of variables.
+
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(3));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(0));
+
+ wam.machine_st.heap.clear();
+
+ // first a 'dangling' partial string, later modified to be a
+ // two-part complete string, then a three-part cyclic string
+ // involving an uncompacted list of chars.
+
+ let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
+
+ wam.machine_st.heap.pop();
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+
+ let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl);
+ let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(4));
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(4));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(3));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(2));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(1));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ wam.machine_st.heap.truncate(4);
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff")));
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+
+ wam.machine_st.heap[3] = pstr_loc_as_cell!(5);
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(5));
+
+ assert!(wam.machine_st.heap[0].get_mark_bit());
+ assert!(wam.machine_st.heap[1].get_mark_bit());
+ assert!(wam.machine_st.heap[2].get_mark_bit());
+ assert!(wam.machine_st.heap[3].get_mark_bit());
+ assert!(!wam.machine_st.heap[4].get_mark_bit());
+ assert!(wam.machine_st.heap[5].get_mark_bit());
+ assert!(wam.machine_st.heap[6].get_mark_bit());
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(5));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff")));
+ wam.machine_st.heap.push(pstr_cell);
+ wam.machine_st.heap.push(pstr_loc_as_cell!(4));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff")));
+ wam.machine_st.heap.push(pstr_second_cell);
+ wam.machine_st.heap.push(pstr_loc_as_cell!(7));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff")));
+ wam.machine_st.heap.push(pstr_offset_as_cell!(1));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(7));
+
+ assert!(!wam.machine_st.heap[0].get_mark_bit());
+ assert!(wam.machine_st.heap[1].get_mark_bit());
+ assert!(wam.machine_st.heap[2].get_mark_bit());
+ assert!(!wam.machine_st.heap[3].get_mark_bit());
+ assert!(wam.machine_st.heap[4].get_mark_bit());
+ assert!(wam.machine_st.heap[5].get_mark_bit());
+ assert!(!wam.machine_st.heap[6].get_mark_bit());
+ assert!(wam.machine_st.heap[7].get_mark_bit());
+ assert!(wam.machine_st.heap[8].get_mark_bit());
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(5));
+
+ assert!(!wam.machine_st.heap[0].get_mark_bit());
+ assert!(wam.machine_st.heap[1].get_mark_bit());
+ assert!(wam.machine_st.heap[2].get_mark_bit());
+ assert!(!wam.machine_st.heap[3].get_mark_bit());
+ assert!(wam.machine_st.heap[4].get_mark_bit());
+ assert!(wam.machine_st.heap[5].get_mark_bit());
+ assert!(!wam.machine_st.heap[6].get_mark_bit());
+ assert!(wam.machine_st.heap[7].get_mark_bit());
+ assert!(wam.machine_st.heap[8].get_mark_bit());
+
+ for cell in &wam.machine_st.heap {
+ assert!(cell.get_forwarding_bit() != Some(true));
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(4));
+
+ assert!(!wam.machine_st.heap[0].get_mark_bit());
+ assert!(wam.machine_st.heap[1].get_mark_bit());
+ assert!(wam.machine_st.heap[2].get_mark_bit());
+ assert!(!wam.machine_st.heap[3].get_mark_bit());
+ assert!(wam.machine_st.heap[4].get_mark_bit());
+ assert!(wam.machine_st.heap[5].get_mark_bit());
+ assert!(!wam.machine_st.heap[6].get_mark_bit());
+ assert!(wam.machine_st.heap[7].get_mark_bit());
+ assert!(wam.machine_st.heap[8].get_mark_bit());
+
+ for cell in &wam.machine_st.heap {
+ assert!(cell.get_forwarding_bit() != Some(true));
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(2));
+
+ assert!(!wam.machine_st.heap[0].get_mark_bit());
+ assert!(wam.machine_st.heap[1].get_mark_bit());
+ assert!(wam.machine_st.heap[2].get_mark_bit());
+ assert!(!wam.machine_st.heap[3].get_mark_bit());
+ assert!(wam.machine_st.heap[4].get_mark_bit());
+ assert!(wam.machine_st.heap[5].get_mark_bit());
+ assert!(!wam.machine_st.heap[6].get_mark_bit());
+ assert!(wam.machine_st.heap[7].get_mark_bit());
+ assert!(wam.machine_st.heap[8].get_mark_bit());
+
+ for cell in &wam.machine_st.heap {
+ assert!(cell.get_forwarding_bit() != Some(true));
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(1));
+
+ assert!(!wam.machine_st.heap[0].get_mark_bit());
+ assert!(wam.machine_st.heap[1].get_mark_bit());
+ assert!(wam.machine_st.heap[2].get_mark_bit());
+ assert!(!wam.machine_st.heap[3].get_mark_bit());
+ assert!(wam.machine_st.heap[4].get_mark_bit());
+ assert!(wam.machine_st.heap[5].get_mark_bit());
+ assert!(!wam.machine_st.heap[6].get_mark_bit());
+ assert!(wam.machine_st.heap[7].get_mark_bit());
+ assert!(wam.machine_st.heap[8].get_mark_bit());
+
+ for cell in &wam.machine_st.heap {
+ assert!(cell.get_forwarding_bit() != Some(true));
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2)));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ wam.machine_st.heap.clear();
+
+ // embedded cyclic partial string.
+
+ wam.machine_st.heap.push(pstr_cell);
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
+ wam.machine_st.heap.push(list_loc_as_cell!(5));
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(4));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(3)));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), list_loc_as_cell!(5));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), empty_list_as_cell!());
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(pstr_cell);
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
+ wam.machine_st.heap.push(list_loc_as_cell!(5));
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+ wam.machine_st.heap.push(heap_loc_as_cell!(4));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(4));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_offset_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(3)));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), list_loc_as_cell!(5));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(4));
+
+ wam.machine_st.heap.clear();
+
+ // a chain of variables, ending in a self-referential variable.
+
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(3));
+ wam.machine_st.heap.push(heap_loc_as_cell!(3));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3));
+
+ wam.machine_st.heap.clear();
+
+ // print L = [L|L].
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(1));
+
+ wam.machine_st.heap.clear();
+
+ // term is [X,f(Y),Z].
+ // Z is an attributed variable, but has a variable attributes list.
+ wam.machine_st.heap.push(list_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2
+ wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3
+ wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4
+ wam.machine_st.heap.push(heap_loc_as_cell!(8));
+ wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6
+ wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7
+ wam.machine_st.heap.push(list_loc_as_cell!(9));
+ wam.machine_st.heap.push(heap_loc_as_cell!(9));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
+ wam.machine_st.heap.push(heap_loc_as_cell!(12));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!());
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(12));
+
+ // now populate the attributes list.
+ let clpz_atom = atom!("clpz");
+ let p_atom = atom!("p");
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ cell.set_forwarding_bit(false);
+ }
+
+ wam.machine_st.heap.pop();
+
+ wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12
+ wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13
+ wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14
+ wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15
+ wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16
+ wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17
+ wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18
+ wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19
+ wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20
+ wam.machine_st.heap.push(empty_list_as_cell!()); // 21
+ wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22
+ wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!());
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!());
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23));
+
+ for cell in &mut wam.machine_st.heap {
+ cell.set_mark_bit(false);
+ cell.set_forwarding_bit(false);
+ }
+
+ // push some unrelated nonsense cells to the heap and check that they
+ // are unmarked after the marker has finished at 0.
+ wam.machine_st.heap.push(heap_loc_as_cell!(5));
+ wam.machine_st.heap.push(heap_loc_as_cell!(5));
+ wam.machine_st.heap.push(list_loc_as_cell!(5));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&mut wam.machine_st.heap[0..24]);
+
+ for cell in &wam.machine_st.heap[24..] {
+ assert_eq!(cell.get_mark_bit(), false);
+ }
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!());
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!());
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[24]), heap_loc_as_cell!(5));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[25]), heap_loc_as_cell!(5));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[26]), list_loc_as_cell!(5));
+
+ wam.machine_st.heap.clear();
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0)));
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
+
+ assert_eq!(wam.machine_st.heap.len(), 1);
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
+ wam.machine_st.heap.push(atom_as_cell!(atom!("X")));
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+ wam.machine_st.heap.push(list_loc_as_cell!(8));
+ wam.machine_st.heap.push(str_loc_as_cell!(4));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(7));
+
+ assert_eq!(wam.machine_st.heap.len(), 10);
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(atom!("g"), 2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("y")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("="), 2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), atom_as_cell!(atom!("X")));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), list_loc_as_cell!(8));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), str_loc_as_cell!(4));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), empty_list_as_cell!());
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+ wam.machine_st.heap.push(heap_loc_as_cell!(1));
+
+ mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0));
+
+ all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("f"), 2));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
+ assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(1));
+ }
+}
diff --git a/src/machine/heap.rs b/src/machine/heap.rs
index 067bfa93..a7317cc3 100644
--- a/src/machine/heap.rs
+++ b/src/machine/heap.rs
@@ -1,462 +1,282 @@
-use core::marker::PhantomData;
-
-use prolog_parser::ast::Constant;
-
-use crate::machine::machine_indices::*;
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::forms::*;
use crate::machine::partial_string::*;
-use crate::machine::raw_block::*;
+use crate::parser::ast::*;
+use crate::types::*;
-use std::convert::TryFrom;
-use std::mem;
-use std::ops::{Index, IndexMut};
-use std::ptr;
+use ordered_float::OrderedFloat;
+use rug::{Integer, Rational};
-#[derive(Debug)]
-pub(crate) struct StandardHeapTraits {}
+use std::convert::TryFrom;
-impl RawBlockTraits for StandardHeapTraits {
- #[inline]
- fn init_size() -> usize {
- 256 * mem::size_of::<HeapCellValue>()
- }
+pub(crate) type Heap = Vec<HeapCellValue>;
+impl From<Literal> for HeapCellValue {
#[inline]
- fn align() -> usize {
- mem::align_of::<HeapCellValue>()
- }
-}
-
-#[derive(Debug)]
-pub(crate) struct HeapTemplate<T: RawBlockTraits> {
- buf: RawBlock<T>,
- _marker: PhantomData<HeapCellValue>,
-}
-
-pub(crate) type Heap = HeapTemplate<StandardHeapTraits>;
-
-impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
- fn drop(&mut self) {
- self.clear();
- self.buf.deallocate();
+ fn from(literal: Literal) -> Self {
+ match literal {
+ Literal::Atom(name) => atom_as_cell!(name),
+ Literal::Char(c) => char_as_cell!(c),
+ Literal::Fixnum(n) => fixnum_as_cell!(n),
+ Literal::Integer(bigint_ptr) => {
+ typed_arena_ptr_as_cell!(bigint_ptr)
+ }
+ Literal::Rational(bigint_ptr) => {
+ typed_arena_ptr_as_cell!(bigint_ptr)
+ }
+ Literal::Float(f) => HeapCellValue::from(f),
+ Literal::String(s) => {
+ if s == atom!("") {
+ empty_list_as_cell!()
+ } else {
+ string_as_cstr_cell!(s)
+ }
+ }
+ }
}
}
-#[derive(Debug)]
-pub(crate) struct HeapIntoIter<T: RawBlockTraits> {
- offset: usize,
- buf: RawBlock<T>,
-}
+impl TryFrom<HeapCellValue> for Literal {
+ type Error = ();
-impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
- fn drop(&mut self) {
- let mut heap = HeapTemplate {
- buf: self.buf.take(),
- _marker: PhantomData,
- };
-
- heap.truncate(self.offset / mem::size_of::<HeapCellValue>());
- heap.buf.deallocate();
+ fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
+ read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ Ok(Literal::Atom(name))
+ } else {
+ Err(())
+ }
+ }
+ (HeapCellValueTag::Char, c) => {
+ Ok(Literal::Char(c))
+ }
+ (HeapCellValueTag::Fixnum, n) => {
+ Ok(Literal::Fixnum(n))
+ }
+ (HeapCellValueTag::F64, f) => {
+ Ok(Literal::Float(f))
+ }
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Integer, n) => {
+ Ok(Literal::Integer(n))
+ }
+ (ArenaHeaderTag::Rational, n) => {
+ Ok(Literal::Rational(n))
+ }
+ (ArenaHeaderTag::F64, f) => {
+ // remove this redundancy.
+ Ok(Literal::Float(F64Ptr(f)))
+ }
+ _ => {
+ Err(())
+ }
+ )
+ }
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ Ok(Literal::String(cstr_atom))
+ }
+ _ => {
+ Err(())
+ }
+ )
}
}
-impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
- type Item = HeapCellValue;
-
- fn next(&mut self) -> Option<Self::Item> {
- let ptr = self.buf.base as usize + self.offset;
- self.offset += mem::size_of::<HeapCellValue>();
+// sometimes we need to dereference variables that are found only in
+// the heap without access to the full WAM (e.g., while detecting
+// cycles in terms), and which therefore may only point other cells in
+// the heap (thanks to the design of the WAM).
+pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
+ loop {
+ let new_value = read_heap_cell!(value,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ heap[h]
+ }
+ _ => {
+ value
+ }
+ );
- if ptr < self.buf.top as usize {
- unsafe { Some(ptr::read(ptr as *const HeapCellValue)) }
- } else {
- None
+ if new_value != value && new_value.is_var() {
+ value = new_value;
+ continue;
}
- }
-}
-
-#[derive(Debug)]
-pub(crate) struct HeapIter<'a, T: RawBlockTraits> {
- offset: usize,
- buf: &'a RawBlock<T>,
-}
-impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
- pub(crate) fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
- HeapIter { buf, offset }
+ return value;
}
}
-impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
- type Item = &'a HeapCellValue;
-
- fn next(&mut self) -> Option<Self::Item> {
- let ptr = self.buf.base as usize + self.offset;
- self.offset += mem::size_of::<HeapCellValue>();
-
- if ptr < self.buf.top as usize {
- unsafe { Some(&*(ptr as *const _)) }
- } else {
- None
+pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
+ read_heap_cell!(value,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ heap[h]
}
- }
+ _ => {
+ value
+ }
+ )
}
#[allow(dead_code)]
-pub(crate) fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
+pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
for (index, term) in heap.enumerate() {
- println!("{} : {}", h + index, term);
+ println!("{} : {:?}", h + index, term);
}
}
-#[derive(Debug)]
-pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> {
- offset: usize,
- buf: &'a mut RawBlock<T>,
-}
-
-impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
- pub(crate) fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
- HeapIterMut { buf, offset }
- }
-}
-
-impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
- type Item = &'a mut HeapCellValue;
-
- fn next(&mut self) -> Option<Self::Item> {
- let ptr = self.buf.base as usize + self.offset;
- self.offset += mem::size_of::<HeapCellValue>();
-
- if ptr < self.buf.top as usize {
- unsafe { Some(&mut *(ptr as *mut _)) }
- } else {
- None
- }
- }
-}
-
-impl<T: RawBlockTraits> HeapTemplate<T> {
- #[inline]
- pub(crate) fn new() -> Self {
- HeapTemplate {
- buf: RawBlock::new(),
- _marker: PhantomData,
- }
- }
-
- #[inline]
- pub(crate) 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::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)),
- &HeapCellValue::NamedStr(arity, ref name, ref op) => {
- HeapCellValue::NamedStr(arity, name.clone(), op.clone())
- }
- &HeapCellValue::PartialString(..) => HeapCellValue::Addr(Addr::PStrLocation(h, 0)),
- &HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
- &HeapCellValue::Stream(_) => HeapCellValue::Addr(Addr::Stream(h)),
- &HeapCellValue::TcpListener(_) => HeapCellValue::Addr(Addr::TcpListener(h)),
- }
- }
-
- #[inline]
- pub(crate) fn put_complete_string(&mut self, s: &str) -> Addr {
- if s.is_empty() {
- return Addr::EmptyList;
- }
-
- 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!()
+#[inline]
+pub(crate) fn put_complete_string(
+ heap: &mut Heap,
+ s: &str,
+ atom_tbl: &mut AtomTable,
+) -> HeapCellValue {
+ match allocate_pstr(heap, s, atom_tbl) {
+ Some(h) => {
+ heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
+
+ if heap.len() == h + 1 {
+ let pstr_atom = cell_as_atom!(heap[h]);
+ heap[h] = atom_as_cstr_cell!(pstr_atom);
+ heap_loc_as_cell!(h)
+ } else {
+ heap.push(empty_list_as_cell!());
+ pstr_loc_as_cell!(h)
}
}
-
- 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::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),
+ None => {
+ let h = heap.len();
+ heap.push(empty_list_as_cell!());
+ heap_loc_as_cell!(h)
}
}
+}
- #[inline]
- pub(crate) fn is_empty(&self) -> bool {
- self.h() == 0
- }
-
- #[inline]
- pub(crate) fn pop(&mut self) {
- let h = self.h();
-
- if h > 0 {
- self.truncate(h - 1);
+#[inline]
+pub(crate) fn put_partial_string(
+ heap: &mut Heap,
+ s: &str,
+ atom_tbl: &mut AtomTable,
+) -> HeapCellValue {
+ match allocate_pstr(heap, s, atom_tbl) {
+ Some(h) => {
+ pstr_loc_as_cell!(h)
}
- }
-
- #[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;
+ None => {
+ empty_list_as_cell!()
}
-
- 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::LoadStatePayload(_) => Addr::LoadStatePayload(self.push(val)),
- val @ HeapCellValue::NamedStr(..) => Addr::Str(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));
- }
+#[inline]
+pub(crate) fn allocate_pstr(
+ heap: &mut Heap,
+ mut src: &str,
+ atom_tbl: &mut AtomTable,
+) -> Option<usize> {
+ let orig_h = heap.len();
+
+ loop {
+ if src == "" {
+ return if orig_h == heap.len() {
+ None
+ } else {
+ let tail_h = heap.len() - 1;
+ heap[tail_h] = heap_loc_as_cell!(tail_h);
- Addr::Con(h)
- }
- val @ HeapCellValue::Stream(..) => Addr::Stream(self.push(val)),
- val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)),
+ Some(orig_h)
+ };
}
- }
-
- #[inline]
- pub(crate) fn allocate_pstr(&mut self, src: &str) -> Addr {
- self.write_pstr(src).unwrap_or_else(|| Addr::EmptyList)
- }
- #[inline]
- fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
- let orig_h = self.h();
+ let h = heap.len();
- loop {
- if src == "" {
- return if orig_h == self.h() {
- None
+ let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
+ Some(tuple) => tuple,
+ None => {
+ if src.len() > '\u{0}'.len_utf8() {
+ src = &src['\u{0}'.len_utf8()..];
+ continue;
+ } else if orig_h == h {
+ return None;
} else {
- let tail_h = self.h() - 1;
- self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
-
- Some(Addr::PStrLocation(orig_h, 0))
- };
- }
-
- let h = self.h();
-
- let (pstr, rest_src) = match PartialString::new(src) {
- Some(tuple) => tuple,
- None => {
- if src.len() > '\u{0}'.len_utf8() {
- src = &src['\u{0}'.len_utf8()..];
- continue;
- } else if orig_h == h {
- return None;
- } else {
- self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
- return Some(Addr::PStrLocation(orig_h, 0));
- }
+ heap[h - 1] = heap_loc_as_cell!(h - 1);
+ return Some(orig_h);
}
- };
-
- self.push(HeapCellValue::PartialString(pstr, true));
-
- if rest_src != "" {
- self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
- src = rest_src;
- } else {
- self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
- return Some(Addr::PStrLocation(orig_h, 0));
- }
- }
- }
-
- #[inline]
- pub(crate) fn truncate(&mut self, h: usize) {
- let new_top = h * mem::size_of::<HeapCellValue>() + self.buf.base as usize;
- let mut h = new_top;
-
- unsafe {
- while h as *const _ < self.buf.top {
- let val = h as *mut HeapCellValue;
- ptr::drop_in_place(val);
- h += mem::size_of::<HeapCellValue>();
}
- }
-
- self.buf.top = new_top as *const _;
- }
+ };
- #[inline]
- pub(crate) fn h(&self) -> usize {
- (self.buf.top as usize - self.buf.base as usize) / mem::size_of::<HeapCellValue>()
- }
+ heap.push(string_as_pstr_cell!(pstr));
- pub(crate) fn append(&mut self, vals: Vec<HeapCellValue>) {
- for val in vals {
- self.push(val);
+ if rest_src != "" {
+ heap.push(pstr_loc_as_cell!(h + 2));
+ src = rest_src;
+ } else {
+ heap.push(heap_loc_as_cell!(h + 1));
+ return Some(orig_h);
}
}
+}
- pub(crate) fn clear(&mut self) {
- if !self.buf.base.is_null() {
- self.truncate(0);
- self.buf.top = self.buf.base;
- }
- }
+pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
+ heap: &mut Heap,
+ values: impl Iterator<Item = SrcT>,
+ filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
+) -> usize {
+ let head_addr = heap.len();
+ let mut h = head_addr;
- pub(crate) 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 value = value.into();
- for value in values.map(|v| v.into()) {
- self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
- self.push(value);
+ if filter_fn(heap, value) {
+ heap.push(list_loc_as_cell!(h + 1));
+ heap.push(value);
h += 2;
}
-
- 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) -> HeapIter<'a, T> {
- HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
- }
-
- pub(crate) 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) -> HeapIntoIter<T> {
- HeapIntoIter {
- buf: self.buf.take(),
- offset: 0,
- }
- }
+ heap.push(empty_list_as_cell!());
- pub(crate) fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
- for hcv in iter {
- self.push(hcv);
- }
- }
-
- pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
- let extract_integer = |s: usize| -> Option<usize> {
- match &self[s] {
- &HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
- &HeapCellValue::Integer(ref n) => n.to_usize(),
- _ => None,
- }
- };
+ head_addr
+}
- match addr {
- Addr::Str(s) => {
- match &self[*s] {
- HeapCellValue::NamedStr(arity, ref name, _) => {
- match (name.as_str(), *arity) {
- ("dir_entry", 1) => extract_integer(s + 1).map(LocalCodePtr::DirEntry),
- /*
- ("top_level", 2) => {
- if let Some(chunk_num) = extract_integer(s+1) {
- if let Some(p) = extract_integer(s+2) {
- return Some(LocalCodePtr::TopLevel(chunk_num, p));
- }
- }
+#[inline(always)]
+pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
+where
+ Iter: Iterator<Item = SrcT>,
+ SrcT: Into<HeapCellValue>,
+{
+ filtered_iter_to_heap_list(heap, values, |_, _| true)
+}
- None
- }
- */
- _ => None,
- }
- }
- _ => unreachable!(),
- }
- }
+pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
+ let extract_integer = |s: usize| -> Option<usize> {
+ match Number::try_from(heap[s]) {
+ Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+ Ok(Number::Integer(n)) => n.to_usize(),
_ => None,
}
- }
+ };
- #[inline]
- pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
- match addr {
- &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => {
- RefOrOwned::Borrowed(&self[h])
- }
- addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)),
- }
- }
-}
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
-impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
- type Output = HeapCellValue;
-
- #[inline]
- fn index(&self, index: usize) -> &Self::Output {
- unsafe {
- let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
- &*(ptr as *const HeapCellValue)
+ if name == atom!("dir_entry") && arity == 1 {
+ extract_integer(s+1)
+ } else {
+ panic!(
+ "to_local_code_ptr crashed with p.i. {}/{}",
+ name.as_str(),
+ arity,
+ );
+ }
}
- }
-}
-
-impl<T: RawBlockTraits> IndexMut<usize> for HeapTemplate<T> {
- #[inline]
- fn index_mut(&mut self, index: usize) -> &mut Self::Output {
- unsafe {
- let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
- &mut *(ptr as *mut HeapCellValue)
+ _ => {
+ None
}
- }
+ )
}
diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs
index d0a0d126..1ad94f15 100644
--- a/src/machine/load_state.rs
+++ b/src/machine/load_state.rs
@@ -1,26 +1,21 @@
+use crate::forms::*;
+use crate::machine::loader::*;
+use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::preprocessor::*;
use crate::machine::term_stream::*;
use crate::machine::*;
+use crate::parser::ast::*;
-use prolog_parser::clause_name;
-
+use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use ref_thread_local::RefThreadLocal;
use slice_deque::{sdeq, SliceDeque};
-type ModuleOpExports = Vec<(OpDecl, Option<(usize, Specifier)>)>;
-
-/*
- * We will want to borrow these fields from Loader separately, without
- * restricting access to other fields by borrowing them mutably.
- */
-pub(super) struct LoadState<'a> {
- pub(super) compilation_target: CompilationTarget,
- pub(super) module_op_exports: ModuleOpExports,
- pub(super) retraction_info: RetractionInfo,
- pub(super) wam: &'a mut Machine,
-}
+use std::fs::File;
+use std::mem;
+
+pub(super) type ModuleOpExports = Vec<(OpDecl, Option<OpDesc>)>;
pub(super) fn set_code_index(
retraction_info: &mut RetractionInfo,
@@ -42,10 +37,10 @@ pub(super) fn set_code_index(
CompilationTarget::Module(ref module_name) => {
if IndexPtr::Undefined == code_index.get() {
code_index.set(code_ptr);
- RetractionRecord::AddedModulePredicate(module_name.clone(), key)
+ RetractionRecord::AddedModulePredicate(*module_name, key)
} else {
let replaced = code_index.replace(code_ptr);
- RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, replaced)
+ RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced)
}
}
};
@@ -69,18 +64,17 @@ fn add_op_decl_as_module_export(
*/
match op_decl.insert_into_op_dir(wam_op_dir) {
- Some((prec, spec)) => {
+ Some(op_desc) => {
retraction_info.push_record(RetractionRecord::ReplacedUserOp(
- op_decl.clone(),
- prec,
- spec,
+ *op_decl,
+ op_desc,
));
- module_op_exports.push((op_decl.clone(), Some((prec, spec))));
+ module_op_exports.push((*op_decl, Some(op_desc)));
}
None => {
- retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone()));
- module_op_exports.push((op_decl.clone(), None));
+ retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
+ module_op_exports.push((*op_decl, None));
}
}
@@ -94,31 +88,29 @@ pub(super) fn add_op_decl(
op_decl: &OpDecl,
) {
match op_decl.insert_into_op_dir(op_dir) {
- Some((prec, spec)) => match &compilation_target {
+ Some(op_desc) => match &compilation_target {
CompilationTarget::User => {
retraction_info.push_record(RetractionRecord::ReplacedUserOp(
- op_decl.clone(),
- prec,
- spec,
+ *op_decl,
+ op_desc,
));
}
CompilationTarget::Module(ref module_name) => {
retraction_info.push_record(RetractionRecord::ReplacedModuleOp(
- module_name.clone(),
- op_decl.clone(),
- prec,
- spec,
+ *module_name,
+ *op_decl,
+ op_desc,
));
}
},
None => match &compilation_target {
CompilationTarget::User => {
- retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone()));
+ retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
}
CompilationTarget::Module(ref module_name) => {
retraction_info.push_record(RetractionRecord::AddedModuleOp(
- module_name.clone(),
- op_decl.clone(),
+ *module_name,
+ *op_decl,
));
}
},
@@ -135,16 +127,16 @@ pub(super) fn import_module_exports(
) -> Result<(), SessionError> {
for export in imported_module.module_decl.exports.iter() {
match export {
- ModuleExport::PredicateKey((ref name, arity)) => {
- let key = (name.clone(), *arity);
+ ModuleExport::PredicateKey((name, arity)) => {
+ let key = (*name, *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
- meta_predicates.insert(key.clone(), meta_specs.clone());
+ meta_predicates.insert(key, meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir
- .entry(key.clone())
+ .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
@@ -157,8 +149,8 @@ pub(super) fn import_module_exports(
);
} else {
return Err(SessionError::ModuleDoesNotContainExport(
- imported_module.module_decl.name.clone(),
- (name.clone(), *arity),
+ imported_module.module_decl.name,
+ key,
));
}
}
@@ -183,8 +175,8 @@ fn import_module_exports_into_module(
) -> Result<(), SessionError> {
for export in imported_module.module_decl.exports.iter() {
match export {
- ModuleExport::PredicateKey((ref name, arity)) => {
- let key = (name.clone(), *arity);
+ ModuleExport::PredicateKey((name, arity)) => {
+ let key = (*name, *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
meta_predicates.insert(key.clone(), meta_specs.clone());
@@ -192,7 +184,7 @@ fn import_module_exports_into_module(
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir
- .entry(key.clone())
+ .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
@@ -206,7 +198,7 @@ fn import_module_exports_into_module(
} else {
return Err(SessionError::ModuleDoesNotContainExport(
imported_module.module_decl.name.clone(),
- (name.clone(), *arity),
+ (*name, *arity),
));
}
}
@@ -241,8 +233,8 @@ fn import_qualified_module_exports(
}
match export {
- ModuleExport::PredicateKey((ref name, arity)) => {
- let key = (name.clone(), *arity);
+ ModuleExport::PredicateKey((name, arity)) => {
+ let key = (*name, *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
meta_predicates.insert(key.clone(), meta_specs.clone());
@@ -264,7 +256,7 @@ fn import_qualified_module_exports(
} else {
return Err(SessionError::ModuleDoesNotContainExport(
imported_module.module_decl.name.clone(),
- (name.clone(), *arity),
+ (*name, *arity),
));
}
}
@@ -294,16 +286,16 @@ fn import_qualified_module_exports_into_module(
}
match export {
- ModuleExport::PredicateKey((ref name, arity)) => {
- let key = (name.clone(), *arity);
+ ModuleExport::PredicateKey((name, arity)) => {
+ let key = (*name, *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
- meta_predicates.insert(key.clone(), meta_specs.clone());
+ meta_predicates.insert(key, meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir
- .entry(key.clone())
+ .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
@@ -317,7 +309,7 @@ fn import_qualified_module_exports_into_module(
} else {
return Err(SessionError::ModuleDoesNotContainExport(
imported_module.module_decl.name.clone(),
- (name.clone(), *arity),
+ (*name, *arity),
));
}
}
@@ -337,15 +329,15 @@ fn import_qualified_module_exports_into_module(
Ok(())
}
-impl<'a> LoadState<'a> {
- pub(super) fn retract_local_clauses(
+impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
+ pub(super) fn retract_local_clauses_impl(
&mut self,
compilation_target: CompilationTarget,
key: PredicateKey,
clause_locs: &SliceDeque<usize>,
) {
let result_opt = self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton(&compilation_target, &key)
.map(|skeleton| {
@@ -377,15 +369,18 @@ impl<'a> LoadState<'a> {
mut clause_target_poses: Vec<Option<usize>>,
is_dynamic: bool,
) {
- let old_compilation_target = mem::replace(&mut self.compilation_target, compilation_target);
+ let old_compilation_target = mem::replace(
+ &mut self.payload.compilation_target,
+ compilation_target,
+ );
while let Some(target_pos_opt) = clause_target_poses.pop() {
match target_pos_opt {
Some(target_pos) if is_dynamic => {
- self.retract_dynamic_clause(key.clone(), target_pos);
+ self.retract_dynamic_clause(key, target_pos);
}
Some(target_pos) => {
- self.retract_clause(key.clone(), target_pos);
+ self.retract_clause(key, target_pos);
}
None => {
// Here because the clause was been removed
@@ -395,7 +390,7 @@ impl<'a> LoadState<'a> {
}
}
- self.compilation_target = old_compilation_target;
+ self.payload.compilation_target = old_compilation_target;
}
pub(super) fn retract_local_clause_clauses(
@@ -403,20 +398,23 @@ impl<'a> LoadState<'a> {
clause_clause_compilation_target: CompilationTarget,
clause_locs: &SliceDeque<usize>,
) {
- let key = (clause_name!("$clause"), 2);
-
- match self.wam.indices.get_local_predicate_skeleton_mut(
- self.compilation_target.clone(),
- clause_clause_compilation_target.clone(),
- self.listing_src_file_name(),
- key.clone(),
+ let key = (atom!("$clause"), 2);
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
+ self.payload.compilation_target,
+ clause_clause_compilation_target,
+ listing_src_file_name,
+ key,
) {
Some(skeleton) => {
- self.retraction_info.push_record(
+ let payload_compilation_target = self.payload.compilation_target;
+
+ self.payload.retraction_info.push_record(
RetractionRecord::RemovedLocalSkeletonClauseLocations(
- self.compilation_target.clone(),
- clause_clause_compilation_target.clone(),
- key.clone(),
+ payload_compilation_target,
+ clause_clause_compilation_target,
+ key,
mem::replace(&mut skeleton.clause_clause_locs, sdeq![]),
),
);
@@ -430,7 +428,7 @@ impl<'a> LoadState<'a> {
}
};
- self.retract_local_clauses(clause_clause_compilation_target, key, &clause_locs);
+ self.retract_local_clauses_impl(clause_clause_compilation_target, key, &clause_locs);
}
pub(super) fn try_term_to_tl(
@@ -450,19 +448,18 @@ impl<'a> LoadState<'a> {
#[inline]
pub(super) fn remove_module_op_exports(&mut self) {
- for (mut op_decl, record) in self.module_op_exports.drain(0..) {
- op_decl.remove(&mut self.wam.indices.op_dir);
+ for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) {
+ op_decl.remove(&mut self.wam_prelude.indices.op_dir);
- if let Some((prec, spec)) = record {
- op_decl.prec = prec;
- op_decl.spec = spec;
- op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir);
+ if let Some(op_desc) = record {
+ op_decl.op_desc = op_desc;
+ op_decl.insert_into_op_dir(&mut self.wam_prelude.indices.op_dir);
}
}
}
- pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: ClauseName) {
- let removed_module = match self.wam.indices.modules.remove(&module_name) {
+ pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: Atom) {
+ let mut removed_module = match self.wam_prelude.indices.modules.remove(&module_name) {
Some(module) => module,
None => return,
};
@@ -470,29 +467,36 @@ impl<'a> LoadState<'a> {
for (key, code_index) in &removed_module.code_dir {
match removed_module
.local_extensible_predicates
- .get(&(CompilationTarget::User, key.clone()))
+ .get(&(CompilationTarget::User, *key))
{
Some(skeleton) if skeleton.is_multifile => continue,
_ => {}
}
- if code_index.get() != IndexPtr::Undefined {
- let old_index_ptr = code_index.replace(IndexPtr::Undefined);
+ let old_index_ptr = code_index.replace(IndexPtr::Undefined);
- self.retraction_info
- .push_record(RetractionRecord::ReplacedModulePredicate(
- module_name.clone(),
- key.clone(),
- old_index_ptr,
- ));
- }
+ self.payload.retraction_info
+ .push_record(RetractionRecord::ReplacedModulePredicate(
+ module_name,
+ *key,
+ old_index_ptr,
+ ));
}
- self.wam.indices.modules.insert(module_name, removed_module);
+ for (key, skeleton) in removed_module.extensible_predicates.drain(..) {
+ self.payload.retraction_info
+ .push_record(RetractionRecord::RemovedSkeleton(
+ CompilationTarget::Module(module_name),
+ key,
+ skeleton,
+ ));
+ }
+
+ self.wam_prelude.indices.modules.insert(module_name, removed_module);
}
- pub(super) fn remove_module_exports(&mut self, module_name: ClauseName) {
- let removed_module = match self.wam.indices.modules.remove(&module_name) {
+ pub(super) fn remove_module_exports(&mut self, module_name: Atom) {
+ let removed_module = match self.wam_prelude.indices.modules.remove(&module_name) {
Some(module) => module,
None => return,
};
@@ -503,7 +507,7 @@ impl<'a> LoadState<'a> {
op_dir: &mut OpDir,
retraction_info: &mut RetractionInfo,
predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord,
- op_retractor: impl Fn(OpDecl, usize, Specifier) -> RetractionRecord,
+ op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord,
) {
for export in removed_module.module_decl.exports.iter() {
match export {
@@ -513,55 +517,51 @@ impl<'a> LoadState<'a> {
if module_code_index.get() == target_code_index.get() =>
{
let old_index_ptr = target_code_index.replace(IndexPtr::Undefined);
-
- retraction_info
- .push_record(predicate_retractor(key.clone(), old_index_ptr));
+ retraction_info.push_record(predicate_retractor(*key, old_index_ptr));
}
_ => {}
}
}
ModuleExport::OpDecl(op_decl) => {
let op_dir_value_opt =
- op_dir.remove(&(op_decl.name.clone(), op_decl.fixity()));
+ op_dir.remove(&(op_decl.name, fixity(op_decl.op_desc.get_spec() as u32)));
- if let Some(op_dir_value) = op_dir_value_opt {
- let (prec, spec) = op_dir_value.shared_op_desc().get();
-
- retraction_info.push_record(op_retractor(op_decl.clone(), prec, spec));
+ if let Some(op_desc) = op_dir_value_opt {
+ retraction_info.push_record(op_retractor(*op_decl, op_desc));
}
}
}
}
}
- match &self.compilation_target {
+ match self.payload.compilation_target {
CompilationTarget::User => {
remove_module_exports(
&removed_module,
- &mut self.wam.indices.code_dir,
- &mut self.wam.indices.op_dir,
- &mut self.retraction_info,
+ &mut self.wam_prelude.indices.code_dir,
+ &mut self.wam_prelude.indices.op_dir,
+ &mut self.payload.retraction_info,
RetractionRecord::ReplacedUserPredicate,
RetractionRecord::ReplacedUserOp,
);
}
- CompilationTarget::Module(ref target_module_name)
- if target_module_name.as_str() != module_name.as_str() =>
+ CompilationTarget::Module(target_module_name)
+ if target_module_name != module_name =>
{
let predicate_retractor = |key, index_ptr| {
- RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, index_ptr)
+ RetractionRecord::ReplacedModulePredicate(module_name, key, index_ptr)
};
- let op_retractor = |op_decl, prec, spec| {
- RetractionRecord::ReplacedModuleOp(module_name.clone(), op_decl, prec, spec)
+ let op_retractor = |op_decl, op_desc| {
+ RetractionRecord::ReplacedModuleOp(module_name, op_decl, op_desc)
};
- if let Some(module) = self.wam.indices.modules.get_mut(target_module_name) {
+ if let Some(module) = self.wam_prelude.indices.modules.get_mut(&target_module_name) {
remove_module_exports(
&removed_module,
&mut module.code_dir,
&mut module.op_dir,
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
predicate_retractor,
op_retractor,
);
@@ -572,24 +572,24 @@ impl<'a> LoadState<'a> {
CompilationTarget::Module(_) => {}
};
- self.wam.indices.modules.insert(module_name, removed_module);
+ self.wam_prelude.indices.modules.insert(module_name, removed_module);
}
fn get_or_insert_local_code_index(
&mut self,
- module_name: ClauseName,
+ module_name: Atom,
key: PredicateKey,
) -> CodeIndex {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => module
.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone(),
None => {
- self.add_dynamically_generated_module(&module_name);
+ self.add_dynamically_generated_module(module_name);
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => module
.code_dir
.entry(key)
@@ -610,7 +610,7 @@ impl<'a> LoadState<'a> {
) -> CodeIndex {
match compilation_target {
CompilationTarget::User => self
- .wam
+ .wam_prelude
.indices
.code_dir
.entry(key)
@@ -624,12 +624,12 @@ impl<'a> LoadState<'a> {
pub(super) fn get_or_insert_qualified_code_index(
&mut self,
- module_name: ClauseName,
+ module_name: Atom,
key: PredicateKey,
) -> CodeIndex {
- if module_name.as_str() == "user" {
+ if module_name == atom!("user") {
return self
- .wam
+ .wam_prelude
.indices
.code_dir
.entry(key)
@@ -649,18 +649,18 @@ impl<'a> LoadState<'a> {
) {
match compilation_target {
CompilationTarget::User => {
- self.wam
+ self.wam_prelude
.indices
.extensible_predicates
- .insert(key.clone(), skeleton);
+ .insert(key, skeleton);
let record =
RetractionRecord::AddedExtensiblePredicate(CompilationTarget::User, key);
- self.retraction_info.push_record(record);
+ self.payload.retraction_info.push_record(record);
}
CompilationTarget::Module(module_name) => {
- if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
+ if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
module.extensible_predicates.insert(key.clone(), skeleton);
let record = RetractionRecord::AddedExtensiblePredicate(
@@ -668,7 +668,7 @@ impl<'a> LoadState<'a> {
key,
);
- self.retraction_info.push_record(record);
+ self.payload.retraction_info.push_record(record);
} else {
unreachable!()
}
@@ -685,21 +685,21 @@ impl<'a> LoadState<'a> {
) {
let src_compilation_target = match self.listing_src_file_name() {
Some(filename) => CompilationTarget::Module(filename),
- None => self.compilation_target.clone(),
+ None => self.payload.compilation_target,
};
match src_compilation_target {
CompilationTarget::User => {
- self.wam
+ self.wam_prelude
.indices
.local_extensible_predicates
- .insert((local_compilation_target.clone(), key.clone()), skeleton);
+ .insert((local_compilation_target, key), skeleton);
}
CompilationTarget::Module(module_name) => {
- if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
+ if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
module
.local_extensible_predicates
- .insert((local_compilation_target.clone(), key.clone()), skeleton);
+ .insert((local_compilation_target, key), skeleton);
} else {
unreachable!()
}
@@ -708,10 +708,13 @@ impl<'a> LoadState<'a> {
}
pub(super) fn add_op_decl(&mut self, op_decl: &OpDecl) {
- match &self.compilation_target {
+ let listing_src_file_name = self.listing_src_file_name();
+ let payload_compilation_target = self.payload.compilation_target;
+
+ match payload_compilation_target {
CompilationTarget::User => {
- if let Some(filename) = self.listing_src_file_name() {
- match self.wam.indices.modules.get_mut(&filename) {
+ if let Some(filename) = listing_src_file_name {
+ match self.wam_prelude.indices.modules.get_mut(&filename) {
Some(ref mut module) => {
op_decl.insert_into_op_dir(&mut module.op_dir);
}
@@ -720,21 +723,23 @@ impl<'a> LoadState<'a> {
}
add_op_decl(
- &mut self.retraction_info,
- &self.compilation_target,
- &mut self.wam.indices.op_dir,
+ &mut self.payload.retraction_info,
+ &payload_compilation_target,
+ &mut self.wam_prelude.indices.op_dir,
op_decl,
);
}
CompilationTarget::Module(ref module_name) => {
- match self.wam.indices.modules.get_mut(module_name) {
+ match self.wam_prelude.indices.modules.get_mut(module_name) {
Some(ref mut module) => {
+ let payload: &mut LoadStatePayload<_> = &mut self.payload;
+
add_op_decl_as_module_export(
&mut module.op_dir,
- &self.compilation_target,
- &mut self.retraction_info,
- &mut self.wam.indices.op_dir,
- &mut self.module_op_exports,
+ &payload.compilation_target,
+ &mut payload.retraction_info,
+ &mut self.wam_prelude.indices.op_dir,
+ &mut payload.module_op_exports,
op_decl,
);
}
@@ -746,28 +751,17 @@ impl<'a> LoadState<'a> {
}
}
- pub(super) fn get_clause_type(
- &mut self,
- name: ClauseName,
- arity: usize,
- fixity: Option<SharedOpDesc>,
- ) -> ClauseType {
- match ClauseType::from(name, arity, fixity) {
- ClauseType::Named(name, arity, _) => {
- let idx = self.get_or_insert_code_index(
- (name.clone(), arity),
- self.compilation_target.clone(),
- );
+ pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType {
+ match ClauseType::from(name, arity) {
+ ClauseType::Named(arity, name, _) => {
+ let payload_compilation_target = self.payload.compilation_target;
- ClauseType::Named(name, arity, idx)
- }
- ClauseType::Op(name, fixity, _) => {
let idx = self.get_or_insert_code_index(
- (name.clone(), arity),
- self.compilation_target.clone(),
+ (name, arity),
+ payload_compilation_target,
);
- ClauseType::Op(name, fixity, idx)
+ ClauseType::Named(arity, name, idx)
}
ct => ct,
}
@@ -775,23 +769,16 @@ impl<'a> LoadState<'a> {
pub(super) fn get_qualified_clause_type(
&mut self,
- module_name: ClauseName,
- name: ClauseName,
+ module_name: Atom,
+ name: Atom,
arity: usize,
- fixity: Option<SharedOpDesc>,
) -> ClauseType {
- match ClauseType::from(name, arity, fixity) {
- ClauseType::Named(name, arity, _) => {
- let key = (name.clone(), arity);
- let idx = self.get_or_insert_qualified_code_index(module_name, key);
-
- ClauseType::Named(name, arity, idx)
- }
- ClauseType::Op(name, fixity, _) => {
- let key = (name.clone(), arity);
+ match ClauseType::from(name, arity) {
+ ClauseType::Named(arity, name, _) => {
+ let key = (name, arity);
let idx = self.get_or_insert_qualified_code_index(module_name, key);
- ClauseType::Op(name, fixity, idx)
+ ClauseType::Named(arity, name, idx)
}
ct => ct,
}
@@ -799,68 +786,68 @@ impl<'a> LoadState<'a> {
pub(super) fn add_meta_predicate_record(
&mut self,
- module_name: ClauseName,
- name: ClauseName,
+ module_name: Atom,
+ name: Atom,
meta_specs: Vec<MetaSpec>,
) {
let arity = meta_specs.len();
let key = (name, arity);
- match module_name.as_str() {
- "user" => {
+ match module_name {
+ atom!("user") => {
match self
- .wam
+ .wam_prelude
.indices
.meta_predicates
- .insert(key.clone(), meta_specs)
+ .insert(key, meta_specs)
{
Some(old_meta_specs) => {
- self.retraction_info
+ self.payload.retraction_info
.push_record(RetractionRecord::ReplacedMetaPredicate(
- module_name.clone(),
+ module_name,
key.0,
old_meta_specs,
));
}
None => {
- self.retraction_info
+ self.payload.retraction_info
.push_record(RetractionRecord::AddedMetaPredicate(
- module_name.clone(),
+ module_name,
key,
));
}
}
}
_ => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
match module.meta_predicates.insert(key.clone(), meta_specs) {
Some(old_meta_specs) => {
- self.retraction_info.push_record(
+ self.payload.retraction_info.push_record(
RetractionRecord::ReplacedMetaPredicate(
- module_name.clone(),
+ module_name,
key.0,
old_meta_specs,
),
);
}
None => {
- self.retraction_info.push_record(
- RetractionRecord::AddedMetaPredicate(module_name.clone(), key),
+ self.payload.retraction_info.push_record(
+ RetractionRecord::AddedMetaPredicate(module_name, key),
);
}
}
}
None => {
- self.add_dynamically_generated_module(&module_name);
+ self.add_dynamically_generated_module(module_name);
- if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
+ if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
module.meta_predicates.insert(key.clone(), meta_specs);
} else {
unreachable!()
}
- self.retraction_info
+ self.payload.retraction_info
.push_record(RetractionRecord::AddedMetaPredicate(
module_name.clone(),
key,
@@ -871,7 +858,7 @@ impl<'a> LoadState<'a> {
}
}
- pub(super) fn add_dynamically_generated_module(&mut self, module_name: &ClauseName) {
+ pub(super) fn add_dynamically_generated_module(&mut self, module_name: Atom) {
let module_decl = ModuleDecl {
name: module_name.clone(),
exports: vec![],
@@ -881,34 +868,34 @@ impl<'a> LoadState<'a> {
let mut module = Module::new(module_decl, listing_src);
self.import_builtins_in_module(
- module_name.clone(),
+ module_name,
&mut module.code_dir,
&mut module.op_dir,
&mut module.meta_predicates,
);
- self.retraction_info
+ self.payload.retraction_info
.push_record(RetractionRecord::AddedModule(module_name.clone()));
- self.wam.indices.modules.insert(module_name.clone(), module);
+ self.wam_prelude.indices.modules.insert(module_name.clone(), module);
}
fn import_builtins_in_module(
&mut self,
- module_name: ClauseName,
+ module_name: Atom,
code_dir: &mut CodeDir,
op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir,
) {
- if let Some(builtins) = self.wam.indices.modules.get(&clause_name!("builtins")) {
+ if let Some(builtins) = self.wam_prelude.indices.modules.get(&atom!("builtins")) {
let module_compilation_target = CompilationTarget::Module(module_name);
- if CompilationTarget::Module(clause_name!("builtins")) == self.compilation_target {
+ if CompilationTarget::Module(atom!("builtins")) == self.payload.compilation_target {
return;
}
import_module_exports(
- &mut self.retraction_info,
+ &mut self.payload.retraction_info,
&module_compilation_target,
builtins,
code_dir,
@@ -924,29 +911,29 @@ impl<'a> LoadState<'a> {
module_decl: ModuleDecl,
listing_src: &ListingSource,
) {
- let module_name = module_decl.name.clone();
+ let module_name = module_decl.name;
- self.remove_module_exports(module_name.clone());
- self.remove_replaced_in_situ_module(module_name.clone());
+ self.remove_module_exports(module_name);
+ self.remove_replaced_in_situ_module(module_name);
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(module) => {
let old_module_decl = mem::replace(&mut module.module_decl, module_decl.clone());
let local_extensible_predicates = mem::replace(
&mut module.local_extensible_predicates,
- LocalExtensiblePredicates::new(),
+ LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()),
);
for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() {
- self.retract_local_clauses(
- compilation_target.clone(),
- key.clone(),
+ self.retract_local_clauses_impl(
+ *compilation_target,
+ *key,
&skeleton.clause_clause_locs,
);
let is_dynamic = self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton(compilation_target, key)
.map(|skeleton| skeleton.core.is_dynamic)
@@ -955,7 +942,7 @@ impl<'a> LoadState<'a> {
if is_dynamic {
let clause_clause_compilation_target = match compilation_target {
CompilationTarget::User => {
- CompilationTarget::Module(clause_name!("builtins"))
+ CompilationTarget::Module(atom!("builtins"))
}
module => module.clone(),
};
@@ -967,7 +954,7 @@ impl<'a> LoadState<'a> {
}
}
- self.retraction_info
+ self.payload.retraction_info
.push_record(RetractionRecord::ReplacedModule(
old_module_decl,
listing_src.clone(),
@@ -980,23 +967,24 @@ impl<'a> LoadState<'a> {
pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) {
self.reset_in_situ_module(module_decl.clone(), &listing_src);
- let module_name = module_decl.name.clone();
+ let module_name = module_decl.name;
- let mut module = match self.wam.indices.modules.remove(&module_name) {
+ let mut module = match self.wam_prelude.indices.modules.remove(&module_name) {
Some(mut module) => {
module.listing_src = listing_src;
module
}
None => {
- self.retraction_info
- .push_record(RetractionRecord::AddedModule(module_name.clone()));
+ self.payload
+ .retraction_info
+ .push_record(RetractionRecord::AddedModule(module_name));
Module::new(module_decl, listing_src)
}
};
self.import_builtins_in_module(
- module_name.clone(),
+ module_name,
&mut module.code_dir,
&mut module.op_dir,
&mut module.meta_predicates,
@@ -1004,62 +992,68 @@ impl<'a> LoadState<'a> {
for export in &module.module_decl.exports {
if let ModuleExport::OpDecl(ref op_decl) = export {
+ let payload: &mut LoadStatePayload<_> = &mut self.payload;
+
add_op_decl_as_module_export(
&mut module.op_dir,
- &self.compilation_target, // this is a Module.
- &mut self.retraction_info,
- &mut self.wam.indices.op_dir,
- &mut self.module_op_exports,
+ &payload.compilation_target, // this is a Module.
+ &mut payload.retraction_info,
+ &mut self.wam_prelude.indices.op_dir,
+ &mut payload.module_op_exports,
op_decl,
);
}
}
- if let Some(load_context) = self.wam.load_contexts.last_mut() {
- load_context.module = module_name.clone();
+ if let Some(load_context) = self.wam_prelude.load_contexts.last_mut() {
+ load_context.module = module_name;
}
- self.wam.indices.modules.insert(module_name, module);
+ self.wam_prelude.indices.modules.insert(module_name, module);
}
- pub(super) fn import_module(&mut self, module_name: ClauseName) -> Result<(), SessionError> {
- if let Some(module) = self.wam.indices.modules.remove(&module_name) {
- match &self.compilation_target {
+ pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> {
+ if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) {
+ let payload_compilation_target = self.payload.compilation_target;
+
+ match &payload_compilation_target {
CompilationTarget::User => {
import_module_exports(
- &mut self.retraction_info,
- &self.compilation_target,
+ &mut self.payload.retraction_info,
+ &payload_compilation_target,
&module,
- &mut self.wam.indices.code_dir,
- &mut self.wam.indices.op_dir,
- &mut self.wam.indices.meta_predicates,
+ &mut self.wam_prelude.indices.code_dir,
+ &mut self.wam_prelude.indices.op_dir,
+ &mut self.wam_prelude.indices.meta_predicates,
)?;
}
CompilationTarget::Module(ref defining_module_name) => {
- match self.wam.indices.modules.get_mut(defining_module_name) {
+ match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
Some(ref mut target_module) => {
+ let payload: &mut LoadStatePayload<_> = &mut self.payload;
+
import_module_exports_into_module(
- &mut self.retraction_info,
- &self.compilation_target,
+ &mut payload.retraction_info,
+ &payload_compilation_target,
&module,
&mut target_module.code_dir,
&mut target_module.op_dir,
&mut target_module.meta_predicates,
- &mut self.wam.indices.op_dir,
- &mut self.module_op_exports,
+ &mut self.wam_prelude.indices.op_dir,
+ &mut payload.module_op_exports,
)?;
}
None => {
// we find ourselves here because we're trying to import
// a module into itself as it is being defined.
- self.wam.indices.modules.insert(module_name.clone(), module);
+ self.wam_prelude.indices.modules.insert(module_name, module);
return Err(SessionError::ModuleCannotImportSelf(module_name));
}
}
}
}
- self.wam.indices.modules.insert(module_name, module);
+ self.wam_prelude.indices.modules.insert(module_name, module);
Ok(())
} else {
Err(SessionError::ExistenceError(ExistenceError::Module(
@@ -1070,53 +1064,55 @@ impl<'a> LoadState<'a> {
pub(super) fn import_qualified_module(
&mut self,
- module_name: ClauseName,
+ module_name: Atom,
exports: IndexSet<ModuleExport>,
) -> Result<(), SessionError> {
- if let Some(module) = self.wam.indices.modules.remove(&module_name) {
- match &self.compilation_target {
+ if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) {
+ let payload_compilation_target = self.payload.compilation_target;
+
+ match &payload_compilation_target {
CompilationTarget::User => {
import_qualified_module_exports(
- &mut self.retraction_info,
- &self.compilation_target,
+ &mut self.payload.retraction_info,
+ &payload_compilation_target,
&module,
&exports,
- &mut self.wam.indices.code_dir,
- &mut self.wam.indices.op_dir,
- &mut self.wam.indices.meta_predicates,
+ &mut self.wam_prelude.indices.code_dir,
+ &mut self.wam_prelude.indices.op_dir,
+ &mut self.wam_prelude.indices.meta_predicates,
)?;
}
CompilationTarget::Module(ref defining_module_name) => {
- match self.wam.indices.modules.get_mut(defining_module_name) {
+ match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
Some(ref mut target_module) => {
+ let payload: &mut LoadStatePayload<_> = &mut self.payload;
+
import_qualified_module_exports_into_module(
- &mut self.retraction_info,
- &self.compilation_target,
+ &mut payload.retraction_info,
+ &payload_compilation_target,
&module,
&exports,
&mut target_module.code_dir,
&mut target_module.op_dir,
&mut target_module.meta_predicates,
- &mut self.wam.indices.op_dir,
- &mut self.module_op_exports,
+ &mut self.wam_prelude.indices.op_dir,
+ &mut payload.module_op_exports,
)?;
}
None => {
// we find ourselves here because we're trying to import
// a module into itself as it is being defined.
- self.wam.indices.modules.insert(module_name.clone(), module);
+ self.wam_prelude.indices.modules.insert(module_name, module);
return Err(SessionError::ModuleCannotImportSelf(module_name));
}
}
}
}
- self.wam.indices.modules.insert(module_name, module);
+ self.wam_prelude.indices.modules.insert(module_name, module);
Ok(())
} else {
- Err(SessionError::ExistenceError(ExistenceError::Module(
- module_name,
- )))
+ Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
}
}
@@ -1125,23 +1121,30 @@ impl<'a> LoadState<'a> {
ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(filename.as_str());
path_buf.set_extension("pl");
+
let file = File::open(&path_buf)?;
(
- Stream::from_file_as_input(filename.clone(), file),
+ Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena),
ListingSource::File(filename, path_buf),
)
}
ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) {
Some(code) => {
- if let Some(ref module) = self.wam.indices.modules.get(&library) {
+ if let Some(ref module) = self.wam_prelude.indices.modules.get(&library) {
if let ListingSource::DynamicallyGenerated = &module.listing_src {
- (Stream::from(*code), ListingSource::User)
+ (
+ Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena),
+ ListingSource::User,
+ )
} else {
return self.import_module(library);
}
} else {
- (Stream::from(*code), ListingSource::User)
+ (
+ Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena),
+ ListingSource::User,
+ )
}
}
None => {
@@ -1151,16 +1154,23 @@ impl<'a> LoadState<'a> {
};
let compilation_target = {
- let stream = &mut parsing_stream(stream)?;
-
- let ts = BootstrappingTermStream::from_prolog_stream(
+ let term_stream = BootstrappingTermStream::from_char_reader(
stream,
- self.wam.machine_st.atom_tbl.clone(),
- self.wam.machine_st.flags,
+ LS::machine_st(&mut self.payload),
listing_src,
);
- let subloader = Loader::new(ts, self.wam);
+ let subloader: Loader<'_, BootstrappingLoadState> = Loader {
+ payload: BootstrappingLoadState(
+ LoadStatePayload::new(self.wam_prelude.code.len(), term_stream)
+ ),
+ wam_prelude: MachinePreludeView {
+ indices: self.wam_prelude.indices,
+ code: self.wam_prelude.code,
+ load_contexts: self.wam_prelude.load_contexts,
+ }
+ };
+
subloader.load()?
};
@@ -1185,16 +1195,19 @@ impl<'a> LoadState<'a> {
let file = File::open(&path_buf)?;
(
- Stream::from_file_as_input(filename.clone(), file),
+ Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena),
ListingSource::File(filename, path_buf),
)
}
ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) {
Some(code) => {
- if self.wam.indices.modules.contains_key(&library) {
+ if self.wam_prelude.indices.modules.contains_key(&library) {
return self.import_qualified_module(library, exports);
} else {
- (Stream::from(*code), ListingSource::User)
+ (
+ Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena),
+ ListingSource::User,
+ )
}
}
None => {
@@ -1204,16 +1217,23 @@ impl<'a> LoadState<'a> {
};
let compilation_target = {
- let stream = &mut parsing_stream(stream)?;
-
- let ts = BootstrappingTermStream::from_prolog_stream(
+ let term_stream = BootstrappingTermStream::from_char_reader(
stream,
- self.wam.machine_st.atom_tbl.clone(),
- self.wam.machine_st.flags,
+ LS::machine_st(&mut self.payload),
listing_src,
);
- let subloader = Loader::new(ts, self.wam);
+ let subloader: Loader<'_, BootstrappingLoadState> = Loader {
+ payload: BootstrappingLoadState(
+ LoadStatePayload::new(self.wam_prelude.code.len(), term_stream),
+ ),
+ wam_prelude: MachinePreludeView {
+ indices: self.wam_prelude.indices,
+ code: self.wam_prelude.code,
+ load_contexts: self.wam_prelude.load_contexts,
+ }
+ };
+
subloader.load()?
};
@@ -1227,21 +1247,4 @@ impl<'a> LoadState<'a> {
}
}
}
-
- #[inline]
- pub(super) fn composite_op_dir(&self) -> CompositeOpDir {
- match &self.compilation_target {
- CompilationTarget::User => CompositeOpDir::new(&self.wam.indices.op_dir, None),
- CompilationTarget::Module(ref module_name) => {
- match self.wam.indices.modules.get(module_name) {
- Some(ref module) => {
- CompositeOpDir::new(&self.wam.indices.op_dir, Some(&module.op_dir))
- }
- None => {
- unreachable!()
- }
- }
- }
- }
- }
}
diff --git a/src/machine/loader.rs b/src/machine/loader.rs
index 6f48b1d9..0b436f6f 100644
--- a/src/machine/loader.rs
+++ b/src/machine/loader.rs
@@ -1,18 +1,26 @@
-use prolog_parser::ast::*;
-use prolog_parser::{clause_name, temp_v};
-
+use crate::arena::*;
+use crate::atom_table::*;
use crate::forms::*;
+use crate::heap_iter::*;
use crate::indexing::*;
+use crate::instructions::*;
use crate::machine::load_state::*;
+use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::preprocessor::*;
+use crate::machine::term_stream::*;
use crate::machine::*;
+use crate::parser::ast::*;
+use crate::types::*;
use indexmap::IndexSet;
use slice_deque::{sdeq, SliceDeque};
use std::cell::Cell;
use std::convert::TryFrom;
+use std::fmt;
+use std::mem;
+use std::ops::{Deref, DerefMut};
use std::rc::Rc;
/*
@@ -44,19 +52,19 @@ use std::rc::Rc;
#[derive(Debug)]
pub(crate) enum RetractionRecord {
- AddedMetaPredicate(ClauseName, PredicateKey),
- ReplacedMetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>),
- AddedModule(ClauseName),
+ AddedMetaPredicate(Atom, PredicateKey),
+ ReplacedMetaPredicate(Atom, Atom, Vec<MetaSpec>),
+ AddedModule(Atom),
ReplacedModule(ModuleDecl, ListingSource, LocalExtensiblePredicates),
- AddedModuleOp(ClauseName, OpDecl),
- ReplacedModuleOp(ClauseName, OpDecl, usize, Specifier),
- AddedModulePredicate(ClauseName, PredicateKey),
- ReplacedModulePredicate(ClauseName, PredicateKey, IndexPtr),
+ AddedModuleOp(Atom, OpDecl),
+ ReplacedModuleOp(Atom, OpDecl, OpDesc),
+ AddedModulePredicate(Atom, PredicateKey),
+ ReplacedModulePredicate(Atom, PredicateKey, IndexPtr),
AddedDiscontiguousPredicate(CompilationTarget, PredicateKey),
AddedDynamicPredicate(CompilationTarget, PredicateKey),
AddedMultifilePredicate(CompilationTarget, PredicateKey),
AddedUserOp(OpDecl),
- ReplacedUserOp(OpDecl, usize, Specifier),
+ ReplacedUserOp(OpDecl, OpDesc),
AddedExtensiblePredicate(CompilationTarget, PredicateKey),
AddedUserPredicate(PredicateKey),
ReplacedUserPredicate(PredicateKey, IndexPtr),
@@ -75,6 +83,7 @@ pub(crate) enum RetractionRecord {
SkeletonLocalClauseTruncateBack(CompilationTarget, CompilationTarget, PredicateKey, usize),
SkeletonClauseTruncateBack(CompilationTarget, PredicateKey, usize),
SkeletonClauseStartReplaced(CompilationTarget, PredicateKey, usize, usize),
+ RemovedDynamicSkeletonClause(CompilationTarget, PredicateKey, usize, usize),
RemovedSkeletonClause(
CompilationTarget,
PredicateKey,
@@ -113,7 +122,7 @@ impl RetractionInfo {
pub(super) fn new(orig_code_extent: usize) -> Self {
Self {
orig_code_extent,
- records: vec![], //BTreeMap::new(),
+ records: vec![],
}
}
@@ -134,16 +143,417 @@ impl RetractionInfo {
}
}
-impl<'a> Drop for LoadState<'a> {
+impl<'a, LS: LoadState<'a>> Drop for Loader<'a, LS> {
fn drop(&mut self) {
- while let Some(record) = self.retraction_info.records.pop() {
+ if LS::should_drop_load_state(self) {
+ LS::reset_machine(self);
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
+pub enum CompilationTarget {
+ Module(Atom),
+ User,
+}
+
+impl fmt::Display for CompilationTarget {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ CompilationTarget::User => write!(f, "user"),
+ CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name.as_str()),
+ }
+ }
+}
+
+impl Default for CompilationTarget {
+ #[inline]
+ fn default() -> Self {
+ CompilationTarget::User
+ }
+}
+
+impl CompilationTarget {
+ #[inline]
+ pub(crate) fn module_name(&self) -> Atom {
+ match self {
+ CompilationTarget::User => {
+ atom!("user")
+ }
+ CompilationTarget::Module(module_name) => *module_name,
+ }
+ }
+}
+
+pub struct PredicateQueue {
+ pub(super) predicates: Vec<Term>,
+ pub(super) compilation_target: CompilationTarget,
+}
+
+impl PredicateQueue {
+ #[inline]
+ pub(super) fn push(&mut self, clause: Term) {
+ self.predicates.push(clause);
+ }
+
+ #[inline]
+ pub(crate) fn first(&self) -> Option<&Term> {
+ self.predicates.first()
+ }
+
+ #[inline]
+ pub(crate) fn is_empty(&self) -> bool {
+ self.predicates.is_empty()
+ }
+
+ #[inline]
+ pub(super) fn take(&mut self) -> Self {
+ Self {
+ predicates: mem::replace(&mut self.predicates, vec![]),
+ compilation_target: self.compilation_target.clone(),
+ }
+ }
+
+ #[inline]
+ pub(super) fn len(&self) -> usize {
+ self.predicates.len()
+ }
+}
+
+#[macro_export]
+macro_rules! predicate_queue {
+ [$($v:expr),*] => (
+ PredicateQueue {
+ predicates: vec![$($v,)*],
+ compilation_target: CompilationTarget::default(),
+ }
+ )
+}
+
+pub type LiveLoadState = LoadStatePayload<LiveTermStream>;
+
+pub struct BootstrappingLoadState<'a>(
+ pub LoadStatePayload<BootstrappingTermStream<'a>>
+);
+
+impl<'a> Deref for BootstrappingLoadState<'a> {
+ type Target = LoadStatePayload<BootstrappingTermStream<'a>>;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<'a> DerefMut for BootstrappingLoadState<'a> {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+pub trait LoadState<'a>: Sized {
+ type Evacuable;
+ type TS: TermStream;
+ type LoaderFieldType: DerefMut<Target=LoadStatePayload<Self::TS>>;
+
+ fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload<Self::TS>) -> Self::LoaderFieldType;
+ fn evacuate(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
+ fn should_drop_load_state(loader: &Loader<'a, Self>) -> bool;
+ fn reset_machine(loader: &mut Loader<'a, Self>);
+ fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState;
+ fn err_on_builtin_overwrite(
+ loader: &Loader<'a, Self>,
+ key: PredicateKey,
+ ) -> Result<(), SessionError>;
+}
+
+pub struct LiveLoadAndMachineState<'a> {
+ load_state: TypedArenaPtr<LiveLoadState>,
+ machine_st: &'a mut MachineState,
+}
+
+impl<'a> Deref for LiveLoadAndMachineState<'a> {
+ type Target = LiveLoadState;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.load_state
+ }
+}
+
+impl<'a> DerefMut for LiveLoadAndMachineState<'a> {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.load_state
+ }
+}
+
+impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> {
+ type TS = LiveTermStream;
+ type LoaderFieldType = LiveLoadAndMachineState<'a>;
+ type Evacuable = TypedArenaPtr<LiveLoadState>;
+
+ #[inline(always)]
+ fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload<Self::TS>) -> Self::LoaderFieldType {
+ let load_state = arena_alloc!(payload, &mut machine_st.arena);
+ LiveLoadAndMachineState { load_state, machine_st }
+ }
+
+ #[inline(always)]
+ fn evacuate(mut loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError> {
+ loader.payload.load_state.set_tag(ArenaHeaderTag::InactiveLoadState);
+ Ok(loader.payload.load_state)
+ }
+
+ #[inline(always)]
+ fn should_drop_load_state(loader: &Loader<'a, Self>) -> bool {
+ loader.payload.load_state.get_tag() == ArenaHeaderTag::LiveLoadState
+ }
+
+ #[inline(always)]
+ fn reset_machine(loader: &mut Loader<'a, Self>) {
+ if loader.payload.load_state.get_tag() != ArenaHeaderTag::Dropped {
+ loader.payload.load_state.set_tag(ArenaHeaderTag::Dropped);
+ loader.reset_machine();
+ }
+ }
+
+ #[inline(always)]
+ fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState {
+ loader.machine_st
+ }
+
+ #[inline(always)]
+ fn err_on_builtin_overwrite(
+ loader: &Loader<'a, Self>,
+ key: PredicateKey,
+ ) -> Result<(), SessionError> {
+ if let Some(builtins) = loader.wam_prelude.indices.modules.get(&atom!("builtins")) {
+ if builtins.module_decl.exports.contains(&ModuleExport::PredicateKey(key)) {
+ return Err(SessionError::CannotOverwriteBuiltIn(key));
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
+ type TS = BootstrappingTermStream<'a>;
+ type LoaderFieldType = BootstrappingLoadState<'a>;
+ type Evacuable = CompilationTarget;
+
+ #[inline(always)]
+ fn new(_: &'a mut MachineState, payload: LoadStatePayload<Self::TS>) -> Self::LoaderFieldType {
+ BootstrappingLoadState(payload)
+ }
+
+ fn evacuate(mut loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError> {
+ if !loader.payload.predicates.is_empty() {
+ loader.compile_and_submit()?;
+ }
+
+ let repo_len = loader.wam_prelude.code.len();
+
+ loader
+ .payload
+ .retraction_info
+ .reset(repo_len);
+
+ loader.remove_module_op_exports();
+
+ Ok(loader.payload.compilation_target)
+ }
+
+ #[inline(always)]
+ fn should_drop_load_state(_loader: &Loader<'a, Self>) -> bool {
+ true
+ }
+
+ #[inline(always)]
+ fn reset_machine(loader: &mut Loader<'a, Self>) {
+ loader.reset_machine();
+ }
+
+ #[inline(always)]
+ fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState {
+ &mut loader.term_stream.parser.lexer.machine_st
+ }
+
+ #[inline(always)]
+ fn err_on_builtin_overwrite(
+ _loader: &Loader<'a, Self>,
+ _key: PredicateKey,
+ ) -> Result<(), SessionError> {
+ Ok(())
+ }
+}
+
+pub struct Loader<'a, LS: LoadState<'a>> {
+ pub(super) payload: LS::LoaderFieldType,
+ pub(super) wam_prelude: MachinePreludeView<'a>,
+}
+
+impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
+ #[inline]
+ pub(super) fn new(wam: &'a mut Machine, term_stream: <LS as LoadState<'a>>::TS) -> Self {
+ let payload = LoadStatePayload::new(wam.code.len(), term_stream);
+ let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st();
+
+ Self {
+ payload: LS::new(machine_st, payload),
+ wam_prelude,
+ }
+ }
+
+ pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
+ while let Some(decl) = self.dequeue_terms()? {
+ self.load_decl(decl)?;
+ }
+
+ LS::evacuate(self)
+ }
+
+ fn dequeue_terms(&mut self) -> Result<Option<Declaration>, SessionError> {
+ while !self.payload.term_stream.eof()? {
+ let load_state = &mut self.payload;
+ let compilation_target = &load_state.compilation_target;
+ let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target);
+
+ let term = load_state.term_stream.next(&composite_op_dir)?;
+
+ if !term.is_consistent(&load_state.predicates) {
+ self.compile_and_submit()?;
+ }
+
+ let term = match term {
+ Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => {
+ return Ok(Some(setup_declaration(self, terms)?));
+ }
+ term => term,
+ };
+
+ self.payload.predicates.push(term);
+ }
+
+ Ok(None)
+ }
+
+ pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> {
+ match decl {
+ Declaration::Dynamic(name, arity) => {
+ let compilation_target = self.payload.compilation_target;
+ self.add_dynamic_predicate(compilation_target, name, arity)?;
+ }
+ Declaration::MetaPredicate(module_name, name, meta_specs) => {
+ self.add_meta_predicate_record(module_name, name, meta_specs);
+ }
+ Declaration::Module(module_decl) => {
+ self.payload.compilation_target = CompilationTarget::Module(module_decl.name);
+ self.payload.predicates.compilation_target = self.payload.compilation_target;
+
+ let listing_src = self.payload.term_stream.listing_src().clone();
+ self.add_module(module_decl, listing_src);
+ }
+ Declaration::NonCountedBacktracking(name, arity) => {
+ self.payload.non_counted_bt_preds.insert((name, arity));
+ }
+ Declaration::Op(op_decl) => {
+ self.add_op_decl(&op_decl);
+ }
+ Declaration::UseModule(module_src) => {
+ self.use_module(module_src)?;
+ }
+ Declaration::UseQualifiedModule(module_src, exports) => {
+ self.use_qualified_module(module_src, exports)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(super) fn read_term_from_heap(&mut self, heap_term_loc: RegType) -> Result<Term, SessionError> {
+ let machine_st = LS::machine_st(&mut self.payload);
+ let term_addr = machine_st[heap_term_loc];
+
+ let mut term_stack = vec![];
+ let mut iter = stackful_post_order_iter(&mut machine_st.heap, term_addr);
+
+ while let Some(addr) = iter.next() {
+ let addr = unmark_cell_bits!(addr);
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Lis) => {
+ let tail = term_stack.pop().unwrap();
+ let head = term_stack.pop().unwrap();
+
+ term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
+ let offset_string = format!("_{}", h);
+ term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string)));
+ }
+ (HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
+ HeapCellValueTag::Char | HeapCellValueTag::F64) => {
+ term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
+ } else {
+ let subterms = term_stack
+ .drain(term_stack.len() - arity ..)
+ .collect();
+
+ term_stack.push(Term::Clause(Cell::default(), name, subterms));
+ }
+ }
+ (HeapCellValueTag::PStr, string) => {
+ let tail = term_stack.pop().unwrap();
+
+ if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
+ term_stack.push(Term::PartialString(
+ Cell::default(),
+ string,
+ None,
+ ));
+ } else {
+ term_stack.push(Term::PartialString(
+ Cell::default(),
+ string,
+ Some(Box::new(tail)),
+ ));
+ }
+ }
+ (HeapCellValueTag::PStrLoc, h) => {
+ let string = cell_as_atom_cell!(iter.heap[h]).get_name();
+ let tail = term_stack.pop().unwrap();
+
+ term_stack.push(Term::PartialString(
+ Cell::default(),
+ string,
+ Some(Box::new(tail)),
+ ));
+ }
+ _ => {
+ }
+ );
+ }
+
+ debug_assert!(term_stack.len() == 1);
+ Ok(term_stack.pop().unwrap())
+ }
+
+ fn reset_machine(&mut self) {
+ while let Some(record) = self.payload.retraction_info.records.pop() {
match record {
RetractionRecord::AddedMetaPredicate(target_module_name, key) => {
- match target_module_name.as_str() {
- "user" => {
- self.wam.indices.meta_predicates.remove(&key);
+ match target_module_name {
+ atom!("user") => {
+ self.wam_prelude.indices.meta_predicates.remove(&key);
}
- _ => match self.wam.indices.modules.get_mut(&target_module_name) {
+ _ => match self.wam_prelude.indices.modules.get_mut(&target_module_name) {
Some(ref mut module) => {
module.meta_predicates.remove(&key);
}
@@ -154,14 +564,14 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::ReplacedMetaPredicate(target_module_name, name, meta_specs) => {
- match target_module_name.as_str() {
- "user" => {
- self.wam
+ match target_module_name {
+ atom!("user") => {
+ self.wam_prelude
.indices
.meta_predicates
.insert((name, meta_specs.len()), meta_specs);
}
- _ => match self.wam.indices.modules.get_mut(&target_module_name) {
+ _ => match self.wam_prelude.indices.modules.get_mut(&target_module_name) {
Some(ref mut module) => {
module
.meta_predicates
@@ -174,13 +584,13 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::AddedModule(module_name) => {
- self.wam.indices.modules.remove(&module_name);
+ self.wam_prelude.indices.modules.remove(&module_name);
}
RetractionRecord::ReplacedModule(
module_decl,
listing_src,
local_extensible_predicates,
- ) => match self.wam.indices.modules.get_mut(&module_decl.name) {
+ ) => match self.wam_prelude.indices.modules.get_mut(&module_decl.name) {
Some(ref mut module) => {
module.module_decl = module_decl;
module.listing_src = listing_src;
@@ -193,7 +603,7 @@ impl<'a> Drop for LoadState<'a> {
RetractionRecord::AddedDiscontiguousPredicate(compilation_target, key) => {
match compilation_target {
CompilationTarget::User => {
- self.wam
+ self.wam_prelude
.indices
.extensible_predicates
.get_mut(&key)
@@ -202,7 +612,7 @@ impl<'a> Drop for LoadState<'a> {
});
}
CompilationTarget::Module(module_name) => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
module.extensible_predicates.get_mut(&key).map(|skeleton| {
skeleton.core.is_discontiguous = false;
@@ -216,7 +626,7 @@ impl<'a> Drop for LoadState<'a> {
RetractionRecord::AddedDynamicPredicate(compilation_target, key) => {
match compilation_target {
CompilationTarget::User => {
- self.wam
+ self.wam_prelude
.indices
.extensible_predicates
.get_mut(&key)
@@ -225,10 +635,11 @@ impl<'a> Drop for LoadState<'a> {
});
}
CompilationTarget::Module(module_name) => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
module.extensible_predicates.get_mut(&key).map(|skeleton| {
skeleton.core.is_dynamic = false;
+ skeleton.core.retracted_dynamic_clauses = None;
});
}
None => {}
@@ -239,7 +650,7 @@ impl<'a> Drop for LoadState<'a> {
RetractionRecord::AddedMultifilePredicate(compilation_target, key) => {
match compilation_target {
CompilationTarget::User => {
- self.wam
+ self.wam_prelude
.indices
.extensible_predicates
.get_mut(&key)
@@ -248,7 +659,7 @@ impl<'a> Drop for LoadState<'a> {
});
}
CompilationTarget::Module(module_name) => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
module.extensible_predicates.get_mut(&key).map(|skeleton| {
skeleton.core.is_multifile = false;
@@ -260,25 +671,24 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::AddedModuleOp(module_name, mut op_decl) => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
op_decl.remove(&mut module.op_dir);
}
None => {}
}
}
- RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, prec, spec) => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, op_desc) => {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
- op_decl.prec = prec;
- op_decl.spec = spec;
+ op_decl.op_desc = op_desc;
op_decl.insert_into_op_dir(&mut module.op_dir);
}
None => {}
}
}
RetractionRecord::AddedModulePredicate(module_name, key) => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
module.code_dir.remove(&key);
}
@@ -286,7 +696,7 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::ReplacedModulePredicate(module_name, key, old_code_idx) => {
- match self.wam.indices.modules.get_mut(&module_name) {
+ match self.wam_prelude.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
module
.code_dir
@@ -297,23 +707,22 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::AddedExtensiblePredicate(compilation_target, key) => {
- self.wam
+ self.wam_prelude
.indices
.remove_predicate_skeleton(&compilation_target, &key);
}
RetractionRecord::AddedUserOp(mut op_decl) => {
- op_decl.remove(&mut self.wam.indices.op_dir);
+ op_decl.remove(&mut self.wam_prelude.indices.op_dir);
}
- RetractionRecord::ReplacedUserOp(mut op_decl, prec, spec) => {
- op_decl.prec = prec;
- op_decl.spec = spec;
- op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir);
+ RetractionRecord::ReplacedUserOp(mut op_decl, op_desc) => {
+ op_decl.op_desc = op_desc;
+ op_decl.insert_into_op_dir(&mut self.wam_prelude.indices.op_dir);
}
RetractionRecord::AddedUserPredicate(key) => {
- self.wam.indices.code_dir.remove(&key);
+ self.wam_prelude.indices.code_dir.remove(&key);
}
RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => {
- self.wam
+ self.wam_prelude
.indices
.code_dir
.get_mut(&key)
@@ -322,22 +731,22 @@ impl<'a> Drop for LoadState<'a> {
RetractionRecord::AddedIndex(index_key, clause_loc) => {
// WAS: inner_index_locs) => {
if let Some(index_loc) = index_key.switch_on_term_loc() {
- let indexing_code = match &mut self.wam.code_repo.code[index_loc] {
- Line::IndexingCode(indexing_code) => indexing_code,
+ let indexing_code = match &mut self.wam_prelude.code[index_loc] {
+ Instruction::IndexingCode(indexing_code) => indexing_code,
_ => {
unreachable!()
}
};
match index_key {
- OptArgIndexKey::Constant(
+ OptArgIndexKey::Literal(
_,
index_loc,
constant,
overlapping_constants,
) => {
remove_constant_indices(
- &constant,
+ constant,
&overlapping_constants,
indexing_code,
clause_loc - index_loc, // WAS: &inner_index_locs,
@@ -345,7 +754,7 @@ impl<'a> Drop for LoadState<'a> {
}
OptArgIndexKey::Structure(_, index_loc, name, arity) => {
remove_structure_index(
- &name,
+ name,
arity,
indexing_code,
clause_loc - index_loc, // WAS: &inner_index_locs,
@@ -369,10 +778,10 @@ impl<'a> Drop for LoadState<'a> {
// write the retraction logic of this arm.
}
RetractionRecord::ReplacedChoiceOffset(instr_loc, offset) => {
- match &mut self.wam.code_repo.code[instr_loc] {
- Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
- | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
- | Line::Choice(ChoiceInstruction::DefaultRetryMeElse(ref mut o)) => {
+ match self.wam_prelude.code[instr_loc] {
+ Instruction::TryMeElse(ref mut o) |
+ Instruction::RetryMeElse(ref mut o) |
+ Instruction::DefaultRetryMeElse(ref mut o) => {
*o = offset;
}
_ => {
@@ -381,22 +790,15 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::AppendedTrustMe(instr_loc, offset, is_default) => {
- match &mut self.wam.code_repo.code[instr_loc] {
- Line::Choice(ref mut choice_instr) => {
- *choice_instr = if is_default {
- ChoiceInstruction::DefaultTrustMe(offset)
- } else {
- ChoiceInstruction::TrustMe(offset)
- };
- }
- _ => {
- unreachable!();
- }
- }
+ self.wam_prelude.code[instr_loc] = if is_default {
+ Instruction::DefaultTrustMe(offset)
+ } else {
+ Instruction::TrustMe(offset)
+ };
}
RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v) => {
- match &mut self.wam.code_repo.code[index_loc] {
- Line::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] {
+ match self.wam_prelude.code[index_loc] {
+ Instruction::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
_,
ref mut v,
@@ -410,20 +812,17 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::ModifiedTryMeElse(instr_loc, o) => {
- self.wam.code_repo.code[instr_loc] =
- Line::Choice(ChoiceInstruction::TryMeElse(o));
+ self.wam_prelude.code[instr_loc] = Instruction::TryMeElse(o);
}
RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => {
- self.wam.code_repo.code[instr_loc] =
- Line::Choice(ChoiceInstruction::RetryMeElse(o));
+ self.wam_prelude.code[instr_loc] = Instruction::RetryMeElse(o);
}
RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => {
- self.wam.code_repo.code[instr_loc] =
- Line::Control(ControlInstruction::RevJmpBy(o));
+ self.wam_prelude.code[instr_loc] = Instruction::RevJmpBy(o);
}
RetractionRecord::SkeletonClausePopBack(compilation_target, key) => {
match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
@@ -436,7 +835,7 @@ impl<'a> Drop for LoadState<'a> {
}
RetractionRecord::SkeletonClausePopFront(compilation_target, key) => {
match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
@@ -453,10 +852,12 @@ impl<'a> Drop for LoadState<'a> {
local_compilation_target,
key,
) => {
- match self.wam.indices.get_local_predicate_skeleton_mut(
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
src_compilation_target,
local_compilation_target,
- self.listing_src_file_name(),
+ listing_src_file_name,
key,
) {
Some(skeleton) => {
@@ -470,10 +871,12 @@ impl<'a> Drop for LoadState<'a> {
local_compilation_target,
key,
) => {
- match self.wam.indices.get_local_predicate_skeleton_mut(
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
src_compilation_target,
local_compilation_target,
- self.listing_src_file_name(),
+ listing_src_file_name,
key,
) {
Some(skeleton) => {
@@ -488,10 +891,12 @@ impl<'a> Drop for LoadState<'a> {
key,
len,
) => {
- match self.wam.indices.get_local_predicate_skeleton_mut(
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
src_compilation_target,
local_compilation_target,
- self.listing_src_file_name(),
+ listing_src_file_name,
key,
) {
Some(skeleton) => {
@@ -502,7 +907,7 @@ impl<'a> Drop for LoadState<'a> {
}
RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => {
match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
@@ -520,7 +925,7 @@ impl<'a> Drop for LoadState<'a> {
clause_start,
) => {
match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
@@ -530,6 +935,32 @@ impl<'a> Drop for LoadState<'a> {
None => {}
}
}
+ RetractionRecord::RemovedDynamicSkeletonClause(
+ compilation_target,
+ key,
+ target_pos,
+ clause_clause_loc,
+ ) => {
+ match self
+ .wam_prelude
+ .indices
+ .get_predicate_skeleton_mut(&compilation_target, &key)
+ {
+ Some(skeleton) => {
+ if let Some(removed_clauses) = &mut skeleton.core.retracted_dynamic_clauses {
+ let clause_index_info = removed_clauses.pop().unwrap();
+
+ skeleton
+ .core
+ .clause_clause_locs
+ .insert(target_pos, clause_clause_loc);
+
+ skeleton.clauses.insert(target_pos, clause_index_info);
+ }
+ }
+ None => {}
+ }
+ }
RetractionRecord::RemovedSkeletonClause(
compilation_target,
key,
@@ -538,7 +969,7 @@ impl<'a> Drop for LoadState<'a> {
clause_clause_loc,
) => {
match self
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
@@ -553,7 +984,7 @@ impl<'a> Drop for LoadState<'a> {
}
}
RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => {
- self.wam.code_repo.code[index_loc] = Line::IndexingCode(indexing_code);
+ self.wam_prelude.code[index_loc] = Instruction::IndexingCode(indexing_code);
}
RetractionRecord::RemovedLocalSkeletonClauseLocations(
compilation_target,
@@ -561,10 +992,12 @@ impl<'a> Drop for LoadState<'a> {
key,
clause_locs,
) => {
- match self.wam.indices.get_local_predicate_skeleton_mut(
+ let listing_src_file_name = self.listing_src_file_name();
+
+ match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
compilation_target,
local_compilation_target,
- self.listing_src_file_name(),
+ listing_src_file_name,
key,
) {
Some(skeleton) => skeleton.clause_clause_locs = clause_locs,
@@ -574,44 +1007,44 @@ impl<'a> Drop for LoadState<'a> {
RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton) => {
match compilation_target {
CompilationTarget::User => {
- self.wam.indices.extensible_predicates.insert(key, skeleton);
+ self.wam_prelude.indices.extensible_predicates.insert(key, skeleton);
}
CompilationTarget::Module(module_name) => {
- if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
+ if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
module.extensible_predicates.insert(key, skeleton);
}
}
}
}
RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => {
- match &mut self.wam.code_repo.code[instr_loc] {
- Line::Choice(ChoiceInstruction::DynamicElse(
+ match self.wam_prelude.code[instr_loc] {
+ Instruction::DynamicElse(
_,
_,
NextOrFail::Next(ref mut o),
- ))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ )
+ | Instruction::DynamicInternalElse(
_,
_,
NextOrFail::Next(ref mut o),
- )) => {
+ ) => {
*o = next;
}
_ => {}
}
}
RetractionRecord::AppendedNextOrFail(instr_loc, fail) => {
- match &mut self.wam.code_repo.code[instr_loc] {
- Line::Choice(ChoiceInstruction::DynamicElse(
+ match self.wam_prelude.code[instr_loc] {
+ Instruction::DynamicElse(
_,
_,
ref mut next_or_fail,
- ))
- | Line::Choice(ChoiceInstruction::DynamicInternalElse(
+ )
+ | Instruction::DynamicInternalElse(
_,
_,
ref mut next_or_fail,
- )) => {
+ ) => {
*next_or_fail = fail;
}
_ => {}
@@ -619,270 +1052,14 @@ impl<'a> Drop for LoadState<'a> {
}
}
}
-
- // TODO: necessary? unnecessary?
- // self.wam.code_repo.code.truncate(self.retraction_info.orig_code_extent);
- }
-}
-
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-pub(crate) enum CompilationTarget {
- Module(ClauseName),
- User,
-}
-
-impl Default for CompilationTarget {
- #[inline]
- fn default() -> Self {
- CompilationTarget::User
- }
-}
-
-impl CompilationTarget {
- #[inline]
- pub(super) fn take(&mut self) -> CompilationTarget {
- mem::replace(self, CompilationTarget::User)
- }
-
- #[inline]
- pub(crate) fn module_name(&self) -> ClauseName {
- match self {
- CompilationTarget::User => {
- clause_name!("user")
- }
- CompilationTarget::Module(ref module_name) => module_name.clone(),
- }
- }
-}
-
-pub(crate) struct PredicateQueue {
- pub(super) predicates: Vec<Term>,
- pub(super) compilation_target: CompilationTarget,
-}
-
-impl PredicateQueue {
- #[inline]
- pub(super) fn push(&mut self, clause: Term) {
- self.predicates.push(clause);
- }
-
- #[inline]
- pub(crate) fn first(&self) -> Option<&Term> {
- self.predicates.first()
- }
-
- #[inline]
- pub(crate) fn is_empty(&self) -> bool {
- self.predicates.is_empty()
- }
-
- #[inline]
- pub(super) fn take(&mut self) -> Self {
- Self {
- predicates: mem::replace(&mut self.predicates, vec![]),
- compilation_target: self.compilation_target.take(),
- }
- }
-
- #[inline]
- pub(super) fn len(&self) -> usize {
- self.predicates.len()
- }
-}
-
-macro_rules! predicate_queue {
- [$($v:expr),*] => (
- PredicateQueue {
- predicates: vec![$($v,)*],
- compilation_target: CompilationTarget::default(),
- }
- )
-}
-
-pub(crate) struct Loader<'a, TermStream> {
- pub(super) load_state: LoadState<'a>,
- pub(super) predicates: PredicateQueue,
- pub(super) clause_clauses: Vec<(Term, Term)>,
- pub(super) term_stream: TermStream,
- pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
-}
-
-impl<'a, TS: TermStream> Loader<'a, TS> {
- #[inline]
- pub(super) fn new(term_stream: TS, wam: &'a mut Machine) -> Self {
- let load_state = LoadState {
- compilation_target: CompilationTarget::User,
- module_op_exports: vec![],
- retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
- wam,
- };
-
- Self {
- load_state,
- term_stream,
- non_counted_bt_preds: IndexSet::new(),
- predicates: predicate_queue![],
- clause_clauses: vec![],
- }
- }
-
- pub(crate) fn load(mut self) -> Result<TS::Evacuable, SessionError> {
- while let Some(decl) = self.dequeue_terms()? {
- self.load_decl(decl)?;
- }
-
- TS::evacuate(self)
- }
-
- fn dequeue_terms(&mut self) -> Result<Option<Declaration>, SessionError> {
- while !self.term_stream.eof()? {
- let term = self.term_stream.next(&self.load_state.composite_op_dir())?;
-
- // if is_consistent is false, self.predicates is not empty.
- if !term.is_consistent(&self.predicates) {
- self.compile_and_submit()?;
- }
-
- let term = match term {
- Term::Clause(_, name, terms, _) if name.as_str() == ":-" && terms.len() == 1 => {
- return Ok(Some(setup_declaration(&self.load_state, terms)?));
- }
- term => term,
- };
-
- self.predicates.push(term);
- }
-
- Ok(None)
- }
-
- pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> {
- match decl {
- Declaration::Dynamic(name, arity) => {
- let compilation_target = self.load_state.compilation_target.clone();
- self.add_dynamic_predicate(compilation_target, name, arity)?;
- }
- Declaration::MetaPredicate(module_name, name, meta_specs) => {
- self.load_state
- .add_meta_predicate_record(module_name, name, meta_specs);
- }
- Declaration::Module(module_decl) => {
- self.load_state.compilation_target =
- CompilationTarget::Module(module_decl.name.clone());
-
- self.predicates.compilation_target = self.load_state.compilation_target.clone();
-
- self.load_state
- .add_module(module_decl, self.term_stream.listing_src().clone());
- }
- Declaration::NonCountedBacktracking(name, arity) => {
- self.non_counted_bt_preds.insert((name, arity));
- }
- Declaration::Op(op_decl) => {
- self.load_state.add_op_decl(&op_decl);
- }
- Declaration::UseModule(module_src) => {
- self.load_state.use_module(module_src)?;
- }
- Declaration::UseQualifiedModule(module_src, exports) => {
- self.load_state.use_qualified_module(module_src, exports)?;
- }
- }
-
- Ok(())
- }
-
- pub(super) fn read_term_from_heap(&self, heap_term_loc: RegType) -> Result<Term, SessionError> {
- let machine_st = &self.load_state.wam.machine_st;
- let term_addr = machine_st[heap_term_loc];
-
- if machine_st.is_cyclic_term(term_addr) {
- return Err(SessionError::from(CompilationError::CannotParseCyclicTerm));
- }
-
- let mut term_stack = vec![];
-
- for addr in machine_st.post_order_iter(term_addr) {
- match machine_st.heap.index_addr(&addr).as_ref() {
- HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => {
- let tail = term_stack.pop().unwrap();
- let head = term_stack.pop().unwrap();
-
- term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
- }
- HeapCellValue::Addr(addr) => {
- if let Some(r) = addr.as_var() {
- let offset_string = match r {
- Ref::HeapCell(h) | Ref::AttrVar(h) => format!("_{}", h),
- Ref::StackCell(fr, sc) => format!("_s_{}_{}", fr, sc),
- };
-
- term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string)));
- } else {
- match addr.as_constant_index(machine_st) {
- Some(constant) => {
- term_stack.push(Term::Constant(Cell::default(), constant));
- }
- None => {
- return Err(SessionError::from(CompilationError::UnreadableTerm));
- }
- }
- }
- }
- HeapCellValue::Atom(ref name, ref shared_op_desc) => {
- term_stack.push(Term::Constant(
- Cell::default(),
- Constant::Atom(name.clone(), shared_op_desc.clone()),
- ));
- }
- HeapCellValue::Integer(ref integer) => {
- term_stack.push(Term::Constant(
- Cell::default(),
- Constant::Integer(integer.clone()),
- ));
- }
- HeapCellValue::NamedStr(arity, ref name, ref shared_op_desc) => {
- let subterms = term_stack
- .drain(term_stack.len() - arity..)
- .map(Box::new)
- .collect();
-
- term_stack.push(Term::Clause(
- Cell::default(),
- name.clone(),
- subterms,
- shared_op_desc.clone(),
- ));
- }
- HeapCellValue::PartialString(..) => {
- let string = machine_st.heap_pstr_iter(addr).to_string();
- term_stack.push(Term::Constant(
- Cell::default(),
- Constant::String(Rc::new(string)),
- ));
- }
- HeapCellValue::Rational(ref rational) => {
- term_stack.push(Term::Constant(
- Cell::default(),
- Constant::Rational(rational.clone()),
- ));
- }
- _ => {
- return Err(SessionError::from(CompilationError::UnreadableTerm));
- }
- }
- }
-
- debug_assert!(term_stack.len() == 1);
- Ok(term_stack.pop().unwrap())
}
fn extract_module_export_list_from_heap(
- &self,
+ &mut self,
r: RegType,
) -> Result<IndexSet<ModuleExport>, SessionError> {
let export_list = self.read_term_from_heap(r)?;
- let atom_tbl = self.load_state.wam.machine_st.atom_tbl.clone();
+ let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
let export_list = setup_module_export_list(export_list, atom_tbl)?;
Ok(export_list.into_iter().collect())
@@ -890,19 +1067,16 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
match term {
- Term::Clause(_, turnstile, mut terms, _)
- if turnstile.as_str() == ":-" && terms.len() == 2 =>
+ Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 =>
{
- let body = *terms.pop().unwrap();
- let head = *terms.pop().unwrap();
+ let body = terms.pop().unwrap();
+ let head = terms.pop().unwrap();
- self.clause_clauses.push((head, body));
+ self.payload.clause_clauses.push((head, body));
}
- head @ Term::Constant(_, Constant::Atom(..)) | head @ Term::Clause(..) => {
- let body =
- Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None));
-
- self.clause_clauses.push((head, body));
+ head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => {
+ let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
+ self.payload.clause_clauses.push((head, body));
}
_ => {
return Err(CompilationError::InadmissibleFact);
@@ -915,7 +1089,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
fn add_extensible_predicate_declaration(
&mut self,
compilation_target: CompilationTarget,
- name: ClauseName,
+ name: Atom,
arity: usize,
flag_accessor: impl Fn(&mut LocalPredicateSkeleton) -> &mut bool,
retraction_fn: impl Fn(CompilationTarget, PredicateKey) -> RetractionRecord,
@@ -926,8 +1100,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
match &compilation_target {
CompilationTarget::User => {
match self
- .load_state
- .wam
+ .wam_prelude
.indices
.extensible_predicates
.get_mut(&key)
@@ -936,19 +1109,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
if !*flag_accessor(&mut skeleton.core) {
*flag_accessor(&mut skeleton.core) = true;
- self.load_state.retraction_info.push_record(retraction_fn(
- compilation_target.clone(),
- key.clone(),
+ self.payload.retraction_info.push_record(retraction_fn(
+ compilation_target,
+ key,
));
}
}
None => {
- if self.load_state.compilation_target == compilation_target {
+ if self.payload.compilation_target == compilation_target {
let mut skeleton = PredicateSkeleton::new();
*flag_accessor(&mut skeleton.core) = true;
- self.load_state.add_extensible_predicate(
- key.clone(),
+ self.add_extensible_predicate(
+ key,
skeleton,
CompilationTarget::User,
);
@@ -959,27 +1132,27 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
}
CompilationTarget::Module(ref module_name) => {
- match self.load_state.wam.indices.modules.get_mut(module_name) {
+ match self.wam_prelude.indices.modules.get_mut(module_name) {
Some(ref mut module) => match module.extensible_predicates.get_mut(&key) {
Some(ref mut skeleton) => {
if !*flag_accessor(&mut skeleton.core) {
*flag_accessor(&mut skeleton.core) = true;
- self.load_state.retraction_info.push_record(retraction_fn(
- compilation_target.clone(),
- key.clone(),
+ self.payload.retraction_info.push_record(retraction_fn(
+ compilation_target,
+ key,
));
}
}
None => {
- if self.load_state.compilation_target == compilation_target {
+ if self.payload.compilation_target == compilation_target {
let mut skeleton = PredicateSkeleton::new();
*flag_accessor(&mut skeleton.core) = true;
- self.load_state.add_extensible_predicate(
- key.clone(),
+ self.add_extensible_predicate(
+ key,
skeleton,
- compilation_target.clone(),
+ compilation_target,
);
} else {
throw_permission_error = true;
@@ -987,16 +1160,15 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
},
None => {
- self.load_state
- .add_dynamically_generated_module(module_name);
+ self.add_dynamically_generated_module(*module_name);
let mut skeleton = PredicateSkeleton::new();
*flag_accessor(&mut skeleton.core) = true;
- self.load_state.add_extensible_predicate(
- key.clone(),
+ self.add_extensible_predicate(
+ key,
skeleton,
- compilation_target.clone(),
+ compilation_target,
);
}
}
@@ -1004,17 +1176,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
if !throw_permission_error {
- match self.load_state.compilation_target.clone() {
+ let listing_src_file_name = self.listing_src_file_name();
+ let payload_compilation_target = self.payload.compilation_target;
+
+ match payload_compilation_target {
CompilationTarget::User => {
match self
- .load_state
- .wam
+ .wam_prelude
.indices
.get_local_predicate_skeleton_mut(
- self.load_state.compilation_target.clone(),
- compilation_target.clone(),
- self.load_state.listing_src_file_name(),
- key.clone(),
+ payload_compilation_target,
+ compilation_target,
+ listing_src_file_name,
+ key,
) {
Some(skeleton) => {
if !*flag_accessor(skeleton) {
@@ -1025,19 +1199,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
let mut skeleton = LocalPredicateSkeleton::new();
*flag_accessor(&mut skeleton) = true;
- self.load_state.add_local_extensible_predicate(
- compilation_target.clone(),
- key.clone(),
+ self.add_local_extensible_predicate(
+ compilation_target,
+ key,
skeleton,
);
}
}
}
CompilationTarget::Module(ref module_name) => {
- match self.load_state.wam.indices.modules.get_mut(module_name) {
+ match self.wam_prelude.indices.modules.get_mut(module_name) {
Some(module) => match module
.local_extensible_predicates
- .get_mut(&(compilation_target.clone(), key.clone()))
+ .get_mut(&(compilation_target, key))
{
Some(skeleton) => {
if !*flag_accessor(skeleton) {
@@ -1048,23 +1222,22 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
let mut skeleton = LocalPredicateSkeleton::new();
*flag_accessor(&mut skeleton) = true;
- self.load_state.add_local_extensible_predicate(
- compilation_target.clone(),
- key.clone(),
+ self.add_local_extensible_predicate(
+ compilation_target,
+ key,
skeleton,
);
}
},
None => {
- self.load_state
- .add_dynamically_generated_module(module_name);
+ self.add_dynamically_generated_module(*module_name);
let mut skeleton = LocalPredicateSkeleton::new();
*flag_accessor(&mut skeleton) = true;
- self.load_state.add_local_extensible_predicate(
- compilation_target.clone(),
- key.clone(),
+ self.add_local_extensible_predicate(
+ compilation_target,
+ key,
skeleton,
);
}
@@ -1072,7 +1245,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
}
- self.fail_on_undefined(&compilation_target, key);
+ self.fail_on_undefined(compilation_target, key);
Ok(())
} else {
@@ -1083,20 +1256,18 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
}
- fn fail_on_undefined(&mut self, compilation_target: &CompilationTarget, key: PredicateKey) {
+ fn fail_on_undefined(&mut self, compilation_target: CompilationTarget, key: PredicateKey) {
/*
* DynamicUndefined isn't only applied to dynamic predicates
* but to multifile and discontiguous predicates as well.
*/
- let code_index = self
- .load_state
- .get_or_insert_code_index(key.clone(), compilation_target.clone());
+ let code_index = self.get_or_insert_code_index(key, compilation_target);
if let IndexPtr::Undefined = code_index.get() {
set_code_index(
- &mut self.load_state.retraction_info,
- compilation_target,
+ &mut self.payload.retraction_info,
+ &compilation_target,
key,
&code_index,
IndexPtr::DynamicUndefined,
@@ -1107,7 +1278,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
fn add_discontiguous_predicate(
&mut self,
compilation_target: CompilationTarget,
- name: ClauseName,
+ name: Atom,
arity: usize,
) -> Result<(), SessionError> {
self.add_extensible_predicate_declaration(
@@ -1122,12 +1293,12 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
fn add_dynamic_predicate(
&mut self,
compilation_target: CompilationTarget,
- name: ClauseName,
+ name: Atom,
arity: usize,
) -> Result<(), SessionError> {
self.add_extensible_predicate_declaration(
- compilation_target.clone(),
- name.clone(),
+ compilation_target,
+ name,
arity,
|skeleton| &mut skeleton.is_dynamic,
RetractionRecord::AddedDynamicPredicate,
@@ -1137,7 +1308,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
fn add_multifile_predicate(
&mut self,
compilation_target: CompilationTarget,
- name: ClauseName,
+ name: Atom,
arity: usize,
) -> Result<(), SessionError> {
self.add_extensible_predicate_declaration(
@@ -1152,13 +1323,13 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
if let Some(predicate_name) = ClauseInfo::name(term) {
let arity = ClauseInfo::arity(term);
+ let predicates_compilation_target = self.payload.predicates.compilation_target;
let is_dynamic = self
- .load_state
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton(
- &self.predicates.compilation_target,
+ &predicates_compilation_target,
&(predicate_name, arity),
)
.map(|skeleton| skeleton.core.is_dynamic)
@@ -1173,15 +1344,18 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
pub(super) fn retract_local_clauses(&mut self, key: &PredicateKey, is_dynamic: bool) {
+ let payload_compilation_target = self.payload.compilation_target;
+ let predicates_compilation_target = self.payload.predicates.compilation_target;
+ let listing_src_file_name = self.listing_src_file_name();
+
let clause_locs = match self
- .load_state
- .wam
+ .wam_prelude
.indices
.get_local_predicate_skeleton_mut(
- self.load_state.compilation_target.clone(),
- self.predicates.compilation_target.clone(),
- self.load_state.listing_src_file_name(),
- key.clone(),
+ payload_compilation_target,
+ predicates_compilation_target,
+ listing_src_file_name,
+ *key,
) {
Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => {
mem::replace(&mut skeleton.clause_clause_locs, sdeq![])
@@ -1189,121 +1363,125 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
_ => return,
};
- self.load_state.retraction_info.push_record(
+ self.payload.retraction_info.push_record(
RetractionRecord::RemovedLocalSkeletonClauseLocations(
- self.load_state.compilation_target.clone(),
- self.predicates.compilation_target.clone(),
- key.clone(),
+ payload_compilation_target,
+ predicates_compilation_target,
+ *key,
clause_locs.clone(),
),
);
- self.load_state.retract_local_clauses(
- self.predicates.compilation_target.clone(),
- key.clone(),
+ self.retract_local_clauses_impl(
+ predicates_compilation_target,
+ *key,
&clause_locs,
);
if is_dynamic {
- let clause_clause_compilation_target = match &self.predicates.compilation_target {
- CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")),
- module_name => module_name.clone(),
+ let clause_clause_compilation_target = match predicates_compilation_target {
+ CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
+ module_name => module_name,
};
- self.load_state
- .retract_local_clause_clauses(clause_clause_compilation_target, &clause_locs);
+ self.retract_local_clause_clauses(clause_clause_compilation_target, &clause_locs);
+ }
+ }
+}
+
+impl<'a> MachinePreludeView<'a> {
+ #[inline]
+ pub(super) fn composite_op_dir(&self, compilation_target: &CompilationTarget) -> CompositeOpDir {
+ match compilation_target {
+ CompilationTarget::User => CompositeOpDir::new(&self.indices.op_dir, None),
+ CompilationTarget::Module(ref module_name) => {
+ match self.indices.modules.get(module_name) {
+ Some(ref module) => {
+ CompositeOpDir::new(&self.indices.op_dir, Some(&module.op_dir))
+ }
+ None => {
+ unreachable!()
+ }
+ }
+ }
}
}
}
impl Machine {
- pub(crate) fn use_module(&mut self) {
+ pub(crate) fn use_module(&mut self) -> CallResult {
let subevacuable_addr = self
.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(2)]));
-
- let module_src = ModuleSource::Library(match subevacuable_addr {
- Addr::LoadStatePayload(payload) => match &self.machine_st.heap[payload] {
- HeapCellValue::LoadStatePayload(payload) => match &payload.compilation_target {
- CompilationTarget::Module(ref module_name) => module_name.clone(),
- CompilationTarget::User => {
- return;
- }
- },
- _ => {
- unreachable!()
+ .store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ let module_src = ModuleSource::Library({
+ let payload = cell_as_load_state_payload!(subevacuable_addr);
+
+ match payload.compilation_target {
+ CompilationTarget::Module(module_name) => module_name,
+ CompilationTarget::User => {
+ return Ok(());
}
- },
- _ => {
- unreachable!()
}
});
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(1));
let use_module = || {
let export_list = loader.extract_module_export_list_from_heap(temp_v!(3))?;
if export_list.is_empty() {
- loader.load_state.use_module(module_src)?;
+ loader.use_module(module_src)?;
} else {
- loader
- .load_state
- .use_qualified_module(module_src, export_list)?;
+ loader.use_qualified_module(module_src, export_list)?;
}
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = use_module();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn load_compiled_library(&mut self) {
- let library = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ pub(crate) fn load_compiled_library(&mut self) -> CallResult {
+ let library = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
if let Some(module) = self.indices.modules.get(&library) {
if let ListingSource::DynamicallyGenerated = module.listing_src {
self.machine_st.fail = true;
- return;
+ return Ok(());
}
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
let import_module = || {
let export_list = loader.extract_module_export_list_from_heap(temp_v!(2))?;
if export_list.is_empty() {
- loader.load_state.import_module(library)?;
+ loader.import_module(library)?;
} else {
- loader
- .load_state
- .import_qualified_module(library, export_list)?;
+ loader.import_qualified_module(library, export_list)?;
}
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = import_module();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
} else {
self.machine_st.fail = true;
+ Ok(())
}
}
- pub(crate) fn declare_module(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ pub(crate) fn declare_module(&mut self) -> CallResult {
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
- // let export_list = self.machine_st.extract_module_export_list(temp_v!(2));
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
let declare_module = || {
// let export_list = export_list?;
@@ -1315,181 +1493,171 @@ impl Machine {
};
loader.load_decl(Declaration::Module(module_decl))?;
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = declare_module();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
#[inline]
- pub(crate) fn add_discontiguous_predicate(&mut self) {
+ pub(crate) fn add_discontiguous_predicate(&mut self) -> CallResult {
self.add_extensible_predicate_declaration(
|loader, compilation_target, clause_name, arity| {
loader.add_discontiguous_predicate(compilation_target, clause_name, arity)
},
- );
+ )
}
#[inline]
- pub(crate) fn add_dynamic_predicate(&mut self) {
+ pub(crate) fn add_dynamic_predicate(&mut self) -> CallResult {
self.add_extensible_predicate_declaration(
|loader, compilation_target, clause_name, arity| {
loader.add_dynamic_predicate(compilation_target, clause_name, arity)
},
- );
+ )
}
#[inline]
- pub(crate) fn add_multifile_predicate(&mut self) {
+ pub(crate) fn add_multifile_predicate(&mut self) -> CallResult {
self.add_extensible_predicate_declaration(
|loader, compilation_target, clause_name, arity| {
loader.add_multifile_predicate(compilation_target, clause_name, arity)
},
- );
+ )
}
fn add_extensible_predicate_declaration(
&mut self,
- decl_adder: impl Fn(
- &mut Loader<LiveTermStream>,
+ decl_adder: impl for<'a> Fn(
+ &mut Loader<'a, LiveLoadAndMachineState<'a>>,
CompilationTarget,
- ClauseName,
+ Atom,
usize,
) -> Result<(), SessionError>,
- ) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ ) -> CallResult {
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
- let predicate_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(2)]))
+ let predicate_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
);
let arity = self
.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(3)]));
+ .store(self.machine_st.deref(self.machine_st.registers[3]));
- let arity = match Number::try_from((arity, &self.machine_st.heap)) {
+ let arity = match Number::try_from(arity) {
Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => Ok(n.to_usize().unwrap()),
- Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => {
- Ok(usize::try_from(n).unwrap())
+ Ok(Number::Fixnum(n)) if n.get_num() >= 0 && n.get_num() <= MAX_ARITY as i64 => {
+ Ok(usize::try_from(n.get_num()).unwrap())
}
_ => Err(SessionError::from(CompilationError::InvalidRuleHead)),
};
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(4));
- let add_predicate_decl = || {
+ let add_predicate_decl = move || {
decl_adder(&mut loader, compilation_target, predicate_name, arity?)?;
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = add_predicate_decl();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn add_term_expansion_clause(&mut self) {
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2));
+ pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult {
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
let add_clause = || {
let term = loader.read_term_from_heap(temp_v!(1))?;
- loader.load_state.incremental_compile_clause(
- (clause_name!("term_expansion"), 2),
+ loader.incremental_compile_clause(
+ (atom!("term_expansion"), 2),
term,
CompilationTarget::User,
false,
AppendOrPrepend::Append,
)?;
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = add_clause();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn add_goal_expansion_clause(&mut self) {
- let target_module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ pub(crate) fn add_goal_expansion_clause(&mut self) -> CallResult {
+ let target_module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
- let compilation_target = match target_module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match target_module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(target_module_name),
};
let add_clause = || {
let term = loader.read_term_from_heap(temp_v!(2))?;
- loader.load_state.incremental_compile_clause(
- (clause_name!("goal_expansion"), 2),
+ loader.incremental_compile_clause(
+ (atom!("goal_expansion"), 2),
term,
compilation_target,
false, // backtracking inferences are counted by call_with_inference_limit.
AppendOrPrepend::Append,
)?;
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = add_clause();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn add_in_situ_filename_module(&mut self) {
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1));
+ pub(crate) fn add_in_situ_filename_module(&mut self) -> CallResult {
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(1));
let add_in_situ_filename_module = || {
- if let Some(filename) = loader.load_state.listing_src_file_name() {
+ if let Some(filename) = loader.listing_src_file_name() {
let module_decl = ModuleDecl {
name: filename,
exports: vec![],
};
- let module_name = module_decl.name.clone();
+ let module_name = module_decl.name;
if !loader
- .load_state
- .wam
+ .wam_prelude
.indices
.modules
.contains_key(&module_decl.name)
{
let module = Module::new_in_situ(module_decl);
loader
- .load_state
- .wam
+ .wam_prelude
.indices
.modules
.insert(module_name, module);
} else {
- loader.load_state.reset_in_situ_module(
+ loader.reset_in_situ_module(
module_decl.clone(),
&ListingSource::DynamicallyGenerated,
);
- match loader.load_state.wam.indices.modules.get_mut(&module_name) {
+ match loader.wam_prelude.indices.modules.get_mut(&module_name) {
Some(module) => {
for (key, value) in module.op_dir.drain(0..) {
- let (prec, spec) = value.shared_op_desc().get();
- let mut op_decl = OpDecl::new(prec, spec, key.0);
-
- op_decl.remove(&mut loader.load_state.wam.indices.op_dir);
+ let mut op_decl = OpDecl::new(value, key.0);
+ op_decl.remove(&mut loader.wam_prelude.indices.op_dir);
}
}
None => {}
@@ -1497,83 +1665,76 @@ impl Machine {
}
}
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = add_in_situ_filename_module();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn loader_from_heap_evacuable(
- &mut self,
+ pub(crate) fn loader_from_heap_evacuable<'a>(
+ &'a mut self,
r: RegType,
- ) -> (Loader<LiveTermStream>, usize) {
- let (load_state_payload, evacuable_h) = match self
- .machine_st
- .store(self.machine_st.deref(self.machine_st[r]))
- {
- Addr::LoadStatePayload(h) => (
- mem::replace(
- &mut self.machine_st.heap[h],
- HeapCellValue::Addr(Addr::EmptyList),
- ),
- h,
- ),
- _ => {
- unreachable!()
- }
- };
+ ) -> Loader<'a, LiveLoadAndMachineState<'a>> {
+ let mut load_state = cell_as_load_state_payload!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st[r]))
+ );
- match load_state_payload {
- HeapCellValue::LoadStatePayload(payload) => {
- (Loader::from_load_state_payload(self, payload), evacuable_h)
- }
- _ => {
- unreachable!()
- }
+ load_state.set_tag(ArenaHeaderTag::LiveLoadState);
+
+ let (wam_prelude, machine_st) = self.prelude_view_and_machine_st();
+
+ Loader {
+ payload: LiveLoadAndMachineState { load_state, machine_st },
+ wam_prelude,
}
}
#[inline]
pub(crate) fn push_load_state_payload(&mut self) {
- let payload = Box::new(LoadStatePayload::new(self));
- let addr = Addr::LoadStatePayload(
- self.machine_st
- .heap
- .push(HeapCellValue::LoadStatePayload(payload)),
+ let payload = arena_alloc!(
+ LoadStatePayload::new(
+ self.code.len(),
+ LiveTermStream::new(ListingSource::User),
+ ),
+ &mut self.machine_st.arena
);
- self.machine_st
- .bind(self.machine_st[temp_v!(1)].as_var().unwrap(), addr);
+ let var = self.machine_st.deref(self.machine_st.registers[1]);
+
+ self.machine_st.bind(
+ var.as_var().unwrap(),
+ typed_arena_ptr_as_cell!(payload),
+ );
}
#[inline]
pub(crate) fn pop_load_state_payload(&mut self) {
- let load_state_payload = match self
- .machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
- {
- Addr::LoadStatePayload(h) => mem::replace(
- &mut self.machine_st.heap[h],
- HeapCellValue::Addr(Addr::EmptyList),
- ),
- _ => {
- unreachable!()
- }
- };
+ let load_state_payload = self.machine_st.store(
+ self.machine_st.deref(self.machine_st.registers[1])
+ );
- match load_state_payload {
- HeapCellValue::LoadStatePayload(payload) => {
- Loader::from_load_state_payload(self, payload);
- }
- _ => {
- // unlike in loader_from_heap_evacuable,
- // pop_load_state_payload is allowed to fail to find a
- // LoadStatePayload in the heap, as a Rust-side
- // top-level command may have failed to write the
- // load state payload back to the heap.
+ // unlike in loader_from_heap_evacuable,
+ // pop_load_state_payload is allowed to fail to find a
+ // LoadStatePayload in the heap, as a Rust-side
+ // top-level command may have failed to write the
+ // load state payload back to the heap.
+
+ read_heap_cell!(load_state_payload,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::LiveLoadState, payload) => {
+ unsafe {
+ std::ptr::drop_in_place(
+ payload.as_ptr() as *mut LiveLoadState,
+ );
+ }
+ }
+ _ => {}
+ );
}
- }
+ _ => {}
+ );
}
#[inline]
@@ -1581,98 +1742,85 @@ impl Machine {
self.load_contexts.pop();
}
- pub(crate) fn push_load_context(&mut self) {
- let stream = try_or_fail!(
- self.machine_st,
- self.machine_st.get_stream_or_alias(
- self.machine_st[temp_v!(1)],
- &self.indices.stream_aliases,
- "$push_load_context",
- 2,
- )
- );
+ pub(crate) fn push_load_context(&mut self) -> CallResult {
+ let stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("$push_load_context"),
+ 2,
+ )?;
- let path = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(2)]))
+ let path = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
);
- self.load_contexts
- .push(LoadContext::new(path.as_str(), stream));
+ self.load_contexts.push(LoadContext::new(path.as_str(), stream));
+ Ok(())
}
pub(crate) fn restore_load_state_payload(
&mut self,
- result: Result<LoadStatePayload, SessionError>,
- evacuable_h: usize,
- ) {
+ result: Result<TypedArenaPtr<LiveLoadState>, SessionError>,
+ ) -> CallResult {
match result {
- Ok(payload) => {
- self.machine_st.heap[evacuable_h] =
- HeapCellValue::LoadStatePayload(Box::new(payload));
+ Ok(_payload) => {
+ Ok(())
}
Err(e) => {
- self.throw_session_error(e, (clause_name!("load"), 1));
+ let err = self.machine_st.session_error(e);
+ let stub = functor_stub(atom!("load"), 1);
+
+ Err(self.machine_st.error_form(err, stub))
}
}
}
- pub(crate) fn scoped_clause_to_evacuable(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ pub(crate) fn scoped_clause_to_evacuable(&mut self) -> CallResult {
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
- let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3));
+ let loader = self.loader_from_heap_evacuable(temp_v!(3));
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
let result = loader.read_and_enqueue_term(temp_v!(2), compilation_target);
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn clause_to_evacuable(&mut self) {
- let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2));
- let compilation_target = loader.load_state.compilation_target.clone();
+ pub(crate) fn clause_to_evacuable(&mut self) -> CallResult {
+ let loader = self.loader_from_heap_evacuable(temp_v!(2));
+ let compilation_target = loader.payload.compilation_target;
let result = loader.read_and_enqueue_term(temp_v!(1), compilation_target);
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn conclude_load(&mut self) {
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1));
+ pub(crate) fn conclude_load(&mut self) -> CallResult {
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(1));
let compile_final_terms = || {
- if !loader.predicates.is_empty() {
+ if !loader.payload.predicates.is_empty() {
loader.compile_and_submit()?;
}
- loader.load_state.remove_module_op_exports();
- LiveTermStream::evacuate(loader)
+ loader.remove_module_op_exports();
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = compile_final_terms();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
pub(crate) fn load_context_source(&mut self) {
if let Some(load_context) = self.load_contexts.last() {
let path_str = load_context.path.to_str().unwrap();
- let path_atom = clause_name!(path_str.to_string(), self.machine_st.atom_tbl);
-
- let path_addr = Addr::Con(
- self.machine_st
- .heap
- .push(HeapCellValue::Atom(path_atom, None)),
- );
+ let path_atom = self.machine_st.atom_tbl.build_with(path_str);
- self.machine_st
- .unify(path_addr, self.machine_st[temp_v!(1)]);
+ self.machine_st.unify_atom(path_atom, self.machine_st.registers[1]);
} else {
self.machine_st.fail = true;
}
@@ -1683,17 +1831,9 @@ impl Machine {
match load_context.path.file_name() {
Some(file_name) if load_context.path.is_file() => {
let file_name_str = file_name.to_str().unwrap();
- let file_name_atom =
- clause_name!(file_name_str.to_string(), self.machine_st.atom_tbl);
+ let file_name_atom = self.machine_st.atom_tbl.build_with(file_name_str);
- let file_name_addr = Addr::Con(
- self.machine_st
- .heap
- .push(HeapCellValue::Atom(file_name_atom, None)),
- );
-
- self.machine_st
- .unify(file_name_addr, self.machine_st[temp_v!(1)]);
+ self.machine_st.unify_atom(file_name_atom, self.machine_st.registers[1]);
return;
}
_ => {
@@ -1709,18 +1849,9 @@ impl Machine {
if let Some(load_context) = self.load_contexts.last() {
if let Some(directory) = load_context.path.parent() {
let directory_str = directory.to_str().unwrap();
+ let directory_atom = self.machine_st.atom_tbl.build_with(directory_str);
- let directory_atom =
- clause_name!(directory_str.to_string(), self.machine_st.atom_tbl);
-
- let directory_addr = Addr::Con(
- self.machine_st
- .heap
- .push(HeapCellValue::Atom(directory_atom, None)),
- );
-
- self.machine_st
- .unify(directory_addr, self.machine_st[temp_v!(1)]);
+ self.machine_st.unify_atom(directory_atom, self.machine_st.registers[1]);
return;
}
}
@@ -1730,14 +1861,7 @@ impl Machine {
pub(crate) fn load_context_module(&mut self) {
if let Some(load_context) = self.load_contexts.last() {
- let module_name_addr = Addr::Con(
- self.machine_st
- .heap
- .push(HeapCellValue::Atom(load_context.module.clone(), None)),
- );
-
- self.machine_st
- .unify(module_name_addr, self.machine_st[temp_v!(1)]);
+ self.machine_st.unify_atom(load_context.module, self.machine_st.registers[1]);
} else {
self.machine_st.fail = true;
}
@@ -1745,63 +1869,57 @@ impl Machine {
pub(crate) fn load_context_stream(&mut self) {
if let Some(load_context) = self.load_contexts.last() {
- let stream_addr = Addr::Stream(
- self.machine_st
- .heap
- .push(HeapCellValue::Stream(load_context.stream.clone())),
+ self.machine_st.unify_constant(
+ UntypedArenaPtr::from(load_context.stream.as_ptr()),
+ self.machine_st.registers[1],
);
-
- self.machine_st
- .unify(stream_addr, self.machine_st[temp_v!(1)]);
} else {
self.machine_st.fail = true;
}
}
- pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) {
+ pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) -> CallResult {
let key = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]);
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(5)]))
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[5]))
);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
- let compile_assert = || {
- let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
+ let mut compile_assert = || {
+ let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
+ Loader::new(self, LiveTermStream::new(ListingSource::User));
- loader.load_state.compilation_target = compilation_target.clone();
+ loader.payload.compilation_target = compilation_target;
let head = loader.read_term_from_heap(temp_v!(1))?;
let body = loader.read_term_from_heap(temp_v!(2))?;
let asserted_clause = Term::Clause(
Cell::default(),
- clause_name!(":-"),
- vec![Box::new(head.clone()), Box::new(body.clone())],
- fetch_op_spec(clause_name!(":-"), 2, &loader.load_state.wam.indices.op_dir),
+ atom!(":-"),
+ vec![head.clone(), body.clone()],
);
// if a new predicate was just created, make it dynamic.
- loader.add_dynamic_predicate(compilation_target.clone(), key.0.clone(), key.1)?;
+ loader.add_dynamic_predicate(compilation_target, key.0, key.1)?;
- loader.load_state.incremental_compile_clause(
- key.clone(),
+ loader.incremental_compile_clause(
+ key,
asserted_clause,
- compilation_target.clone(),
+ compilation_target,
false,
append_or_prepend,
)?;
// the global clock is incremented after each assertion.
- loader.load_state.wam.machine_st.global_clock += 1;
+ LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
loader.compile_clause_clauses(
key,
@@ -1810,60 +1928,59 @@ impl Machine {
append_or_prepend,
)?;
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
match compile_assert() {
- Ok(_) => {}
+ Ok(_) => Ok(()),
Err(e) => {
- let error_pi = match append_or_prepend {
- AppendOrPrepend::Append => (clause_name!("assertz"), 1),
- AppendOrPrepend::Prepend => (clause_name!("asserta"), 1),
+ let stub = match append_or_prepend {
+ AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
+ AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
};
+ let err = self.machine_st.session_error(e);
- self.throw_session_error(e, error_pi);
+ Err(self.machine_st.error_form(err, stub))
}
}
}
- pub(crate) fn abolish_clause(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ pub(crate) fn abolish_clause(&mut self) -> CallResult {
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
let key = self
.machine_st
- .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
+ .read_predicate_key(self.machine_st.registers[2], self.machine_st.registers[3]);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
- let abolish_clause = || {
- let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
- loader.load_state.compilation_target = compilation_target;
+ let mut abolish_clause = || {
+ let mut loader: Loader<'_, LiveLoadAndMachineState<'_>>
+ = Loader::new(self, LiveTermStream::new(ListingSource::User));
- let clause_clause_compilation_target = match &loader.load_state.compilation_target {
- CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")),
- module => module.clone(),
+ loader.payload.compilation_target = compilation_target;
+
+ let clause_clause_compilation_target = match compilation_target {
+ CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
+ module => module,
};
let mut clause_clause_target_poses: Vec<_> = loader
- .load_state
- .wam
+ .wam_prelude
.indices
- .get_predicate_skeleton(&loader.load_state.compilation_target, &key)
+ .get_predicate_skeleton(&compilation_target, &key)
.map(|skeleton| {
loader
- .load_state
- .wam
+ .wam_prelude
.indices
.get_predicate_skeleton(
&clause_clause_compilation_target,
- &(clause_name!("$clause"), 2),
+ &(atom!("$clause"), 2),
)
.map(|clause_clause_skeleton| {
skeleton
@@ -1882,38 +1999,44 @@ impl Machine {
.unwrap();
loader
- .load_state
- .wam
+ .wam_prelude
.indices
- .get_predicate_skeleton_mut(&loader.load_state.compilation_target, &key)
- .map(|skeleton| skeleton.reset());
+ .remove_predicate_skeleton(&compilation_target, &key);
let code_index = loader
- .load_state
- .get_or_insert_code_index(key, loader.load_state.compilation_target.clone());
+ .get_or_insert_code_index(key, compilation_target);
- code_index.set(IndexPtr::DynamicUndefined);
+ code_index.set(IndexPtr::Undefined);
+
+ /*
+ loader
+ .wam_prelude
+ .indices
+ .get_predicate_skeleton_mut(&compilation_target, &key)
+ .map(|skeleton| skeleton.reset());
- loader.load_state.compilation_target = clause_clause_compilation_target;
+ */
+
+ loader.payload.compilation_target = clause_clause_compilation_target;
while let Some(target_pos) = clause_clause_target_poses.pop() {
- loader
- .load_state
- .retract_clause((clause_name!("$clause"), 2), target_pos);
+ loader.retract_clause((atom!("$clause"), 2), target_pos);
}
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
match abolish_clause() {
- Ok(_) => {}
+ Ok(_) => Ok(()),
Err(e) => {
- self.throw_session_error(e, (clause_name!("abolish"), 1));
+ let stub = functor_stub(atom!("abolish"), 1);
+ let err = self.machine_st.session_error(e);
+ Err(self.machine_st.error_form(err, stub))
}
}
}
- pub(crate) fn retract_clause(&mut self) {
+ pub(crate) fn retract_clause(&mut self) -> CallResult {
let key = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]);
@@ -1922,40 +2045,40 @@ impl Machine {
.machine_st
.store(self.machine_st.deref(self.machine_st[temp_v!(3)]));
- let target_pos = match Number::try_from((target_pos, &self.machine_st.heap)) {
+ let target_pos = match Number::try_from(target_pos) {
Ok(Number::Integer(n)) => n.to_usize().unwrap(),
- Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(),
+ Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
_ => unreachable!(),
};
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(4)]))
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]))
);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
- let clause_clause_compilation_target = match &compilation_target {
- CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")),
- _ => compilation_target.clone(),
+ let clause_clause_compilation_target = match compilation_target {
+ CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
+ _ => compilation_target,
};
- let retract_clause = || {
- let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
- loader.load_state.compilation_target = compilation_target;
+ let mut retract_clause = || {
+ let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
+ Loader::new(self, LiveTermStream::new(ListingSource::User));
+
+ loader.payload.compilation_target = compilation_target;
- let clause_clause_loc = loader.load_state.retract_dynamic_clause(key, target_pos);
+ let clause_clause_loc = loader.retract_dynamic_clause(key, target_pos);
// the global clock is incremented after each retraction.
- loader.load_state.wam.machine_st.global_clock += 1;
+ LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
- let target_pos = match loader.load_state.wam.indices.get_predicate_skeleton(
+ let target_pos = match loader.wam_prelude.indices.get_predicate_skeleton(
&clause_clause_compilation_target,
- &(clause_name!("$clause"), 2),
+ &(atom!("$clause"), 2),
) {
Some(skeleton) => skeleton
.target_pos_of_clause_clause_loc(clause_clause_loc)
@@ -1965,106 +2088,102 @@ impl Machine {
}
};
- loader.load_state.compilation_target = clause_clause_compilation_target;
- loader
- .load_state
- .retract_clause((clause_name!("$clause"), 2), target_pos);
+ loader.payload.compilation_target = clause_clause_compilation_target;
+ loader.retract_clause((atom!("$clause"), 2), target_pos);
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
match retract_clause() {
- Ok(_) => {}
+ Ok(_) => Ok(()),
Err(e) => {
- self.throw_session_error(e, (clause_name!("retract"), 1));
+ let stub = functor_stub(atom!("retract"), 1);
+ let err = self.machine_st.session_error(e);
+
+ Err(self.machine_st.error_form(err, stub))
}
}
}
- pub(crate) fn is_consistent_with_term_queue(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ pub(crate) fn is_consistent_with_term_queue(&mut self) -> CallResult {
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
let key = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
- let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(4));
- loader.load_state.wam.machine_st.fail = (!loader.predicates.is_empty()
- && loader.predicates.compilation_target != compilation_target)
- || !key.is_consistent(&loader.predicates);
+ LiveLoadAndMachineState::machine_st(&mut loader.payload).fail =
+ (!loader.payload.predicates.is_empty()
+ && loader.payload.predicates.compilation_target != compilation_target)
+ || !key.is_consistent(&loader.payload.predicates);
- let result = LiveTermStream::evacuate(loader);
- self.restore_load_state_payload(result, evacuable_h);
+ let result = LiveLoadAndMachineState::evacuate(loader);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn flush_term_queue(&mut self) {
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1));
+ pub(crate) fn flush_term_queue(&mut self) -> CallResult {
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(1));
let flush_term_queue = || {
- if !loader.predicates.is_empty() {
+ if !loader.payload.predicates.is_empty() {
loader.compile_and_submit()?;
}
- LiveTermStream::evacuate(loader)
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = flush_term_queue();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn remove_module_exports(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ pub(crate) fn remove_module_exports(&mut self) -> CallResult {
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
let remove_module_exports = || {
- loader.load_state.remove_module_exports(module_name);
- LiveTermStream::evacuate(loader)
+ loader.remove_module_exports(module_name);
+ LiveLoadAndMachineState::evacuate(loader)
};
let result = remove_module_exports();
- self.restore_load_state_payload(result, evacuable_h);
+ self.restore_load_state_payload(result)
}
- pub(crate) fn add_non_counted_backtracking(&mut self) {
+ pub(crate) fn add_non_counted_backtracking(&mut self) -> CallResult {
let key = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]);
- let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3));
- loader.non_counted_bt_preds.insert(key);
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
+ loader.payload.non_counted_bt_preds.insert(key);
- let result = LiveTermStream::evacuate(loader);
- self.restore_load_state_payload(result, evacuable_h);
+ let result = LiveLoadAndMachineState::evacuate(loader);
+ self.restore_load_state_payload(result)
}
pub(crate) fn meta_predicate_property(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
let (predicate_name, arity) = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
@@ -2073,30 +2192,23 @@ impl Machine {
.get_meta_predicate_spec(predicate_name, arity, &compilation_target)
{
Some(meta_specs) => {
- let list_loc = self
- .machine_st
- .heap
- .to_list(meta_specs.iter().map(|meta_spec| match meta_spec {
- MetaSpec::Minus => HeapCellValue::Atom(clause_name!("+"), None),
- MetaSpec::Plus => HeapCellValue::Atom(clause_name!("-"), None),
- MetaSpec::Either => HeapCellValue::Atom(clause_name!("?"), None),
+ let list_loc = iter_to_heap_list(
+ &mut self.machine_st.heap,
+ meta_specs.iter().map(|meta_spec| match meta_spec {
+ MetaSpec::Minus => atom_as_cell!(atom!("+")),
+ MetaSpec::Plus => atom_as_cell!(atom!("-")),
+ MetaSpec::Either => atom_as_cell!(atom!("?")),
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
- HeapCellValue::Addr(Addr::Usize(*arg_num))
+ fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
}
}));
- let heap_loc = self.machine_st.heap.push(HeapCellValue::NamedStr(
- 1,
- clause_name!("meta_predicate"),
- None,
- ));
+ let heap_loc = self.machine_st.heap.len();
- self.machine_st
- .heap
- .push(HeapCellValue::Addr(Addr::HeapCell(list_loc)));
+ self.machine_st.heap.push(atom_as_cell!(atom!("meta_predicate"), 1));
+ self.machine_st.heap.push(heap_loc_as_cell!(list_loc));
- self.machine_st
- .unify(Addr::HeapCell(heap_loc), self.machine_st[temp_v!(4)]);
+ unify!(self.machine_st, str_loc_as_cell!(heap_loc), self.machine_st.registers[4]);
}
None => {
self.machine_st.fail = true;
@@ -2105,18 +2217,16 @@ impl Machine {
}
pub(crate) fn dynamic_property(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
let key = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
@@ -2134,18 +2244,16 @@ impl Machine {
}
pub(crate) fn multifile_property(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
let key = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
@@ -2163,18 +2271,16 @@ impl Machine {
}
pub(crate) fn discontiguous_property(&mut self) {
- let module_name = atom_from!(
- self.machine_st,
- self.machine_st
- .store(self.machine_st.deref(self.machine_st[temp_v!(1)]))
+ let module_name = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
);
let key = self
.machine_st
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
- let compilation_target = match module_name.as_str() {
- "user" => CompilationTarget::User,
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(module_name),
};
@@ -2194,25 +2300,15 @@ impl Machine {
pub(crate) fn builtin_property(&mut self) {
let key = self
.machine_st
- .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]);
+ .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
- match ClauseType::from(key.0, key.1, None) {
- ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN => {
+ match ClauseType::from(key.0, key.1) {
+ ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN(_) => {
return;
}
- ClauseType::Named(ref name, arity, _) => {
- if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) {
- self.machine_st.fail = !module.code_dir.contains_key(&(name.clone(), arity));
-
- return;
- }
- }
- ClauseType::Op(ref name, ref op_desc, _) => {
- if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) {
- self.machine_st.fail = !module
- .code_dir
- .contains_key(&(name.clone(), op_desc.arity()));
-
+ ClauseType::Named(arity, name, _) => {
+ if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
+ self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
return;
}
}
@@ -2223,63 +2319,24 @@ impl Machine {
}
}
-impl<'a> Loader<'a, LiveTermStream> {
- pub(super) fn to_load_state_payload(mut self) -> LoadStatePayload {
- LoadStatePayload {
- term_stream: mem::replace(
- &mut self.term_stream,
- LiveTermStream::new(ListingSource::User),
- ),
- non_counted_bt_preds: mem::replace(&mut self.non_counted_bt_preds, IndexSet::new()),
- compilation_target: self.load_state.compilation_target.take(),
- retraction_info: mem::replace(
- &mut self.load_state.retraction_info,
- RetractionInfo::new(self.load_state.wam.code_repo.code.len()),
- ),
- predicates: self.predicates.take(),
- clause_clauses: mem::replace(&mut self.clause_clauses, vec![]),
- module_op_exports: mem::replace(&mut self.load_state.module_op_exports, vec![]),
- }
- }
-
- pub(super) fn from_load_state_payload(
- wam: &'a mut Machine,
- mut payload: Box<LoadStatePayload>,
- ) -> Self {
- Loader {
- term_stream: mem::replace(
- &mut payload.term_stream,
- LiveTermStream::new(ListingSource::User),
- ),
- non_counted_bt_preds: mem::replace(&mut payload.non_counted_bt_preds, IndexSet::new()),
- clause_clauses: mem::replace(&mut payload.clause_clauses, vec![]),
- predicates: payload.predicates.take(),
- load_state: LoadState {
- compilation_target: payload.compilation_target.take(),
- module_op_exports: mem::replace(&mut payload.module_op_exports, vec![]),
- retraction_info: mem::replace(&mut payload.retraction_info, RetractionInfo::new(0)),
- wam,
- },
- }
- }
-
+impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
fn read_and_enqueue_term(
mut self,
term_reg: RegType,
compilation_target: CompilationTarget,
- ) -> Result<LoadStatePayload, SessionError> {
- if self.predicates.compilation_target != compilation_target {
- if !self.predicates.is_empty() {
+ ) -> Result<TypedArenaPtr<LoadStatePayload<LiveTermStream>>, SessionError> {
+ if self.payload.predicates.compilation_target != compilation_target {
+ if !self.payload.predicates.is_empty() {
self.compile_and_submit()?;
}
- self.predicates.compilation_target = compilation_target;
+ self.payload.predicates.compilation_target = compilation_target;
}
let term = self.read_term_from_heap(term_reg)?;
self.add_clause_clause_if_dynamic(&term)?;
- self.term_stream.term_queue.push_back(term);
+ self.payload.term_stream.term_queue.push_back(term);
self.load()
}
diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs
index fbfb1bcf..889eb7ee 100644
--- a/src/machine/machine_errors.rs
+++ b/src/machine/machine_errors.rs
@@ -1,17 +1,15 @@
-use prolog_parser::ast::*;
-use prolog_parser::{clause_name, temp_v};
+use crate::atom_table::*;
+use crate::parser::ast::*;
-use crate::forms::{ModuleSource, Number}; //, PredicateKey};
+use crate::forms::*;
use crate::machine::heap::*;
use crate::machine::loader::CompilationTarget;
-use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
-use crate::machine::PredicateKey;
-use crate::rug::Integer;
+use crate::machine::system_calls::BrentAlgState;
+use crate::types::*;
-use std::rc::Rc;
-
-pub(crate) type MachineStub = Vec<HeapCellValue>;
+pub type MachineStub = Vec<HeapCellValue>;
+pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
#[derive(Debug, Clone, Copy)]
enum ErrorProvenance {
@@ -26,13 +24,64 @@ pub(crate) struct MachineError {
from: ErrorProvenance,
}
+// from 7.12.2 b) of 13211-1:1995
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum ValidType {
+ Atom,
+ Atomic,
+ // Boolean,
+ Byte,
+ Callable,
+ Character,
+ Compound,
+ Evaluable,
+ Float,
+ InByte,
+ InCharacter,
+ Integer,
+ List,
+ #[allow(unused)] Number,
+ Pair,
+ // PredicateIndicator,
+ // Variable
+ TcpListener,
+}
+
+impl ValidType {
+ pub(crate) fn as_atom(self) -> Atom {
+ match self {
+ ValidType::Atom => atom!("atom"),
+ ValidType::Atomic => atom!("atomic"),
+ // ValidType::Boolean => atom!("boolean"),
+ ValidType::Byte => atom!("byte"),
+ ValidType::Callable => atom!("callable"),
+ ValidType::Character => atom!("character"),
+ ValidType::Compound => atom!("compound"),
+ ValidType::Evaluable => atom!("evaluable"),
+ ValidType::Float => atom!("float"),
+ ValidType::InByte => atom!("in_byte"),
+ ValidType::InCharacter => atom!("in_character"),
+ ValidType::Integer => atom!("integer"),
+ ValidType::List => atom!("list"),
+ ValidType::Number => atom!("number"),
+ ValidType::Pair => atom!("pair"),
+ // ValidType::PredicateIndicator => atom!("predicate_indicator"),
+ // ValidType::Variable => atom!("variable")
+ ValidType::TcpListener => atom!("tcp_listener"),
+ }
+ }
+}
+
pub(crate) trait TypeError {
- fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
+ fn type_error(self, machine_st: &mut MachineState, 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)]);
+impl TypeError for HeapCellValue {
+ fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
+ let stub = functor!(
+ atom!("type_error"),
+ [atom(valid_type.as_atom()), cell(self)]
+ );
MachineError {
stub,
@@ -42,21 +91,29 @@ impl TypeError for Addr {
}
}
-impl TypeError for HeapCellValue {
- fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
- let stub = functor!("type_error", [atom(valid_type.as_str()), value(self)]);
+impl TypeError for MachineStub {
+ fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
+ let stub = functor!(
+ atom!("type_error"),
+ [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
+ [self]
+ );
MachineError {
stub,
location: None,
- from: ErrorProvenance::Received,
+ from: ErrorProvenance::Constructed,
}
}
}
-impl TypeError for MachineStub {
- fn type_error(self, h: usize, valid_type: ValidType) -> MachineError {
- let stub = functor!("type_error", [atom(valid_type.as_str()), aux(h, 0)], [self]);
+impl TypeError for FunctorStub {
+ fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
+ let stub = functor!(
+ atom!("type_error"),
+ [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
+ [self]
+ );
MachineError {
stub,
@@ -67,8 +124,14 @@ impl TypeError for MachineStub {
}
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)]);
+ fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
+ let stub = functor!(
+ atom!("type_error"),
+ [
+ atom(valid_type.as_atom()),
+ number(&mut machine_st.arena, self)
+ ]
+ );
MachineError {
stub,
@@ -79,14 +142,24 @@ impl TypeError for Number {
}
pub(crate) 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 {
+ fn permission_error(
+ self,
+ machine_st: &mut MachineState,
+ index_atom: Atom,
+ perm: Permission,
+ ) -> MachineError;
+}
+
+impl PermissionError for HeapCellValue {
+ fn permission_error(
+ self,
+ _machine_st: &mut MachineState,
+ index_atom: Atom,
+ perm: Permission,
+ ) -> MachineError {
let stub = functor!(
- "permission_error",
- [atom(perm.as_str()), atom(index_str), addr(self)]
+ atom!("permission_error"),
+ [atom(perm.as_atom()), atom(index_atom), cell(self)]
);
MachineError {
@@ -98,10 +171,19 @@ impl PermissionError for Addr {
}
impl PermissionError for MachineStub {
- fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError {
+ fn permission_error(
+ self,
+ machine_st: &mut MachineState,
+ index_atom: Atom,
+ perm: Permission,
+ ) -> MachineError {
let stub = functor!(
- "permission_error",
- [atom(perm.as_str()), atom(index_str), aux(h, 0)],
+ atom!("permission_error"),
+ [
+ atom(perm.as_atom()),
+ atom(index_atom),
+ str(machine_st.heap.len(), 0)
+ ],
[self]
);
@@ -114,12 +196,12 @@ impl PermissionError for MachineStub {
}
pub(super) trait DomainError {
- fn domain_error(self, error: DomainErrorType) -> MachineError;
+ fn domain_error(self, machine_st: &mut MachineState, 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)]);
+impl DomainError for HeapCellValue {
+ fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
+ let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]);
MachineError {
stub,
@@ -130,8 +212,11 @@ impl DomainError for Addr {
}
impl DomainError for Number {
- fn domain_error(self, error: DomainErrorType) -> MachineError {
- let stub = functor!("domain_error", [atom(error.as_str()), number(self)]);
+ fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
+ let stub = functor!(
+ atom!("domain_error"),
+ [atom(error.as_atom()), number(&mut machine_st.arena, self)]
+ );
MachineError {
stub,
@@ -141,18 +226,19 @@ impl DomainError for Number {
}
}
-impl MachineError {
- pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
- functor!(
- "/",
- SharedOpDesc::new(400, YFX),
- [clause_name(name), integer(arity)]
- )
- }
+pub(super) type FunctorStub = [HeapCellValue; 3];
+
+#[inline(always)]
+pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub {
+ [atom_as_cell!(atom!("/"), 2),
+ atom_as_cell!(name),
+ fixnum_as_cell!(Fixnum::build_with(arity as i64))]
+}
+impl MachineState {
#[inline]
- pub(super) fn interrupt_error() -> Self {
- let stub = functor!("$interrupt_thrown");
+ pub(super) fn interrupt_error(&mut self) -> MachineError {
+ let stub = functor!(atom!("$interrupt_thrown"));
MachineError {
stub,
@@ -161,8 +247,8 @@ impl MachineError {
}
}
- pub(super) fn evaluation_error(eval_error: EvalError) -> Self {
- let stub = functor!("evaluation_error", [atom(eval_error.as_str())]);
+ pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError {
+ let stub = functor!(atom!("evaluation_error"), [atom(eval_error.as_atom())]);
MachineError {
stub,
@@ -171,30 +257,26 @@ impl MachineError {
}
}
- pub(super) fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
- culprit.type_error(h, valid_type)
+ pub(super) fn type_error<T: TypeError>(
+ &mut self,
+ valid_type: ValidType,
+ culprit: T,
+ ) -> MachineError {
+ culprit.type_error(self, valid_type)
}
pub(super) fn module_resolution_error(
- h: usize,
- mod_name: ClauseName,
- name: ClauseName,
+ &mut self,
+ mod_name: Atom,
+ name: Atom,
arity: usize,
- ) -> Self {
- let res_stub = functor!(
- ":",
- SharedOpDesc::new(600, XFY),
- [clause_name(mod_name), clause_name(name)]
- );
+ ) -> MachineError {
+ let h = self.heap.len();
- let ind_stub = functor!(
- "/",
- SharedOpDesc::new(400, YFX),
- [aux(h + 2, 0), integer(arity)],
- [res_stub]
- );
+ let res_stub = functor!(atom!(":"), [atom(mod_name), atom(name)]);
+ let ind_stub = functor!(atom!("/"), [str(h + 2, 0), fixnum(arity)], [res_stub]);
- let stub = functor!("evaluation_error", [aux(h, 0)], [ind_stub]);
+ let stub = functor!(atom!("evaluation_error"), [str(h, 0)], [ind_stub]);
MachineError {
stub,
@@ -203,10 +285,13 @@ impl MachineError {
}
}
- pub(super) fn existence_error(h: usize, err: ExistenceError) -> Self {
+ pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError {
match err {
ExistenceError::Module(name) => {
- let stub = functor!("existence_error", [atom("source_sink"), clause_name(name)]);
+ let stub = functor!(
+ atom!("existence_error"),
+ [atom(atom!("source_sink")), atom(name)]
+ );
MachineError {
stub,
@@ -215,13 +300,13 @@ impl MachineError {
}
}
ExistenceError::Procedure(name, arity) => {
- let culprit = functor!(
- "/",
- SharedOpDesc::new(400, YFX),
- [clause_name(name), integer(arity)]
- );
+ let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]);
- let stub = functor!("existence_error", [atom("procedure"), aux(h, 0)], [culprit]);
+ let stub = functor!(
+ atom!("existence_error"),
+ [atom(atom!("procedure")), str(self.heap.len(), 0)],
+ [culprit]
+ );
MachineError {
stub,
@@ -233,8 +318,8 @@ impl MachineError {
let source_stub = source.as_functor_stub();
let stub = functor!(
- "existence_error",
- [atom("source_sink"), aux(h, 0)],
+ atom!("existence_error"),
+ [atom(atom!("source_sink")), str(self.heap.len(), 0)],
[source_stub]
);
@@ -245,7 +330,10 @@ impl MachineError {
}
}
ExistenceError::SourceSink(culprit) => {
- let stub = functor!("existence_error", [atom("source_sink"), addr(culprit)]);
+ let stub = functor!(
+ atom!("existence_error"),
+ [atom(atom!("source_sink")), cell(culprit)]
+ );
MachineError {
stub,
@@ -254,7 +342,10 @@ impl MachineError {
}
}
ExistenceError::Stream(culprit) => {
- let stub = functor!("existence_error", [atom("stream"), addr(culprit)]);
+ let stub = functor!(
+ atom!("existence_error"),
+ [atom(atom!("stream")), cell(culprit)]
+ );
MachineError {
stub,
@@ -266,36 +357,41 @@ impl MachineError {
}
pub(super) fn permission_error<T: PermissionError>(
- h: usize,
+ &mut self,
err: Permission,
- index_str: &'static str,
+ index_atom: Atom,
culprit: T,
- ) -> Self {
- culprit.permission_error(h, index_str, err)
+ ) -> MachineError {
+ culprit.permission_error(self, index_atom, err)
+ }
+
+ pub(super) fn evaluable_error(&mut self, name: Atom, arity: usize) -> MachineError {
+ let evaluable_stub = functor_stub(name, arity);
+ evaluable_stub.type_error(self, ValidType::Evaluable)
}
- fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
+ fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
match err {
- ArithmeticError::UninstantiatedVar => Self::instantiation_error(),
- ArithmeticError::NonEvaluableFunctor(name, arity) => {
- let culprit = functor!(
- "/",
- SharedOpDesc::new(400, YFX),
- [constant(h, &name), integer(arity)]
- );
+ ArithmeticError::UninstantiatedVar => self.instantiation_error(),
+ ArithmeticError::NonEvaluableFunctor(literal, arity) => {
+ let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]);
- Self::type_error(h, ValidType::Evaluable, culprit)
+ self.type_error(ValidType::Evaluable, culprit)
}
}
}
#[inline]
- pub(super) fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
- culprit.domain_error(error)
+ pub(super) fn domain_error<T: DomainError>(
+ &mut self,
+ error: DomainErrorType,
+ culprit: T,
+ ) -> MachineError {
+ culprit.domain_error(self, error)
}
- pub(super) fn instantiation_error() -> Self {
- let stub = functor!("instantiation_error");
+ pub(super) fn instantiation_error(&mut self) -> MachineError {
+ let stub = functor!(atom!("instantiation_error"));
MachineError {
stub,
@@ -304,81 +400,87 @@ impl MachineError {
}
}
- pub(super) fn session_error(h: usize, err: SessionError) -> Self {
+ pub(super) fn session_error(&mut self, err: SessionError) -> MachineError {
match err {
- // SessionError::CannotOverwriteBuiltIn(pred_str) |
- /*
- SessionError::CannotOverwriteImport(pred_str) => {
- Self::permission_error(
- h,
+ SessionError::CannotOverwriteBuiltIn(key) => {
+ // SessionError::CannotOverwriteImport(pred_atom) => {
+ self.permission_error(
Permission::Modify,
- "private_procedure",
- functor!(clause_name(pred_str)),
+ atom!("private_procedure"),
+ functor_stub(key.0, key.1).into_iter().collect::<MachineStub>(),
)
}
- */
- SessionError::ExistenceError(err) => Self::existence_error(h, err),
+ SessionError::ExistenceError(err) => self.existence_error(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::ModuleCannotImportSelf(module_name) => Self::permission_error(
- h,
- Permission::Modify,
- "module",
- functor!("module_cannot_import_self", [clause_name(module_name)]),
- ),
- SessionError::NamelessEntry => Self::permission_error(
- h,
- Permission::Create,
- "static_procedure",
- functor!("nameless_procedure"),
- ),
+ SessionError::ModuleDoesNotContainExport(..) => {
+ let error_atom = atom!("module_does_not_contain_claimed_export");
+
+ self.permission_error(
+ Permission::Access,
+ atom!("private_procedure"),
+ functor!(error_atom),
+ )
+ }
+ SessionError::ModuleCannotImportSelf(module_name) => {
+ let error_atom = atom!("module_cannot_import_self");
+
+ self.permission_error(
+ Permission::Modify,
+ atom!("module"),
+ functor!(error_atom, [atom(module_name)]),
+ )
+ }
+ SessionError::NamelessEntry => {
+ let error_atom = atom!("nameless_procedure");
+ self.permission_error(Permission::Create, atom!("static_procedure"), functor!(error_atom))
+ }
SessionError::OpIsInfixAndPostFix(op) => {
- Self::permission_error(h, Permission::Create, "operator", functor!(clause_name(op)))
+ self.permission_error(Permission::Create, atom!("operator"), functor!(op))
}
- SessionError::CompilationError(err) => Self::syntax_error(h, err),
+ SessionError::CompilationError(err) => self.syntax_error(err),
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
- let functor_stub = Self::functor_stub(key.0, key.1);
+ let functor_stub = functor_stub(key.0, key.1);
+
let stub = functor!(
- ":",
- SharedOpDesc::new(600, XFY),
- [clause_name(compilation_target.module_name()), aux(h + 4, 0)],
+ atom!(":"),
+ [
+ atom(compilation_target.module_name()),
+ str(self.heap.len() + 4, 0)
+ ],
[functor_stub]
);
- Self::permission_error(
- h,
+ self.permission_error(
Permission::Modify,
- "not_declared_multifile_or_discontiguous",
+ atom!("not_declared_multifile_or_discontiguous"),
stub,
)
}
- SessionError::QueryCannotBeDefinedAsFact => Self::permission_error(
- h,
- Permission::Create,
- "static_procedure",
- functor!("query_cannot_be_defined_as_fact"),
- ),
+ SessionError::QueryCannotBeDefinedAsFact => {
+ let error_atom = atom!("query_cannot_be_defined_as_fact");
+
+ self.permission_error(
+ Permission::Create,
+ atom!("static_procedure"),
+ functor!(error_atom),
+ )
+ }
}
}
- pub(super) fn syntax_error<E: Into<CompilationError>>(h: usize, err: E) -> Self {
+ pub(super) fn syntax_error<E: Into<CompilationError>>(&mut self, err: E) -> MachineError {
let err = err.into();
if let CompilationError::Arithmetic(err) = err {
- return Self::arithmetic_error(h, err);
+ return self.arithmetic_error(err);
}
let location = err.line_and_col_num();
- let stub = err.as_functor(h);
+ let stub = err.as_functor();
- let stub = functor!("syntax_error", [aux(h, 0)], [stub]);
+ let stub = functor!(atom!("syntax_error"), [str(self.heap.len(), 0)], [stub]);
MachineError {
stub,
@@ -387,8 +489,8 @@ impl MachineError {
}
}
- pub(super) fn representation_error(flag: RepFlag) -> Self {
- let stub = functor!("representation_error", [atom(flag.as_str())]);
+ pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError {
+ let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]);
MachineError {
stub,
@@ -397,13 +499,65 @@ impl MachineError {
}
}
+ pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
+ let h = self.heap.len();
+ let location = err.location;
+ let stub_addition_len = if err.len() == 1 {
+ 0 // if err contains 1 cell, it can be inlined at stub[1].
+ } else {
+ err.len()
+ };
+
+ let mut stub = vec![
+ atom_as_cell!(atom!("error"), 2),
+ str_loc_as_cell!(h + 3),
+ str_loc_as_cell!(h + 3 + stub_addition_len),
+ ];
+
+ if stub_addition_len > 0 {
+ stub.extend(err.into_iter(3));
+ } else {
+ stub[1] = err.stub[0];
+ }
+
+ if let Some((line_num, _)) = location {
+ stub.push(atom_as_cell!(atom!(":"), 2));
+ stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
+ stub.push(integer_as_cell!(Number::arena_from(
+ line_num,
+ &mut self.arena
+ )));
+ }
+
+ stub.extend(src.iter());
+ stub
+ }
+
+ pub(super) fn throw_exception(&mut self, err: MachineStub) {
+ let h = self.heap.len();
+ let err_len = err.len();
+
+ self.ball.boundary = 0;
+ self.ball.stub.truncate(0);
+
+ self.heap.extend(err.into_iter());
+
+ self.registers[1] = if err_len == 1 {
+ heap_loc_as_cell!(h)
+ } else {
+ str_loc_as_cell!(h)
+ };
+
+ self.set_ball();
+ self.unwind_stack();
+ }
+}
+
+impl MachineError {
fn into_iter(self, offset: usize) -> Box<dyn Iterator<Item = HeapCellValue>> {
match self.from {
ErrorProvenance::Constructed => {
- Box::new(self.stub.into_iter().map(move |hcv| match hcv {
- HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr + offset),
- hcv => hcv,
- }))
+ Box::new(self.stub.into_iter().map(move |hcv| hcv + offset))
}
ErrorProvenance::Received => Box::new(self.stub.into_iter()),
}
@@ -415,7 +569,7 @@ impl MachineError {
}
#[derive(Debug)]
-pub(crate) enum CompilationError {
+pub enum CompilationError {
Arithmetic(ArithmeticError),
ParserError(ParserError),
// BadPendingByte,
@@ -433,7 +587,7 @@ pub(crate) enum CompilationError {
InvalidModuleExport,
InvalidRuleHead,
InvalidUseModuleDecl,
- InvalidModuleResolution(ClauseName),
+ InvalidModuleResolution(Atom),
UnreadableTerm,
}
@@ -459,34 +613,60 @@ impl CompilationError {
}
}
- pub(crate) fn as_functor(&self, _h: usize) -> MachineStub {
+ pub(crate) fn as_functor(&self) -> MachineStub {
match self {
- &CompilationError::Arithmetic(..) => functor!("arithmetic_error"),
+ &CompilationError::Arithmetic(..) => {
+ functor!(atom!("arithmetic_error"))
+ }
// &CompilationError::BadPendingByte =>
- // functor!("bad_pending_byte"),
- &CompilationError::CannotParseCyclicTerm => functor!("cannot_parse_cyclic_term"),
+ // functor!(atom_from_ss!("bad_pending_byte"), atom_tbl),
+ &CompilationError::CannotParseCyclicTerm => {
+ functor!(atom!("cannot_parse_cyclic_term"))
+ }
// &CompilationError::ExpandedTermsListNotAList =>
- // functor!("expanded_terms_list_is_not_a_list"),
- &CompilationError::ExpectedRel => functor!("expected_relation"),
+ // functor!(atom_tbl.build_with_static_str("expanded_terms_list_is_not_a_list")),
+ &CompilationError::ExpectedRel => {
+ functor!(atom!("expected_relation"))
+ }
// &CompilationError::ExpectedTopLevelTerm =>
- // functor!("expected_atom_or_cons_or_clause"),
- &CompilationError::InadmissibleFact => functor!("inadmissible_fact"),
- &CompilationError::InadmissibleQueryTerm => functor!("inadmissible_query_term"),
- &CompilationError::InconsistentEntry => functor!("inconsistent_entry"),
+ // functor!(atom_from_ss!("expected_atom_or_cons_or_clause"), atom_tbl),
+ &CompilationError::InadmissibleFact => {
+ functor!(atom!("inadmissible_fact"))
+ }
+ &CompilationError::InadmissibleQueryTerm => {
+ functor!(atom!("inadmissible_query_term"))
+ }
+ &CompilationError::InconsistentEntry => {
+ functor!(atom!("inconsistent_entry"))
+ }
// &CompilationError::InvalidDoubleQuotesDecl =>
- // functor!("invalid_double_quotes_declaration"),
+ // functor!(atom_from_ss!("invalid_double_quotes_declaration"), atom_tbl),
// &CompilationError::InvalidHook =>
- // functor!("invalid_hook"),
- &CompilationError::InvalidMetaPredicateDecl => functor!("invalid_meta_predicate_decl"),
- &CompilationError::InvalidModuleDecl => functor!("invalid_module_declaration"),
- &CompilationError::InvalidModuleExport => functor!("invalid_module_export"),
+ // functor!(atom_from_ss!("invalid_hook"), atom_tbl),
+ &CompilationError::InvalidMetaPredicateDecl => {
+ functor!(atom!("invalid_meta_predicate_decl"))
+ }
+ &CompilationError::InvalidModuleDecl => {
+ functor!(atom!("invalid_module_declaration"))
+ }
+ &CompilationError::InvalidModuleExport => {
+ functor!(atom!("invalid_module_export"))
+ }
&CompilationError::InvalidModuleResolution(ref module_name) => {
- functor!("no_such_module", [clause_name(module_name.clone())])
+ functor!(atom!("no_such_module"), [atom(module_name)])
+ }
+ &CompilationError::InvalidRuleHead => {
+ functor!(atom!("invalid_head_of_rule"))
+ }
+ &CompilationError::InvalidUseModuleDecl => {
+ functor!(atom!("invalid_use_module_declaration"))
+ }
+ &CompilationError::ParserError(ref err) => {
+ functor!(err.as_atom())
+ }
+ &CompilationError::UnreadableTerm => {
+ functor!(atom!("unreadable_term"))
}
- &CompilationError::InvalidRuleHead => functor!("invalid_head_of_rule"),
- &CompilationError::InvalidUseModuleDecl => functor!("invalid_use_module_declaration"),
- &CompilationError::ParserError(ref err) => functor!(err.as_str()),
- &CompilationError::UnreadableTerm => functor!("unreadable_term"),
}
}
}
@@ -504,63 +684,15 @@ pub(crate) enum Permission {
impl Permission {
#[inline]
- pub(crate) fn as_str(self) -> &'static str {
+ pub(crate) fn as_atom(self) -> Atom {
match self {
- Permission::Access => "access",
- Permission::Create => "create",
- Permission::InputStream => "input",
- Permission::Modify => "modify",
- Permission::Open => "open",
- Permission::OutputStream => "output",
- Permission::Reposition => "reposition",
- }
- }
-}
-
-// from 7.12.2 b) of 13211-1:1995
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum ValidType {
- Atom,
- Atomic,
- // Boolean,
- Byte,
- Callable,
- Character,
- Compound,
- Evaluable,
- Float,
- InByte,
- InCharacter,
- Integer,
- List,
- Number,
- Pair,
- // PredicateIndicator,
- // Variable
- TcpListener,
-}
-
-impl ValidType {
- pub(crate) fn as_str(self) -> &'static str {
- match self {
- ValidType::Atom => "atom",
- ValidType::Atomic => "atomic",
- // ValidType::Boolean => "boolean",
- ValidType::Byte => "byte",
- ValidType::Callable => "callable",
- ValidType::Character => "character",
- ValidType::Compound => "compound",
- ValidType::Evaluable => "evaluable",
- ValidType::Float => "float",
- ValidType::InByte => "in_byte",
- ValidType::InCharacter => "in_character",
- ValidType::Integer => "integer",
- ValidType::List => "list",
- ValidType::Number => "number",
- ValidType::Pair => "pair",
- // ValidType::PredicateIndicator => "predicate_indicator",
- // ValidType::Variable => "variable"
- ValidType::TcpListener => "tcp_listener",
+ Permission::Access => atom!("access"),
+ Permission::Create => atom!("create"),
+ Permission::InputStream => atom!("input"),
+ Permission::Modify => atom!("modify"),
+ Permission::Open => atom!("open"),
+ Permission::OutputStream => atom!("output"),
+ Permission::Reposition => atom!("reposition"),
}
}
}
@@ -576,14 +708,14 @@ pub(crate) enum DomainErrorType {
}
impl DomainErrorType {
- pub(crate) fn as_str(self) -> &'static str {
+ pub(crate) fn as_atom(self) -> Atom {
match self {
- DomainErrorType::IOMode => "io_mode",
- DomainErrorType::NotLessThanZero => "not_less_than_zero",
- DomainErrorType::Order => "order",
- DomainErrorType::SourceSink => "source_sink",
- DomainErrorType::Stream => "stream",
- DomainErrorType::StreamOrAlias => "stream_or_alias",
+ DomainErrorType::IOMode => atom!("io_mode"),
+ DomainErrorType::NotLessThanZero => atom!("not_less_than_zero"),
+ DomainErrorType::Order => atom!("order"),
+ DomainErrorType::SourceSink => atom!("source_sink"),
+ DomainErrorType::Stream => atom!("stream"),
+ DomainErrorType::StreamOrAlias => atom!("stream_or_alias"),
}
}
}
@@ -601,22 +733,22 @@ pub(crate) enum RepFlag {
}
impl RepFlag {
- pub(crate) fn as_str(self) -> &'static str {
+ pub(crate) fn as_atom(self) -> Atom {
match self {
- RepFlag::Character => "character",
- RepFlag::CharacterCode => "character_code",
- RepFlag::InCharacterCode => "in_character_code",
- RepFlag::MaxArity => "max_arity",
- RepFlag::Term => "term",
- // RepFlag::MaxInteger => "max_integer",
- // RepFlag::MinInteger => "min_integer"
+ RepFlag::Character => atom!("character"),
+ RepFlag::CharacterCode => atom!("character_code"),
+ RepFlag::InCharacterCode => atom!("in_character_code"),
+ RepFlag::MaxArity => atom!("max_arity"),
+ RepFlag::Term => atom!("term"),
+ // RepFlag::MaxInteger => atom!("max_integer"),
+ // RepFlag::MinInteger => atom!("min_integer")
}
}
}
// from 7.12.2 g) of 13211-1:1995
#[derive(Debug, Clone, Copy)]
-pub(crate) enum EvalError {
+pub enum EvalError {
FloatOverflow,
Undefined,
// Underflow,
@@ -624,93 +756,109 @@ pub(crate) enum EvalError {
}
impl EvalError {
- pub(crate) fn as_str(self) -> &'static str {
+ pub(crate) fn as_atom(self) -> Atom {
match self {
- EvalError::FloatOverflow => "float_overflow",
- EvalError::Undefined => "undefined",
- // EvalError::FloatUnderflow => "underflow",
- EvalError::ZeroDivisor => "zero_divisor",
+ EvalError::FloatOverflow => atom!("float_overflow"),
+ EvalError::Undefined => atom!("undefined"),
+ // EvalError::FloatUnderflow => atom!("underflow"),
+ EvalError::ZeroDivisor => atom!("zero_divisor"),
}
}
}
// used by '$skip_max_list'.
-#[derive(Debug, Clone, Copy)]
-pub(super) enum CycleSearchResult {
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum CycleSearchResult {
+ Cyclic(usize),
EmptyList,
- NotList,
+ NotList(usize, HeapCellValue), // the list length until the second argument in the heap
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length.
- PStrLocation(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).
+ PStrLocation(usize, usize), // list length (up to max), the heap address of the PStrOffset
+ UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address).
+ UntouchedCStr(Atom, usize),
}
impl MachineState {
// see 8.4.3 of Draft Technical Corrigendum 2.
- 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()));
+ pub(super) fn check_sort_errors(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("sort"), 2);
- match self.detect_cycles(list.clone()) {
+ let list = self.store(self.deref(self.registers[1]));
+ let sorted = self.registers[2];
+
+ match BrentAlgState::detect_cycles(&self.heap, list) {
CycleSearchResult::PartialList(..) => {
- return Err(self.error_form(MachineError::instantiation_error(), stub))
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub_gen()))
}
- CycleSearchResult::NotList => {
- return Err(
- self.error_form(MachineError::type_error(0, ValidType::List, list), stub)
- )
+ CycleSearchResult::NotList(..) => {
+ let err = self.type_error(ValidType::List, list);
+ return Err(self.error_form(err, stub_gen()));
}
_ => {}
};
- match self.detect_cycles(sorted.clone()) {
- CycleSearchResult::NotList if !sorted.is_ref() => {
- Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub))
+ match BrentAlgState::detect_cycles(&self.heap, sorted) {
+ CycleSearchResult::NotList(..) if !sorted.is_var() => {
+ let err = self.type_error(ValidType::List, sorted);
+ Err(self.error_form(err, stub_gen()))
}
_ => Ok(()),
}
}
- fn check_for_list_pairs(&self, list: Addr) -> CallResult {
- let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
+ fn check_for_list_pairs(&mut self, mut list: HeapCellValue) -> CallResult {
+ let stub_gen = || functor_stub(atom!("keysort"), 2);
- match self.detect_cycles(list.clone()) {
- CycleSearchResult::NotList if !list.is_ref() => {
- Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
+ match BrentAlgState::detect_cycles(&self.heap, list) {
+ CycleSearchResult::NotList(..) if !list.is_var() => {
+ let err = self.type_error(ValidType::List, list);
+ Err(self.error_form(err, stub_gen()))
}
_ => {
- let mut addr = list;
-
- while let Addr::Lis(l) = self.store(self.deref(addr)) {
- let mut new_l = l;
-
- loop {
- 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;
+ loop {
+ read_heap_cell!(self.store(self.deref(list)),
+ (HeapCellValueTag::Lis, l) => {
+ let mut new_l = l;
+
+ loop {
+ read_heap_cell!(self.heap[new_l],
+ (HeapCellValueTag::Str, s) => {
+ new_l = s;
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if name == atom!("-") && arity == 2 {
+ break;
+ } else {
+ let err = self.type_error(
+ ValidType::Pair,
+ list_loc_as_cell!(l),
+ );
+
+ return Err(self.error_form(err, stub_gen()));
+ }
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => {
+ break;
+ }
+ _ => {
+ let err = self.type_error(
+ ValidType::Pair,
+ list_loc_as_cell!(l),
+ );
+
+ return Err(self.error_form(err, stub_gen()));
+ }
+ );
}
- HeapCellValue::Addr(Addr::StackCell(..)) => {
- break;
- }
- _ => {
- return Err(self.error_form(
- MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)),
- stub,
- ))
- }
- };
- }
- addr = Addr::HeapCell(l + 1);
+ list = heap_loc_as_cell!(l+1);
+ }
+ _ => {
+ break;
+ }
+ );
}
Ok(())
@@ -719,112 +867,48 @@ impl MachineState {
}
// see 8.4.4 of Draft Technical Corrigendum 2.
- pub(super) fn check_keysort_errors(&self) -> CallResult {
- let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
+ pub(super) fn check_keysort_errors(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("keysort"), 2);
- let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
- let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
+ let pairs = self.store(self.deref(self[temp_v!(1)]));
+ let sorted = self.store(self.deref(self[temp_v!(2)]));
- match self.detect_cycles(pairs.clone()) {
+ match BrentAlgState::detect_cycles(&self.heap, pairs) {
CycleSearchResult::PartialList(..) => {
- Err(self.error_form(MachineError::instantiation_error(), stub))
+ let err = self.instantiation_error();
+ Err(self.error_form(err, stub_gen()))
}
- CycleSearchResult::NotList => {
- Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub))
+ CycleSearchResult::NotList(..) => {
+ let err = self.type_error(ValidType::List, pairs);
+ Err(self.error_form(err, stub_gen()))
}
_ => Ok(()),
}?;
self.check_for_list_pairs(sorted)
}
-
- #[inline]
- pub(crate) fn type_error<T: TypeError>(
- &self,
- valid_type: ValidType,
- culprit: T,
- caller: ClauseName,
- arity: usize,
- ) -> MachineStub {
- let stub = MachineError::functor_stub(caller, arity);
- let err = MachineError::type_error(self.heap.h(), valid_type, culprit);
-
- return self.error_form(err, stub);
- }
-
- #[inline]
- pub(crate) fn representation_error(
- &self,
- rep_flag: RepFlag,
- caller: ClauseName,
- arity: usize,
- ) -> MachineStub {
- let stub = MachineError::functor_stub(caller, arity);
- let err = MachineError::representation_error(rep_flag);
-
- return self.error_form(err, stub);
- }
-
- pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
- let location = err.location;
- let err_len = err.len();
-
- let h = self.heap.h();
- let mut stub = vec![
- HeapCellValue::NamedStr(2, clause_name!("error"), None),
- HeapCellValue::Addr(Addr::HeapCell(h + 3)),
- HeapCellValue::Addr(Addr::HeapCell(h + 3 + err_len)),
- ];
-
- stub.extend(err.into_iter(3));
-
- if let Some((line_num, _)) = location {
- let colon_op_desc = Some(SharedOpDesc::new(600, XFY));
-
- 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) {
- let h = self.heap.h();
-
- self.ball.boundary = 0;
- self.ball.stub.truncate(0);
-
- self.heap.append(err);
-
- self.registers[1] = Addr::HeapCell(h);
-
- self.set_ball();
- self.unwind_stack();
- }
}
#[derive(Debug)]
-pub(crate) enum ExistenceError {
- Module(ClauseName),
+pub enum ExistenceError {
+ Module(Atom),
ModuleSource(ModuleSource),
- Procedure(ClauseName, usize),
- SourceSink(Addr),
- Stream(Addr),
+ Procedure(Atom, usize),
+ SourceSink(HeapCellValue),
+ Stream(HeapCellValue),
}
#[derive(Debug)]
-pub(crate) enum SessionError {
+pub enum SessionError {
CompilationError(CompilationError),
- // CannotOverwriteBuiltIn(ClauseName),
- // CannotOverwriteImport(ClauseName),
+ CannotOverwriteBuiltIn(PredicateKey),
+ // CannotOverwriteImport(Atom),
ExistenceError(ExistenceError),
- // InvalidFileName(ClauseName),
- ModuleDoesNotContainExport(ClauseName, PredicateKey),
- ModuleCannotImportSelf(ClauseName),
+ // InvalidFileName(Atom),
+ ModuleDoesNotContainExport(Atom, PredicateKey),
+ ModuleCannotImportSelf(Atom),
NamelessEntry,
- OpIsInfixAndPostFix(ClauseName),
+ OpIsInfixAndPostFix(Atom),
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
QueryCannotBeDefinedAsFact,
}
diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs
index e66a8713..794b09b1 100644
--- a/src/machine/machine_indices.rs
+++ b/src/machine/machine_indices.rs
@@ -1,53 +1,38 @@
-use prolog_parser::ast::*;
-use prolog_parser::clause_name;
+use crate::parser::ast::*;
-use crate::clause_types::*;
+use crate::arena::*;
+use crate::atom_table::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::instructions::*;
-use crate::machine::code_repo::CodeRepo;
-use crate::machine::heap::*;
+use crate::machine::loader::*;
use crate::machine::machine_state::*;
-use crate::machine::partial_string::*;
-use crate::machine::raw_block::RawBlockTraits;
use crate::machine::streams::Stream;
-use crate::machine::term_stream::LoadStatePayload;
-use crate::machine::CompilationTarget;
-use crate::rug::{Integer, Rational};
-use ordered_float::OrderedFloat;
+use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use std::cell::Cell;
use std::cmp::Ordering;
-use std::collections::{BTreeMap, BTreeSet};
-use std::convert::TryFrom;
-use std::fmt;
-// use std::mem;
-use std::net::TcpListener;
-use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
+use std::collections::BTreeSet;
+use std::ops::Deref;
use std::rc::Rc;
+use crate::types::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub(crate) struct OrderedOpDirKey(pub(crate) ClauseName, pub(crate) Fixity);
-
-pub(crate) type OssifiedOpDir = BTreeMap<OrderedOpDirKey, (usize, Specifier)>;
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub(crate) enum DBRef {
- NamedPred(ClauseName, usize, Option<SharedOpDesc>),
- Op(
- usize,
- Specifier,
- ClauseName,
- Rc<OssifiedOpDir>,
- SharedOpDesc,
- ),
+pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
+
+pub(crate) type OssifiedOpDir = IndexMap<(Atom, Fixity), (usize, Specifier)>;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DBRef {
+ NamedPred(Atom, usize),
+ Op(Atom, Fixity, TypedArenaPtr<OssifiedOpDir>),
}
// 7.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub(crate) enum TermOrderCategory {
+pub enum TermOrderCategory {
Variable,
FloatingPoint,
Integer,
@@ -55,322 +40,45 @@ pub(crate) enum TermOrderCategory {
Compound,
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) enum Addr {
- AttrVar(usize),
- Char(char),
- Con(usize),
- CutPoint(usize),
- EmptyList,
- Fixnum(isize),
- Float(OrderedFloat<f64>),
- Lis(usize),
- LoadStatePayload(usize),
- HeapCell(usize),
- PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
- StackCell(usize, usize),
- Str(usize),
- Stream(usize),
- TcpListener(usize),
- Usize(usize),
-}
-
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
-pub(crate) enum Ref {
- AttrVar(usize),
- HeapCell(usize),
- StackCell(usize, usize),
-}
-
-impl Ref {
- pub(crate) fn as_addr(self) -> Addr {
- match self {
- Ref::AttrVar(h) => Addr::AttrVar(h),
- Ref::HeapCell(h) => Addr::HeapCell(h),
- Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
- }
- }
-}
-
-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,
- }
- }
-}
-
-impl PartialEq<Ref> for Addr {
+impl PartialEq<Ref> for HeapCellValue {
fn eq(&self, r: &Ref) -> bool {
self.as_var() == Some(*r)
}
}
-// for use crate::in MachineState::bind.
-impl PartialOrd<Ref> for Addr {
+impl PartialOrd<Ref> for HeapCellValue {
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
- match self {
- &Addr::StackCell(fr, sc) => match *r {
- Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater),
- Ref::StackCell(fr1, sc1) => {
- if fr1 < fr || (fr1 == fr && sc1 < sc) {
- Some(Ordering::Greater)
- } else if fr1 == fr && sc1 == sc {
- Some(Ordering::Equal)
- } else {
- Some(Ordering::Less)
+ read_heap_cell!(*self,
+ (HeapCellValueTag::StackVar, s1) => {
+ match r.get_tag() {
+ RefTag::StackCell => {
+ let s2 = r.get_value() as usize;
+ s1.partial_cmp(&s2)
}
+ _ => Some(Ordering::Greater),
}
- },
- &Addr::HeapCell(h) | &Addr::AttrVar(h) => match r {
- Ref::StackCell(..) => Some(Ordering::Less),
- Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1),
- },
- _ => None,
- }
- }
-}
-
-impl Addr {
- #[inline]
- pub(crate) fn is_heap_bound(&self) -> bool {
- match self {
- Addr::Char(_)
- | Addr::EmptyList
- | Addr::CutPoint(_)
- | Addr::Usize(_)
- | Addr::Fixnum(_)
- | Addr::Float(_) => false,
- _ => true,
- }
- }
-
- #[inline]
- pub(crate) fn is_ref(&self) -> bool {
- match self {
- Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => true,
- _ => false,
- }
- }
-
- #[inline]
- pub(crate) 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)),
- _ => 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,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
+ // _ if self.is_ref() => {
+ // let h1 = self.get_value();
+
+ match r.get_tag() {
+ RefTag::StackCell => Some(Ordering::Less),
_ => {
- unreachable!()
+ let h2 = r.get_value() as usize;
+ h1.partial_cmp(&h2)
}
- },
- Addr::Char(_) | Addr::EmptyList => Some(TermOrderCategory::Atom),
- Addr::Fixnum(_) | Addr::Usize(_) => Some(TermOrderCategory::Integer),
- Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
- Some(TermOrderCategory::Compound)
}
- Addr::CutPoint(_)
- | Addr::LoadStatePayload(_)
- | Addr::Stream(_)
- | Addr::TcpListener(_) => None,
- },
- }
- }
-
- pub(crate) fn as_constant_index(&self, machine_st: &MachineState) -> Option<Constant> {
- match self {
- &Addr::Char(c) => Some(Constant::Char(c)),
- &Addr::Con(h) => match &machine_st.heap[h] {
- &HeapCellValue::Atom(ref name, _) if name.is_char() => {
- Some(Constant::Char(name.as_str().chars().next().unwrap()))
- }
- &HeapCellValue::Atom(ref name, _) => Some(Constant::Atom(name.clone(), None)),
- &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::Usize(n) => Some(Constant::Usize(n)),
- _ => None,
- }
- }
-
- pub(crate) fn is_protected(&self, e: usize) -> bool {
- match self {
- &Addr::StackCell(addr, _) if addr >= e => false,
- _ => true,
- }
- }
-}
-
-impl Add<usize> for Addr {
- type Output = 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),
- _ => self,
- }
- }
-}
-
-impl Sub<i64> for Addr {
- type Output = 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::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
- _ => self,
- }
- } else {
- self.sub(rhs as usize)
- }
- }
-}
-
-impl Sub<usize> for Addr {
- type Output = 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::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
- _ => self,
- }
- }
-}
-
-impl SubAssign<usize> for Addr {
- fn sub_assign(&mut self, rhs: usize) {
- *self = self.clone() - rhs;
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum TrailRef {
- Ref(Ref),
- AttrVarHeapLink(usize),
- AttrVarListLink(usize, usize),
- BlackboardEntry(usize),
- BlackboardOffset(usize, usize), // key atom heap location, key value heap location
-}
-
-impl From<Ref> for TrailRef {
- fn from(r: Ref) -> Self {
- TrailRef::Ref(r)
- }
-}
-
-#[derive(Debug)]
-pub(crate) enum HeapCellValue {
- Addr(Addr),
- Atom(ClauseName, Option<SharedOpDesc>),
- DBRef(DBRef),
- Integer(Rc<Integer>),
- LoadStatePayload(Box<LoadStatePayload>),
- NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
- Rational(Rc<Rational>),
- PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
- Stream(Stream),
- TcpListener(TcpListener),
-}
-
-impl HeapCellValue {
- #[inline]
- pub(crate) fn as_addr(&self, focus: usize) -> Addr {
- match self {
- HeapCellValue::Addr(ref a) => *a,
- HeapCellValue::Atom(..)
- | HeapCellValue::DBRef(..)
- | HeapCellValue::Integer(..)
- | HeapCellValue::Rational(..) => Addr::Con(focus),
- HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus),
- HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus),
- HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0),
- HeapCellValue::Stream(_) => Addr::Stream(focus),
- HeapCellValue::TcpListener(_) => Addr::TcpListener(focus),
- }
- }
-
- #[inline]
- pub(crate) 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::LoadStatePayload(_) => {
- HeapCellValue::Atom(clause_name!("$live_term_stream"), None)
- }
- &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)
+ _ => {
+ None
}
- &HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()),
- &HeapCellValue::TcpListener(_) => {
- HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
- }
- }
- }
-}
-
-impl From<Addr> for HeapCellValue {
- #[inline]
- fn from(value: Addr) -> HeapCellValue {
- HeapCellValue::Addr(value)
+ )
}
}
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
-pub(crate) enum IndexPtr {
+pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
DynamicIndex(usize),
Index(usize),
@@ -378,7 +86,7 @@ pub(crate) enum IndexPtr {
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
-pub(crate) struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
+pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
impl Deref for CodeIndex {
type Target = Cell<IndexPtr>;
@@ -418,265 +126,25 @@ impl Default for CodeIndex {
}
}
-#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
-pub(crate) enum REPLCodePtr {
- AddDiscontiguousPredicate,
- AddDynamicPredicate,
- AddMultifilePredicate,
- AddGoalExpansionClause,
- AddTermExpansionClause,
- AddInSituFilenameModule,
- ClauseToEvacuable,
- ScopedClauseToEvacuable,
- ConcludeLoad,
- DeclareModule,
- LoadCompiledLibrary,
- LoadContextSource,
- LoadContextFile,
- LoadContextDirectory,
- LoadContextModule,
- LoadContextStream,
- PopLoadContext,
- PopLoadStatePayload,
- PushLoadContext,
- PushLoadStatePayload,
- UseModule,
- BuiltInProperty,
- MetaPredicateProperty,
- MultifileProperty,
- DiscontiguousProperty,
- DynamicProperty,
- AbolishClause,
- Asserta,
- Assertz,
- Retract,
- IsConsistentWithTermQueue,
- FlushTermQueue,
- RemoveModuleExports,
- AddNonCountedBacktracking,
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub(crate) enum CodePtr {
- BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
- CallN(usize, LocalCodePtr, bool), // arity, local, last call.
- Local(LocalCodePtr),
- // DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
- REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
- VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
-}
-
-impl CodePtr {
- pub(crate) fn local(&self) -> LocalCodePtr {
- match self {
- &CodePtr::BuiltInClause(_, ref local)
- | &CodePtr::CallN(_, ref local, _)
- | &CodePtr::Local(ref local) => local.clone(),
- &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
- &CodePtr::REPL(_, p) => p, // | &CodePtr::DynamicTransaction(_, p) => p,
- }
- }
-
- #[inline]
- pub(crate) fn is_halt(&self) -> bool {
- if let CodePtr::Local(LocalCodePtr::Halt) = self {
- true
- } else {
- false
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub(crate) enum LocalCodePtr {
- DirEntry(usize), // offset
- Halt,
- IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
- // TopLevel(usize, usize), // chunk_num, offset
-}
-
-impl LocalCodePtr {
- pub(crate) fn assign_if_local(&mut self, cp: CodePtr) {
- match cp {
- CodePtr::Local(local) => *self = local,
- _ => {}
- }
- }
-
- #[inline]
- pub(crate) fn abs_loc(&self) -> usize {
- match self {
- LocalCodePtr::DirEntry(ref p) => *p,
- LocalCodePtr::IndexingBuf(ref p, ..) => *p,
- LocalCodePtr::Halt => unreachable!(),
- }
- }
-
- pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool {
- match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) {
- Some(line) => match line.as_ref() {
- Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
- if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
- return true;
- }
- }
- _ => {}
- },
- None => {}
- }
-
- false
- }
-
- pub(crate) fn as_functor<T: RawBlockTraits>(&self, heap: &mut HeapTemplate<T>) -> Addr {
- let addr = Addr::HeapCell(heap.h());
-
- match self {
- LocalCodePtr::DirEntry(p) => {
- heap.append(functor!("dir_entry", [integer(*p)]));
- }
- LocalCodePtr::Halt => {
- heap.append(functor!("halt"));
- }
- /*
- LocalCodePtr::TopLevel(chunk_num, offset) => {
- heap.append(functor!(
- "top_level",
- [integer(*chunk_num), integer(*offset)]
- ));
- }
- */
- LocalCodePtr::IndexingBuf(p, o, i) => {
- heap.append(functor!(
- "indexed_buf",
- [integer(*p), integer(*o), integer(*i)]
- ));
- }
- }
-
- addr
- }
-}
-
-impl Default for CodePtr {
- #[inline]
- fn default() -> Self {
- CodePtr::Local(LocalCodePtr::default())
- }
-}
+pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
+pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
-impl Default for LocalCodePtr {
- #[inline]
- fn default() -> Self {
- LocalCodePtr::DirEntry(0)
- }
-}
+pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
-impl Add<usize> for LocalCodePtr {
- type Output = LocalCodePtr;
-
- #[inline]
- fn add(self, rhs: usize) -> Self::Output {
- match self {
- LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs),
- LocalCodePtr::Halt => unreachable!(),
- LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs),
- }
- }
-}
-
-impl Sub<usize> for LocalCodePtr {
- type Output = Option<LocalCodePtr>;
-
- #[inline]
- fn sub(self, rhs: usize) -> Self::Output {
- match self {
- LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
- LocalCodePtr::Halt => unreachable!(),
- LocalCodePtr::IndexingBuf(p, o, i) => i
- .checked_sub(rhs)
- .map(|r| LocalCodePtr::IndexingBuf(p, o, r)),
- }
- }
-}
-
-impl SubAssign<usize> for LocalCodePtr {
- #[inline]
- fn sub_assign(&mut self, rhs: usize) {
- match self {
- LocalCodePtr::DirEntry(ref mut p) => *p -= rhs,
- LocalCodePtr::Halt | LocalCodePtr::IndexingBuf(..) => unreachable!(),
- }
- }
-}
-
-impl AddAssign<usize> for LocalCodePtr {
- #[inline]
- fn add_assign(&mut self, rhs: usize) {
- match self {
- &mut LocalCodePtr::DirEntry(ref mut p) /* |
- &mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs,
- &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
- &mut LocalCodePtr::Halt => unreachable!(),
- }
- }
-}
-
-impl Add<usize> for CodePtr {
- type Output = CodePtr;
-
- fn add(self, rhs: usize) -> Self::Output {
- match self {
- p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => {
- // |
- // p @ CodePtr::DynamicTransaction(..) => {
- p
- }
- CodePtr::Local(local) => CodePtr::Local(local + rhs),
- CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
- CodePtr::Local(local + rhs)
- }
- }
- }
-}
-
-impl AddAssign<usize> for CodePtr {
- fn add_assign(&mut self, rhs: usize) {
- match self {
- &mut CodePtr::VerifyAttrInterrupt(_) => {}
- &mut CodePtr::Local(ref mut local) => *local += rhs,
- _ => *self = CodePtr::Local(self.local() + rhs),
- }
- }
-}
-
-impl SubAssign<usize> for CodePtr {
- #[inline]
- fn sub_assign(&mut self, rhs: usize) {
- match self {
- CodePtr::Local(ref mut local) => *local -= rhs,
- _ => unreachable!(),
- }
- }
-}
-
-pub(crate) type HeapVarDict = IndexMap<Rc<Var>, Addr>;
-pub(crate) type AllocVarDict = IndexMap<Rc<Var>, VarData>;
-
-pub(crate) type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<Addr>)>;
-
-pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
+pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
pub(crate) type StreamDir = BTreeSet<Stream>;
-pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>;
+pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>, FxBuildHasher>;
-pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton>;
+pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton, FxBuildHasher>;
pub(crate) type LocalExtensiblePredicates =
- IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>;
+ IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton, FxBuildHasher>;
+
+pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex, FxBuildHasher>;
#[derive(Debug)]
-pub(crate) struct IndexStore {
+pub struct IndexStore {
pub(super) code_dir: CodeDir,
pub(super) extensible_predicates: ExtensiblePredicates,
pub(super) local_extensible_predicates: LocalExtensiblePredicates,
@@ -688,31 +156,21 @@ pub(crate) struct IndexStore {
pub(super) stream_aliases: StreamAliasDir,
}
-impl Default for IndexStore {
- #[inline]
- fn default() -> Self {
- index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
- }
-}
-
impl IndexStore {
pub(crate) fn get_predicate_skeleton_mut(
&mut self,
compilation_target: &CompilationTarget,
key: &PredicateKey,
) -> Option<&mut PredicateSkeleton> {
- match (key.0.as_str(), key.1) {
- // ("term_expansion", 2) => self.extensible_predicates.get_mut(key),
- _ => match compilation_target {
- CompilationTarget::User => self.extensible_predicates.get_mut(key),
- CompilationTarget::Module(ref module_name) => {
- if let Some(module) = self.modules.get_mut(module_name) {
- module.extensible_predicates.get_mut(key)
- } else {
- None
- }
+ match compilation_target {
+ CompilationTarget::User => self.extensible_predicates.get_mut(key),
+ CompilationTarget::Module(ref module_name) => {
+ if let Some(module) = self.modules.get_mut(module_name) {
+ module.extensible_predicates.get_mut(key)
+ } else {
+ None
}
- },
+ }
}
}
@@ -737,7 +195,7 @@ impl IndexStore {
&mut self,
mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget,
- listing_src_file_name: Option<ClauseName>,
+ listing_src_file_name: Option<Atom>,
key: PredicateKey,
) -> Option<&mut LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name {
@@ -748,8 +206,8 @@ impl IndexStore {
CompilationTarget::User => self
.local_extensible_predicates
.get_mut(&(local_compilation_target, key)),
- CompilationTarget::Module(ref module_name) => {
- if let Some(module) = self.modules.get_mut(module_name) {
+ CompilationTarget::Module(module_name) => {
+ if let Some(module) = self.modules.get_mut(&module_name) {
module
.local_extensible_predicates
.get_mut(&(local_compilation_target, key))
@@ -764,7 +222,7 @@ impl IndexStore {
&self,
mut src_compilation_target: CompilationTarget,
local_compilation_target: CompilationTarget,
- listing_src_file_name: Option<ClauseName>,
+ listing_src_file_name: Option<Atom>,
key: PredicateKey,
) -> Option<&LocalPredicateSkeleton> {
if let Some(filename) = listing_src_file_name {
@@ -775,8 +233,8 @@ impl IndexStore {
CompilationTarget::User => self
.local_extensible_predicates
.get(&(local_compilation_target, key)),
- CompilationTarget::Module(ref module_name) => {
- if let Some(module) = self.modules.get(module_name) {
+ CompilationTarget::Module(module_name) => {
+ if let Some(module) = self.modules.get(&module_name) {
module
.local_extensible_predicates
.get(&(local_compilation_target, key))
@@ -806,35 +264,30 @@ impl IndexStore {
pub(crate) fn get_predicate_code_index(
&self,
- name: ClauseName,
+ name: Atom,
arity: usize,
- module: ClauseName,
- op_spec: Option<SharedOpDesc>,
+ module: Atom,
) -> Option<CodeIndex> {
- if module.as_str() == "user" {
- match ClauseType::from(name, arity, op_spec) {
- ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(),
- ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(),
+ if module == atom!("user") {
+ match ClauseType::from(name, arity) {
+ ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(),
_ => None,
}
} else {
- self.modules.get(&module).and_then(|module| {
- match ClauseType::from(name, arity, op_spec) {
- ClauseType::Named(name, arity, _) => {
+ self.modules
+ .get(&module)
+ .and_then(|module| match ClauseType::from(name, arity) {
+ ClauseType::Named(arity, name, _) => {
module.code_dir.get(&(name, arity)).cloned()
}
- ClauseType::Op(name, spec, ..) => {
- module.code_dir.get(&(name, spec.arity())).cloned()
- }
_ => None,
- }
- })
+ })
}
}
pub(crate) fn get_meta_predicate_spec(
&self,
- name: ClauseName,
+ name: Atom,
arity: usize,
compilation_target: &CompilationTarget,
) -> Option<&Vec<MetaSpec>> {
@@ -850,9 +303,13 @@ impl IndexStore {
}
}
- pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool {
- match module_name.as_str() {
- "user" => self
+ pub(crate) fn is_dynamic_predicate(
+ &self,
+ module_name: Atom,
+ key: PredicateKey,
+ ) -> bool {
+ match module_name {
+ atom!("user") => self
.extensible_predicates
.get(&key)
.map(|skeleton| skeleton.core.is_dynamic)
@@ -870,62 +327,10 @@ impl IndexStore {
#[inline]
pub(super) fn new() -> Self {
- IndexStore::default()
- }
-
- pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
- let r_w_h = clause_name!("run_cleaners_with_handling");
- let r_wo_h = clause_name!("run_cleaners_without_handling");
- let iso_ext = clause_name!("iso_ext");
-
- let r_w_h = self
- .get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None)
- .and_then(|item| item.local());
- let r_wo_h = self
- .get_predicate_code_index(r_wo_h, 1, iso_ext, None)
- .and_then(|item| item.local());
-
- if let Some(r_w_h) = r_w_h {
- if let Some(r_wo_h) = r_wo_h {
- return (r_w_h, r_wo_h);
- }
- }
-
- return (0, 0);
- }
-}
-
-pub(crate) type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
-
-pub(crate) enum RefOrOwned<'a, T: 'a> {
- Borrowed(&'a T),
- Owned(T),
-}
-
-impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &RefOrOwned::Borrowed(ref borrowed) => write!(f, "Borrowed({:?})", borrowed),
- &RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned),
- }
- }
-}
-
-impl<'a, T> RefOrOwned<'a, T> {
- pub(crate) fn as_ref(&'a self) -> &'a T {
- match self {
- &RefOrOwned::Borrowed(r) => r,
- &RefOrOwned::Owned(ref r) => r,
- }
- }
-
- pub(crate) fn to_owned(self) -> T
- where
- T: Clone,
- {
- match self {
- RefOrOwned::Borrowed(item) => item.clone(),
- RefOrOwned::Owned(item) => item,
- }
+ index_store!(
+ CodeDir::with_hasher(FxBuildHasher::default()),
+ default_op_dir(),
+ ModuleDir::with_hasher(FxBuildHasher::default())
+ )
}
}
diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs
index 9e845f04..5b859fa9 100644
--- a/src/machine/machine_state.rs
+++ b/src/machine/machine_state.rs
@@ -1,35 +1,197 @@
-use prolog_parser::ast::*;
-use prolog_parser::tabled_rc::*;
-use prolog_parser::{clause_name, temp_v};
-
-use crate::clause_types::*;
+use crate::arena::*;
+use crate::atom_table::*;
use crate::forms::*;
+use crate::heap_iter::*;
use crate::heap_print::*;
+use crate::machine::Machine;
use crate::machine::attributed_variables::*;
use crate::machine::copier::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
-use crate::machine::partial_string::HeapPStrIter;
use crate::machine::stack::*;
use crate::machine::streams::*;
-use crate::rug::Integer;
+use crate::parser::ast::*;
+use crate::types::*;
-use downcast::{
- downcast, downcast_methods, downcast_methods_core, downcast_methods_std, impl_downcast, Any,
-};
+use crate::parser::rug::Integer;
use indexmap::IndexMap;
-use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt;
-use std::mem;
use std::ops::{Index, IndexMut};
use std::rc::Rc;
+pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
+
+#[derive(Debug, Clone, Copy)]
+pub(super) enum MachineMode {
+ Read,
+ Write,
+}
+
+#[derive(Debug, Clone)]
+pub(super) enum HeapPtr {
+ HeapCell(usize),
+ PStrChar(usize, usize),
+ PStrLocation(usize, usize),
+}
+
+impl Default for HeapPtr {
+ fn default() -> Self {
+ HeapPtr::HeapCell(0)
+ }
+}
+
+#[derive(Debug)]
+pub enum FirstOrNext {
+ First,
+ Next,
+}
+
+pub struct MachineState {
+ pub atom_tbl: AtomTable,
+ pub arena: Arena,
+ pub(super) pdl: Vec<HeapCellValue>,
+ pub(super) s: HeapPtr,
+ pub(super) s_offset: usize,
+ pub(super) p: usize,
+ pub(super) oip: u32, // first internal code ptr
+ pub(super) iip : u32, // second internal code ptr
+ pub(super) b: usize,
+ pub(super) b0: usize,
+ pub(super) e: usize,
+ pub(super) num_of_args: usize,
+ pub(super) cp: usize,
+ pub(super) attr_var_init: AttrVarInitializer,
+ pub(super) fail: bool,
+ pub heap: Heap,
+ pub(super) mode: MachineMode,
+ pub(crate) stack: Stack,
+ pub(super) registers: Registers,
+ pub(super) trail: Vec<TrailEntry>,
+ pub(super) tr: usize,
+ pub(super) hb: usize,
+ pub(super) block: usize, // an offset into the OR stack.
+ pub(super) ball: Ball,
+ pub(super) lifted_heap: Heap,
+ pub(super) interms: Vec<Number>, // intermediate numbers.
+ // locations of cleaners, cut points, the previous block. for setup_call_cleanup.
+ pub(super) cont_pts: Vec<(HeapCellValue, usize, usize)>,
+ pub(super) cwil: CWIL,
+ pub(crate) flags: MachineFlags,
+ pub(crate) cc: usize,
+ pub(crate) global_clock: usize,
+ pub(crate) dynamic_mode: FirstOrNext,
+ pub(crate) unify_fn: fn(&mut MachineState),
+ pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
+ pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
+ pub(crate) increment_call_count_fn: fn(&mut MachineState) -> CallResult,
+}
+
+impl fmt::Debug for MachineState {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("MachineState")
+ .field("atom_tbl", &self.atom_tbl)
+ .field("arena", &self.arena)
+ .field("s", &self.s)
+ .field("p", &self.p)
+ .field("b", &self.b)
+ .field("b0", &self.b0)
+ .field("e", &self.e)
+ .field("num_of_args", &self.num_of_args)
+ .field("cp", &self.cp)
+ .field("attr_var_init", &self.attr_var_init)
+ .field("fail", &self.fail)
+ .field("heap", &self.heap)
+ .field("mode", &self.mode)
+ .field("stack", &self.stack)
+ .field("registers", &self.registers)
+ .field("trail", &self.trail)
+ .field("tr", &self.tr)
+ .field("hb", &self.hb)
+ .field("block", &self.block)
+ .field("ball", &self.ball)
+ .field("lifted_heap", &self.lifted_heap)
+ .field("interms", &self.interms)
+ .field("flags", &self.flags)
+ .field("cc", &self.cc)
+ .field("global_clock", &self.global_clock)
+ .field("dynamic_mode", &self.dynamic_mode)
+ .field(
+ "unify_fn",
+ if self.unify_fn as usize == MachineState::unify as usize {
+ &"MachineState::unify"
+ } else if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
+ &"MachineState::unify_with_occurs_check"
+ } else {
+ &"MachineState::unify_with_occurs_check_with_error"
+ },
+ )
+ .field(
+ "bind_fn",
+ if self.bind_fn as usize == MachineState::bind as usize {
+ &"MachineState::bind"
+ } else if self.bind_fn as usize
+ == MachineState::bind_with_occurs_check_wrapper as usize
+ {
+ &"MachineState::bind_with_occurs_check"
+ } else {
+ &"MachineState::bind_with_occurs_check_with_error_wrapper"
+ },
+ )
+ .finish()
+ }
+}
+
+impl Index<RegType> for MachineState {
+ type Output = HeapCellValue;
+
+ #[inline(always)]
+ fn index(&self, reg: RegType) -> &Self::Output {
+ match reg {
+ RegType::Temp(temp) => &self.registers[temp],
+ RegType::Perm(perm) => {
+ let e = self.e;
+ &self.stack[stack_loc!(AndFrame, e, perm)]
+ }
+ }
+ }
+}
+
+impl IndexMut<RegType> for MachineState {
+ #[inline(always)]
+ fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
+ match reg {
+ RegType::Temp(temp) => &mut self.registers[temp],
+ RegType::Perm(perm) => {
+ let e = self.e;
+ &mut self.stack[stack_loc!(AndFrame, e, perm)]
+ }
+ }
+ }
+}
+
+pub type CallResult = Result<(), Vec<HeapCellValue>>;
+
+#[inline(always)]
+pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) {
+ read_heap_cell!(heap[index],
+ (HeapCellValueTag::PStr | HeapCellValueTag::CStr) => {
+ (index, Fixnum::build_with(0))
+ }
+ (HeapCellValueTag::PStrOffset, h) => {
+ (h, cell_as_fixnum!(heap[index+1]))
+ }
+ _ => {
+ unreachable!()
+ }
+ )
+}
+
#[derive(Debug)]
-pub(crate) struct Ball {
+pub struct Ball {
pub(super) boundary: usize,
pub(super) stub: Heap,
}
@@ -49,16 +211,10 @@ impl Ball {
pub(super) fn copy_and_align(&self, h: usize) -> Heap {
let diff = self.boundary as i64 - h as i64;
- let mut stub = Heap::new();
- for heap_value in self.stub.iter_from(0) {
- stub.push(match heap_value {
- &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
- heap_value => heap_value.context_free_clone(),
- });
- }
-
- stub
+ self.stub.iter().cloned().map(|heap_value| {
+ heap_value - diff
+ }).collect()
}
}
@@ -69,42 +225,48 @@ pub(super) struct CopyTerm<'a> {
impl<'a> CopyTerm<'a> {
pub(super) fn new(state: &'a mut MachineState) -> Self {
- CopyTerm { state: state }
+ CopyTerm { state }
}
}
impl<'a> Index<usize> for CopyTerm<'a> {
type Output = HeapCellValue;
+ #[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
&self.state.heap[index]
}
}
impl<'a> IndexMut<usize> for CopyTerm<'a> {
+ #[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.state.heap[index]
}
}
-// the ordinary, heap term copier, used by duplicate_term.
impl<'a> CopierTarget for CopyTerm<'a> {
+ #[inline(always)]
fn threshold(&self) -> usize {
- self.state.heap.h()
+ self.state.heap.len()
}
+ #[inline(always)]
fn push(&mut self, hcv: HeapCellValue) {
self.state.heap.push(hcv);
}
- fn store(&self, a: Addr) -> Addr {
- self.state.store(a)
+ #[inline(always)]
+ fn store(&self, value: HeapCellValue) -> HeapCellValue {
+ self.state.store(value)
}
- fn deref(&self, a: Addr) -> Addr {
- self.state.deref(a)
+ #[inline(always)]
+ fn deref(&self, value: HeapCellValue) -> HeapCellValue {
+ self.state.deref(value)
}
+ #[inline(always)]
fn stack(&mut self) -> &mut Stack {
&mut self.state.stack
}
@@ -120,7 +282,7 @@ pub(super) struct CopyBallTerm<'a> {
impl<'a> CopyBallTerm<'a> {
pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self {
- let hb = heap.h();
+ let hb = heap.len();
CopyBallTerm {
stack,
@@ -155,35 +317,39 @@ impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
}
}
-// the ordinary, heap term copier, used by duplicate_term.
impl<'a> CopierTarget for CopyBallTerm<'a> {
fn threshold(&self) -> usize {
- self.heap_boundary + self.stub.h()
+ self.heap_boundary + self.stub.len()
}
fn push(&mut self, value: HeapCellValue) {
self.stub.push(value);
}
- fn store(&self, addr: Addr) -> Addr {
- match addr {
- Addr::HeapCell(h) | Addr::AttrVar(h) if h < self.heap_boundary => {
- self.heap[h].as_addr(h)
+ fn store(&self, value: HeapCellValue) -> HeapCellValue {
+ read_heap_cell!(value,
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
+ if h < self.heap_boundary {
+ self.heap[h]
+ } else {
+ let index = h - self.heap_boundary;
+ self.stub[index]
+ }
}
- Addr::HeapCell(h) | Addr::AttrVar(h) => {
- let index = h - self.heap_boundary;
- self.stub[index].as_addr(h)
+ (HeapCellValueTag::StackVar, s) => {
+ self.stack[s]
}
- Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc],
- addr => addr,
- }
+ _ => {
+ value
+ }
+ )
}
- fn deref(&self, mut addr: Addr) -> Addr {
+ fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue {
loop {
let value = self.store(addr);
- if value.is_ref() && value != addr {
+ if value.is_var() && value != addr {
addr = value;
continue;
}
@@ -197,219 +363,150 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
}
}
-impl Index<RegType> for MachineState {
- type Output = Addr;
+impl MachineState {
+ pub(crate) fn backtrack(&mut self) {
+ let b = self.b;
+ let or_frame = self.stack.index_or_frame(b);
- fn index(&self, reg: RegType) -> &Self::Output {
- match reg {
- RegType::Temp(temp) => &self.registers[temp],
- RegType::Perm(perm) => {
- let e = self.e;
- &self.stack.index_and_frame(e)[perm]
- }
- }
+ self.b0 = or_frame.prelude.b0;
+ self.p = or_frame.prelude.bp;
+
+ self.oip = or_frame.prelude.boip;
+ self.iip = or_frame.prelude.biip;
+
+ self.pdl.clear();
+ self.fail = false;
}
-}
-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::Perm(perm) => {
- let e = self.e;
+ pub(crate) fn increment_call_count(&mut self) -> CallResult {
+ if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 {
+ return Ok(());
+ }
- &mut self.stack.index_and_frame_mut(e)[perm]
+ if let Some(&(ref limit, bp)) = self.cwil.limits.last() {
+ if self.cwil.count == *limit {
+ self.cwil.inference_limit_exceeded = true;
+
+ return Err(
+ functor!(atom!("inference_limit_exceeded"), [fixnum(bp)])
+ );
+ } else {
+ self.cwil.count += 1;
}
}
- }
-}
-pub(crate) type Registers = Vec<Addr>;
+ Ok(())
+ }
-#[derive(Debug, Clone, Copy)]
-pub(super) enum MachineMode {
- Read,
- Write,
-}
+ #[allow(dead_code)]
+ pub(super) fn try_char_list(&mut self, addrs: Vec<HeapCellValue>) -> Result<String, MachineError> {
+ let mut chars = String::new();
-#[derive(Debug, Clone)]
-pub(super) enum HeapPtr {
- HeapCell(usize),
- PStrChar(usize, usize),
- PStrLocation(usize, usize),
-}
+ for addr in addrs {
+ let addr = self.store(self.deref(addr));
-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
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Char, c) => {
+ chars.push(c);
+ continue;
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ if let Some(c) = name.as_char() {
+ chars.push(c);
+ continue;
+ }
}
- } else {
- unreachable!()
}
- }
- &HeapPtr::PStrLocation(h, n) => Addr::PStrLocation(h, n),
+ _ => {
+ }
+ );
+
+ return Err(self.type_error(ValidType::Character, addr));
}
- }
-}
-impl Default for HeapPtr {
- fn default() -> Self {
- HeapPtr::HeapCell(0)
+ Ok(chars)
}
-}
-#[derive(Debug)]
-pub enum FirstOrNext {
- First,
- Next,
-}
+ pub(super) fn throw_undefined_error(&mut self, name: Atom, arity: usize) -> MachineStub {
+ let stub = functor_stub(name, arity);
+ let err = self.existence_error(ExistenceError::Procedure(name, arity));
-// #[derive(Debug)]
-pub(crate) struct MachineState {
- pub(crate) atom_tbl: TabledData<Atom>,
- pub(super) s: HeapPtr,
- pub(super) p: CodePtr,
- pub(super) b: usize,
- pub(super) b0: usize,
- pub(super) e: usize,
- pub(super) num_of_args: usize,
- pub(super) cp: LocalCodePtr,
- pub(super) attr_var_init: AttrVarInitializer,
- pub(super) fail: bool,
- pub(crate) heap: Heap,
- pub(super) mode: MachineMode,
- pub(crate) stack: Stack,
- pub(super) registers: Registers,
- pub(super) trail: Vec<TrailRef>,
- pub(super) tr: usize,
- pub(super) hb: usize,
- pub(super) block: usize, // an offset into the OR stack.
- pub(super) ball: Ball,
- pub(super) lifted_heap: Heap,
- pub(super) interms: Vec<Number>, // intermediate numbers.
- pub(super) last_call: bool,
- pub(crate) flags: MachineFlags,
- pub(crate) cc: usize,
- pub(crate) global_clock: usize,
- pub(crate) dynamic_mode: FirstOrNext,
- pub(crate) unify_fn: fn(&mut MachineState, Addr, Addr),
- pub(crate) bind_fn: fn(&mut MachineState, Ref, Addr),
-}
+ self.error_form(err, stub)
+ }
-impl fmt::Debug for MachineState {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("MachineState")
- .field("atom_tbl", &self.atom_tbl)
- .field("s", &self.s)
- .field("p", &self.p)
- .field("b", &self.b)
- .field("b0", &self.b0)
- .field("e", &self.e)
- .field("num_of_args", &self.num_of_args)
- .field("cp", &self.cp)
- .field("attr_var_init", &self.attr_var_init)
- .field("fail", &self.fail)
- .field("heap", &self.heap)
- .field("mode", &self.mode)
- .field("stack", &self.stack)
- .field("registers", &self.registers)
- .field("trail", &self.trail)
- .field("tr", &self.tr)
- .field("hb", &self.hb)
- .field("block", &self.block)
- .field("ball", &self.ball)
- .field("lifted_heap", &self.lifted_heap)
- .field("interms", &self.interms)
- .field("last_call", &self.last_call)
- .field("flags", &self.flags)
- .field("cc", &self.cc)
- .field("global_clock", &self.global_clock)
- .field("dynamic_mode", &self.dynamic_mode)
- .field(
- "unify_fn",
- if self.unify_fn as usize == MachineState::unify as usize {
- &"MachineState::unify"
- } else if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
- &"MachineState::unify_with_occurs_check"
- } else {
- &"MachineState::unify_with_occurs_check_with_error"
- },
- )
- .field(
- "bind_fn",
- if self.bind_fn as usize == MachineState::bind as usize {
- &"MachineState::bind"
- } else if self.bind_fn as usize
- == MachineState::bind_with_occurs_check_wrapper as usize
- {
- &"MachineState::bind_with_occurs_check"
- } else {
- &"MachineState::bind_with_occurs_check_with_error_wrapper"
- },
- )
- .finish()
+ #[inline(always)]
+ pub(super) fn call_at_index(&mut self, arity: usize, p: usize) {
+ self.cp = self.p + 1;
+ self.p = p;
+ self.oip = 0;
+ self.iip = 0;
+ self.num_of_args = arity;
+ self.b0 = self.b;
}
-}
-impl MachineState {
- pub(crate) fn read_term(&mut self, mut stream: Stream, indices: &mut IndexStore) -> CallResult {
+ #[inline(always)]
+ pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) {
+ self.p = p;
+ self.oip = 0;
+ self.iip = 0;
+ self.num_of_args = arity;
+ self.b0 = self.b;
+ }
+
+ pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
fn push_var_eq_functors<'a>(
heap: &mut Heap,
- iter: impl Iterator<Item = (&'a Rc<Var>, &'a Addr)>,
- op_dir: &OpDir,
- atom_tbl: TabledData<Atom>,
- ) -> Vec<Addr> {
+ iter: impl Iterator<Item = (&'a Rc<String>, &'a HeapCellValue)>,
+ atom_tbl: &mut AtomTable,
+ ) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![];
for (var, binding) in iter {
- let var_atom = clause_name!(var.to_string(), atom_tbl);
+ let var_atom = atom_tbl.build_with(&var);
+ let h = heap.len();
- let h = heap.h();
- let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir);
+ heap.push(atom_as_cell!(atom!("="), 2));
+ heap.push(atom_as_cell!(var_atom));
+ heap.push(*binding);
- heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
- heap.push(HeapCellValue::Atom(var_atom, None));
- heap.push(HeapCellValue::Addr(*binding));
-
- list_of_var_eqs.push(Addr::Str(h));
+ list_of_var_eqs.push(str_loc_as_cell!(h));
}
list_of_var_eqs
}
self.check_stream_properties(
- &mut stream,
+ stream,
StreamType::Text,
- Some(self[temp_v!(2)]),
- clause_name!("read_term"),
+ Some(self.registers[2]),
+ atom!("read_term"),
3,
)?;
if stream.past_end_of_stream() {
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
+ if EOFAction::Reset != stream.options().eof_action() {
+ return Ok(());
} else if self.fail {
return Ok(());
}
}
- let mut orig_stream = stream.clone();
-
loop {
- match self.read(stream.clone(), self.atom_tbl.clone(), &indices.op_dir) {
+ match self.read(stream, &indices.op_dir) {
Ok(term_write_result) => {
- let term = self[temp_v!(2)];
- (self.unify_fn)(self, Addr::HeapCell(term_write_result.heap_loc), term);
+ let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
+ (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
+ pstr_loc_as_cell!(term_write_result.heap_loc)
+ }
+ _ => {
+ heap_loc_as_cell!(term_write_result.heap_loc)
+ }
+ );
+
+ let term = self.registers[2];
+ unify_fn!(*self, heap_loc, term);
+ let term = heap_loc;
if self.fail {
return Ok(());
@@ -417,7 +514,9 @@ impl MachineState {
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
- for addr in self.acyclic_pre_order_iter(term) {
+ for addr in stackful_preorder_iter(&mut self.heap, term) {
+ let addr = unmark_cell_bits!(addr);
+
if let Some(var) = addr.as_var() {
if !singleton_var_set.contains_key(&var) {
singleton_var_set.insert(var, true);
@@ -436,8 +535,7 @@ impl MachineState {
false
}
}),
- &indices.op_dir,
- self.atom_tbl.clone(),
+ &mut self.atom_tbl,
);
let mut var_list = Vec::with_capacity(singleton_var_set.len());
@@ -454,48 +552,48 @@ impl MachineState {
let list_of_var_eqs = push_var_eq_functors(
&mut self.heap,
var_list.iter().map(|(var_name, var,_)| (var_name,var)),
- &indices.op_dir,
- self.atom_tbl.clone(),
+ &mut self.atom_tbl,
);
- let singleton_addr = self[temp_v!(3)];
- let singletons_offset = Addr::HeapCell(self.heap.to_list(
- singleton_var_list.into_iter()
- ));
+ let singleton_addr = self.registers[3];
+ let singletons_offset = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter())
+ );
- (self.unify_fn)(self, singletons_offset, singleton_addr);
+ unify_fn!(*self, singletons_offset, singleton_addr);
if self.fail {
return Ok(());
}
- let vars_addr = self[temp_v!(4)];
- let vars_offset = Addr::HeapCell(self.heap.to_list(
- var_list.into_iter().map(|(_,var,_)| var)
- ));
+ let vars_addr = self.registers[4];
+ let vars_offset = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.heap, var_list.into_iter().map(|(_,cell,_)| cell))
+ );
- (self.unify_fn)(self, vars_offset, vars_addr);
+ unify_fn!(*self, vars_offset, vars_addr);
if self.fail {
return Ok(());
}
- let var_names_addr = self[temp_v!(5)];
- let var_names_offset =
- Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
+ let var_names_addr = self.registers[5];
+ let var_names_offset = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.heap, list_of_var_eqs.into_iter())
+ );
- return Ok((self.unify_fn)(self, var_names_offset, var_names_addr));
+ return Ok(unify_fn!(*self, var_names_offset, var_names_addr));
}
Err(err) => {
if let ParserError::UnexpectedEOF = err {
self.eof_action(
- self[temp_v!(2)],
- &mut orig_stream,
- clause_name!("read_term"),
+ self.registers[2],
+ stream,
+ atom!("read_term"),
3,
)?;
- if orig_stream.options().eof_action == EOFAction::Reset {
+ if stream.options().eof_action() == EOFAction::Reset {
if self.fail == false {
continue;
}
@@ -504,8 +602,8 @@ impl MachineState {
return Ok(());
}
- let stub = MachineError::functor_stub(clause_name!("read_term"), 3);
- let err = MachineError::syntax_error(self.heap.h(), err);
+ let stub = functor_stub(atom!("read_term"), 3);
+ let err = self.syntax_error(err);
return Err(self.error_form(err, stub));
}
@@ -514,870 +612,210 @@ impl MachineState {
}
pub(crate) fn write_term<'a>(
- &'a self,
+ &'a mut self,
op_dir: &'a OpDir,
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub> {
- let ignore_ops = self.store(self.deref(self[temp_v!(3)]));
- let numbervars = self.store(self.deref(self[temp_v!(4)]));
- let quoted = self.store(self.deref(self[temp_v!(5)]));
- let max_depth = self.store(self.deref(self[temp_v!(7)]));
-
- 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!()
- }
- }
+ let ignore_ops = self.store(self.deref(self.registers[3]));
+ let numbervars = self.store(self.deref(self.registers[4]));
+ let quoted = self.store(self.deref(self.registers[5]));
+ let max_depth = self.store(self.deref(self.registers[7]));
- if let &Addr::Con(h) = &quoted {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- printer.quoted = name.as_str() == "true";
- } else {
- unreachable!()
- }
- }
+ let term_to_be_printed = self.store(self.deref(self.registers[2]));
+ let stub_gen = || functor_stub(atom!("write_term"), 2);
- 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!(6), stub) {
+ let printer = match self.try_from_list(self.registers[6], stub_gen) {
Ok(addrs) => {
- let mut var_names: IndexMap<Addr, String> = IndexMap::new();
+ let mut var_names: IndexMap<HeapCellValue, Rc<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));
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[s])
+ .get_name_and_arity();
+
+ if name == atom!("=") && arity == 2 {
+ let atom = self.store(self.deref(self.heap[s+1]));
+ let var = self.store(self.deref(self.heap[s+2]));
if var_names.contains_key(&var) {
continue;
}
- var_names.insert(var, atom);
+ var_names.insert(var, Rc::new(cell_as_atom!(atom).as_str().to_owned()));
}
- _ => {}
- },
- _ => {}
- }
+ }
+ _ => {
+ }
+ );
}
- printer.var_names = var_names;
- }
- Err(err) => {
- return Err(err);
- }
- }
-
- Ok(Some(printer))
- }
-
- pub(super) fn throw_undefined_error(&mut self, name: ClauseName, arity: usize) -> MachineStub {
- let stub = MachineError::functor_stub(name.clone(), arity);
- let h = self.heap.h();
- let key = ExistenceError::Procedure(name, arity);
-
- self.error_form(MachineError::existence_error(h, key), stub)
- }
-
- #[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();
+ let mut printer = HCPrinter::new(
+ &mut self.heap,
+ &mut self.arena,
+ op_dir,
+ PrinterOutputter::new(),
+ term_to_be_printed,
+ );
+
+ if let HeapCellValueTag::Atom = ignore_ops.get_tag() {
+ let name = cell_as_atom!(ignore_ops);
+ printer.ignore_ops = name == atom!("true");
+ } else {
+ unreachable!();
+ }
- while let Some(addr) = iter.next() {
- let addr = self.store(self.deref(*addr));
+ if let HeapCellValueTag::Atom = numbervars.get_tag() {
+ let name = cell_as_atom!(numbervars);
+ printer.numbervars = name == atom!("true");
+ } else {
+ unreachable!();
+ }
- match addr {
- Addr::Char(c) => {
- chars.push(c);
- continue;
+ if let HeapCellValueTag::Atom = quoted.get_tag() {
+ let name = cell_as_atom!(quoted);
+ printer.quoted = name == atom!("true");
+ } else {
+ unreachable!();
}
- Addr::Con(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- if name.is_char() {
- chars += name.as_str();
- continue;
+
+ match Number::try_from(max_depth) {
+ Ok(Number::Fixnum(n)) => {
+ if let Ok(n) = usize::try_from(n.get_num()) {
+ printer.max_depth = n;
+ } else {
+ self.fail = true;
+ return Ok(None);
}
}
- }
- _ => {}
- };
-
- let h = self.heap.h();
-
- return Err(MachineError::type_error(h, ValidType::Character, addr));
- }
-
- Ok(chars)
- }
-
- pub(super) fn read_predicate_key(&self, name: Addr, arity: Addr) -> (ClauseName, usize) {
- let predicate_name = atom_from!(self, self.store(self.deref(name)));
- let arity = self.store(self.deref(arity));
-
- let arity = match Number::try_from((arity, &self.heap)) {
- Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => n.to_usize().unwrap(),
- Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => {
- usize::try_from(n).unwrap()
- }
- _ => unreachable!(),
- };
-
- (predicate_name, arity)
- }
-
- pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) {
- self.cp.assign_if_local(self.p.clone() + 1);
- self.num_of_args = arity;
- self.b0 = self.b;
- self.p = CodePtr::Local(p);
- }
-
- pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) {
- self.num_of_args = arity;
- self.b0 = self.b;
- self.p = CodePtr::Local(p);
- }
-
- pub(super) fn module_lookup(
- &mut self,
- indices: &IndexStore,
- call_policy: &mut Box<dyn CallPolicy>,
- key: PredicateKey,
- module_name: ClauseName,
- _last_call: bool,
- stream_aliases: &StreamAliasDir,
- ) -> CallResult {
- if module_name.as_str() == "user" {
- return call_policy.call_clause_type(
- self,
- key,
- &indices.code_dir,
- &indices.op_dir,
- stream_aliases,
- );
- } else if let Some(module) = indices.modules.get(&module_name) {
- return call_policy.call_clause_type(
- self,
- key,
- &module.code_dir,
- &module.op_dir,
- stream_aliases,
- );
- }
-
- let (name, arity) = key;
-
- let h = self.heap.h();
- let stub = MachineError::functor_stub(name.clone(), arity);
- let err = MachineError::module_resolution_error(h, module_name, name, arity);
-
- return Err(self.error_form(err, stub));
- }
-}
-
-pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
-
-pub(crate) trait CallPolicy: Any + fmt::Debug {
- fn retry_me_else(
- &mut self,
- machine_st: &mut MachineState,
- offset: usize,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- let b = machine_st.b;
- 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];
- }
-
- machine_st.num_of_args = n;
- machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
- machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
-
- machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset;
-
- let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
- let curr_tr = machine_st.tr;
-
- machine_st.unwind_trail(old_tr, curr_tr, global_variables);
- machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
-
- machine_st.trail.truncate(machine_st.tr);
- machine_st
- .heap
- .truncate(machine_st.stack.index_or_frame(b).prelude.h);
-
- machine_st.attr_var_init.reset();
-
- machine_st.hb = machine_st.heap.h();
- machine_st.p += 1;
-
- Ok(())
- }
-
- fn retry(
- &mut self,
- machine_st: &mut MachineState,
- offset: usize,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- let b = machine_st.b;
- 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];
- }
-
- machine_st.num_of_args = n;
- machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
- machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
-
- machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + 1;
-
- let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
- let curr_tr = machine_st.tr;
-
- machine_st.unwind_trail(old_tr, curr_tr, global_variables);
- machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
-
- machine_st.trail.truncate(machine_st.tr);
- machine_st
- .heap
- .truncate(machine_st.stack.index_or_frame(b).prelude.h);
-
- machine_st.attr_var_init.reset();
-
- machine_st.hb = machine_st.heap.h();
- machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
-
- Ok(())
- }
-
- fn trust(
- &mut self,
- machine_st: &mut MachineState,
- offset: usize,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- let b = machine_st.b;
- 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];
- }
-
- machine_st.num_of_args = n;
- machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
- machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
-
- let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
- let curr_tr = machine_st.tr;
-
- machine_st.unwind_trail(old_tr, curr_tr, global_variables);
- machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
-
- machine_st.trail.truncate(machine_st.tr);
- machine_st
- .heap
- .truncate(machine_st.stack.index_or_frame(b).prelude.h);
-
- machine_st.attr_var_init.reset();
-
- 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 = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
-
- Ok(())
- }
-
- fn trust_me(
- &mut self,
- machine_st: &mut MachineState,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- let b = machine_st.b;
- 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];
- }
-
- machine_st.num_of_args = n;
- machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
- machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
-
- let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
- let curr_tr = machine_st.tr;
-
- machine_st.unwind_trail(old_tr, curr_tr, global_variables);
- machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
-
- machine_st.trail.truncate(machine_st.tr);
- machine_st
- .heap
- .truncate(machine_st.stack.index_or_frame(b).prelude.h);
-
- machine_st.attr_var_init.reset();
-
- 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;
-
- Ok(())
- }
-
- fn context_call(
- &mut self,
- machine_st: &mut MachineState,
- name: ClauseName,
- arity: usize,
- idx: &CodeIndex,
- ) -> CallResult {
- if machine_st.last_call {
- self.try_execute(machine_st, name, arity, idx)
- } else {
- self.try_call(machine_st, name, arity, idx)
- }
- }
-
- fn try_call(
- &mut self,
- machine_st: &mut MachineState,
- name: ClauseName,
- arity: usize,
- idx: &CodeIndex,
- ) -> CallResult {
- match idx.get() {
- IndexPtr::DynamicUndefined => {
- machine_st.fail = true;
- return Ok(());
- }
- IndexPtr::Undefined => {
- return Err(machine_st.throw_undefined_error(name, arity));
- }
- IndexPtr::DynamicIndex(compiled_tl_index) => {
- machine_st.dynamic_mode = FirstOrNext::First;
- machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
- }
- IndexPtr::Index(compiled_tl_index) => {
- machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
- }
- }
-
- Ok(())
- }
-
- fn try_execute(
- &mut self,
- machine_st: &mut MachineState,
- name: ClauseName,
- arity: usize,
- idx: &CodeIndex,
- ) -> CallResult {
- match idx.get() {
- IndexPtr::DynamicUndefined => {
- machine_st.fail = true;
- return Ok(());
- }
- IndexPtr::Undefined => {
- return Err(machine_st.throw_undefined_error(name, arity));
- }
- IndexPtr::DynamicIndex(compiled_tl_index) => {
- machine_st.dynamic_mode = FirstOrNext::First;
- machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index));
- }
- IndexPtr::Index(compiled_tl_index) => {
- machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
- }
- }
-
- Ok(())
- }
-
- fn call_builtin(
- &mut self,
- machine_st: &mut MachineState,
- ct: &BuiltInClauseType,
- _code_dir: &CodeDir,
- op_dir: &OpDir,
- stream_aliases: &StreamAliasDir,
- ) -> CallResult {
- match ct {
- &BuiltInClauseType::AcyclicTerm => {
- 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)
- }
- &BuiltInClauseType::Arg => {
- machine_st.try_arg()?;
- return_from_clause!(machine_st.last_call, machine_st)
- }
- &BuiltInClauseType::Compare => {
- let a1 = machine_st.store(machine_st.deref(machine_st[temp_v!(1)]));
- let a2 = machine_st[temp_v!(2)];
- let a3 = machine_st[temp_v!(3)];
-
- match a1 {
- Addr::Con(h) if machine_st.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &machine_st.heap[h] {
- match atom.as_str() {
- ">" | "<" | "=" => {}
- _ => {
- let stub =
- MachineError::functor_stub(clause_name!("compare"), 3);
-
- let err =
- MachineError::domain_error(DomainErrorType::Order, a1);
- return Err(machine_st.error_form(err, stub));
- }
- }
+ Ok(Number::Integer(n)) => {
+ if let Some(n) = n.to_usize() {
+ printer.max_depth = n;
} else {
- unreachable!()
+ self.fail = true;
+ return Ok(None);
}
}
- addr if !addr.is_ref() => {
- let h = machine_st.heap.h();
- let stub = MachineError::functor_stub(clause_name!("compare"), 3);
- let err = MachineError::type_error(h, ValidType::Atom, a1);
- return Err(machine_st.error_form(err, stub));
+ _ => {
+ unreachable!();
}
- _ => {}
}
- let atom = match machine_st.compare_term_test(&a2, &a3) {
- Some(Ordering::Greater) => {
- let spec = fetch_atom_op_spec(clause_name!(">"), None, op_dir);
- HeapCellValue::Atom(clause_name!(">"), spec)
- }
- Some(Ordering::Equal) => {
- let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir);
- HeapCellValue::Atom(clause_name!("="), spec)
- }
- None | Some(Ordering::Less) => {
- let spec = fetch_atom_op_spec(clause_name!("<"), None, op_dir);
- HeapCellValue::Atom(clause_name!("<"), spec)
- }
- };
-
- let h = machine_st.heap.h();
-
- machine_st.heap.push(atom);
- (machine_st.unify_fn)(machine_st, 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::Read => {
- let stream = machine_st.get_stream_or_alias(
- machine_st[temp_v!(1)],
- stream_aliases,
- "read",
- 2,
- )?;
-
- match machine_st.read(stream, machine_st.atom_tbl.clone(), op_dir) {
- Ok(offset) => {
- let addr = machine_st[temp_v!(2)];
- (machine_st.unify_fn)(machine_st, addr, Addr::HeapCell(offset.heap_loc));
- }
- Err(ParserError::UnexpectedEOF) => {
- let addr = machine_st[temp_v!(2)];
- let eof = clause_name!("end_of_file".to_string(), machine_st.atom_tbl);
-
- let atom = machine_st.heap.to_unifiable(HeapCellValue::Atom(eof, None));
-
- (machine_st.unify_fn)(machine_st, addr, atom);
- }
- Err(e) => {
- let h = machine_st.heap.h();
- let stub = MachineError::functor_stub(clause_name!("read"), 2);
-
- let err = MachineError::syntax_error(h, e);
- let err = machine_st.error_form(err, stub);
-
- return Err(err);
- }
- };
-
- return_from_clause!(machine_st.last_call, machine_st)
- }
- &BuiltInClauseType::CopyTerm => {
- machine_st.copy_term(AttrVarPolicy::DeepCopy);
- return_from_clause!(machine_st.last_call, machine_st)
- }
- &BuiltInClauseType::Eq => {
- let a1 = machine_st[temp_v!(1)];
- let a2 = machine_st[temp_v!(2)];
+ printer.var_names = var_names;
- machine_st.fail = machine_st.eq_test(a1, a2);
- return_from_clause!(machine_st.last_call, machine_st)
- }
- &BuiltInClauseType::Ground => {
- machine_st.fail = machine_st.ground_test();
- return_from_clause!(machine_st.last_call, machine_st)
+ printer
}
- &BuiltInClauseType::Functor => {
- machine_st.try_functor(op_dir)?;
- return_from_clause!(machine_st.last_call, machine_st)
- }
- &BuiltInClauseType::NotEq => {
- let a1 = machine_st[temp_v!(1)];
- let a2 = machine_st[temp_v!(2)];
-
- machine_st.fail =
- if let Some(Ordering::Equal) = machine_st.compare_term_test(&a1, &a2) {
- true
- } else {
- false
- };
-
- return_from_clause!(machine_st.last_call, machine_st)
+ Err(err) => {
+ return Err(err);
}
- &BuiltInClauseType::Sort => {
- machine_st.check_sort_errors()?;
-
- 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)
- .unwrap_or(Ordering::Less)
- });
+ };
- machine_st.term_dedup(&mut list);
+ Ok(Some(printer))
+ }
- let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter()));
+ pub(super) fn read_predicate_key(&self, name: HeapCellValue, arity: HeapCellValue) -> (Atom, usize) {
+ let name = cell_as_atom!(self.store(self.deref(name)));
+ let arity = cell_as_fixnum!(self.store(self.deref(arity)));
- let r2 = machine_st[temp_v!(2)];
- (machine_st.unify_fn)(machine_st, r2, heap_addr);
+ (name, usize::try_from(arity.get_num()).unwrap())
+ }
- return_from_clause!(machine_st.last_call, machine_st)
- }
- &BuiltInClauseType::KeySort => {
- machine_st.check_keysort_errors()?;
+ #[inline(always)]
+ pub(super) fn cut_body(&mut self, value: HeapCellValue) {
+ let b = self.b;
- let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
- let list = machine_st.try_from_list(temp_v!(1), stub)?;
- let mut key_pairs = Vec::new();
+ read_heap_cell!(value,
+ (HeapCellValueTag::Fixnum, b0) => {
+ let b0 = b0.get_num() as usize;
- for val in list {
- let key = machine_st.project_onto_key(val.clone())?;
- key_pairs.push((key, val.clone()));
+ if b > b0 {
+ self.b = b0;
}
-
- 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)];
- (machine_st.unify_fn)(machine_st, r2, heap_addr);
-
- return_from_clause!(machine_st.last_call, machine_st)
}
- &BuiltInClauseType::Is(r, ref 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_fn)(machine_st, a1, n2);
-
- return_from_clause!(machine_st.last_call, machine_st)
+ _ => {
+ self.fail = true;
}
- }
+ );
}
- fn call_clause_type(
- &mut self,
- machine_st: &mut MachineState,
- key: PredicateKey,
- code_dir: &CodeDir,
- op_dir: &OpDir,
- stream_aliases: &StreamAliasDir,
- ) -> CallResult {
- let (name, arity) = key;
-
- 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, code_dir, op_dir, stream_aliases)?;
- }
- ClauseType::CallN => {
- machine_st.handle_internal_call_n(arity);
+ #[inline(always)]
+ pub(super) fn try_me_else(&mut self, offset: usize) {
+ let n = self.num_of_args;
+ let b = self.stack.allocate_or_frame(n);
+ let or_frame = self.stack.index_or_frame_mut(b);
- if machine_st.fail {
- return Ok(());
- }
+ or_frame.prelude.univ_prelude.num_cells = n;
+ or_frame.prelude.e = self.e;
+ or_frame.prelude.cp = self.cp;
+ or_frame.prelude.b = self.b;
+ or_frame.prelude.bp = self.p + offset;
+ or_frame.prelude.boip = 0;
+ or_frame.prelude.biip = 0;
+ or_frame.prelude.tr = self.tr;
+ or_frame.prelude.h = self.heap.len();
+ or_frame.prelude.b0 = self.b0;
- machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
- }
- ClauseType::Inlined(inlined) => {
- machine_st.execute_inlined(&inlined);
+ self.b = b;
- if machine_st.last_call {
- machine_st.p = CodePtr::Local(machine_st.cp);
- }
- }
- ClauseType::Op(..) | ClauseType::Named(..) => {
- if let Some(idx) = code_dir.get(&(name.clone(), arity)) {
- self.context_call(machine_st, name, arity, idx)?;
- } else {
- return Err(machine_st.throw_undefined_error(name, arity));
- }
- }
- ClauseType::System(_) => {
- 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(machine_st.heap.h(), ValidType::Callable, name),
- stub,
- ));
- }
+ for i in 0..n {
+ or_frame[i] = self.registers[i+1];
}
- Ok(())
- }
-
- fn call_n(
- &mut self,
- machine_st: &mut MachineState,
- arity: usize,
- code_dir: &CodeDir,
- op_dir: &OpDir,
- stream_aliases: &StreamAliasDir,
- ) -> CallResult {
- if let Some(key) = machine_st.setup_call_n(arity) {
- self.call_clause_type(machine_st, key, code_dir, op_dir, stream_aliases)?;
- }
-
- Ok(())
- }
-}
-
-impl CallPolicy for CWILCallPolicy {
- fn context_call(
- &mut self,
- machine_st: &mut MachineState,
- name: ClauseName,
- arity: usize,
- idx: &CodeIndex,
- ) -> CallResult {
- self.prev_policy
- .context_call(machine_st, name, arity, idx)?; //, indices)?;
- self.increment(machine_st)
+ self.hb = self.heap.len();
+ self.p += 1;
}
- fn retry_me_else(
- &mut self,
- machine_st: &mut MachineState,
- offset: usize,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- self.prev_policy
- .retry_me_else(machine_st, offset, global_variables)?;
- self.increment(machine_st)
- }
+ #[inline(always)]
+ pub(super) fn indexed_try(&mut self, offset: usize) {
+ let n = self.num_of_args;
+ let b = self.stack.allocate_or_frame(n);
+ let or_frame = self.stack.index_or_frame_mut(b);
- fn retry(
- &mut self,
- machine_st: &mut MachineState,
- offset: usize,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- self.prev_policy
- .retry(machine_st, offset, global_variables)?;
- self.increment(machine_st)
- }
+ or_frame.prelude.univ_prelude.num_cells = n;
+ or_frame.prelude.e = self.e;
+ or_frame.prelude.cp = self.cp;
+ or_frame.prelude.b = self.b;
+ or_frame.prelude.bp = self.p; // + 1; in self.iip now!
+ or_frame.prelude.boip = self.oip;
+ or_frame.prelude.biip = self.iip + 1;
+ or_frame.prelude.tr = self.tr;
+ or_frame.prelude.h = self.heap.len();
+ or_frame.prelude.b0 = self.b0;
- fn trust_me(
- &mut self,
- machine_st: &mut MachineState,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- self.prev_policy.trust_me(machine_st, global_variables)?;
- self.increment(machine_st)
- }
+ self.b = b;
- fn trust(
- &mut self,
- machine_st: &mut MachineState,
- offset: usize,
- global_variables: &mut GlobalVarDir,
- ) -> CallResult {
- self.prev_policy
- .trust(machine_st, offset, global_variables)?;
- self.increment(machine_st)
- }
+ for i in 0..n {
+ or_frame[i] = self.registers[i+1];
+ }
- fn call_builtin(
- &mut self,
- machine_st: &mut MachineState,
- ct: &BuiltInClauseType,
- code_dir: &CodeDir,
- op_dir: &OpDir,
- stream_aliases: &StreamAliasDir,
- ) -> CallResult {
- self.prev_policy
- .call_builtin(machine_st, ct, code_dir, op_dir, stream_aliases)?;
-
- self.increment(machine_st)
- }
+ self.hb = self.heap.len();
+ self.p = self.p + offset;
- fn call_n(
- &mut self,
- machine_st: &mut MachineState,
- arity: usize,
- code_dir: &CodeDir,
- op_dir: &OpDir,
- stream_aliases: &StreamAliasDir,
- ) -> CallResult {
- self.prev_policy
- .call_n(machine_st, arity, code_dir, op_dir, stream_aliases)?;
-
- self.increment(machine_st)
+ self.oip = 0;
+ self.iip = 0;
}
}
-downcast!(dyn CallPolicy);
-
#[derive(Debug)]
-pub(crate) struct DefaultCallPolicy {}
-
-impl CallPolicy for DefaultCallPolicy {}
-
-#[derive(Debug)]
-pub(crate) struct CWILCallPolicy {
- pub(crate) prev_policy: Box<dyn CallPolicy>,
+pub(crate) struct CWIL {
count: Integer,
limits: Vec<(Integer, usize)>,
inference_limit_exceeded: bool,
}
-impl CWILCallPolicy {
- 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);
-
- let new_policy = CWILCallPolicy {
- prev_policy,
+impl CWIL {
+ pub(crate) fn new() -> Self {
+ CWIL {
count: Integer::from(0),
limits: vec![],
inference_limit_exceeded: false,
- };
-
- *policy = Box::new(new_policy);
- }
-
- fn increment(&mut self, machine_st: &MachineState) -> CallResult {
- if self.inference_limit_exceeded || machine_st.ball.stub.h() > 0 {
- return Ok(());
}
-
- if let Some(&(ref limit, bp)) = self.limits.last() {
- if self.count == *limit {
- self.inference_limit_exceeded = true;
-
- return Err(functor!(
- "inference_limit_exceeded",
- [addr(Addr::Usize(bp))]
- ));
- } else {
- self.count += 1;
- }
- }
-
- Ok(())
}
- pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer {
+ pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer {
+ let mut limit = Integer::from(limit);
limit += &self.count;
- match self.limits.last().cloned() {
+ match self.limits.last() {
Some((ref inner_limit, _)) if *inner_limit <= limit => {}
_ => self.limits.push((limit, b)),
};
@@ -1385,9 +823,10 @@ impl CWILCallPolicy {
&self.count
}
+ #[inline(always)]
pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer {
- if let Some((_, bp)) = self.limits.last().cloned() {
- if bp == b {
+ if let Some((_, bp)) = self.limits.last() {
+ if bp == &b {
self.limits.pop();
}
}
@@ -1395,126 +834,15 @@ impl CWILCallPolicy {
&self.count
}
- pub(crate) fn is_empty(&self) -> bool {
- self.limits.is_empty()
+ #[inline(always)]
+ pub(crate) fn reset(&mut self) {
+ self.count = Integer::from(0);
+ self.limits.clear();
+ self.inference_limit_exceeded = false;
}
- 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
- }
-}
-
-pub(crate) trait CutPolicy: Any + fmt::Debug {
- // returns true iff we fail or cut redirected the MachineState's p itself
- fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool;
-}
-
-downcast!(dyn CutPolicy);
-
-fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool {
- let b = machine_st.b;
-
- match addr {
- &Addr::CutPoint(b0) | &Addr::Usize(b0) => {
- if b > b0 {
- machine_st.b = b0;
- }
- }
- _ => {
- machine_st.fail = true;
- return true;
- }
- };
-
- false
-}
-
-#[derive(Debug)]
-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]));
- 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];
- cut_body(machine_st, &addr)
- }
-}
-
-#[derive(Debug)]
-pub(crate) struct SCCCutPolicy {
- // locations of cleaners, cut points, the previous block
- cont_pts: Vec<(Addr, usize, usize)>,
- r_c_w_h: usize,
- r_c_wo_h: usize,
-}
-
-impl SCCCutPolicy {
- pub(crate) fn new(r_c_w_h: usize, r_c_wo_h: usize) -> Self {
- SCCCutPolicy {
- cont_pts: vec![],
- r_c_w_h,
- r_c_wo_h,
- }
- }
-
- pub(crate) fn out_of_cont_pts(&self) -> bool {
- self.cont_pts.is_empty()
- }
-
- pub(crate) fn push_cont_pt(&mut self, addr: Addr, b: usize, prev_b: usize) {
- self.cont_pts.push((addr, b, prev_b));
- }
-
- pub(crate) fn pop_cont_pt(&mut self) -> Option<(Addr, usize, usize)> {
- self.cont_pts.pop()
- }
-
- fn run_cleaners(&self, machine_st: &mut MachineState) -> bool {
- if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
- if machine_st.b < b_cutoff {
- let (idx, arity) = if machine_st.block < prev_block {
- (dir_entry!(self.r_c_w_h), 0)
- } else {
- machine_st[temp_v!(1)] = Addr::Usize(b_cutoff);
- (dir_entry!(self.r_c_wo_h), 1)
- };
-
- if machine_st.last_call {
- machine_st.execute_at_index(arity, idx);
- } else {
- machine_st.call_at_index(arity, idx);
- }
-
- return true;
- }
- }
-
- false
- }
-}
-
-impl CutPolicy for SCCCutPolicy {
- fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
- let b = machine_st.b;
-
- match machine_st[r] {
- Addr::Usize(b0) | Addr::CutPoint(b0) => {
- if b > b0 {
- machine_st.b = b0;
- }
- }
- _ => {
- machine_st.fail = true;
- return true;
- }
- }
-
- self.run_cleaners(machine_st)
+ #[inline(always)]
+ pub(crate) fn is_empty(&self) -> bool {
+ self.limits.is_empty()
}
}
diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs
index c4929d2d..fc60afcc 100644
--- a/src/machine/machine_state_impl.rs
+++ b/src/machine/machine_state_impl.rs
@@ -1,14 +1,9 @@
-use prolog_parser::ast::*;
-use prolog_parser::tabled_rc::*;
-use prolog_parser::{clause_name, perm_v, temp_v};
-
-use crate::clause_types::*;
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::types::*;
use crate::forms::*;
use crate::heap_iter::*;
-use crate::indexing::*;
-use crate::instructions::*;
use crate::machine::attributed_variables::*;
-use crate::machine::code_repo::CodeRepo;
use crate::machine::copier::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::*;
@@ -16,82 +11,79 @@ use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::stack::*;
-use crate::machine::streams::*;
-use crate::machine::INTERRUPT;
-use crate::rug::Integer;
+use crate::parser::ast::*;
+use crate::parser::rug::{Integer, Rational};
+
use ordered_float::*;
-use indexmap::{IndexMap, IndexSet};
+use indexmap::IndexSet;
use std::cmp::Ordering;
use std::convert::TryFrom;
-use std::rc::Rc;
impl MachineState {
pub(crate) fn new() -> Self {
MachineState {
- atom_tbl: TabledData::new(Rc::new("".to_owned())),
+ arena: Arena::new(),
+ atom_tbl: AtomTable::new(),
+ pdl: Vec::with_capacity(1024),
s: HeapPtr::default(),
- p: CodePtr::default(),
+ s_offset: 0,
+ p: 0,
+ oip: 0,
+ iip: 0,
b: 0,
b0: 0,
e: 0,
num_of_args: 0,
- cp: LocalCodePtr::default(),
+ cp: 0,
attr_var_init: AttrVarInitializer::new(0),
fail: false,
- heap: Heap::new(),
+ heap: Heap::with_capacity(256 * 256),
mode: MachineMode::Write,
stack: Stack::new(),
- registers: vec![Addr::HeapCell(0); MAX_ARITY + 1], // self.registers[0] is never used.
+ registers: [heap_loc_as_cell!(0); MAX_ARITY + 1], // self.registers[0] is never used.
trail: vec![],
tr: 0,
hb: 0,
block: 0,
ball: Ball::new(),
lifted_heap: Heap::new(),
- interms: vec![Number::default(); 256],
- last_call: false,
+ interms: vec![Number::default();256],
+ cont_pts: Vec::with_capacity(256),
+ cwil: CWIL::new(),
flags: MachineFlags::default(),
cc: 0,
global_clock: 0,
dynamic_mode: FirstOrNext::First,
unify_fn: MachineState::unify,
bind_fn: MachineState::bind,
+ run_cleaners_fn: |_| { false },
+ increment_call_count_fn: |_| { Ok(()) },
}
}
#[inline]
- pub(crate) fn machine_flags(&self) -> MachineFlags {
- self.flags
- }
-
- pub(crate) fn store(&self, addr: Addr) -> Addr {
- match addr {
- Addr::AttrVar(h) | Addr::HeapCell(h) => self.heap[h].as_addr(h),
- Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc],
- Addr::PStrLocation(h, n) => {
- if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] {
- if !pstr.at_end(n) {
- Addr::PStrLocation(h, n)
- } else if has_tail {
- Addr::HeapCell(h + 1)
- } else {
- Addr::EmptyList
- }
- } else {
- unreachable!()
- }
+ pub(crate) fn store(&self, value: HeapCellValue) -> HeapCellValue {
+ read_heap_cell!(value,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ self.heap[h]
}
- addr => addr,
- }
+ (HeapCellValueTag::StackVar, s) => {
+ self.stack[s]
+ }
+ _ => {
+ value
+ }
+ )
}
- pub(crate) fn deref(&self, mut addr: Addr) -> Addr {
+ #[inline]
+ pub fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue {
loop {
let value = self.store(addr);
- if value.is_ref() && value != addr {
+ if value.is_var() && value != addr {
addr = value;
continue;
}
@@ -100,2485 +92,2230 @@ impl MachineState {
}
}
- fn bind_attr_var(&mut self, h: usize, addr: Addr) {
- match addr.as_var() {
- Some(Ref::HeapCell(hc)) => {
- self.heap[hc] = HeapCellValue::Addr(Addr::AttrVar(h));
- self.trail(TrailRef::Ref(Ref::HeapCell(hc)));
+ pub fn trail(&mut self, r: TrailRef) {
+ match r {
+ TrailRef::Ref(r) => {
+ let h = r.get_value() as usize;
+
+ match r.get_tag() {
+ RefTag::HeapCell => {
+ if h < self.hb {
+ self.trail.push(TrailEntry::build_with(
+ TrailEntryTag::TrailedHeapVar,
+ h as u64,
+ ));
+
+ self.tr += 1;
+ }
+ }
+ RefTag::StackCell => {
+ if h < self.b {
+ self.trail.push(TrailEntry::build_with(
+ TrailEntryTag::TrailedStackVar,
+ h as u64,
+ ));
+
+ self.tr += 1;
+ }
+ }
+ RefTag::AttrVar => {
+ if h < self.hb {
+ self.trail.push(TrailEntry::build_with(
+ TrailEntryTag::TrailedAttrVar,
+ h as u64,
+ ));
+
+ self.tr += 1;
+ }
+ }
+ }
+ }
+ TrailRef::AttrVarHeapLink(h) => {
+ if h < self.hb {
+ self.trail.push(TrailEntry::build_with(
+ TrailEntryTag::TrailedAttrVarHeapLink,
+ h as u64,
+ ));
+
+ self.tr += 1;
+ }
}
- Some(Ref::StackCell(fr, sc)) => {
- self.stack.index_and_frame_mut(fr)[sc] = Addr::AttrVar(h);
- self.trail(TrailRef::Ref(Ref::StackCell(fr, sc)));
+ TrailRef::AttrVarListLink(h, l) => {
+ if h < self.hb {
+ self.trail.push(TrailEntry::build_with(
+ TrailEntryTag::TrailedAttrVarListLink,
+ h as u64,
+ ));
+
+ self.trail.push(TrailEntry::from_bytes(
+ list_loc_as_cell!(l).into_bytes()
+ ));
+
+ self.tr += 2;
+ }
}
- _ => {
- self.push_attr_var_binding(h, addr);
- self.heap[h] = HeapCellValue::Addr(addr);
- self.trail(TrailRef::Ref(Ref::AttrVar(h)));
+ TrailRef::BlackboardEntry(key_atom) => {
+ self.trail.push(TrailEntry::build_with(
+ TrailEntryTag::TrailedBlackboardEntry,
+ key_atom.index as u64,
+ ));
+
+ self.tr += 1;
+ }
+ TrailRef::BlackboardOffset(key_atom, value_cell) => {
+ self.trail.push(TrailEntry::build_with(
+ TrailEntryTag::TrailedBlackboardOffset,
+ key_atom.index as u64,
+ ));
+
+ self.trail.push(TrailEntry::from_bytes(
+ value_cell.into_bytes(),
+ ));
+
+ self.tr += 2;
}
}
}
- pub(super) fn bind(&mut self, r1: Ref, a2: Addr) {
- let t1 = self.store(r1.as_addr());
+ pub fn allocate(&mut self, num_cells: usize) {
+ let e = self.stack.allocate_and_frame(num_cells);
+ let and_frame = self.stack.index_and_frame_mut(e);
+
+ and_frame.prelude.e = self.e;
+ and_frame.prelude.cp = self.cp;
+
+ self.e = e;
+ self.p += 1;
+ }
+
+ pub fn bind(&mut self, r1: Ref, a2: HeapCellValue) {
+ let t1 = self.store(r1.as_heap_cell_value());
let t2 = self.store(a2);
- if t1.is_ref() && (!t2.is_ref() || a2 < r1) {
- match r1 {
- Ref::StackCell(fr, sc) => {
- self.stack.index_and_frame_mut(fr)[sc] = t2;
+ if t1.is_var() && (!t2.is_var() || a2 < r1) {
+ match r1.get_tag() {
+ RefTag::StackCell => {
+ self.stack[r1.get_value() as usize] = t2;
+ self.trail(TrailRef::Ref(r1));
}
- Ref::HeapCell(h) => {
- self.heap[h] = HeapCellValue::Addr(t2);
+ RefTag::HeapCell => {
+ self.heap[r1.get_value() as usize] = t2;
+ self.trail(TrailRef::Ref(r1));
}
- Ref::AttrVar(h) => {
- return self.bind_attr_var(h, t2);
+ RefTag::AttrVar => {
+ self.bind_attr_var(r1.get_value() as usize, t2);
}
};
-
- self.trail(TrailRef::from(r1));
} else {
- match a2.as_var() {
- Some(Ref::StackCell(fr, sc)) => {
- self.stack.index_and_frame_mut(fr)[sc] = t1;
- self.trail(TrailRef::Ref(Ref::StackCell(fr, sc)));
+ read_heap_cell!(a2,
+ (HeapCellValueTag::StackVar, s) => {
+ self.stack[s] = t1;
+ self.trail(TrailRef::Ref(Ref::stack_cell(s)));
}
- Some(Ref::HeapCell(h)) => {
- self.heap[h] = HeapCellValue::Addr(t1);
- self.trail(TrailRef::Ref(Ref::HeapCell(h)));
+ (HeapCellValueTag::Var, h) => {
+ self.heap[h] = t1;
+ self.trail(TrailRef::Ref(Ref::heap_cell(h)));
}
- Some(Ref::AttrVar(h)) => {
+ (HeapCellValueTag::AttrVar, h) => {
self.bind_attr_var(h, t1);
}
- None => {}
- }
- }
- }
-
- #[inline]
- pub(super) fn bind_with_occurs_check_with_error_wrapper(&mut self, r: Ref, addr: Addr) {
- if self.bind_with_occurs_check(r, addr) {
- let err = self.representation_error(
- RepFlag::Term,
- clause_name!("unify_with_occurs_check"),
- 2,
+ _ => {
+ unreachable!();
+ }
);
-
- self.throw_exception(err);
}
}
- #[inline]
- pub(super) fn bind_with_occurs_check_wrapper(&mut self, r: Ref, addr: Addr) {
- self.bind_with_occurs_check(r, addr);
+ pub fn bind_attr_var(&mut self, h: usize, addr: HeapCellValue) {
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Var, hc) => {
+ self.heap[hc] = attr_var_as_cell!(h);
+ self.trail(TrailRef::Ref(Ref::heap_cell(hc)));
+ }
+ (HeapCellValueTag::StackVar, hc) => {
+ self.stack[hc] = attr_var_as_cell!(h);
+ self.trail(TrailRef::Ref(Ref::stack_cell(hc)));
+ }
+ _ => {
+ self.push_attr_var_binding(h, addr);
+ self.heap[h] = addr;
+ self.trail(TrailRef::Ref(Ref::attr_var(h)));
+ }
+ )
}
- #[inline]
- pub(super) fn bind_with_occurs_check(&mut self, r: Ref, addr: Addr) -> bool {
- if let Ref::StackCell(..) = r {
- // local variable optimization -- r cannot occur in the
- // data structure bound to addr, so don't bother
- // traversing it.
- self.bind(r, addr);
- return false;
- }
+ fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
+ // s1 is the value of a STR cell.
+ let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity();
- let mut occurs_triggered = false;
+ read_heap_cell!(value,
+ (HeapCellValueTag::Str, s2) => {
+ let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
+ .get_name_and_arity();
- for addr in self.acyclic_pre_order_iter(addr) {
- if let Some(inner_r) = addr.as_var() {
- if r == inner_r {
- occurs_triggered = true;
- break;
+ if n1 == n2 && a1 == a2 {
+ for idx in 0..a1 {
+ self.pdl.push(heap_loc_as_cell!(s2+1+idx));
+ self.pdl.push(heap_loc_as_cell!(s1+1+idx));
+ }
+ } else {
+ self.fail = true;
}
}
- }
+ (HeapCellValueTag::Lis, l2) => {
+ if a1 == 2 && n1 == atom!(".") {
+ for idx in 0..2 {
+ self.pdl.push(heap_loc_as_cell!(l2+1+idx));
+ self.pdl.push(heap_loc_as_cell!(s1+1+idx));
+ }
+ } else {
+ self.fail = true;
+ }
+ }
+ (HeapCellValueTag::Atom, (n2, a2)) => {
+ if !(a1 == 0 && a2 == 0 && n1 == n2) {
+ self.fail = true;
+ }
+ }
+ (HeapCellValueTag::AttrVar, h) => {
+ self.bind(Ref::attr_var(h), str_loc_as_cell!(s1));
+ }
+ (HeapCellValueTag::Var, h) => {
+ self.bind(Ref::heap_cell(h), str_loc_as_cell!(s1));
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.bind(Ref::stack_cell(s), str_loc_as_cell!(s1));
+ }
+ _ => {
+ self.fail = true;
+ }
+ )
+ }
- self.fail = occurs_triggered;
- self.bind(r, addr);
+ fn unify_list(&mut self, l1: usize, d2: HeapCellValue) {
+ read_heap_cell!(d2,
+ (HeapCellValueTag::Lis, l2) => {
+ for idx in 0..2 {
+ self.pdl.push(heap_loc_as_cell!(l2 + idx));
+ self.pdl.push(heap_loc_as_cell!(l1 + idx));
+ }
+ }
+ (HeapCellValueTag::Str, s2) => {
+ let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
+ .get_name_and_arity();
- return occurs_triggered;
+ if a2 == 2 && n2 == atom!(".") {
+ for idx in 0..2 {
+ self.pdl.push(heap_loc_as_cell!(s2+1+idx));
+ self.pdl.push(heap_loc_as_cell!(l1+idx));
+ }
+ } else {
+ self.fail = true;
+ }
+ }
+ (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => {
+ self.unify_partial_string(list_loc_as_cell!(l1), d2)
+ }
+ (HeapCellValueTag::AttrVar, h) => {
+ self.bind(Ref::attr_var(h), list_loc_as_cell!(l1));
+ }
+ (HeapCellValueTag::Var, h) => {
+ self.bind(Ref::heap_cell(h), list_loc_as_cell!(l1));
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.bind(Ref::stack_cell(s), list_loc_as_cell!(l1));
+ }
+ _ => {
+ self.fail = true;
+ }
+ )
}
- pub(super) fn unify_with_occurs_check_with_error(&mut self, a1: Addr, a2: Addr) {
- let mut throw_error = false;
- self.unify_with_occurs_check_loop(a1, a2, || throw_error = true);
-
- if throw_error {
- let err = self.representation_error(
- RepFlag::Term,
- clause_name!("unify_with_occurs_check"),
- 2,
- );
+ pub fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) {
+ if let Some(r) = value.as_var() {
+ if atom == atom!("") {
+ self.bind(r, atom_as_cell!(atom!("[]")));
+ } else {
+ self.bind(r, atom_as_cstr_cell!(atom));
+ }
- self.throw_exception(err);
+ return;
}
- }
- pub(super) fn unify_with_occurs_check(&mut self, a1: Addr, a2: Addr) {
- self.unify_with_occurs_check_loop(a1, a2, || {})
+ read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (cstr_atom, arity)) if atom == atom!("") => {
+ debug_assert_eq!(arity, 0);
+ self.fail = cstr_atom != atom!("[]");
+ }
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ self.fail = atom != cstr_atom;
+ }
+ (HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
+ self.unify_partial_string(atom_as_cstr_cell!(atom), value);
+
+ if !self.pdl.is_empty() {
+ self.unify();
+ }
+ }
+ _ => {
+ self.fail = true;
+ }
+ );
}
- pub(super) fn unify_with_occurs_check_loop(
- &mut self,
- a1: Addr,
- a2: Addr,
- mut occurs_trigger: impl FnMut(),
- ) {
- let mut pdl = vec![a1, a2];
- let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new();
+ // d1's tag is LIS, STR or PSTRLOC.
+ pub fn unify_partial_string(&mut self, d1: HeapCellValue, d2: HeapCellValue) {
+ if let Some(r) = d2.as_var() {
+ self.bind(r, d1);
+ return;
+ }
- self.fail = false;
+ let s1 = self.heap.len();
- while !(pdl.is_empty() || self.fail) {
- let d1 = self.deref(pdl.pop().unwrap());
- let d2 = self.deref(pdl.pop().unwrap());
+ self.heap.push(d1);
+ self.heap.push(d2);
- if d1 != d2 {
- let d1 = self.store(d1);
- let d2 = self.store(d2);
+ let mut pstr_iter1 = HeapPStrIter::new(&self.heap, s1);
+ let mut pstr_iter2 = HeapPStrIter::new(&self.heap, s1 + 1);
- if tabu_list.contains(&(d1, d2)) {
- continue;
+ match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
+ PStrCmpResult::Ordered(Ordering::Equal) => {}
+ PStrCmpResult::Ordered(Ordering::Less) => {
+ if pstr_iter2.focus.as_var().is_none() {
+ self.fail = true;
} else {
- tabu_list.insert((d1, d2));
+ self.pdl.push(empty_list_as_cell!());
+ self.pdl.push(pstr_iter2.focus);
+ }
+ }
+ PStrCmpResult::Ordered(Ordering::Greater) => {
+ if pstr_iter1.focus.as_var().is_none() {
+ self.fail = true;
+ } else {
+ self.pdl.push(empty_list_as_cell!());
+ self.pdl.push(pstr_iter1.focus);
+ }
+ }
+ continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
+ continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
+ if continuable.is_second_iter() {
+ std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
}
- match (d1, d2) {
- (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => {
- if self.bind_with_occurs_check(Ref::AttrVar(h), addr) {
- occurs_trigger();
- }
- }
- (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => {
- if self.bind_with_occurs_check(Ref::HeapCell(h), addr) {
- occurs_trigger();
- }
- }
- (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => {
- if self.bind_with_occurs_check(Ref::StackCell(fr, sc), addr) {
- occurs_trigger();
- }
- }
- (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => {
- if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] {
- if f2.as_str() == "." && n2 == 2 {
- pdl.push(Addr::HeapCell(a1));
- pdl.push(Addr::HeapCell(a2 + 1));
+ let mut chars_iter = PStrCharsIter {
+ iter: pstr_iter1,
+ item: Some(iteratee),
+ };
- pdl.push(Addr::HeapCell(a1 + 1));
- pdl.push(Addr::HeapCell(a2 + 2));
+ let mut focus = pstr_iter2.focus;
- continue;
- }
- }
+ 'outer: loop {
+ while let Some(c) = chars_iter.peek() {
+ read_heap_cell!(focus,
+ (HeapCellValueTag::Lis, l) => {
+ let val = pstr_iter2.heap[l];
- self.fail = true;
- }
- (Addr::PStrLocation(h, n), Addr::Lis(l))
- | (Addr::Lis(l), Addr::PStrLocation(h, n)) => {
- if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] {
- if let Some(c) = pstr.range_from(n..).next() {
- pdl.push(Addr::PStrLocation(h, n + c.len_utf8()));
- pdl.push(Addr::HeapCell(l + 1));
+ self.pdl.push(val);
+ self.pdl.push(char_as_cell!(c));
- pdl.push(Addr::Char(c));
- pdl.push(Addr::HeapCell(l));
- } else {
- unreachable!()
+ focus = pstr_iter2.heap[l+1];
}
- } else {
- unreachable!()
- }
- }
- (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => {
- if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1]
- {
- if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) =
- &self.heap[h2]
- {
- let pstr1_s = pstr1.as_str_from(n1);
- let pstr2_s = pstr2.as_str_from(n2);
-
- let m_len = if pstr1_s.starts_with(pstr2_s) {
- pstr2_s.len()
- } else if pstr2_s.starts_with(pstr1_s) {
- pstr1_s.len()
- } else {
- self.fail = true;
- return;
- };
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s])
+ .get_name_and_arity();
- if pstr1.at_end(n1 + m_len) {
- if has_tail_1 {
- pdl.push(Addr::HeapCell(h1 + 1));
- } else {
- pdl.push(Addr::EmptyList);
- }
+ if name == atom!(".") && arity == 2 {
+ self.pdl.push(pstr_iter2.heap[s+1]);
+ self.pdl.push(char_as_cell!(c));
- if pstr2.at_end(n2 + m_len) {
- if has_tail_2 {
- pdl.push(Addr::HeapCell(h2 + 1));
- } else {
- pdl.push(Addr::EmptyList);
- }
- } else {
- pdl.push(Addr::PStrLocation(h2, n2 + m_len));
- }
+ focus = pstr_iter2.heap[s+2];
} else {
- pdl.push(Addr::PStrLocation(h1, n1 + m_len));
-
- if pstr2.at_end(n2 + m_len) {
- if has_tail_2 {
- pdl.push(Addr::HeapCell(h2 + 1));
- } else {
- pdl.push(Addr::EmptyList);
- }
- } else {
- pdl.push(Addr::PStrLocation(h2, n2 + m_len));
- }
+ self.fail = true;
+ break 'outer;
}
- } else {
- unreachable!()
}
- } else {
- unreachable!()
- }
- }
- (Addr::Lis(a1), Addr::Lis(a2)) => {
- pdl.push(Addr::HeapCell(a1));
- pdl.push(Addr::HeapCell(a2));
-
- pdl.push(Addr::HeapCell(a1 + 1));
- pdl.push(Addr::HeapCell(a2 + 1));
- }
- (Addr::Str(a1), Addr::Str(a2)) => {
- let r1 = &self.heap[a1];
- let r2 = &self.heap[a2];
-
- if let &HeapCellValue::NamedStr(n1, ref f1, _) = r1 {
- if let &HeapCellValue::NamedStr(n2, ref f2, _) = r2 {
- if n1 == n2 && *f1 == *f2 {
- for i in 1..n1 + 1 {
- pdl.push(Addr::HeapCell(a1 + i));
- pdl.push(Addr::HeapCell(a2 + i));
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ match chars_iter.item.unwrap() {
+ PStrIteratee::Char(focus, _) => {
+ self.pdl.push(self.heap[focus]);
+ self.pdl.push(heap_loc_as_cell!(h));
}
+ PStrIteratee::PStrSegment(focus, _, n) => {
+ read_heap_cell!(self.heap[focus],
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
+ if focus < self.heap.len() - 2 {
+ self.heap.pop();
+ self.heap.pop();
+ }
+
+ if n == 0 {
+ let target_cell = match self.heap[focus].get_tag() {
+ HeapCellValueTag::CStr => {
+ atom_as_cstr_cell!(pstr_atom)
+ }
+ HeapCellValueTag::PStr => {
+ pstr_loc_as_cell!(focus)
+ }
+ _ => {
+ unreachable!()
+ }
+ };
+
+ self.pdl.push(target_cell);
+ self.pdl.push(heap_loc_as_cell!(h));
+ } else {
+ let h_len = self.heap.len();
+
+ self.heap.push(pstr_offset_as_cell!(focus));
+ self.heap.push(fixnum_as_cell!(
+ Fixnum::build_with(n as i64)
+ ));
+
+ self.pdl.push(pstr_loc_as_cell!(h_len));
+ self.pdl.push(heap_loc_as_cell!(h));
+ }
+
+ return;
+ }
+ (HeapCellValueTag::PStrOffset, pstr_loc) => {
+ let n0 = cell_as_fixnum!(self.heap[focus+1])
+ .get_num() as usize;
+
+ if pstr_loc < self.heap.len() - 2 {
+ self.heap.pop();
+ self.heap.pop();
+ }
+
+ if n == n0 {
+ self.pdl.push(pstr_loc_as_cell!(focus));
+ self.pdl.push(heap_loc_as_cell!(h));
+ } else {
+ let h_len = self.heap.len();
+
+ self.heap.push(pstr_offset_as_cell!(pstr_loc));
+ self.heap.push(fixnum_as_cell!(
+ Fixnum::build_with(n as i64)
+ ));
+
+ self.pdl.push(pstr_loc_as_cell!(h_len));
+ self.pdl.push(heap_loc_as_cell!(h));
+ }
+
+ return;
+ }
+ _ => {
+ }
+ );
- continue;
- }
- }
- }
+ if focus < self.heap.len() - 2 {
+ self.heap.pop();
+ self.heap.pop();
+ }
- self.fail = true;
- }
- (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) {
- (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _))
- if n1.as_str() == n2.as_str() => {}
- (
- &HeapCellValue::DBRef(ref db_ref_1),
- &HeapCellValue::DBRef(ref db_ref_2),
- ) if db_ref_1 == db_ref_2 => {}
- (v1, v2) => {
- if let Ok(n1) = Number::try_from(v1) {
- if let Ok(n2) = Number::try_from(v2) {
- if n1 == n2 {
- continue;
+ self.pdl.push(self.heap[focus]);
+ self.pdl.push(heap_loc_as_cell!(h));
+
+ return;
}
}
- }
- self.fail = true;
- }
- },
- (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => {
- match &self.heap[h] {
- &HeapCellValue::Atom(ref name, _) if name.is_char() => {
- if name.as_str().chars().next() != Some(c) {
- self.fail = true;
- return;
- }
+ break 'outer;
}
_ => {
self.fail = true;
- return;
- }
- }
- }
- (Addr::Stream(s1), Addr::Stream(s2)) => {
- if s1 != s2 {
- self.fail = true;
- }
- }
- (v, Addr::Con(h)) | (Addr::Con(h), v) => {
- if let Ok(n1) = Number::try_from(&self.heap[h]) {
- if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) {
- if n1 == v {
- continue;
- }
+ break 'outer;
}
- }
+ );
- self.fail = true;
+ chars_iter.next();
}
- (a1, a2) => {
- if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) {
- if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) {
- if n1 == n2 {
- continue;
- }
- }
- }
- if a1 != a2 {
- self.fail = true;
- }
- }
- };
+ chars_iter.iter.next();
+
+ self.pdl.push(chars_iter.iter.focus);
+ self.pdl.push(focus);
+
+ break;
+ }
+ }
+ PStrCmpResult::Unordered => {
+ self.pdl.push(pstr_iter1.focus);
+ self.pdl.push(pstr_iter2.focus);
}
}
+
+ self.heap.pop();
+ self.heap.pop();
+ }
+
+ pub fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) {
+ read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ self.fail = !(arity == 0 && name == atom);
+ }
+ (HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => {
+ self.fail = cstr_atom != atom!("");
+ }
+ (HeapCellValueTag::Char, c1) => {
+ if let Some(c2) = atom.as_char() {
+ self.fail = c1 != c2;
+ } else {
+ self.fail = true;
+ }
+ }
+ (HeapCellValueTag::AttrVar, h) => {
+ self.bind(Ref::attr_var(h), atom_as_cell!(atom));
+ }
+ (HeapCellValueTag::Var, h) => {
+ self.bind(Ref::heap_cell(h), atom_as_cell!(atom));
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.bind(Ref::stack_cell(s), atom_as_cell!(atom));
+ }
+ _ => {
+ self.fail = true;
+ }
+ );
+ }
+
+ pub fn unify_char(&mut self, c: char, value: HeapCellValue) {
+ read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if let Some(c2) = name.as_char() {
+ self.fail = !(c == c2 && arity == 0);
+ } else {
+ self.fail = true;
+ }
+ }
+ (HeapCellValueTag::Char, c2) => {
+ if c != c2 {
+ self.fail = true;
+ }
+ }
+ (HeapCellValueTag::AttrVar, h) => {
+ self.bind(Ref::attr_var(h), char_as_cell!(c));
+ }
+ (HeapCellValueTag::Var, h) => {
+ self.bind(Ref::heap_cell(h), char_as_cell!(c));
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.bind(Ref::stack_cell(s), char_as_cell!(c));
+ }
+ _ => {
+ self.fail = true;
+ }
+ );
}
- pub(super) fn unify(&mut self, a1: Addr, a2: Addr) {
- let mut pdl = vec![a1, a2];
+ pub fn unify_fixnum(&mut self, n1: Fixnum, value: HeapCellValue) {
+ if let Some(r) = value.as_var() {
+ self.bind(r, fixnum_as_cell!(n1));
+ return;
+ }
- let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new();
+ match Number::try_from(value) {
+ Ok(n2) => match n2 {
+ Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {}
+ Number::Integer(n2) if n1.get_num() == *n2 => {}
+ Number::Rational(n2) if n1.get_num() == *n2 => {}
+ _ => {
+ self.fail = true;
+ }
+ },
+ Err(_) => {
+ self.fail = true;
+ }
+ }
+ }
- self.fail = false;
+ pub fn unify_big_int(&mut self, n1: TypedArenaPtr<Integer>, value: HeapCellValue) {
+ if let Some(r) = value.as_var() {
+ self.bind(r, typed_arena_ptr_as_cell!(n1));
+ return;
+ }
- while !(pdl.is_empty() || self.fail) {
- let d1 = self.deref(pdl.pop().unwrap());
- let d2 = self.deref(pdl.pop().unwrap());
+ match Number::try_from(value) {
+ Ok(n2) => match n2 {
+ Number::Fixnum(n2) if *n1 == n2.get_num() => {}
+ Number::Integer(n2) if *n1 == *n2 => {}
+ Number::Rational(n2) if *n1 == *n2 => {}
+ _ => {
+ self.fail = true;
+ }
+ },
+ Err(_) => {
+ self.fail = true;
+ }
+ }
+ }
- if d1 != d2 {
- let d1 = self.store(d1);
- let d2 = self.store(d2);
+ pub fn unify_rational(&mut self, n1: TypedArenaPtr<Rational>, value: HeapCellValue) {
+ if let Some(r) = value.as_var() {
+ self.bind(r, typed_arena_ptr_as_cell!(n1));
+ return;
+ }
- if tabu_list.contains(&(d1, d2)) {
- continue;
- } else {
- tabu_list.insert((d1, d2));
+ match Number::try_from(value) {
+ Ok(n2) => match n2 {
+ Number::Fixnum(n2) if *n1 == n2.get_num() => {}
+ Number::Integer(n2) if *n1 == *n2 => {}
+ Number::Rational(n2) if *n1 == *n2 => {}
+ _ => {
+ self.fail = true;
}
+ },
+ Err(_) => {
+ self.fail = true;
+ }
+ }
+ }
+
+ pub fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) {
+ if let Some(r) = value.as_var() {
+ self.bind(r, typed_arena_ptr_as_cell!(f1));
+ return;
+ }
+
+ read_heap_cell!(value,
+ (HeapCellValueTag::F64, f2) => {
+ self.fail = **f1 != **f2;
+ }
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::F64, f2) => {
+ self.fail = **f1 != **F64Ptr(f2);
+ }
+ _ => {
+ self.fail = true;
+ }
+ );
+ }
+ _ => {
+ self.fail = true;
+ }
+ );
+ }
+
+ pub fn unify_constant(&mut self, ptr: UntypedArenaPtr, value: HeapCellValue) {
+ if let Some(ptr2) = value.to_untyped_arena_ptr() {
+ if ptr.get_ptr() == ptr2.get_ptr() {
+ return;
+ }
+ }
+
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Integer, int_ptr) => {
+ self.unify_big_int(int_ptr, value);
+ }
+ (ArenaHeaderTag::Rational, rat_ptr) => {
+ self.unify_rational(rat_ptr, value);
+ }
+ _ => {
+ if let Some(r) = value.as_var() {
+ self.bind(r, untyped_arena_ptr_as_cell!(ptr));
+ } else {
+ self.fail = true;
+ }
+ }
+ );
+ }
- match (d1, d2) {
- (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => {
- self.bind(Ref::AttrVar(h), addr);
+ pub fn unify(&mut self) {
+ let mut tabu_list: IndexSet<(usize, usize)> = IndexSet::new();
+
+ while !(self.pdl.is_empty() || self.fail) {
+ let s1 = self.pdl.pop().unwrap();
+ let s1 = self.deref(s1);
+
+ let s2 = self.pdl.pop().unwrap();
+ let s2 = self.deref(s2);
+
+ if s1 != s2 {
+ let d1 = self.store(s1);
+ let d2 = self.store(s2);
+
+ read_heap_cell!(d1,
+ (HeapCellValueTag::AttrVar, h) => {
+ self.bind(Ref::attr_var(h), d2);
}
- (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => {
- self.bind(Ref::HeapCell(h), addr);
+ (HeapCellValueTag::Var, h) => {
+ self.bind(Ref::heap_cell(h), d2);
}
- (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => {
- self.bind(Ref::StackCell(fr, sc), addr);
+ (HeapCellValueTag::StackVar, s) => {
+ self.bind(Ref::stack_cell(s), d2);
}
- (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => {
- if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] {
- if f2.as_str() == "." && n2 == 2 {
- pdl.push(Addr::HeapCell(a1));
- pdl.push(Addr::HeapCell(a2 + 1));
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert!(arity == 0);
+ self.unify_atom(name, d2);
+ }
+ (HeapCellValueTag::Str, s1) => {
+ if d2.is_constant() {
+ self.fail = true;
+ break;
+ }
- pdl.push(Addr::HeapCell(a1 + 1));
- pdl.push(Addr::HeapCell(a2 + 2));
+ let s2 = s2.get_value() as usize;
- continue;
- }
+ if tabu_list.contains(&(s1, s2)) {
+ continue;
}
- self.fail = true;
- }
- (Addr::PStrLocation(h, n), Addr::Lis(l))
- | (Addr::Lis(l), Addr::PStrLocation(h, n)) => {
- if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] {
- if let Some(c) = pstr.range_from(n..).next() {
- pdl.push(Addr::PStrLocation(h, n + c.len_utf8()));
- pdl.push(Addr::HeapCell(l + 1));
+ self.unify_structure(s1, d2);
- pdl.push(Addr::Char(c));
- pdl.push(Addr::HeapCell(l));
- } else {
- unreachable!()
- }
- } else {
- unreachable!()
+ if !self.fail {
+ tabu_list.insert((s1, s2));
}
}
- (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => {
- if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1]
- {
- if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) =
- &self.heap[h2]
- {
- let pstr1_s = pstr1.as_str_from(n1);
- let pstr2_s = pstr2.as_str_from(n2);
-
- let m_len = if pstr1_s.starts_with(pstr2_s) {
- pstr2_s.len()
- } else if pstr2_s.starts_with(pstr1_s) {
- pstr1_s.len()
- } else {
- self.fail = true;
- return;
- };
+ (HeapCellValueTag::Lis, l1) => {
+ if d2.is_ref() {
+ let l2 = s2.get_value();
- if pstr1.at_end(n1 + m_len) {
- if has_tail_1 {
- pdl.push(Addr::HeapCell(h1 + 1));
- } else {
- pdl.push(Addr::EmptyList);
- }
-
- if pstr2.at_end(n2 + m_len) {
- if has_tail_2 {
- pdl.push(Addr::HeapCell(h2 + 1));
- } else {
- pdl.push(Addr::EmptyList);
- }
- } else {
- pdl.push(Addr::PStrLocation(h2, n2 + m_len));
- }
- } else {
- pdl.push(Addr::PStrLocation(h1, n1 + m_len));
-
- if pstr2.at_end(n2 + m_len) {
- if has_tail_2 {
- pdl.push(Addr::HeapCell(h2 + 1));
- } else {
- pdl.push(Addr::EmptyList);
- }
- } else {
- pdl.push(Addr::PStrLocation(h2, n2 + m_len));
- }
- }
+ if tabu_list.contains(&(l1, l2)) {
+ continue;
}
+
+ tabu_list.insert((l1, l2));
}
- }
- (Addr::Lis(a1), Addr::Lis(a2)) => {
- pdl.push(Addr::HeapCell(a1));
- pdl.push(Addr::HeapCell(a2));
- pdl.push(Addr::HeapCell(a1 + 1));
- pdl.push(Addr::HeapCell(a2 + 1));
+ self.unify_list(l1, d2);
}
- (Addr::Str(a1), Addr::Str(a2)) => {
- let r1 = &self.heap[a1];
- let r2 = &self.heap[a2];
-
- if let &HeapCellValue::NamedStr(n1, ref f1, _) = r1 {
- if let &HeapCellValue::NamedStr(n2, ref f2, _) = r2 {
- if n1 == n2 && *f1 == *f2 {
- for i in 1..n1 + 1 {
- pdl.push(Addr::HeapCell(a1 + i));
- pdl.push(Addr::HeapCell(a2 + i));
- }
-
+ (HeapCellValueTag::PStrLoc, pstr1_loc) => {
+ read_heap_cell!(d2,
+ (HeapCellValueTag::PStrLoc |
+ HeapCellValueTag::Lis |
+ HeapCellValueTag::Str,
+ pstr2_loc) => {
+ if tabu_list.contains(&(pstr1_loc, pstr2_loc)) {
continue;
}
}
- }
-
- self.fail = true;
- }
- (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) {
- (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _))
- if n1.as_str() == n2.as_str() => {}
- (
- &HeapCellValue::DBRef(ref db_ref_1),
- &HeapCellValue::DBRef(ref db_ref_2),
- ) if db_ref_1 == db_ref_2 => {}
- (v1, v2) => {
- if let Ok(n1) = Number::try_from(v1) {
- if let Ok(n2) = Number::try_from(v2) {
- if n1 == n2 {
- continue;
- }
- }
+ (HeapCellValueTag::CStr |
+ HeapCellValueTag::AttrVar |
+ HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar) => {
}
+ _ => {
+ self.fail = true;
+ break;
+ }
+ );
- self.fail = true;
+ self.unify_partial_string(d1, d2);
+
+ if !self.fail && !d2.is_constant() {
+ tabu_list.insert((pstr1_loc, d2.get_value()));
}
- },
- (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => {
- match &self.heap[h] {
- &HeapCellValue::Atom(ref name, _) if name.is_char() => {
- if name.as_str().chars().next() != Some(c) {
- self.fail = true;
- return;
- }
+ }
+ (HeapCellValueTag::CStr) => {
+ read_heap_cell!(d2,
+ (HeapCellValueTag::AttrVar, h) => {
+ self.bind(Ref::attr_var(h), d1);
+ continue;
+ }
+ (HeapCellValueTag::Var, h) => {
+ self.bind(Ref::heap_cell(h), d1);
+ continue;
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.bind(Ref::stack_cell(s), d1);
+ continue;
+ }
+ (HeapCellValueTag::Str |
+ HeapCellValueTag::Lis |
+ HeapCellValueTag::PStrLoc) => {
+ }
+ (HeapCellValueTag::CStr) => {
+ self.fail = d1 != d2;
+ continue;
}
_ => {
self.fail = true;
return;
}
- }
+ );
+
+ self.unify_partial_string(d2, d1);
}
- (Addr::Stream(s1), Addr::Stream(s2)) => {
- if s1 != s2 {
- self.fail = true;
- }
+ (HeapCellValueTag::F64, f1) => {
+ self.unify_f64(f1, d2);
}
- (v, Addr::Con(h)) | (Addr::Con(h), v) => {
- if let Ok(n1) = Number::try_from(&self.heap[h]) {
- if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) {
- if n1 == v {
- continue;
- }
- }
- }
-
- self.fail = true;
+ (HeapCellValueTag::Fixnum, n1) => {
+ self.unify_fixnum(n1, d2);
}
- (a1, a2) => {
- if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) {
- if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) {
- if n1 == n2 {
- continue;
- }
- }
- }
-
- if a1 != a2 {
- self.fail = true;
- }
+ (HeapCellValueTag::Char, c1) => {
+ self.unify_char(c1, d2);
}
- };
+ (HeapCellValueTag::Cons, ptr_1) => {
+ self.unify_constant(ptr_1, d2);
+ }
+ _ => {
+ unreachable!();
+ }
+ );
}
}
}
- pub(super) fn trail(&mut self, r: TrailRef) {
- match r {
- TrailRef::Ref(Ref::HeapCell(h)) => {
- if h < self.hb {
- self.trail.push(TrailRef::Ref(Ref::HeapCell(h)));
- self.tr += 1;
- }
- }
- TrailRef::Ref(Ref::AttrVar(h)) => {
- if h < self.hb {
- self.trail.push(TrailRef::Ref(Ref::AttrVar(h)));
- self.tr += 1;
- }
- }
- TrailRef::AttrVarHeapLink(h) => {
- if h < self.hb {
- self.trail.push(TrailRef::AttrVarHeapLink(h));
- self.tr += 1;
- }
- }
- TrailRef::AttrVarListLink(h, l) => {
- if h < self.hb {
- self.trail.push(TrailRef::AttrVarListLink(h, l));
- self.tr += 1;
- }
- }
- TrailRef::Ref(Ref::StackCell(b, sc)) => {
- if b < self.b {
- self.trail.push(TrailRef::Ref(Ref::StackCell(b, sc)));
- self.tr += 1;
- }
- }
- TrailRef::BlackboardOffset(key_h, value_h) => {
- self.trail.push(TrailRef::BlackboardOffset(key_h, value_h));
- self.tr += 1;
- }
- TrailRef::BlackboardEntry(key_h) => {
- self.trail.push(TrailRef::BlackboardEntry(key_h));
- self.tr += 1;
- }
- }
- }
+ pub(super) fn set_ball(&mut self) {
+ self.ball.reset();
- fn increment_s_ptr(&mut self, rhs: usize) {
- match &mut self.s {
- HeapPtr::HeapCell(ref mut h) => {
- *h += rhs;
- }
- &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => {
- match &self.heap[h] {
- &HeapCellValue::PartialString(ref pstr, _) => {
- for c in pstr.range_from(*n..).take(rhs) {
- *n += c.len_utf8();
- }
+ let addr = self.registers[1];
+ self.ball.boundary = self.heap.len();
- self.s = HeapPtr::PStrLocation(h, *n);
- }
- _ => {}
- }
- }
- }
+ copy_term(
+ CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub),
+ addr,
+ AttrVarPolicy::DeepCopy,
+ );
}
- pub(super) fn unwind_trail(
- &mut self,
- a1: usize,
- a2: usize,
- global_variables: &mut GlobalVarDir,
- ) {
- // the sequence is reversed to respect the chronology of trail
- // additions, now that deleted attributes can be undeleted by
- // backtracking.
- for i in (a1..a2).rev() {
- match self.trail[i] {
- TrailRef::Ref(Ref::HeapCell(h)) => {
- self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h))
- }
- TrailRef::Ref(Ref::AttrVar(h)) => {
- self.heap[h] = HeapCellValue::Addr(Addr::AttrVar(h))
- }
- TrailRef::Ref(Ref::StackCell(fr, sc)) => {
- self.stack.index_and_frame_mut(fr)[sc] = Addr::StackCell(fr, sc)
- }
- TrailRef::AttrVarHeapLink(h) => {
- self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h));
- }
- TrailRef::AttrVarListLink(h, l) => {
- self.heap[h] = HeapCellValue::Addr(Addr::Lis(l));
- }
- TrailRef::BlackboardOffset(key_h, value_h) => {
- let key = atom_from!(
- self,
- self.store(self.deref(self.heap[key_h].as_addr(key_h)))
- );
+ pub(super) fn unwind_stack(&mut self) {
+ self.b = self.block;
+ self.fail = true;
+ }
- let value_addr = self.heap[value_h].as_addr(value_h);
+ #[inline]
+ pub fn bind_with_occurs_check(&mut self, r: Ref, value: HeapCellValue) -> bool {
+ if let RefTag::StackCell = r.get_tag() {
+ // local variable optimization -- r cannot occur in the
+ // heap structure bound to value, so don't bother
+ // traversing value.
+ self.bind(r, value);
+ return false;
+ }
- match global_variables.get_mut(&key) {
- Some((_, ref mut loc)) => *loc = Some(value_addr),
- None => unreachable!(),
- }
- }
- TrailRef::BlackboardEntry(key_h) => {
- let key = atom_from!(
- self,
- self.store(self.deref(self.heap[key_h].as_addr(key_h)))
- );
+ let mut occurs_triggered = false;
- match global_variables.get_mut(&key) {
- Some((_, ref mut loc)) => *loc = None,
- None => unreachable!(),
+ if !value.is_constant() {
+ for addr in stackful_preorder_iter(&mut self.heap, value) {
+ let addr = unmark_cell_bits!(addr);
+
+ if let Some(inner_r) = addr.as_var() {
+ if r == inner_r {
+ occurs_triggered = true;
+ break;
}
}
}
}
- }
- pub(super) fn match_partial_string(&mut self, addr: Addr, string: &String, has_tail: bool) {
- let mut heap_pstr_iter = self.heap_pstr_iter(addr);
+ if occurs_triggered {
+ self.fail = true;
+ } else {
+ self.bind(r, value);
+ }
- match compare_pstr_to_string(&mut heap_pstr_iter, string) {
- Some(prefix_len) if prefix_len == string.len() => {
- let focus = heap_pstr_iter.focus();
+ return occurs_triggered;
+ }
- match focus {
- Addr::PStrLocation(h, n) => {
- if has_tail {
- self.s = HeapPtr::PStrLocation(h, n);
- self.mode = MachineMode::Read;
- } else {
- self.fail = true;
- }
- }
- addr => {
- if has_tail {
- let h = self.heap.h();
+ #[inline]
+ pub(super) fn bind_with_occurs_check_wrapper(&mut self, r: Ref, value: HeapCellValue) {
+ self.bind_with_occurs_check(r, value);
+ }
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
- self.bind(Ref::HeapCell(h), addr);
+ #[inline]
+ pub(super) fn bind_with_occurs_check_with_error_wrapper(
+ &mut self,
+ r: Ref,
+ value: HeapCellValue,
+ ) {
+ if self.bind_with_occurs_check(r, value) {
+ let err = self.representation_error(RepFlag::Term);
+ let stub = functor_stub(atom!("unify_with_occurs_check"), 2);
+ let err = self.error_form(err, stub);
- self.s = HeapPtr::HeapCell(h);
- self.mode = MachineMode::Read;
- } else {
- if let Some(var) = addr.as_var() {
- self.bind(var, Addr::EmptyList);
- } else {
- self.fail = addr != Addr::EmptyList;
- }
- }
- }
- }
- }
- Some(prefix_len) => match heap_pstr_iter.focus() {
- addr if addr.is_ref() => {
- let h = self.heap.h();
+ self.throw_exception(err);
+ }
+ }
- let pstr_addr = if has_tail {
- self.s = HeapPtr::HeapCell(h + 1);
- self.mode = MachineMode::Read;
+ pub(super) fn unify_with_occurs_check_with_error(&mut self) {
+ let mut throw_error = false;
+ self.unify_with_occurs_check_loop(|| throw_error = true);
- self.heap.allocate_pstr(&string[prefix_len..])
- } else {
- self.heap.put_complete_string(&string[prefix_len..])
- };
+ if throw_error {
+ let err = self.representation_error(RepFlag::Term);
+ let stub = functor_stub(atom!("unify_with_occurs_check"), 2);
+ let err = self.error_form(err, stub);
- self.bind(addr.as_var().unwrap(), pstr_addr);
- }
- Addr::Lis(l) => {
- let h = self.heap.h();
+ self.throw_exception(err);
+ }
+ }
- let pstr_addr = if has_tail {
- self.s = HeapPtr::HeapCell(h + 1);
- self.mode = MachineMode::Read;
+ pub(super) fn unify_with_occurs_check(&mut self) {
+ self.unify_with_occurs_check_loop(|| {})
+ }
- self.heap.allocate_pstr(&string[prefix_len..])
- } else {
- self.heap.put_complete_string(&string[prefix_len..])
- };
+ fn unify_structure_with_occurs_check(
+ &mut self,
+ s1: usize,
+ value: HeapCellValue,
+ mut occurs_trigger: impl FnMut(),
+ ) {
+ // s1 is the value of a STR cell.
+ let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity();
- (self.unify_fn)(self, Addr::Lis(l), pstr_addr);
- }
- _ => {
- self.fail = true;
- }
- },
- None => {
- self.fail = true;
- }
- }
- }
+ read_heap_cell!(value,
+ (HeapCellValueTag::Str, s2) => {
+ let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
+ .get_name_and_arity();
- pub(super) fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) {
- match self.store(self.deref(addr)) {
- Addr::Con(c1) => {
- match &self.heap[c1] {
- HeapCellValue::Atom(ref n1, _) => {
- self.fail = match c {
- Constant::Atom(ref n2, _) => n1 != n2,
- Constant::Char(c) if n1.is_char() => {
- Some(*c) != n1.as_str().chars().next()
- }
- _ => true,
- };
- }
- HeapCellValue::Integer(ref n1) => {
- self.fail = match c {
- Constant::Fixnum(n2) => n1.to_isize() != Some(*n2),
- Constant::Integer(ref n2) => n1 != n2,
- Constant::Usize(n2) => n1.to_usize() != Some(*n2),
- _ => true,
- };
- }
- HeapCellValue::Rational(ref r1) => {
- self.fail = if let Constant::Rational(ref r2) = c {
- r1 != r2
- } else {
- true
- }
- }
- HeapCellValue::PartialString(..) => {
- if let Constant::String(ref s2) = c {
- self.match_partial_string(Addr::PStrLocation(c1, 0), &s2, false);
- } else {
- self.fail = true;
- }
- }
- _ => {
- unreachable!()
- }
- };
- }
- Addr::Char(ch) => {
- self.fail = match c {
- Constant::Atom(ref n2, _) if n2.is_char() => {
- Some(ch) != n2.as_str().chars().next()
+ if n1 == n2 && a1 == a2 {
+ for idx in 0..a1 {
+ self.pdl.push(heap_loc_as_cell!(s2+1+idx));
+ self.pdl.push(heap_loc_as_cell!(s1+1+idx));
}
- Constant::Char(c) => *c != ch,
- _ => true,
- };
- }
- Addr::EmptyList => {
- if let Constant::EmptyList = c {
} else {
self.fail = true;
}
}
- Addr::Lis(l) => {
- let addr = self.heap.put_constant(c.clone());
- self.unify(Addr::Lis(l), addr);
- }
- Addr::PStrLocation(h, n) => {
- if let Constant::String(ref s2) = c {
- self.match_partial_string(Addr::PStrLocation(h, n), &s2, false)
+ (HeapCellValueTag::Lis, l2) => {
+ if a1 == 2 && n1 == atom!(".") {
+ for idx in 0..2 {
+ self.pdl.push(heap_loc_as_cell!(l2+idx));
+ self.pdl.push(heap_loc_as_cell!(s1+1+idx));
+ }
} else {
self.fail = true;
- };
- }
- Addr::Stream(_) => {
- self.fail = true;
- }
- addr => {
- let c = self.heap.put_constant(c.clone());
-
- if let Some(r) = addr.as_var() {
- self.bind(r, c);
- } else {
- self.unify(addr, c);
}
}
- };
- }
-
- pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
-
- match instr {
- &ArithmeticInstruction::Add(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
-
- self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 + n2, stub));
- self.p += 1;
+ (HeapCellValueTag::Atom, (n2, a2)) => {
+ if !(a1 == 0 && a2 == 0 && n1 == n2) {
+ self.fail = true;
+ }
}
- &ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
-
- self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 - n2, stub));
- self.p += 1;
+ (HeapCellValueTag::AttrVar, h) => {
+ if self.bind_with_occurs_check(Ref::attr_var(h), str_loc_as_cell!(s1)) {
+ occurs_trigger();
+ }
}
- &ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
-
- self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 * n2, stub));
- self.p += 1;
+ (HeapCellValueTag::Var, h) => {
+ if self.bind_with_occurs_check(Ref::heap_cell(h), str_loc_as_cell!(s1)) {
+ occurs_trigger();
+ }
}
- &ArithmeticInstruction::Max(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
-
- self.interms[t - 1] = try_or_fail!(self, self.max(n1, n2));
- self.p += 1;
+ (HeapCellValueTag::StackVar, s) => {
+ if self.bind_with_occurs_check(Ref::stack_cell(s), str_loc_as_cell!(s1)) {
+ occurs_trigger();
+ }
}
- &ArithmeticInstruction::Min(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
-
- self.interms[t - 1] = try_or_fail!(self, self.min(n1, n2));
- self.p += 1;
+ _ => {
+ self.fail = true;
}
- &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ )
+ }
- self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2));
- self.p += 1;
+ // the return value of unify_partial_string_with_occurs_check is
+ // interpreted as follows:
+ //
+ // Some(None) -- the strings are equal, nothing to unify
+ // Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1
+ // None -- prefixes not equal, unification fails
+ //
+ // d1's tag is assumed to be one of LIS, STR or PSTRLOC.
+ pub fn unify_partial_string_with_occurs_check(
+ &mut self,
+ d1: HeapCellValue,
+ d2: HeapCellValue,
+ mut occurs_trigger: impl FnMut(),
+ ) {
+ if let Some(r) = d2.as_var() {
+ if self.bind_with_occurs_check(r, d1) {
+ occurs_trigger();
}
- &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
- self.interms[t - 1] = try_or_fail!(self, self.gcd(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Pow(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ return;
+ }
- self.interms[t - 1] = try_or_fail!(self, self.pow(n1, n2, "(**)"));
- self.p += 1;
- }
- &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => {
- let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2);
+ let s1 = self.heap.len();
- let (r1, stub) = try_or_fail!(self, self.get_rational(a1, stub));
- let (r2, _) = try_or_fail!(self, self.get_rational(a2, stub));
+ self.heap.push(d1);
+ self.heap.push(d2);
- self.interms[t - 1] =
- Number::Rational(Rc::new(try_or_fail!(self, self.rdiv(r1, r2))));
- self.p += 1;
- }
- &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ let mut pstr_iter1 = HeapPStrIter::new(&self.heap, s1);
+ let mut pstr_iter2 = HeapPStrIter::new(&self.heap, s1 + 1);
- self.interms[t - 1] = try_or_fail!(self, self.int_floor_div(n1, n2));
- self.p += 1;
+ match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
+ PStrCmpResult::Ordered(Ordering::Equal) => {}
+ PStrCmpResult::Ordered(Ordering::Less) => {
+ if pstr_iter2.focus.as_var().is_none() {
+ self.fail = true;
+ } else {
+ self.pdl.push(empty_list_as_cell!());
+ self.pdl.push(pstr_iter2.focus);
+ }
}
- &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
-
- self.interms[t - 1] = try_or_fail!(self, self.idiv(n1, n2));
- self.p += 1;
+ PStrCmpResult::Ordered(Ordering::Greater) => {
+ if pstr_iter1.focus.as_var().is_none() {
+ self.fail = true;
+ } else {
+ self.pdl.push(empty_list_as_cell!());
+ self.pdl.push(pstr_iter1.focus);
+ }
}
- &ArithmeticInstruction::Abs(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
+ continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
+ if continuable.is_second_iter() {
+ std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
+ }
- self.interms[t - 1] = n1.abs();
- self.p += 1;
- }
- &ArithmeticInstruction::Sign(ref a1, t) => {
- let n = try_or_fail!(self, self.get_number(a1));
+ let mut chars_iter = PStrCharsIter {
+ iter: pstr_iter1,
+ item: Some(iteratee),
+ };
- self.interms[t - 1] = self.sign(n);
- self.p += 1;
- }
- &ArithmeticInstruction::Neg(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ let mut focus = pstr_iter2.focus;
- self.interms[t - 1] = -n1;
- self.p += 1;
- }
- &ArithmeticInstruction::BitwiseComplement(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ 'outer: loop {
+ while let Some(c) = chars_iter.peek() {
+ read_heap_cell!(focus,
+ (HeapCellValueTag::Lis, l) => {
+ let val = pstr_iter2.heap[l];
- self.interms[t - 1] = try_or_fail!(self, self.bitwise_complement(n1));
- self.p += 1;
- }
- &ArithmeticInstruction::Div(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ self.pdl.push(val);
+ self.pdl.push(char_as_cell!(c));
- self.interms[t - 1] = try_or_fail!(self, self.div(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Shr(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ focus = pstr_iter2.heap[l+1];
+ }
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s])
+ .get_name_and_arity();
- self.interms[t - 1] = try_or_fail!(self, self.shr(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Shl(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ if name == atom!(".") && arity == 2 {
+ self.pdl.push(pstr_iter2.heap[s+1]);
+ self.pdl.push(char_as_cell!(c));
- self.interms[t - 1] = try_or_fail!(self, self.shl(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Xor(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ focus = pstr_iter2.heap[s+2];
+ } else {
+ self.fail = true;
+ break 'outer;
+ }
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ match chars_iter.item.unwrap() {
+ PStrIteratee::Char(focus, _) => {
+ self.pdl.push(self.heap[focus]);
+ self.pdl.push(heap_loc_as_cell!(h));
+ }
+ PStrIteratee::PStrSegment(focus, _, n) => {
+ read_heap_cell!(self.heap[focus],
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
+ if focus < self.heap.len() - 2 {
+ self.heap.pop();
+ self.heap.pop();
+ }
+
+ if n == 0 {
+ let target_cell = match self.heap[focus].get_tag() {
+ HeapCellValueTag::CStr => {
+ atom_as_cstr_cell!(pstr_atom)
+ }
+ HeapCellValueTag::PStr => {
+ pstr_loc_as_cell!(focus)
+ }
+ _ => {
+ unreachable!()
+ }
+ };
+
+ self.pdl.push(target_cell);
+ self.pdl.push(heap_loc_as_cell!(h));
+ } else {
+ let h_len = self.heap.len();
+
+ self.heap.push(pstr_offset_as_cell!(focus));
+ self.heap.push(fixnum_as_cell!(
+ Fixnum::build_with(n as i64)
+ ));
+
+ self.pdl.push(pstr_loc_as_cell!(h_len));
+ self.pdl.push(heap_loc_as_cell!(h));
+ }
+
+ return;
+ }
+ (HeapCellValueTag::PStrOffset, pstr_loc) => {
+ let n0 = cell_as_fixnum!(self.heap[focus+1])
+ .get_num() as usize;
+
+ if pstr_loc < self.heap.len() - 2 {
+ self.heap.pop();
+ self.heap.pop();
+ }
+
+ if n == n0 {
+ self.pdl.push(pstr_loc_as_cell!(focus));
+ self.pdl.push(heap_loc_as_cell!(h));
+ } else {
+ let h_len = self.heap.len();
+
+ self.heap.push(pstr_offset_as_cell!(pstr_loc));
+ self.heap.push(fixnum_as_cell!(
+ Fixnum::build_with(n as i64)
+ ));
+
+ self.pdl.push(pstr_loc_as_cell!(h_len));
+ self.pdl.push(heap_loc_as_cell!(h));
+ }
+
+ return;
+ }
+ _ => {
+ }
+ );
- self.interms[t - 1] = try_or_fail!(self, self.xor(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::And(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ if focus < self.heap.len() - 2 {
+ self.heap.pop();
+ self.heap.pop();
+ }
- self.interms[t - 1] = try_or_fail!(self, self.and(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Or(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ self.pdl.push(self.heap[focus]);
+ self.pdl.push(heap_loc_as_cell!(h));
- self.interms[t - 1] = try_or_fail!(self, self.or(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Mod(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ return;
+ }
+ }
- self.interms[t - 1] = try_or_fail!(self, self.modulus(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Rem(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
+ break 'outer;
+ }
+ _ => {
+ self.fail = true;
+ break 'outer;
+ }
+ );
- self.interms[t - 1] = try_or_fail!(self, self.remainder(n1, n2));
- self.p += 1;
- }
- &ArithmeticInstruction::Cos(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ chars_iter.next();
+ }
- self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.cos(n1))));
- self.p += 1;
- }
- &ArithmeticInstruction::Sin(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ chars_iter.iter.next();
- self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.sin(n1))));
- self.p += 1;
- }
- &ArithmeticInstruction::Tan(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ self.pdl.push(chars_iter.iter.focus);
+ self.pdl.push(focus);
- self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.tan(n1))));
- self.p += 1;
+ break;
+ }
}
- &ArithmeticInstruction::Sqrt(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
-
- self.interms[t - 1] =
- Number::Float(OrderedFloat(try_or_fail!(self, self.sqrt(n1))));
- self.p += 1;
+ PStrCmpResult::Unordered => {
+ self.pdl.push(pstr_iter1.focus);
+ self.pdl.push(pstr_iter2.focus);
}
- &ArithmeticInstruction::Log(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ }
- self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.log(n1))));
- self.p += 1;
- }
- &ArithmeticInstruction::Exp(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ self.heap.pop();
+ self.heap.pop();
+ }
- self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.exp(n1))));
- self.p += 1;
+ fn unify_list_with_occurs_trigger(
+ &mut self,
+ l1: usize,
+ d2: HeapCellValue,
+ mut occurs_trigger: impl FnMut(),
+ ) {
+ read_heap_cell!(d2,
+ (HeapCellValueTag::Lis, l2) => {
+ for idx in 0..2 {
+ self.pdl.push(heap_loc_as_cell!(l2+idx));
+ self.pdl.push(heap_loc_as_cell!(l1+idx));
+ }
}
- &ArithmeticInstruction::ACos(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ (HeapCellValueTag::Str, s2) => {
+ let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
+ .get_name_and_arity();
- self.interms[t - 1] =
- Number::Float(OrderedFloat(try_or_fail!(self, self.acos(n1))));
- self.p += 1;
+ if a2 == 2 && n2 == atom!(".") {
+ for idx in 0..2 {
+ self.pdl.push(heap_loc_as_cell!(s2+1+idx));
+ self.pdl.push(heap_loc_as_cell!(l1+idx));
+ }
+ } else {
+ self.fail = true;
+ }
}
- &ArithmeticInstruction::ASin(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
-
- self.interms[t - 1] =
- Number::Float(OrderedFloat(try_or_fail!(self, self.asin(n1))));
- self.p += 1;
+ (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => {
+ self.unify_partial_string_with_occurs_check(
+ list_loc_as_cell!(l1),
+ d2,
+ &mut occurs_trigger,
+ )
}
- &ArithmeticInstruction::ATan(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
-
- self.interms[t - 1] =
- Number::Float(OrderedFloat(try_or_fail!(self, self.atan(n1))));
- self.p += 1;
+ (HeapCellValueTag::AttrVar, h) => {
+ if self.bind_with_occurs_check(Ref::attr_var(h), list_loc_as_cell!(l1)) {
+ occurs_trigger();
+ }
}
- &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
- let n2 = try_or_fail!(self, self.get_number(a2));
-
- self.interms[t - 1] =
- Number::Float(OrderedFloat(try_or_fail!(self, self.atan2(n1, n2))));
- self.p += 1;
+ (HeapCellValueTag::Var, h) => {
+ if self.bind_with_occurs_check(Ref::heap_cell(h), list_loc_as_cell!(l1)) {
+ occurs_trigger();
+ }
}
- &ArithmeticInstruction::Float(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
-
- self.interms[t - 1] =
- Number::Float(OrderedFloat(try_or_fail!(self, self.float(n1))));
- self.p += 1;
+ (HeapCellValueTag::StackVar, s) => {
+ if self.bind_with_occurs_check(Ref::stack_cell(s), list_loc_as_cell!(l1)) {
+ occurs_trigger();
+ }
}
- &ArithmeticInstruction::Truncate(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
-
- self.interms[t - 1] = self.truncate(n1);
- self.p += 1;
+ _ => {
+ self.fail = true;
}
- &ArithmeticInstruction::Round(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ )
+ }
- self.interms[t - 1] = try_or_fail!(self, self.round(n1));
- self.p += 1;
- }
- &ArithmeticInstruction::Ceiling(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ pub(super) fn unify_with_occurs_check_loop(&mut self, mut occurs_trigger: impl FnMut()) {
+ let mut tabu_list: IndexSet<(usize, usize)> = IndexSet::new();
- self.interms[t - 1] = self.ceiling(n1);
- self.p += 1;
- }
- &ArithmeticInstruction::Floor(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ // self.fail = false;
- self.interms[t - 1] = self.floor(n1);
- self.p += 1;
- }
- &ArithmeticInstruction::Plus(ref a1, t) => {
- let n1 = try_or_fail!(self, self.get_number(a1));
+ while !(self.pdl.is_empty() || self.fail) {
+ let s1 = self.pdl.pop().unwrap();
+ let s1 = self.deref(s1);
- self.interms[t - 1] = n1;
- self.p += 1;
- }
- };
- }
+ let s2 = self.pdl.pop().unwrap();
+ let s2 = self.deref(s2);
- pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) {
- match instr {
- &FactInstruction::GetConstant(_, ref c, reg) => {
- let addr = self[reg];
- self.write_constant_to_var(addr, c);
- }
- &FactInstruction::GetList(_, reg) => {
- let addr = self.store(self.deref(self[reg]));
+ if s1 != s2 {
+ let d1 = self.store(s1);
+ let d2 = self.store(s2);
- match addr {
- Addr::PStrLocation(h, n) => {
- self.s = HeapPtr::PStrChar(h, n);
- self.mode = MachineMode::Read;
+ read_heap_cell!(d1,
+ (HeapCellValueTag::AttrVar, h) => {
+ if self.bind_with_occurs_check(Ref::attr_var(h), d2) {
+ occurs_trigger();
+ }
}
- addr @ Addr::AttrVar(_)
- | addr @ Addr::StackCell(..)
- | addr @ Addr::HeapCell(_) => {
- let h = self.heap.h();
-
- self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
- self.bind(addr.as_var().unwrap(), Addr::HeapCell(h));
-
- self.mode = MachineMode::Write;
+ (HeapCellValueTag::Var, h) => {
+ if self.bind_with_occurs_check(Ref::heap_cell(h), d2) {
+ occurs_trigger();
+ }
}
- Addr::Lis(a) => {
- self.s = HeapPtr::HeapCell(a);
- self.mode = MachineMode::Read;
+ (HeapCellValueTag::StackVar, s) => {
+ if self.bind_with_occurs_check(Ref::stack_cell(s), d2) {
+ occurs_trigger();
+ }
}
- _ => {
- self.fail = true;
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert!(arity == 0);
+ self.unify_atom(name, d2);
}
- };
- }
- &FactInstruction::GetPartialString(_, ref string, reg, has_tail) => {
- let addr = self.store(self.deref(self[reg]));
- self.match_partial_string(addr, string, has_tail);
- }
- &FactInstruction::GetStructure(ref ct, arity, reg) => {
- let addr = self.deref(self[reg]);
+ (HeapCellValueTag::Str, s1) => {
+ if d2.is_constant() {
+ self.fail = true;
+ break;
+ }
- match self.store(addr) {
- Addr::Str(a) => {
- let result = &self.heap[a];
+ let s2 = s2.get_value() as usize;
- if let &HeapCellValue::NamedStr(narity, ref s, _) = result {
- if narity == arity && ct.name() == *s {
- self.s = HeapPtr::HeapCell(a + 1);
- self.mode = MachineMode::Read;
- } else {
- self.fail = true;
+ if tabu_list.contains(&(s1, s2)) {
+ continue;
+ }
+
+ self.unify_structure_with_occurs_check(s1, d2, &mut occurs_trigger);
+
+ if !self.fail {
+ tabu_list.insert((s1, s2));
+ }
+ }
+ (HeapCellValueTag::Lis, l1) => {
+ if d2.is_ref() {
+ let l2 = s2.get_value() as usize;
+
+ if tabu_list.contains(&(l1, l2)) {
+ continue;
}
+
+ tabu_list.insert((l1, l2));
}
+
+ self.unify_list_with_occurs_trigger(l1, d2, &mut occurs_trigger);
}
- Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => {
- let h = self.heap.h();
+ (HeapCellValueTag::PStrLoc, pstr1_loc) => {
+ read_heap_cell!(d2,
+ (HeapCellValueTag::PStrLoc |
+ HeapCellValueTag::Lis |
+ HeapCellValueTag::Str,
+ pstr2_loc) => {
+ if tabu_list.contains(&(pstr1_loc, pstr2_loc)) {
+ continue;
+ }
+ }
+ (HeapCellValueTag::CStr |
+ HeapCellValueTag::AttrVar |
+ HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar) => {
+ }
+ _ => {
+ self.fail = true;
+ break;
+ }
+ );
- self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1)));
- self.heap
- .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec()));
+ self.unify_partial_string_with_occurs_check(
+ d1,
+ d2,
+ &mut occurs_trigger,
+ );
- self.bind(addr.as_var().unwrap(), Addr::HeapCell(h));
+ if !self.fail && !d2.is_constant() {
+ tabu_list.insert((pstr1_loc, d2.get_value()));
+ }
+ }
+ (HeapCellValueTag::CStr) => {
+ read_heap_cell!(d2,
+ (HeapCellValueTag::AttrVar, h) => {
+ self.bind(Ref::attr_var(h), d1);
+ continue;
+ }
+ (HeapCellValueTag::Var, h) => {
+ self.bind(Ref::heap_cell(h), d1);
+ continue;
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.bind(Ref::stack_cell(s), d1);
+ continue;
+ }
+ (HeapCellValueTag::Str |
+ HeapCellValueTag::Lis |
+ HeapCellValueTag::PStrLoc) => {
+ }
+ _ => {
+ self.fail = true;
+ return;
+ }
+ );
- self.mode = MachineMode::Write;
+ self.unify_partial_string(d2, d1);
+ }
+ (HeapCellValueTag::F64, f1) => {
+ self.unify_f64(f1, d2);
+ }
+ (HeapCellValueTag::Fixnum, n1) => {
+ self.unify_fixnum(n1, d2);
+ }
+ (HeapCellValueTag::Char, c1) => {
+ self.unify_char(c1, d2);
+ }
+ (HeapCellValueTag::Cons, ptr_1) => {
+ self.unify_constant(ptr_1, d2);
}
_ => {
- self.fail = true;
+ unreachable!();
}
- };
- }
- &FactInstruction::GetVariable(norm, arg) => {
- self[norm] = self.registers[arg];
- }
- &FactInstruction::GetValue(norm, arg) => {
- let norm_addr = self[norm];
- let reg_addr = self.registers[arg];
-
- (self.unify_fn)(self, norm_addr, reg_addr);
+ );
}
- &FactInstruction::UnifyConstant(ref c) => {
- match self.mode {
- MachineMode::Read => {
- let addr = self.s.read(&self.heap);
+ }
+ }
- self.write_constant_to_var(addr, c);
- self.increment_s_ptr(1);
+ pub(crate) fn read_s(&mut self) -> HeapCellValue {
+ match &mut self.s {
+ &mut HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]),
+ &mut HeapPtr::PStrChar(h, n) if self.s_offset == 0 => {
+ read_heap_cell!(self.heap[h],
+ (HeapCellValueTag::PStr, pstr_atom) => {
+ let pstr = PartialString::from(pstr_atom);
+
+ if let Some(c) = pstr.as_str_from(n).chars().next() {
+ char_as_cell!(c)
+ } else {
+ self.deref(self.heap[h+1])
+ }
}
- MachineMode::Write => {
- let addr = self.heap.put_constant(c.clone());
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ let pstr = PartialString::from(cstr_atom);
- if !addr.is_heap_bound() {
- self.heap.push(HeapCellValue::Addr(addr));
+ if let Some(c) = pstr.as_str_from(n).chars().next() {
+ char_as_cell!(c)
+ } else {
+ empty_list_as_cell!()
}
}
- };
- }
- &FactInstruction::UnifyVariable(reg) => {
- match self.mode {
- MachineMode::Read => {
- self[reg] = self.s.read(&self.heap);
- self.increment_s_ptr(1);
- }
- MachineMode::Write => {
- let h = self.heap.h();
-
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
- self[reg] = Addr::HeapCell(h);
+ _ => {
+ unreachable!()
}
- };
+ )
}
- &FactInstruction::UnifyLocalValue(reg) => {
- match self.mode {
- MachineMode::Read => {
- let reg_addr = self[reg];
+ &mut HeapPtr::PStrChar(h, ref mut n) |
+ &mut HeapPtr::PStrLocation(h, ref mut n) => {
+ read_heap_cell!(self.heap[h],
+ (HeapCellValueTag::PStr, pstr_atom) => {
+ let pstr = PartialString::from(pstr_atom);
+ let n_offset: usize = pstr.as_str_from(*n)
+ .chars()
+ .take(self.s_offset)
+ .map(|c| c.len_utf8())
+ .sum();
- (self.unify_fn)(self, reg_addr, self.s.read(&self.heap));
- self.increment_s_ptr(1);
- }
- MachineMode::Write => {
- let addr = self.store(self.deref(self[reg]));
- let h = self.heap.h();
+ self.s_offset = 0;
+ *n += n_offset;
- if let Addr::HeapCell(hc) = addr {
- let val = self.heap.clone(hc);
+ if *n < pstr_atom.len() {
+ let h_len = self.heap.len();
- self.heap.push(val);
- self.increment_s_ptr(1);
+ self.heap.push(pstr_offset_as_cell!(h));
+ self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64)));
- return;
+ pstr_loc_as_cell!(h_len)
+ } else {
+ self.deref(self.heap[h+1])
}
-
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
- (self.bind_fn)(self, Ref::HeapCell(h), addr);
}
- };
- }
- &FactInstruction::UnifyValue(reg) => {
- match self.mode {
- MachineMode::Read => {
- let reg_addr = self[reg];
-
- (self.unify_fn)(self, reg_addr, self.s.read(&self.heap));
- self.increment_s_ptr(1);
- }
- MachineMode::Write => {
- let h = self.heap.h();
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ let pstr = PartialString::from(cstr_atom);
+ let n_offset: usize = pstr.as_str_from(*n)
+ .chars()
+ .take(self.s_offset)
+ .map(|c| c.len_utf8())
+ .sum();
- let addr = self.store(self[reg]);
- (self.bind_fn)(self, Ref::HeapCell(h), addr);
+ self.s_offset = 0;
+ *n += n_offset;
- // the former code of this match arm was:
+ if *n < cstr_atom.len() {
+ let h_len = self.heap.len();
- // let addr = self.store(self[reg]);
- // self.heap.push(HeapCellValue::Addr(addr));
-
- // the old code didn't perform the occurs
- // check when enabled and so it was changed to
- // the above, which is only slightly less
- // efficient when the occurs_check is disabled.
- }
- };
- }
- &FactInstruction::UnifyVoid(n) => {
- match self.mode {
- MachineMode::Read => {
- self.increment_s_ptr(n);
- }
- MachineMode::Write => {
- let h = self.heap.h();
+ self.heap.push(pstr_offset_as_cell!(h));
+ self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64)));
- for i in h..h + n {
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i)));
+ pstr_loc_as_cell!(h_len)
+ } else {
+ empty_list_as_cell!()
}
}
- };
+ _ => {
+ unreachable!()
+ }
+ )
}
- };
+ }
}
- pub(super) fn execute_indexing_instr(
- &mut self,
- indexing_lines: &Vec<IndexingLine>,
- code_repo: &CodeRepo,
- ) {
- fn dynamic_external_of_clause_is_valid(
- machine_st: &mut MachineState,
- code: &Code,
- p: usize,
- ) -> bool {
- match &code[p] {
- Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {
- machine_st.dynamic_mode = FirstOrNext::First;
- return true;
- }
- _ => {}
- }
+ pub fn compare_term_test(&mut self) -> Option<Ordering> {
+ let mut tabu_list = IndexSet::new();
- match &code[p - 1] {
- &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => {
- if birth < machine_st.cc && Death::Finite(machine_st.cc) <= death {
- return true;
- } else {
- return false;
- }
- }
- _ => {}
- }
+ while !self.pdl.is_empty() {
+ let s1 = self.pdl.pop().unwrap();
+ let s1 = self.deref(s1);
- true
- }
+ let s2 = self.pdl.pop().unwrap();
+ let s2 = self.deref(s2);
- let mut index = 0;
- let addr = match &indexing_lines[0] {
- &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
- self.store(self.deref(self[temp_v!(arg)]))
- }
- _ => {
- unreachable!()
+ if s1 == s2 {
+ continue;
}
- };
- loop {
- match &indexing_lines[index] {
- &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
- let offset = match addr {
- Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
- IndexingCodePtr::Fail
- }
- Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => v,
- Addr::PStrLocation(..) => l,
- Addr::Char(_)
- | Addr::Con(_)
- | Addr::CutPoint(_)
- | Addr::EmptyList
- | Addr::Fixnum(_)
- | Addr::Float(_)
- | Addr::Usize(_) => c,
- Addr::Lis(_) => l,
- Addr::Str(_) => s,
- };
-
- match offset {
- IndexingCodePtr::Fail => {
- self.fail = true;
- break;
- }
- IndexingCodePtr::DynamicExternal(o) => {
- // either points directly to a
- // DynamicInternalElse, or just ahead of
- // one. Or neither!
- let p = self.p.local().abs_loc();
+ let v1 = self.store(s1);
+ let v2 = self.store(s2);
- if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
- self.fail = true;
- } else {
- self.p += o;
- }
+ let order_cat_v1 = v1.order_category();
+ let order_cat_v2 = v2.order_category();
- break;
- }
- IndexingCodePtr::External(o) => {
- self.p += o;
- break;
- }
- IndexingCodePtr::Internal(o) => {
- index += o;
- }
- };
- }
- &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
- let offset = match addr.as_constant_index(&self) {
- Some(c) => match hm.get(&c) {
- Some(offset) => *offset,
- _ => IndexingCodePtr::Fail,
- },
- None => IndexingCodePtr::Fail,
- };
+ if order_cat_v1 != order_cat_v2 {
+ self.pdl.clear();
+ return Some(order_cat_v1.cmp(&order_cat_v2));
+ }
- match offset {
- IndexingCodePtr::Fail => {
- self.fail = true;
- break;
- }
- IndexingCodePtr::DynamicExternal(o) => {
- // either points directly to a
- // DynamicInternalElse, or just ahead of
- // one. Or neither!
- let p = self.p.local().abs_loc();
+ match order_cat_v1 {
+ Some(TermOrderCategory::Variable) => {
+ let v1 = v1.as_var().unwrap();
+ let v2 = v2.as_var().unwrap();
- if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
- self.fail = true;
- } else {
- self.p += o;
- }
+ if v1 != v2 {
+ self.pdl.clear();
+ return Some(v1.cmp(&v2));
+ }
+ }
+ Some(TermOrderCategory::FloatingPoint) => {
+ let v1 = cell_as_f64_ptr!(v1);
+ let v2 = cell_as_f64_ptr!(v2);
- break;
- }
- IndexingCodePtr::External(o) => {
- self.p += o;
- break;
- }
- IndexingCodePtr::Internal(o) => {
- index += o;
- }
- };
- }
- &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
- let offset = match addr {
- Addr::Str(s) => {
- if let &HeapCellValue::NamedStr(arity, ref name, _) = &self.heap[s] {
- match hm.get(&(name.clone(), arity)) {
- Some(offset) => *offset,
- _ => IndexingCodePtr::Fail,
+ if v1 != v2 {
+ self.pdl.clear();
+ return Some(v1.cmp(&v2));
+ }
+ }
+ Some(TermOrderCategory::Integer) => {
+ let v1 = Number::try_from(v1).unwrap();
+ let v2 = Number::try_from(v2).unwrap();
+
+ if v1 != v2 {
+ self.pdl.clear();
+ return Some(v1.cmp(&v2));
+ }
+ }
+ Some(TermOrderCategory::Atom) => {
+ read_heap_cell!(v1,
+ (HeapCellValueTag::Atom, (n1, _a1)) => {
+ read_heap_cell!(v2,
+ (HeapCellValueTag::Atom, (n2, _a2)) => {
+ if n1 != n2 {
+ self.pdl.clear();
+ return Some(n1.cmp(&n2));
+ }
}
- } else {
- IndexingCodePtr::Fail
- }
+ (HeapCellValueTag::Char, c2) => {
+ if let Some(c1) = n1.as_char() {
+ if c1 != c2 {
+ self.pdl.clear();
+ return Some(c1.cmp(&c2));
+ }
+ } else {
+ self.pdl.clear();
+ return Some(Ordering::Greater);
+ }
+ }
+ _ => {
+ unreachable!();
+ }
+ )
+ }
+ (HeapCellValueTag::Char, c1) => {
+ read_heap_cell!(v2,
+ (HeapCellValueTag::Atom, (n2, _a2)) => {
+ if let Some(c2) = n2.as_char() {
+ if c1 != c2 {
+ self.pdl.clear();
+ return Some(c1.cmp(&c2));
+ }
+ } else {
+ self.pdl.clear();
+ return Some(Ordering::Less);
+ }
+ }
+ (HeapCellValueTag::Char, c2) => {
+ if c1 != c2 {
+ self.pdl.clear();
+ return Some(c1.cmp(&c2));
+ }
+ }
+ _ => {
+ unreachable!()
+ }
+ )
}
- _ => IndexingCodePtr::Fail,
- };
-
- match offset {
- IndexingCodePtr::Fail => {
- self.fail = true;
- break;
+ _ => {
+ unreachable!()
}
- IndexingCodePtr::DynamicExternal(o) => {
- let p = self.p.local().abs_loc();
+ )
+ }
+ Some(TermOrderCategory::Compound) => {
+ fn stalled_pstr_iter_handler(
+ string_iter: HeapPStrIter,
+ stalled_iter: HeapPStrIter,
+ pdl: &mut Vec<HeapCellValue>,
+ ) -> Option<Ordering> {
+ let l = read_heap_cell!(stalled_iter.focus,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(stalled_iter.heap[s])
+ .get_name_and_arity();
+
+ if !(name == atom!(".") && arity == 2) {
+ pdl.clear();
+ return Some((atom!("."),2).cmp(&(name,arity)));
+ }
- if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
- self.fail = true;
- } else {
- self.p += o;
+ s+1
}
+ (HeapCellValueTag::Lis, l) => {
+ l
+ }
+ _ => {
+ unreachable!()
+ }
+ );
- break;
- }
- IndexingCodePtr::External(o) => {
- self.p += o;
- break;
- }
- IndexingCodePtr::Internal(o) => {
- index += o;
- }
- }
- }
- &IndexingLine::IndexedChoice(_) => {
- if let LocalCodePtr::DirEntry(p) = self.p.local() {
- self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
- } else {
- unreachable!()
- }
+ let c2 = stalled_iter.heap[l];
+ let c1 = string_iter.chars().next().unwrap();
- break;
- }
- &IndexingLine::DynamicIndexedChoice(_) => {
- self.dynamic_mode = FirstOrNext::First;
+ pdl.push(c2);
+ pdl.push(char_as_cell!(c1));
- if let LocalCodePtr::DirEntry(p) = self.p.local() {
- self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
- } else {
- unreachable!()
+ None
}
- break;
- }
- }
- }
- }
+ fn pstr_comparator(
+ heap: &[HeapCellValue],
+ pdl: &mut Vec<HeapCellValue>,
+ s1: usize,
+ s2: usize,
+ ) -> Option<Ordering> {
+ let mut iter1 = HeapPStrIter::new(heap, s1);
+ let mut iter2 = HeapPStrIter::new(heap, s2);
- pub(super) fn execute_query_instr(&mut self, instr: &QueryInstruction) {
- match instr {
- &QueryInstruction::GetVariable(norm, arg) => {
- self[norm] = self.registers[arg];
- }
- &QueryInstruction::PutConstant(_, ref c, reg) => {
- self[reg] = self.heap.put_constant(c.clone());
- }
- &QueryInstruction::PutList(_, reg) => {
- self[reg] = Addr::Lis(self.heap.h());
- }
- &QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => {
- let pstr_addr = if has_tail {
- if !string.is_empty() {
- let pstr_addr = self.heap.allocate_pstr(&string);
- self.heap.pop(); // the tail will be added by the next instruction.
- pstr_addr
- } else {
- Addr::EmptyList
- }
- } else {
- self.heap.put_complete_string(&string)
- };
+ match compare_pstr_prefixes(&mut iter1, &mut iter2) {
+ PStrCmpResult::Ordered(ordering) => Some(ordering),
+ _ => {
+ if iter1.num_steps() == 0 && iter2.num_steps() == 0 {
+ return read_heap_cell!(iter2.focus,
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
+ let result = stalled_pstr_iter_handler(iter2, iter1, pdl);
+
+ if let Some(ordering) = result {
+ Some(ordering.reverse())
+ } else {
+ let pdl_len = pdl.len();
+ pdl.swap(pdl_len - 2, pdl_len - 1);
+ result
+ }
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if name == atom!("[]") && arity == 0 {
+ return Some(Ordering::Greater);
+ } else {
+ stalled_pstr_iter_handler(iter1, iter2, pdl)
+ }
+ }
+ _ => {
+ stalled_pstr_iter_handler(iter1, iter2, pdl)
+ }
+ );
+ }
- self[reg] = pstr_addr;
- }
- &QueryInstruction::PutStructure(ref ct, arity, reg) => {
- let h = self.heap.h();
+ pdl.push(iter2.focus);
+ pdl.push(iter1.focus);
- self.heap
- .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec()));
- self[reg] = Addr::Str(h);
- }
- &QueryInstruction::PutUnsafeValue(n, arg) => {
- let e = self.e;
- let addr = self.store(self.deref(Addr::StackCell(e, n)));
+ None
+ }
+ }
+ }
- if addr.is_protected(e) {
- self.registers[arg] = addr;
- } else {
- let h = self.heap.h();
+ read_heap_cell!(v1,
+ (HeapCellValueTag::Lis, l1) => {
+ read_heap_cell!(v2,
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
+ let h = self.heap.len();
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
- (self.bind_fn)(self, Ref::HeapCell(h), addr);
+ self.heap.push(v1);
+ self.heap.push(v2);
- self.registers[arg] = self.heap[h].as_addr(h);
- }
- }
- &QueryInstruction::PutValue(norm, arg) => {
- self.registers[arg] = self[norm];
- }
- &QueryInstruction::PutVariable(norm, arg) => {
- match norm {
- RegType::Perm(n) => {
- let e = self.e;
+ if let Some(ordering) = pstr_comparator(
+ &self.heap, &mut self.pdl, h, h+1
+ ) {
+ if ordering != Ordering::Equal {
+ self.heap.pop();
+ self.heap.pop();
- self[norm] = Addr::StackCell(e, n);
- self.registers[arg] = self[norm];
- }
- RegType::Temp(_) => {
- let h = self.heap.h();
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
+ self.pdl.clear();
- self[norm] = Addr::HeapCell(h);
- self.registers[arg] = Addr::HeapCell(h);
- }
- };
- }
- &QueryInstruction::SetConstant(ref c) => {
- let addr = self.heap.put_constant(c.clone());
+ return Some(ordering);
+ }
+ }
- if !addr.is_heap_bound() {
- self.heap.push(HeapCellValue::Addr(addr));
- }
- }
- &QueryInstruction::SetLocalValue(reg) => {
- let addr = self.deref(self[reg]);
- let h = self.heap.h();
+ self.heap.pop();
+ self.heap.pop();
+ }
+ (HeapCellValueTag::Lis, l2) => {
+ if tabu_list.contains(&(l1, l2)) {
+ continue;
+ }
- if addr < Ref::HeapCell(h) {
- self.heap.push(HeapCellValue::Addr(addr));
- return;
- }
+ tabu_list.insert((l1, l2));
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
- (self.bind_fn)(self, Ref::HeapCell(h), addr);
- }
- &QueryInstruction::SetVariable(reg) => {
- let h = self.heap.h();
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
- self[reg] = Addr::HeapCell(h);
- }
- &QueryInstruction::SetValue(reg) => {
- let heap_val = self.store(self[reg]);
- self.heap.push(HeapCellValue::Addr(heap_val));
- }
- &QueryInstruction::SetVoid(n) => {
- let h = self.heap.h();
+ self.pdl.push(self.heap[l2 + 1]);
+ self.pdl.push(self.heap[l1 + 1]);
- for i in h..h + n {
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i)));
- }
- }
- }
- }
+ self.pdl.push(self.heap[l2]);
+ self.pdl.push(self.heap[l1]);
+ }
+ (HeapCellValueTag::Str, s2) => {
+ if tabu_list.contains(&(l1, s2)) {
+ continue;
+ }
- pub(super) fn set_ball(&mut self) {
- self.ball.reset();
+ let (name, arity) = cell_as_atom_cell!(self.heap[s2])
+ .get_name_and_arity();
- let addr = self[temp_v!(1)];
- self.ball.boundary = self.heap.h();
+ match (atom!("."), 2).cmp(&(name, arity)) {
+ Ordering::Equal => {
+ tabu_list.insert((l1, s2));
- copy_term(
- CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub),
- addr,
- AttrVarPolicy::DeepCopy,
- );
- }
+ self.pdl.push(self.heap[s2 + 2]);
+ self.pdl.push(self.heap[l1 + 1]);
- pub(super) fn handle_internal_call_n(&mut self, arity: usize) {
- let arity = arity + 1;
- let pred = self.registers[1];
+ self.pdl.push(self.heap[s2 + 1]);
+ self.pdl.push(self.heap[l1]);
+ }
+ ordering => {
+ self.pdl.clear();
+ return Some(ordering);
+ }
+ }
+ }
+ _ => {
+ unreachable!();
+ }
+ )
+ }
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
+ let h = self.heap.len();
- for i in 2..arity {
- self.registers[i - 1] = self.registers[i];
- }
+ self.heap.push(v1);
+ self.heap.push(v2);
- if arity > 1 {
- self.registers[arity - 1] = pred;
- return;
- }
+ if let Some(ordering) = pstr_comparator(
+ &self.heap, &mut self.pdl, h, h+1,
+ ) {
+ if ordering != Ordering::Equal {
+ self.heap.pop();
+ self.heap.pop();
- self.fail = true;
- }
+ self.pdl.clear();
- pub(super) fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey> {
- let addr = self.store(self.deref(self.registers[arity]));
+ return Some(ordering);
+ }
+ }
- let (name, narity) = match addr {
- Addr::Str(a) => {
- let result = self.heap.clone(a);
+ self.heap.pop();
+ self.heap.pop();
+ }
+ (HeapCellValueTag::Str, s1) => {
+ read_heap_cell!(v2,
+ (HeapCellValueTag::Str, s2) => {
+ if tabu_list.contains(&(s1, s2)) {
+ continue;
+ }
- if let HeapCellValue::NamedStr(narity, name, _) = result {
- let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
+ let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
+ .get_name_and_arity();
- if narity + arity > MAX_ARITY {
- let representation_error = self.error_form(
- MachineError::representation_error(RepFlag::MaxArity),
- stub,
- );
+ let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
+ .get_name_and_arity();
- self.throw_exception(representation_error);
- return None;
- }
+ match (n1,a1).cmp(&(n2,a2)) {
+ Ordering::Equal => {
+ tabu_list.insert((s1, s2));
- for i in (1..arity).rev() {
- self.registers[i + narity] = self.registers[i];
- }
+ for idx in (1 .. a1+1).rev() {
+ self.pdl.push(self.heap[s2+idx]);
+ self.pdl.push(self.heap[s1+idx]);
+ }
+ }
+ ordering => {
+ self.pdl.clear();
+ return Some(ordering);
+ }
+ }
+ }
+ (HeapCellValueTag::Lis, l2) => {
+ if tabu_list.contains(&(s1, l2)) {
+ continue;
+ }
- for i in 1..narity + 1 {
- self.registers[i] = self.heap[a + i].as_addr(a + i);
- }
+ tabu_list.insert((s1, l2));
- (name, narity)
- } else {
- self.fail = true;
- return None;
- }
- }
- Addr::Char(c) => (clause_name!(c.to_string(), self.atom_tbl), 0),
- Addr::Con(h) => match &self.heap[h] {
- HeapCellValue::Atom(ref name, _) => (name.clone(), 0),
- _ => {
- self.fail = true;
- return None;
- }
- },
- Addr::HeapCell(_) | Addr::StackCell(_, _) => {
- let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
- let instantiation_error =
- self.error_form(MachineError::instantiation_error(), stub);
-
- self.throw_exception(instantiation_error);
- return None;
- }
- addr => {
- let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
- let type_error = self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Callable, addr),
- stub,
- );
+ let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
+ .get_name_and_arity();
- self.throw_exception(type_error);
- return None;
- }
- };
+ match (n1,a1).cmp(&(atom!("."), 2)) {
+ Ordering::Equal => {
+ self.pdl.push(self.heap[l2]);
+ self.pdl.push(self.heap[s1+1]);
- Some((name, arity + narity - 1))
- }
+ self.pdl.push(self.heap[l2+1]);
+ self.pdl.push(self.heap[s1+2]);
+ }
+ ordering => {
+ self.pdl.clear();
+ return Some(ordering);
+ }
+ }
+ }
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
+ let h = self.heap.len();
- pub(super) fn unwind_stack(&mut self) {
- self.b = self.block;
- self.fail = true;
- }
+ self.heap.push(v1);
+ self.heap.push(v2);
- pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool {
- let mut seen = IndexSet::new();
- let mut fail = false;
- let mut iter = self.pre_order_iter(addr);
- let mut parent_stack = vec![];
+ if let Some(ordering) = pstr_comparator(
+ &self.heap, &mut self.pdl, h, h+1,
+ ) {
+ if ordering != Ordering::Equal {
+ self.heap.pop();
+ self.heap.pop();
- let is_composite = |addr: Addr| match addr {
- Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => true,
- _ => false,
- };
+ self.pdl.clear();
- 'outer: loop {
- if let Some(addr) = iter.stack().last().cloned() {
- let addr = self.store(self.deref(addr));
+ return Some(ordering);
+ }
+ }
- if is_composite(addr) {
- if !seen.contains(&addr) {
- seen.insert(addr);
- } else {
- // when we again encounter a seen composite
- // term, check that it precedes itself as a
- // parent in the post-order traversal. in the
- // future, when value cells have mark bits,
- // use them to designate parenthood instead of
- // this linear search.
-
- for (_, prec_addr) in parent_stack.iter().rev().cloned() {
- if prec_addr == addr {
- fail = true;
- break 'outer;
- }
+ self.heap.pop();
+ self.heap.pop();
+ }
+ _ => {
+ unreachable!()
+ }
+ )
}
- }
-
- let arity = match addr {
- Addr::Str(h) => match &self.heap[h] {
- &HeapCellValue::NamedStr(arity, ..) => arity,
- _ => unreachable!(),
- },
- _ => 2,
- };
-
- parent_stack.push((arity, addr));
+ _ => {
+ unreachable!()
+ }
+ );
}
- }
-
- if iter.next().is_none() {
- break;
- } else {
- while let Some((rem_children, addr)) = parent_stack.pop() {
- if rem_children > 0 {
- parent_stack.push((rem_children - 1, addr));
- break;
+ None => {
+ if v1 != v2 {
+ self.pdl.clear();
+ return None;
}
}
}
}
- fail
+ Some(Ordering::Equal)
}
- // arg(+N, +Term, ?Arg)
- pub(super) fn try_arg(&mut self) -> CallResult {
- let stub = MachineError::functor_stub(clause_name!("arg"), 3);
- let n = self.store(self.deref(self[temp_v!(1)]));
-
- match n {
- Addr::HeapCell(_) | Addr::StackCell(..) => {
- // 8.5.2.3 a)
- return Err(self.error_form(MachineError::instantiation_error(), stub));
- }
- addr => {
- let n = match Number::try_from((addr, &self.heap)) {
- Ok(Number::Fixnum(n)) => Integer::from(n),
- Ok(Number::Integer(n)) => Integer::from(n.as_ref()),
- _ => {
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, addr),
- stub,
- ));
- }
- };
-
- if n < 0 {
- // 8.5.2.3 e)
- let n = Number::from(n);
- let dom_err = MachineError::domain_error(DomainErrorType::NotLessThanZero, n);
-
- return Err(self.error_form(dom_err, stub));
- }
-
- let n = match n.to_usize() {
- Some(n) => n,
- None => {
- self.fail = true;
- return Ok(());
- }
- };
-
- let term = self.store(self.deref(self[temp_v!(2)]));
+ pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) {
+ let h = self.heap.len();
+ self.heap.push(value);
- match term {
- Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => {
- // 8.5.2.3 b)
- return Err(self.error_form(MachineError::instantiation_error(), stub));
- }
- Addr::Str(o) => match self.heap.clone(o) {
- HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => {
- let a3 = self[temp_v!(3)];
- let h_a = Addr::HeapCell(o + n);
+ let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h);
+ let s = string.as_str();
- (self.unify_fn)(self, a3, h_a);
- }
- _ => {
- self.fail = true;
- }
- },
- Addr::Lis(l) => {
- if n == 1 || n == 2 {
- let a3 = self[temp_v!(3)];
- let h_a = Addr::HeapCell(l + n - 1);
+ match heap_pstr_iter.compare_pstr_to_string(s) {
+ Some(PStrPrefixCmpResult { focus, offset, prefix_len }) if prefix_len == s.len() => {
+ let focus_addr = self.heap[focus];
- (self.unify_fn)(self, a3, h_a);
+ read_heap_cell!(focus_addr,
+ (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => {
+ if has_tail {
+ self.s = HeapPtr::PStrLocation(focus, offset);
+ self.s_offset = 0;
+ self.mode = MachineMode::Read;
+ } else if offset == pstr_atom.len() {
+ let focus = heap_pstr_iter.focus;
+ unify!(self, focus, empty_list_as_cell!());
} else {
self.fail = true;
}
}
- Addr::PStrLocation(h, offset) => {
- if n == 1 || n == 2 {
- let a3 = self[temp_v!(3)];
- let h_a =
- if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] {
- if let Some(c) = pstr.range_from(offset..).next() {
- if n == 1 {
- Addr::Char(c)
- } else {
- Addr::PStrLocation(h, offset + c.len_utf8())
- }
- } else {
- unreachable!()
- }
- } else {
- unreachable!()
- };
+ (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, h) => {
+ let (focus, _) = pstr_loc_and_offset(&self.heap, h);
+ let pstr_atom = read_heap_cell!(self.heap[focus],
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
+ pstr_atom
+ }
+ _ => {
+ unreachable!()
+ }
+ );
- (self.unify_fn)(self, a3, h_a);
+ if has_tail {
+ self.s = HeapPtr::PStrLocation(focus, offset);
+ self.s_offset = 0;
+ self.mode = MachineMode::Read;
+ } else if offset == pstr_atom.len() {
+ let focus = heap_pstr_iter.focus;
+ unify!(self, focus, empty_list_as_cell!());
} else {
self.fail = true;
}
}
_ => {
- // 8.5.2.3 d)
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Compound, term),
- stub,
- ));
+ let focus = heap_pstr_iter.focus();
+
+ if has_tail {
+ self.s = HeapPtr::HeapCell(focus);
+ self.s_offset = 0;
+ self.mode = MachineMode::Read;
+ } else {
+ let focus = heap_pstr_iter.focus;
+ unify!(self, focus, empty_list_as_cell!());
+ }
}
- }
+ );
}
- }
-
- Ok(())
- }
+ Some(PStrPrefixCmpResult { prefix_len, .. }) => {
+ let focus = heap_pstr_iter.focus();
+ let tail_addr = self.heap[focus];
- fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) {
- let ordering = n1.cmp(&n2);
-
- self.fail = match cmp {
- CompareNumberQT::GreaterThan if ordering == Ordering::Greater => false,
- CompareNumberQT::GreaterThanOrEqual if ordering != Ordering::Less => false,
- CompareNumberQT::LessThan if ordering == Ordering::Less => false,
- CompareNumberQT::LessThanOrEqual if ordering != Ordering::Greater => false,
- CompareNumberQT::NotEqual if ordering != Ordering::Equal => false,
- CompareNumberQT::Equal if ordering == Ordering::Equal => false,
- _ => true,
- };
+ let h = self.heap.len();
- self.p += 1;
- }
+ let target_cell = if has_tail {
+ self.s = HeapPtr::HeapCell(h + 1);
+ self.s_offset = 0;
+ self.mode = MachineMode::Read;
- pub(super) fn compare_term(&mut self, qt: CompareTermQT) {
- let a1 = self[temp_v!(1)];
- let a2 = self[temp_v!(2)];
+ put_partial_string(
+ &mut self.heap,
+ &string.as_str()[prefix_len ..],
+ &mut self.atom_tbl,
+ )
+ } else {
+ put_complete_string(
+ &mut self.heap,
+ &string.as_str()[prefix_len ..],
+ &mut self.atom_tbl,
+ )
+ };
- match self.compare_term_test(&a1, &a2) {
- Some(Ordering::Greater) => match qt {
- CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => return,
- _ => self.fail = true,
- },
- Some(Ordering::Equal) => match qt {
- CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => return,
- _ => self.fail = true,
- },
- Some(Ordering::Less) => match qt {
- CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => return,
- _ => self.fail = true,
- },
+ unify!(self, tail_addr, target_cell);
+ }
None => {
self.fail = true;
}
- };
+ }
}
- // returns true on failure.
- pub(super) fn eq_test(&self, a1: Addr, a2: Addr) -> bool {
- let mut iter = self.zipped_acyclic_pre_order_iter(a1, a2);
-
- while let Some((v1, v2)) = iter.next() {
- match (v1, v2) {
- (Addr::Str(s1), Addr::Str(s2)) => {
- if let HeapCellValue::NamedStr(ar1, n1, _) = &self.heap[s1] {
- if let HeapCellValue::NamedStr(ar2, n2, _) = &self.heap[s2] {
- if ar1 != ar2 || n1 != n2 {
- return true;
- }
- } else {
- unreachable!()
- }
- } else {
- unreachable!()
- }
- }
- (Addr::PStrLocation(..), Addr::Lis(_)) | (Addr::Lis(_), Addr::PStrLocation(..)) => {
- continue;
- }
- (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => {
- let mut i1 = self.heap_pstr_iter(pstr1);
- let mut i2 = self.heap_pstr_iter(pstr2);
-
- let ordering = compare_pstr_prefixes(&mut i1, &mut i2);
+ pub(super) fn write_literal_to_var(&mut self, deref_v: HeapCellValue, lit: HeapCellValue) {
+ let store_v = self.store(deref_v);
- if let Some(ordering) = ordering {
- if ordering != Ordering::Equal {
- return true;
- }
+ read_heap_cell!(lit,
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ if arity == 0 {
+ self.unify_atom(atom, store_v);
+ } else {
+ self.fail = true;
+ }
+ }
+ (HeapCellValueTag::Char, c) => {
+ self.unify_char(c, store_v);
+ }
+ (HeapCellValueTag::Fixnum, n) => {
+ self.unify_fixnum(n, store_v);
+ }
+ (HeapCellValueTag::F64, f64_ptr) => {
+ self.unify_f64(f64_ptr, store_v);
+ }
+ (HeapCellValueTag::Cons, ptr) => {
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Integer, n) => {
+ self.unify_big_int(n, store_v);
+ }
+ (ArenaHeaderTag::Rational, r) => {
+ self.unify_rational(r, store_v);
+ }
+ _ => {
+ self.fail = true;
+ }
+ )
+ }
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ match store_v.get_tag() {
+ HeapCellValueTag::PStrLoc
+ | HeapCellValueTag::Lis
+ | HeapCellValueTag::Str => {
+ self.match_partial_string(store_v, cstr_atom, false);
}
+ HeapCellValueTag::AttrVar | HeapCellValueTag::Var => {
+ let r = store_v.as_var().unwrap();
+ self.bind(r, lit);
+ }
+ _ => {
+ self.fail = true;
+ }
+ }
+ }
+ _ => {
+ unreachable!()
+ }
+ )
+ }
- let (lstack, rstack) = iter.stack();
-
- lstack.pop();
- lstack.pop();
+ pub(super) fn setup_call_n(&mut self, arity: usize) -> Result<PredicateKey, MachineStub> {
+ let addr = self.store(self.deref(self.registers[arity]));
- rstack.pop();
- rstack.pop();
+ let (name, narity) = read_heap_cell!(addr,
+ (HeapCellValueTag::Str, s) => {
+ let (name, narity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
- lstack.push(i1.focus());
- rstack.push(i2.focus());
- }
- (Addr::Lis(_), Addr::Lis(_)) => {
- continue;
+ if narity + arity > MAX_ARITY {
+ let stub = functor_stub(atom!("call"), arity + 1);
+ let err = self.representation_error(RepFlag::MaxArity);
+ return Err(self.error_form(err, stub));
}
- (Addr::Con(h1), Addr::Con(h2)) => match (&self.heap[h1], &self.heap[h2]) {
- (
- &HeapCellValue::Atom(ref n1, ref spec_1),
- &HeapCellValue::Atom(ref n2, ref spec_2),
- ) => {
- if n1 != n2 || spec_1 != spec_2 {
- return true;
- }
- }
- (&HeapCellValue::DBRef(ref db_ref_1), &HeapCellValue::DBRef(ref db_ref_2)) => {
- if db_ref_1 != db_ref_2 {
- return true;
- }
- }
- (v1, v2) => {
- if let Ok(n1) = Number::try_from(v1) {
- if let Ok(n2) = Number::try_from(v2) {
- if n1 == n2 {
- continue;
- }
- }
- }
- return true;
- }
- },
- (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => {
- match &self.heap[h] {
- &HeapCellValue::Atom(ref name, _) if name.is_char() => {
- if name.as_str().chars().next() != Some(c) {
- return true;
- }
- }
- _ => {
- return true;
- }
- }
+ for i in (1..arity).rev() {
+ self.registers[i + narity] = self.registers[i];
}
- (a1, a2) => {
- if let Ok(n1) = Number::try_from((a1, &self.heap)) {
- if let Ok(n2) = Number::try_from((a2, &self.heap)) {
- if n1 != n2 {
- return true;
- } else {
- continue;
- }
- }
- }
- if a1 != a2 {
- return true;
- }
+ for i in 1..narity + 1 {
+ self.registers[i] = self.heap[s + i];
}
+
+ (name, narity)
}
- }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+ (name, 0)
+ }
+ (HeapCellValueTag::Char, c) => {
+ (self.atom_tbl.build_with(&c.to_string()), 0)
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => {
+ let stub = functor_stub(atom!("call"), arity + 1);
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub));
+ }
+ _ => {
+ let stub = functor_stub(atom!("call"), arity + 1);
+ let err = self.type_error(ValidType::Callable, addr);
+ return Err(self.error_form(err, stub));
+ }
+ );
- // did the two iterators expire at the same step?
- iter.first_to_expire != Ordering::Equal
+ Ok((name, arity + narity - 1))
}
- pub(super) fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Option<Ordering> {
- let mut iter = self.zipped_acyclic_pre_order_iter(*a1, *a2);
+ #[inline]
+ pub fn is_cyclic_term(&mut self, addr: HeapCellValue) -> bool {
+ if addr.is_constant() {
+ return false;
+ }
- while let Some((v1, v2)) = iter.next() {
- let order_cat_v1 = v1.order_category(&self.heap);
- let order_cat_v2 = v2.order_category(&self.heap);
+ let addr = self.store(self.deref(addr));
+ let mut iter = stackful_preorder_iter(&mut self.heap, addr);
- if order_cat_v1 != order_cat_v2 {
- return Some(order_cat_v1.cmp(&order_cat_v2));
+ while let Some(value) = iter.next() {
+ if value.is_forwarded() {
+ let value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value));
+
+ if value.is_compound() {
+ return true;
+ }
}
+ }
- match order_cat_v1 {
- Some(TermOrderCategory::Variable) => {
- let v1 = v1.as_var().unwrap();
- let v2 = v2.as_var().unwrap();
+ false
+ }
- if v1 != v2 {
- return Some(v1.cmp(&v2));
- }
- }
- Some(TermOrderCategory::FloatingPoint) => {
- if let Addr::Float(f1) = v1 {
- if let Addr::Float(f2) = v2 {
- return Some(f1.cmp(&f2));
- } else {
- unreachable!()
- }
- } else {
- unreachable!()
+ // arg(+N, +Term, ?Arg)
+ pub fn try_arg(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("arg"), 3);
+ let n = self.store(self.deref(self.registers[1]));
+
+ read_heap_cell!(n,
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ // 8.5.2.3 a)
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub_gen()));
+ }
+ _ => {
+ let n = match Number::try_from(n) {
+ Ok(Number::Fixnum(n)) => Number::Fixnum(n),
+ Ok(Number::Integer(n)) => Number::Integer(n),
+ _ => {
+ let err = self.type_error(ValidType::Integer, n);
+ return Err(self.error_form(err, stub_gen()));
}
+ };
+
+ if n < 0 {
+ // 8.5.2.3 e)
+ let err = self.domain_error(DomainErrorType::NotLessThanZero, n);
+ return Err(self.error_form(err, stub_gen()));
}
- Some(TermOrderCategory::Integer) => match (v1, v2) {
- (Addr::Con(h1), Addr::Con(h2)) => {
- if let Ok(n1) = Number::try_from(&self.heap[h1]) {
- if let Ok(n2) = Number::try_from(&self.heap[h2]) {
- if n1 != n2 {
- return Some(n1.cmp(&n2));
- }
- } else {
- unreachable!()
- }
- } else {
- unreachable!()
- }
+
+ let n = match n {
+ Number::Fixnum(n) => n.get_num() as usize,
+ Number::Integer(n) if *n >= 0 && *n <= std::usize::MAX => n.to_usize().unwrap(),
+ _ => {
+ self.fail = true;
+ return Ok(());
}
- (Addr::Con(h1), v2) => {
- if let Ok(n1) = Number::try_from(&self.heap[h1]) {
- if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) {
- if n1 != n2 {
- return Some(n1.cmp(&n2));
- }
- } else {
- unreachable!()
- }
- } else {
- unreachable!()
- }
+ };
+
+ let term = self.deref(self.registers[2]);
+
+ read_heap_cell!(self.store(term),
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub_gen()));
}
- (v1, Addr::Con(h2)) => {
- if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) {
- if let Ok(n2) = Number::try_from(&self.heap[h2]) {
- if n1 != n2 {
- return Some(n1.cmp(&n2));
- }
- } else {
- unreachable!()
- }
+ (HeapCellValueTag::Str, o) => {
+ let arity = cell_as_atom_cell!(self.heap[o]).get_arity();
+
+ if 1 <= n && n <= arity {
+ let a3 = self.registers[3];
+ unify_fn!(*self, a3, heap_loc_as_cell!(o + n));
} else {
- unreachable!()
+ self.fail = true;
}
}
- (v1, v2) => {
- if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) {
- if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) {
- if n1 != n2 {
- return Some(n1.cmp(&n2));
- }
- } else {
- unreachable!()
- }
+ (HeapCellValueTag::Lis, l) => {
+ if n == 1 || n == 2 {
+ let a3 = self.registers[3];
+ unify_fn!(*self, a3, heap_loc_as_cell!(l + n - 1));
} else {
- unreachable!()
+ self.fail = true;
}
}
- },
- Some(TermOrderCategory::Atom) => match (v1, v2) {
- (Addr::Con(h1), Addr::Con(h2)) => {
- if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] {
- if let HeapCellValue::Atom(ref n2, _) = &self.heap[h2] {
- if n1 != n2 {
- return Some(n1.cmp(&n2));
+ (HeapCellValueTag::PStrLoc, pstr_loc) => {
+ if n == 1 || n == 2 {
+ let a3 = self.registers[3];
+ let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc);
+
+ let pstr = cell_as_string!(self.heap[h]);
+ let offset = offset.get_num() as usize;
+
+ if let Some(c) = pstr.as_str_from(offset).chars().next() {
+ if n == 1 {
+ self.unify_char(c, a3);
+ } else {
+ let offset = (offset + c.len_utf8()) as i64;
+ let h_len = self.heap.len();
+ let pstr_atom: Atom = pstr.into();
+
+ if pstr_atom.len() > offset as usize {
+ self.heap.push(pstr_offset_as_cell!(h));
+ self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset)));
+
+ unify_fn!(*self, pstr_loc_as_cell!(h_len), a3);
+ } else {
+ match self.heap[h].get_tag() {
+ HeapCellValueTag::CStr => {
+ self.unify_atom(atom!("[]"), self.store(self.deref(a3)));
+ }
+ HeapCellValueTag::PStr => {
+ unify_fn!(*self, self.heap[h+1], a3);
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+ }
}
} else {
unreachable!()
}
} else {
- unreachable!()
- }
- }
- (Addr::Con(h1), Addr::Char(c)) => {
- if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] {
- if n1.is_char() {
- if n1.as_str().chars().next() != Some(c) {
- return Some(n1.as_str().chars().next().cmp(&Some(c)));
- }
- } else {
- return Some(Ordering::Greater);
- }
- } else {
- unreachable!()
- }
- }
- (Addr::Char(c), Addr::Con(h1)) => {
- if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] {
- if n1.is_char() {
- if n1.as_str().chars().next() != Some(c) {
- return Some(Some(c).cmp(&n1.as_str().chars().next()));
- }
- } else {
- return Some(Ordering::Less);
- }
- } else {
- unreachable!()
- }
- }
- (Addr::EmptyList, Addr::Con(h)) => {
- if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] {
- if "[]" != n1.as_str() {
- return Some("[]".cmp(n1.as_str()));
- }
- } else {
- unreachable!()
- }
- }
- (Addr::Con(h), Addr::EmptyList) => {
- if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] {
- if "[]" != n1.as_str() {
- return Some(n1.as_str().cmp("[]"));
- }
- } else {
- unreachable!()
- }
- }
- (Addr::Char(c1), Addr::Char(c2)) => {
- if c1 != c2 {
- return Some(c1.cmp(&c2));
+ self.fail = true;
}
}
- (Addr::Char(c), Addr::EmptyList) => {
- return if c == '[' {
- Some(Ordering::Less)
- } else {
- Some(c.cmp(&'['))
- };
- }
- (Addr::EmptyList, Addr::Char(c)) => {
- return if c == '[' {
- Some(Ordering::Greater)
- } else {
- Some('['.cmp(&c))
- };
- }
- (Addr::EmptyList, Addr::EmptyList) => {}
- _ => {
- return None;
- }
- },
- Some(TermOrderCategory::Compound) => match (v1, v2) {
- (Addr::Lis(_), Addr::Lis(_)) => {}
- (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => {
- let mut i1 = self.heap_pstr_iter(pstr1);
- let mut i2 = self.heap_pstr_iter(pstr2);
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ let cstr = PartialString::from(cstr_atom);
- let ordering = compare_pstr_prefixes(&mut i1, &mut i2);
+ if let Some(c) = cstr.as_str_from(0).chars().next() {
+ if n == 1 {
+ self.unify_char(c, self.store(self.deref(self.registers[3])));
+ } else if n == 2 {
+ let offset = c.len_utf8() as i64;
+ let h_len = self.heap.len();
- if let Some(ordering) = ordering {
- if ordering != Ordering::Equal {
- return Some(ordering);
- }
- } else {
- let (lstack, rstack) = iter.stack();
-
- lstack.pop();
- lstack.pop();
-
- rstack.pop();
- rstack.pop();
+ if cstr_atom.len() > offset as usize {
+ self.heap.push(atom_as_cstr_cell!(cstr_atom));
+ self.heap.push(pstr_offset_as_cell!(h_len));
+ self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset)));
- lstack.push(i1.focus());
- rstack.push(i2.focus());
- }
- }
- (Addr::Str(h1), Addr::Str(h2)) => {
- if let HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[h1] {
- if let HeapCellValue::NamedStr(a2, ref n2, _) = &self.heap[h2] {
- if a1 != a2 || n1.as_str() != n2.as_str() {
- return Some(
- a1.cmp(&a2).then_with(|| n1.as_str().cmp(n2.as_str())),
- );
+ unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]);
+ } else {
+ self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[3])));
}
} else {
- unreachable!()
- }
- } else {
- unreachable!()
- }
- }
- (Addr::Lis(_), Addr::PStrLocation(..))
- | (Addr::PStrLocation(..), Addr::Lis(_)) => {}
- (Addr::Lis(_), Addr::Str(s)) => {
- if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] {
- if a1 != 2 || n1.as_str() != "." {
- return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp(".")));
- }
- } else {
- unreachable!()
- }
- }
- (Addr::Str(s), Addr::Lis(_)) => {
- if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] {
- if a1 != 2 || n1.as_str() != "." {
- return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str())));
- }
- } else {
- unreachable!()
- }
- }
- (Addr::PStrLocation(..), Addr::Str(s)) => {
- if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] {
- if a1 != 2 || n1.as_str() != "." {
- return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp(".")));
- }
- } else {
- unreachable!()
- }
- }
- (Addr::Str(s), Addr::PStrLocation(..)) => {
- if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] {
- if a1 != 2 || n1.as_str() != "." {
- return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str())));
+ self.fail = true;
}
} else {
unreachable!()
}
}
_ => {
- return None;
+ // 8.5.2.3 d)
+ let err = self.type_error(ValidType::Compound, term);
+ return Err(self.error_form(err, stub_gen()));
}
- },
- None => {
- return None;
- }
+ )
}
- }
-
- Some(iter.first_to_expire)
- }
+ );
- pub(super) fn reset_block(&mut self, addr: Addr) {
- match self.store(addr) {
- Addr::Usize(b) => self.block = b,
- _ => self.fail = true,
- };
+ Ok(())
}
- pub(super) fn execute_inlined(&mut self, inlined: &InlinedClauseType) {
- match inlined {
- &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => {
- let n1 = try_or_fail!(self, self.get_number(at_1));
- let n2 = try_or_fail!(self, self.get_number(at_2));
-
- self.compare_numbers(cmp, n1, n2);
- }
- &InlinedClauseType::IsAtom(r1) => {
- let d = self.store(self.deref(self[r1]));
-
- match d {
- Addr::Con(h) => {
- if let HeapCellValue::Atom(..) = &self.heap[h] {
- self.p += 1;
- } else {
- self.fail = true;
- }
- }
- Addr::Char(_) => self.p += 1,
- Addr::EmptyList => self.p += 1,
- _ => self.fail = true,
- };
- }
- &InlinedClauseType::IsAtomic(r1) => {
- let d = self.store(self.deref(self[r1]));
-
- match d {
- Addr::Char(_)
- | Addr::Con(_)
- | Addr::EmptyList
- | Addr::Fixnum(_)
- | Addr::Float(_)
- | Addr::Usize(_) => self.p += 1,
- _ => self.fail = true,
- };
- }
- &InlinedClauseType::IsInteger(r1) => {
- let d = self.store(self.deref(self[r1]));
-
- match Number::try_from((d, &self.heap)) {
- Ok(Number::Fixnum(_)) => {
- self.p += 1;
- }
- Ok(Number::Integer(_)) => {
- self.p += 1;
- }
- Ok(Number::Rational(n)) => {
- if n.denom() == &1 {
- self.p += 1;
- } else {
- self.fail = true;
- }
- }
- _ => {
- self.fail = true;
- }
- }
- }
- &InlinedClauseType::IsCompound(r1) => {
- let d = self.store(self.deref(self[r1]));
-
- match d {
- Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => self.p += 1,
- _ => self.fail = true,
- };
- }
- &InlinedClauseType::IsFloat(r1) => {
- let d = self.store(self.deref(self[r1]));
-
- match d {
- Addr::Float(_) => self.p += 1,
- _ => self.fail = true,
- };
- }
- &InlinedClauseType::IsNumber(r1) => match self.store(self.deref(self[r1])) {
- Addr::Float(_) => self.p += 1,
- d => match Number::try_from((d, &self.heap)) {
- Ok(Number::Fixnum(_)) => {
- self.p += 1;
- }
- Ok(Number::Integer(_)) => {
- self.p += 1;
- }
- Ok(Number::Rational(n)) => {
- if n.denom() == &1 {
- self.p += 1;
- } else {
- self.fail = true;
- }
- }
- _ => {
- self.fail = true;
- }
- },
- },
- &InlinedClauseType::IsRational(r1) => {
- let d = self.store(self.deref(self[r1]));
+ // returns true on failure, false on success.
+ pub fn eq_test(&mut self, h1: HeapCellValue, h2: HeapCellValue) -> bool {
+ if h1 == h2 {
+ return false;
+ }
- match d {
- Addr::Con(h) => {
- if let HeapCellValue::Rational(_) = &self.heap[h] {
- self.p += 1;
- } else {
- self.fail = true;
- }
- }
- _ => {
- self.fail = true;
- }
- };
- }
- &InlinedClauseType::IsNonVar(r1) => {
- let d = self.store(self.deref(self[r1]));
+ compare_term_test!(self, h1, h2)
+ .map(|o| o != Ordering::Equal)
+ .unwrap_or(true)
+ }
- match d {
- Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => {
- self.fail = true;
- }
- _ => {
- self.p += 1;
- }
- };
+ pub fn reset_block(&mut self, addr: HeapCellValue) {
+ read_heap_cell!(self.store(addr),
+ (HeapCellValueTag::Fixnum, n) => {
+ self.block = n.get_num() as usize;
}
- &InlinedClauseType::IsVar(r1) => {
- let d = self.store(self.deref(self[r1]));
-
- match d {
- Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => {
- self.p += 1;
- }
- _ => {
- self.fail = true;
- }
- };
+ _ => {
+ self.fail = true;
}
- }
+ )
}
- fn try_functor_compound_case(
- &mut self,
- name: ClauseName,
- arity: usize,
- spec: Option<SharedOpDesc>,
- ) {
- let name = self.heap.to_unifiable(HeapCellValue::Atom(name, spec));
- self.try_functor_unify_components(name, arity);
+ #[inline(always)]
+ fn try_functor_compound_case(&mut self, name: Atom, arity: usize) {
+ self.try_functor_unify_components(atom_as_cell!(name), arity);
}
- fn try_functor_unify_components(&mut self, name: Addr, arity: usize) {
- let a2 = self[temp_v!(2)];
- let a3 = self[temp_v!(3)];
-
- (self.unify_fn)(self, a2, name);
+ fn try_functor_unify_components(&mut self, name: HeapCellValue, arity: usize) {
+ let a2 = self.deref(self.registers[2]);
+ self.write_literal_to_var(a2, name);
if !self.fail {
- (self.unify_fn)(self, a3, Addr::Usize(arity));
+ let a3 = self.store(self.deref(self.registers[3]));
+ self.unify_fixnum(Fixnum::build_with(arity as i64), a3);
}
}
- fn try_functor_fabricate_struct(
- &mut self,
- name: ClauseName,
- arity: usize,
- spec: Option<SharedOpDesc>,
- op_dir: &OpDir,
- r: Ref,
- ) {
- let spec = spec.and_then(|spec| {
- if spec.arity() != arity {
- fetch_op_spec(name.clone(), arity, op_dir)
- } else {
- Some(spec)
- }
- });
+ fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) {
+ let h = self.heap.len();
+
+ let f_a = if name == atom!(".") && arity == 2 {
+ self.heap.push(heap_loc_as_cell!(h));
+ self.heap.push(heap_loc_as_cell!(h+1));
- let f_a = if name.as_str() == "." && arity == 2 {
- Addr::Lis(self.heap.h())
+ list_loc_as_cell!(h)
} else {
- self.heap
- .to_unifiable(HeapCellValue::NamedStr(arity, name, spec))
- };
+ self.heap.push(atom_as_cell!(name, arity));
- let h = self.heap.h();
+ for i in 0..arity {
+ self.heap.push(heap_loc_as_cell!(h + i + 1));
+ }
- for i in 0..arity {
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + i)));
- }
+ if arity == 0 {
+ heap_loc_as_cell!(h)
+ } else {
+ str_loc_as_cell!(h)
+ }
+ };
(self.bind_fn)(self, r, f_a);
}
- pub(super) fn try_functor(&mut self, op_dir: &OpDir) -> CallResult {
- let stub = MachineError::functor_stub(clause_name!("functor"), 3);
- let a1 = self.store(self.deref(self[temp_v!(1)]));
+ pub fn try_functor(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("functor"), 3);
+ let a1 = self.store(self.deref(self.registers[1]));
- match a1 {
- Addr::Stream(_) => {
- self.fail = true;
+ read_heap_cell!(a1,
+ (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum |
+ HeapCellValueTag::F64) => {
+ self.try_functor_unify_components(a1, 0);
}
- Addr::Char(_)
- | Addr::Con(_)
- | Addr::Fixnum(_)
- | Addr::Float(_)
- | Addr::EmptyList
- | Addr::Usize(_) => {
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ debug_assert_eq!(arity, 0);
self.try_functor_unify_components(a1, 0);
}
- Addr::Str(o) => match self.heap.clone(o) {
- HeapCellValue::NamedStr(arity, name, spec) => {
- let spec = fetch_op_spec_from_existing(name.clone(), arity, spec, &op_dir);
-
- self.try_functor_compound_case(name, arity, spec)
- }
- _ => {
- self.fail = true;
- }
- },
- Addr::Lis(_) | Addr::PStrLocation(..) => {
- let spec = fetch_op_spec_from_existing(clause_name!("."), 2, None, &op_dir);
-
- self.try_functor_compound_case(clause_name!("."), 2, spec)
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
+ self.try_functor_compound_case(name, arity);
+ }
+ (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+ self.try_functor_compound_case(atom!("."), 2);
}
- Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => {
- let name = self.store(self.deref(self[temp_v!(2)]));
- let arity = self.store(self.deref(self[temp_v!(3)]));
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ let deref_name = self.deref(self.registers[2]);
+ let store_name = self.store(deref_name);
- if name.is_ref() || arity.is_ref() {
+ let arity = self.store(self.deref(self.registers[3]));
+
+ if store_name.is_var() || arity.is_var() {
// 8.5.1.3 a) & 8.5.1.3 b)
- return Err(self.error_form(MachineError::instantiation_error(), stub));
- }
-
- let arity = match Number::try_from((arity, &self.heap)) {
- Ok(Number::Fixnum(n)) => Some(n),
- Ok(Number::Integer(n)) => n.to_isize(),
- Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().to_isize(),
- _ => match arity {
- arity => {
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, arity),
- stub,
- ));
- }
- },
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub_gen()));
+ }
+
+ let arity = match Number::try_from(arity) {
+ Ok(Number::Fixnum(n)) => Some(n.get_num()),
+ Ok(Number::Integer(n)) => n.to_i64(),
+ Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().to_i64(),
+ _ => {
+ let err = self.type_error(ValidType::Integer, arity);
+ return Err(self.error_form(err, stub_gen()));
+ }
};
let arity = match arity {
@@ -2589,989 +2326,302 @@ impl MachineState {
}
};
- if arity > MAX_ARITY as isize {
+ if arity > MAX_ARITY as i64 {
// 8.5.1.3 f)
- let rep_err = MachineError::representation_error(RepFlag::MaxArity);
- return Err(self.error_form(rep_err, stub));
+ let err = self.representation_error(RepFlag::MaxArity);
+ return Err(self.error_form(err, stub_gen()));
} else if arity < 0 {
// 8.5.1.3 g)
- let arity = Number::Integer(Rc::new(Integer::from(arity)));
- let dom_err =
- MachineError::domain_error(DomainErrorType::NotLessThanZero, arity);
-
- return Err(self.error_form(dom_err, stub));
- }
-
- match name {
- Addr::Char(_)
- | Addr::Con(_)
- | Addr::Fixnum(_)
- | Addr::Float(_)
- | Addr::EmptyList
- | Addr::PStrLocation(..)
- | Addr::Usize(_)
- if arity == 0 =>
- {
- (self.unify_fn)(self, a1, name);
- }
- Addr::Con(h) => {
- if let HeapCellValue::Atom(name, spec) = self.heap.clone(h) {
- self.try_functor_fabricate_struct(
- name,
- arity as usize,
- spec,
- &op_dir,
- a1.as_var().unwrap(),
- );
- } else {
- // 8.5.1.3 e)
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Atom, name),
- stub,
- ));
- }
+ let arity = Number::Fixnum(Fixnum::build_with(arity));
+ let err = self.domain_error(DomainErrorType::NotLessThanZero, arity);
+
+ return Err(self.error_form(err, stub_gen()));
+ }
+
+ read_heap_cell!(store_name,
+ (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum |
+ HeapCellValueTag::F64) if arity == 0 => {
+ self.bind(a1.as_var().unwrap(), deref_name);
+ }
+ (HeapCellValueTag::Atom, (name, atom_arity)) => {
+ debug_assert_eq!(atom_arity, 0);
+ self.try_functor_fabricate_struct(
+ name,
+ arity as usize,
+ a1.as_var().unwrap(),
+ );
}
- Addr::Char(c) => {
+ (HeapCellValueTag::Char, c) => {
+ let c = self.atom_tbl.build_with(&c.to_string());
+
self.try_functor_fabricate_struct(
- clause_name!(c.to_string(), self.atom_tbl),
+ c,
arity as usize,
- None,
- &op_dir,
a1.as_var().unwrap(),
);
}
_ => {
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Atomic, name),
- stub,
- ));
+ let err = self.type_error(ValidType::Atomic, store_name);
+ return Err(self.error_form(err, stub_gen()));
} // 8.5.1.3 c)
- }
+ );
}
_ => {
self.fail = true;
}
- }
+ );
Ok(())
}
- pub(super) fn term_dedup(&self, list: &mut Vec<Addr>) {
- let mut result = vec![];
-
- for a2 in list.iter() {
- if let Some(a1) = result.last() {
- if self.compare_term_test(&a1, &a2) == Some(Ordering::Equal) {
- continue;
+ pub fn try_from_list(
+ &mut self,
+ value: HeapCellValue,
+ stub_gen: impl Fn() -> FunctorStub,
+ ) -> Result<Vec<HeapCellValue>, MachineStub> {
+ let deref_v = self.deref(value);
+ let store_v = self.store(deref_v);
+
+ read_heap_cell!(store_v,
+ (HeapCellValueTag::Lis, l) => {
+ self.try_from_inner_list(vec![], l, stub_gen, store_v)
+ }
+ (HeapCellValueTag::PStrLoc, h) => {
+ self.try_from_partial_string(vec![], h, stub_gen, store_v)
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
+ let err = self.instantiation_error();
+ Err(self.error_form(err, stub_gen()))
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if name == atom!("[]") && arity == 0 {
+ Ok(vec![])
+ } else {
+ let err = self.type_error(ValidType::List, store_v);
+ Err(self.error_form(err, stub_gen()))
}
}
-
- result.push(*a2);
- }
-
- *list = result;
- }
-
- pub(super) fn integers_to_bytevec(&self, r: RegType, caller: MachineStub) -> Vec<u8> {
- let mut bytes: Vec<u8> = Vec::new();
-
- match self.try_from_list(r, caller) {
- Err(_) => {
- unreachable!()
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ let cstr = cstr_atom.as_str();
+ Ok(cstr.chars().map(|c| char_as_cell!(c)).collect())
}
- Ok(addrs) => {
- for addr in addrs {
- let addr = self.store(self.deref(addr));
-
- match Number::try_from((addr, &self.heap)) {
- Ok(Number::Fixnum(n)) => {
- match u8::try_from(n) {
- Ok(b) => {
- bytes.push(b);
- }
- Err(_) => {}
- }
-
- continue;
- }
- Ok(Number::Integer(n)) => {
- if let Some(b) = n.to_u8() {
- bytes.push(b);
- }
-
- continue;
- }
- _ => {}
- }
- }
+ _ => {
+ let err = self.type_error(ValidType::List, store_v);
+ Err(self.error_form(err, stub_gen()))
}
- }
- bytes
- }
-
- pub(super) fn try_from_list(
- &self,
- r: RegType,
- caller: MachineStub,
- ) -> Result<Vec<Addr>, MachineStub> {
- let a1 = self.store(self.deref(self[r]));
-
- match a1 {
- Addr::Lis(l) => self.try_from_inner_list(vec![], l, caller, a1),
- Addr::PStrLocation(h, n) => self.try_from_partial_string(vec![], h, n, caller, a1),
- Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => {
- Err(self.error_form(MachineError::instantiation_error(), caller))
- }
- Addr::EmptyList => Ok(vec![]),
- _ => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::List, a1),
- caller,
- )),
- }
+ )
}
fn try_from_inner_list(
- &self,
- mut result: Vec<Addr>,
+ &mut self,
+ mut result: Vec<HeapCellValue>,
mut l: usize,
- caller: MachineStub,
- a1: Addr,
- ) -> Result<Vec<Addr>, MachineStub> {
- result.push(self.heap[l].as_addr(l));
+ stub_gen: impl Fn() -> FunctorStub,
+ a1: HeapCellValue,
+ ) -> Result<Vec<HeapCellValue>, MachineStub> {
+ result.push(self.heap[l]);
l += 1;
loop {
- match &self.heap[l] {
- HeapCellValue::Addr(ref addr) => match self.store(self.deref(*addr)) {
- Addr::Lis(hcp) => {
- result.push(self.heap[hcp].as_addr(hcp));
- l = hcp + 1;
- }
- Addr::PStrLocation(h, n) => {
- return self.try_from_partial_string(result, h, n, caller, a1);
- }
- Addr::EmptyList => {
+ let deref_v = self.deref(self.heap[l]);
+ let store_v = self.store(self.heap[l]);
+
+ read_heap_cell!(store_v,
+ (HeapCellValueTag::Lis, hcp) => {
+ result.push(self.heap[hcp]);
+ l = hcp + 1;
+ }
+ (HeapCellValueTag::PStrOffset) => {
+ return self.try_from_partial_string(result, deref_v.get_value(), stub_gen, a1);
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if name == atom!("[]") && arity == 0 {
break;
+ } else {
+ let err = self.type_error(ValidType::List, a1);
+ return Err(self.error_form(err, stub_gen()));
}
- Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => {
- return Err(self.error_form(MachineError::instantiation_error(), caller))
- }
- _ => {
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::List, a1),
- caller,
- ))
- }
- },
+ }
_ => {
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::List, a1),
- caller,
- ))
+ if store_v.is_var() {
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub_gen()));
+ } else {
+ let err = self.type_error(ValidType::List, a1);
+ return Err(self.error_form(err, stub_gen()));
+ }
}
- }
+ );
}
Ok(result)
}
fn try_from_partial_string(
- &self,
- mut chars: Vec<Addr>,
- mut h: usize,
- mut n: usize,
- caller: MachineStub,
- a1: Addr,
- ) -> Result<Vec<Addr>, MachineStub> {
- loop {
- if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] {
- chars.extend(pstr.range_from(n..).map(Addr::Char));
-
- if !has_tail {
- return Ok(chars);
- }
-
- let tail = self.heap[h + 1].as_addr(h + 1);
-
- match self.store(self.deref(tail)) {
- Addr::EmptyList => {
- return Ok(chars);
- }
- Addr::Lis(l) => {
- return self.try_from_inner_list(chars, l, caller, a1);
- }
- Addr::PStrLocation(h1, n1) => {
- chars.push(Addr::Char('\u{0}'));
-
- h = h1;
- n = n1;
- }
- _ => {
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::List, a1),
- caller,
- ))
- }
+ &mut self,
+ mut chars: Vec<HeapCellValue>,
+ h: usize,
+ stub_gen: impl Fn() -> FunctorStub,
+ a1: HeapCellValue,
+ ) -> Result<Vec<HeapCellValue>, MachineStub> {
+ let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h);
+
+ while let Some(iteratee) = heap_pstr_iter.next() {
+ match iteratee {
+ PStrIteratee::Char(_, c) =>
+ chars.push(char_as_cell!(c)),
+ PStrIteratee::PStrSegment(_, pstr_atom, n) => {
+ let pstr = PartialString::from(pstr_atom);
+ chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c)));
}
- } else {
- unreachable!()
}
}
- }
- // see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide.
- pub(super) fn project_onto_key(&self, a: Addr) -> Result<Addr, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
-
- match self.store(self.deref(a)) {
- Addr::HeapCell(_) | Addr::StackCell(..) => {
- Err(self.error_form(MachineError::instantiation_error(), stub))
- }
- Addr::Str(s) => match self.heap.clone(s) {
- HeapCellValue::NamedStr(2, ref name, Some(_)) if *name == clause_name!("-") => {
- Ok(Addr::HeapCell(s + 1))
- }
- _ => Err(self.error_form(
- MachineError::type_error(
- self.heap.h(),
- ValidType::Pair,
- self.heap[s].as_addr(s),
- ),
- stub,
- )),
- },
- a => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Pair, a),
- stub,
- )),
- }
- }
-
- pub(super) fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) {
- let old_h = self.heap.h();
-
- let a1 = self[temp_v!(1)];
- let a2 = self[temp_v!(2)];
-
- copy_term(CopyTerm::new(self), a1, attr_var_policy);
-
- (self.unify_fn)(self, Addr::HeapCell(old_h), a2);
- }
-
- // returns true on failure.
- pub(super) fn structural_eq_test(&self) -> bool {
- let a1 = self[temp_v!(1)];
- let a2 = self[temp_v!(2)];
-
- let mut var_pairs = IndexMap::new();
-
- let iter = self.zipped_acyclic_pre_order_iter(a1, a2);
-
- for (v1, v2) in iter {
- match (
- self.heap.index_addr(&v1).as_ref(),
- self.heap.index_addr(&v2).as_ref(),
- ) {
- (
- HeapCellValue::Addr(Addr::Lis(_)),
- HeapCellValue::Addr(Addr::PStrLocation(..)),
- )
- | (
- HeapCellValue::Addr(Addr::PStrLocation(..)),
- HeapCellValue::Addr(Addr::Lis(_)),
- ) => {}
- (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => {
- if ar1 != ar2 || n1 != n2 {
- return true;
- }
- }
- (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => {}
- (
- &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)),
- &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::StackCell(..)),
- &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)),
- &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)),
- &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)),
- &HeapCellValue::Addr(v2 @ Addr::StackCell(..)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)),
- &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)),
- &HeapCellValue::Addr(v2 @ Addr::StackCell(..)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::StackCell(..)),
- &HeapCellValue::Addr(v2 @ Addr::StackCell(..)),
- )
- | (
- &HeapCellValue::Addr(v1 @ Addr::StackCell(..)),
- &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)),
- ) => match (var_pairs.get(&v1), var_pairs.get(&v2)) {
- (Some(ref v2_p), Some(ref v1_p)) if **v1_p == v1 && **v2_p == v2 => {
- continue;
- }
- (Some(_), _) | (_, Some(_)) => {
- return true;
- }
- (None, None) => {
- var_pairs.insert(v1, v2);
- var_pairs.insert(v2, v1);
- }
- },
- (
- HeapCellValue::PartialString(ref pstr1, has_tail_1),
- HeapCellValue::PartialString(ref pstr2, has_tail_2),
- ) => {
- if has_tail_1 != has_tail_2 {
- return true;
- }
-
- let pstr1_iter = pstr1.range_from(0..);
- let pstr2_iter = pstr2.range_from(0..);
-
- for (c1, c2) in pstr1_iter.zip(pstr2_iter) {
- if c1 != c2 {
- return true;
- }
- }
- }
- (
- HeapCellValue::Addr(Addr::PStrLocation(..)),
- HeapCellValue::Addr(Addr::PStrLocation(..)),
- ) => {}
- (
- HeapCellValue::Atom(ref n1, ref spec_1),
- HeapCellValue::Atom(ref n2, ref spec_2),
- ) => {
- if n1 != n2 || spec_1 != spec_2 {
- return true;
- }
- }
- (HeapCellValue::DBRef(ref db_ref_1), HeapCellValue::DBRef(ref db_ref_2)) => {
- if db_ref_1 != db_ref_2 {
- return true;
- }
- }
- (v1, v2) => {
- if let Ok(n1) = Number::try_from(v1) {
- if let Ok(n2) = Number::try_from(v2) {
- if n1 != n2 {
- return true;
+ match self.heap[h].get_tag() {
+ HeapCellValueTag::PStr => {
+ if heap_pstr_iter.at_string_terminator() {
+ Ok(chars)
+ } else {
+ read_heap_cell!(self.heap[heap_pstr_iter.focus()],
+ (HeapCellValueTag::Lis, l) => {
+ self.try_from_inner_list(chars, l, stub_gen, a1)
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if name == atom!(".") && arity == 2 {
+ let l = heap_pstr_iter.focus() + 1;
+ self.try_from_inner_list(chars, l, stub_gen, a1)
} else {
- continue;
- }
- } else {
- return true;
- }
- }
-
- match (v1, v2) {
- (HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) => {
- if a1 != a2 {
- return true;
+ let err = self.type_error(ValidType::List, a1);
+ Err(self.error_form(err, stub_gen()))
}
}
_ => {
- return true;
+ let err = self.type_error(ValidType::List, a1);
+ Err(self.error_form(err, stub_gen()))
}
- }
+ )
}
}
+ HeapCellValueTag::CStr => Ok(chars),
+ _ => {
+ unreachable!()
+ }
}
-
- false
}
// returns true on failure.
- pub(super) fn ground_test(&self) -> bool {
- let a = self.store(self.deref(self[temp_v!(1)]));
-
- for v in self.acyclic_pre_order_iter(a) {
- match v {
- Addr::HeapCell(..) => return true,
- Addr::StackCell(..) => return true,
- Addr::AttrVar(..) => return true,
- _ => {}
- }
+ pub fn ground_test(&mut self) -> bool {
+ if self.registers[1].is_constant() {
+ return false;
}
- false
- }
-
- pub(super) fn setup_built_in_call(&mut self, ct: BuiltInClauseType) {
- self.num_of_args = ct.arity();
- self.b0 = self.b;
-
- self.p = CodePtr::BuiltInClause(ct, self.p.local());
- }
-
- pub(super) fn allocate(&mut self, num_cells: usize) {
- let e = self.stack.allocate_and_frame(num_cells);
- let and_frame = self.stack.index_and_frame_mut(e);
-
- and_frame.prelude.e = self.e;
- and_frame.prelude.cp = self.cp;
-
- self.e = e;
- self.p += 1;
- }
-
- pub(super) fn deallocate(&mut self) {
- let e = self.e;
- let frame = self.stack.index_and_frame(e);
-
- self.cp = frame.prelude.cp;
- self.e = frame.prelude.e;
+ let value = self.store(self.deref(self.registers[1]));
- if e > self.b {
- self.stack.truncate(e);
+ if value.is_stack_var() {
+ return true;
}
- self.p += 1;
- }
-
- fn throw_interrupt_exception(&mut self) {
- let err = MachineError::interrupt_error();
- let src = functor!("repl");
- let err = self.error_form(err, src);
-
- self.throw_exception(err);
- }
-
- fn handle_call_clause(
- &mut self,
- indices: &mut IndexStore,
- code_repo: &CodeRepo,
- call_policy: &mut Box<dyn CallPolicy>,
- cut_policy: &mut Box<dyn CutPolicy>,
- current_input_stream: &mut Stream,
- current_output_stream: &mut Stream,
- ct: &ClauseType,
- arity: usize,
- lco: bool,
- use_default_cp: bool,
- ) {
- let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
+ for v in stackful_preorder_iter(&mut self.heap, value) {
+ let v = unmark_cell_bits!(v);
- match INTERRUPT.compare_exchange(
- interrupted,
- false,
- std::sync::atomic::Ordering::Relaxed,
- std::sync::atomic::Ordering::Relaxed,
- ) {
- Ok(interruption) => {
- if interruption {
- self.throw_interrupt_exception();
- return;
- }
+ if v.is_var() {
+ return true;
}
- Err(_) => unreachable!(),
}
- let mut default_call_policy: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
-
- let call_policy = if use_default_cp {
- &mut default_call_policy
- } else {
- call_policy
- };
-
- self.last_call = lco;
-
- match ct {
- &ClauseType::BuiltIn(ref ct) => try_or_fail!(
- self,
- call_policy.call_builtin(
- self,
- ct,
- &indices.code_dir,
- &indices.op_dir,
- &indices.stream_aliases,
- )
- ),
- &ClauseType::CallN => try_or_fail!(
- self,
- call_policy.call_n(
- self,
- arity,
- &indices.code_dir,
- &indices.op_dir,
- &indices.stream_aliases,
- )
- ),
- &ClauseType::Inlined(ref ct) => {
- self.execute_inlined(ct);
-
- if lco {
- self.p = CodePtr::Local(self.cp);
- }
- }
- &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
- try_or_fail!(
- self,
- call_policy.context_call(self, name.clone(), arity, idx)
- )
- }
- &ClauseType::System(ref ct) => try_or_fail!(
- self,
- self.system_call(
- ct,
- code_repo,
- indices,
- call_policy,
- cut_policy,
- current_input_stream,
- current_output_stream,
- )
- ),
- };
-
- self.last_call = false;
+ false
}
- pub(super) fn execute_ctrl_instr(
+ pub fn integers_to_bytevec(
&mut self,
- indices: &mut IndexStore,
- code_repo: &CodeRepo,
- call_policy: &mut Box<dyn CallPolicy>,
- cut_policy: &mut Box<dyn CutPolicy>,
- current_input_stream: &mut Stream,
- current_output_stream: &mut Stream,
- instr: &ControlInstruction,
- ) {
- match instr {
- &ControlInstruction::Allocate(num_cells) => {
- self.allocate(num_cells);
- }
- &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => self
- .handle_call_clause(
- indices,
- code_repo,
- call_policy,
- cut_policy,
- current_input_stream,
- current_output_stream,
- ct,
- arity,
- lco,
- use_default_cp,
- ),
- &ControlInstruction::Deallocate => self.deallocate(),
- &ControlInstruction::JmpBy(arity, offset, _, lco) => {
- if !lco {
- self.cp.assign_if_local(self.p.clone() + 1);
- }
-
- self.num_of_args = arity;
- self.b0 = self.b;
- self.p += offset;
- }
- &ControlInstruction::RevJmpBy(offset) => {
- self.p -= offset;
- }
- &ControlInstruction::Proceed => {
- self.p = CodePtr::Local(self.cp);
+ value: HeapCellValue,
+ stub_gen: impl Fn() -> FunctorStub,
+ ) -> Vec<u8> {
+ let mut bytes: Vec<u8> = Vec::new();
+
+ match self.try_from_list(value, stub_gen) {
+ Err(_) => {
+ unreachable!()
}
- };
- }
+ Ok(addrs) => {
+ for addr in addrs {
+ let addr = self.store(self.deref(addr));
- pub(super) fn execute_dynamic_indexed_choice_instr(
- &mut self,
- code_repo: &CodeRepo,
- call_policy: &mut Box<dyn CallPolicy>,
- global_variables: &mut GlobalVarDir,
- ) {
- let p = self.p.local();
-
- match code_repo.find_living_dynamic(p, self.cc) {
- Some((offset, oi, ii, is_next_clause)) => {
- self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii));
-
- match self.dynamic_mode {
- FirstOrNext::First if !is_next_clause => {
- self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
- }
- FirstOrNext::First => {
- // there's a leading DynamicElse that sets self.cc.
- // self.cc = self.global_clock;
-
- match code_repo.find_living_dynamic(
- LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1),
- self.cc,
- ) {
- Some(_) => {
- self.registers[self.num_of_args + 1] = Addr::Usize(self.cc);
- self.num_of_args += 1;
-
- self.execute_indexed_choice_instr(
- &IndexedChoiceInstruction::Try(offset),
- call_policy,
- global_variables,
- );
-
- self.num_of_args -= 1;
- }
- None => {
- self.p =
- CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
- }
- }
- }
- FirstOrNext::Next => {
- let n = self
- .stack
- .index_or_frame(self.b)
- .prelude
- .univ_prelude
- .num_cells;
-
- self.cc = match self.stack.index_or_frame(self.b)[n - 1] {
- Addr::Usize(cc) => cc,
- _ => unreachable!(),
- };
-
- if is_next_clause {
- match code_repo.find_living_dynamic(
- LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1),
- self.cc,
- ) {
- Some(_) => {
- try_or_fail!(
- self,
- call_policy.retry(self, offset, global_variables,)
- )
- }
- None => {
- try_or_fail!(
- self,
- call_policy.trust(self, offset, global_variables,)
- )
- }
+ match Number::try_from(addr) {
+ Ok(Number::Fixnum(n)) => match u8::try_from(n.get_num()) {
+ Ok(b) => bytes.push(b),
+ Err(_) => {}
+ },
+ Ok(Number::Integer(n)) => {
+ if let Some(b) = n.to_u8() {
+ bytes.push(b);
}
- } else {
- try_or_fail!(self, call_policy.trust(self, offset, global_variables,))
}
+ _ => {}
}
}
}
- None => {
- self.fail = true;
- }
}
- self.dynamic_mode = FirstOrNext::Next;
+ bytes
}
- pub(super) fn execute_indexed_choice_instr(
- &mut self,
- instr: &IndexedChoiceInstruction,
- call_policy: &mut Box<dyn CallPolicy>,
- global_variables: &mut GlobalVarDir,
- ) {
- match instr {
- &IndexedChoiceInstruction::Try(offset) => {
- let n = self.num_of_args;
- let b = self.stack.allocate_or_frame(n);
- let or_frame = self.stack.index_or_frame_mut(b);
+ // see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide.
+ pub fn project_onto_key(&mut self, value: HeapCellValue) -> Result<HeapCellValue, MachineStub> {
+ let stub_gen = || functor_stub(atom!("keysort"), 2);
+ let store_v = self.store(self.deref(value));
- or_frame.prelude.univ_prelude.num_cells = n;
- or_frame.prelude.e = self.e;
- or_frame.prelude.cp = self.cp;
- or_frame.prelude.b = self.b;
- or_frame.prelude.bp = self.p.local() + 1;
- or_frame.prelude.tr = self.tr;
- or_frame.prelude.h = self.heap.h();
- or_frame.prelude.b0 = self.b0;
+ if store_v.is_var() {
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub_gen()));
+ }
- self.b = b;
+ read_heap_cell!(store_v,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
- for i in 1..n + 1 {
- self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i];
+ if name == atom!("-") && arity == 2 {
+ Ok(heap_loc_as_cell!(s + 1))
+ } else {
+ let err = self.type_error(ValidType::Pair, self.heap[s]);
+ Err(self.error_form(err, stub_gen()))
}
-
- self.hb = self.heap.h();
- self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset));
}
- &IndexedChoiceInstruction::Retry(l) => {
- try_or_fail!(self, call_policy.retry(self, l, global_variables));
- }
- &IndexedChoiceInstruction::Trust(l) => {
- try_or_fail!(self, call_policy.trust(self, l, global_variables));
+ _ => {
+ let err = self.type_error(ValidType::Pair, store_v);
+ Err(self.error_form(err, stub_gen()))
}
- };
+ )
}
- pub(super) fn execute_choice_instr(
- &mut self,
- instr: &ChoiceInstruction,
- code_repo: &CodeRepo,
- call_policy: &mut Box<dyn CallPolicy>,
- global_variables: &mut GlobalVarDir,
- ) {
- match instr {
- &ChoiceInstruction::DynamicElse(..) => {
- if let FirstOrNext::First = self.dynamic_mode {
- self.cc = self.global_clock;
- }
-
- let p = self.p.local().abs_loc();
-
- match code_repo.find_living_dynamic_else(p, self.cc) {
- Some((p, next_i)) => {
- self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-
- match self.dynamic_mode {
- FirstOrNext::First if next_i == 0 => {
- self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
- }
- FirstOrNext::First => {
- self.cc = self.global_clock;
-
- match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
- Some(_) => {
- self.registers[self.num_of_args + 1] = Addr::Usize(self.cc);
- self.num_of_args += 1;
-
- self.execute_choice_instr(
- &ChoiceInstruction::TryMeElse(next_i),
- code_repo,
- call_policy,
- global_variables,
- );
-
- self.num_of_args -= 1;
- }
- None => {
- self.p += 1;
- }
- }
- }
- FirstOrNext::Next => {
- let n = self
- .stack
- .index_or_frame(self.b)
- .prelude
- .univ_prelude
- .num_cells;
-
- self.cc = match self.stack.index_or_frame(self.b)[n - 1] {
- Addr::Usize(cc) => cc,
- _ => unreachable!(),
- };
-
- if next_i > 0 {
- match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
- Some(_) => {
- try_or_fail!(
- self,
- call_policy.retry_me_else(
- self,
- next_i,
- global_variables,
- )
- )
- }
- None => {
- try_or_fail!(
- self,
- call_policy.trust_me(self, global_variables,)
- )
- }
- }
- } else {
- try_or_fail!(
- self,
- call_policy.trust_me(self, global_variables,)
- )
- }
- }
- }
- }
- None => {
- self.fail = true;
- }
- }
-
- self.dynamic_mode = FirstOrNext::Next;
- }
- &ChoiceInstruction::DynamicInternalElse(..) => {
- let p = self.p.local().abs_loc();
-
- match code_repo.find_living_dynamic_else(p, self.cc) {
- Some((p, next_i)) => {
- self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-
- match self.dynamic_mode {
- FirstOrNext::First if next_i == 0 => {
- self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
- }
- FirstOrNext::First => {
- match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
- Some(_) => {
- self.registers[self.num_of_args + 1] = Addr::Usize(self.cc);
- self.num_of_args += 1;
-
- self.execute_choice_instr(
- &ChoiceInstruction::TryMeElse(next_i),
- code_repo,
- call_policy,
- global_variables,
- );
-
- self.num_of_args -= 1;
- }
- None => {
- self.p += 1;
- }
- }
- }
- FirstOrNext::Next => {
- let n = self
- .stack
- .index_or_frame(self.b)
- .prelude
- .univ_prelude
- .num_cells;
-
- self.cc = match self.stack.index_or_frame(self.b)[n - 1] {
- Addr::Usize(cc) => cc,
- _ => unreachable!(),
- };
-
- if next_i > 0 {
- match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
- Some(_) => {
- try_or_fail!(
- self,
- call_policy.retry_me_else(
- self,
- next_i,
- global_variables,
- )
- )
- }
- None => {
- try_or_fail!(
- self,
- call_policy.trust_me(self, global_variables,)
- )
- }
- }
- } else {
- try_or_fail!(
- self,
- call_policy.trust_me(self, global_variables,)
- )
- }
- }
- }
- }
- None => {
- self.fail = true;
- }
- }
-
- self.dynamic_mode = FirstOrNext::Next;
- }
- &ChoiceInstruction::TryMeElse(offset) => {
- let n = self.num_of_args;
- let b = self.stack.allocate_or_frame(n);
- let or_frame = self.stack.index_or_frame_mut(b);
-
- or_frame.prelude.univ_prelude.num_cells = n;
- or_frame.prelude.e = self.e;
- or_frame.prelude.cp = self.cp;
- or_frame.prelude.b = self.b;
- or_frame.prelude.bp = self.p.local() + offset;
- or_frame.prelude.tr = self.tr;
- or_frame.prelude.h = self.heap.h();
- or_frame.prelude.b0 = self.b0;
-
- self.b = b;
-
- for i in 1..n + 1 {
- self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i];
- }
+ /*
+ pub fn setup_built_in_call(&mut self, ct: BuiltInClauseType) {
+ self.num_of_args = ct.arity();
+ self.b0 = self.b;
- self.hb = self.heap.h();
- self.p += 1;
- }
- &ChoiceInstruction::DefaultRetryMeElse(offset) => {
- let mut call_policy = DefaultCallPolicy {};
- try_or_fail!(
- self,
- call_policy.retry_me_else(self, offset, global_variables)
- )
- }
- &ChoiceInstruction::DefaultTrustMe(_) => {
- let mut call_policy = DefaultCallPolicy {};
- try_or_fail!(self, call_policy.trust_me(self, global_variables))
- }
- &ChoiceInstruction::RetryMeElse(offset) => {
- try_or_fail!(
- self,
- call_policy.retry_me_else(self, offset, global_variables)
- )
- }
- &ChoiceInstruction::TrustMe(_) => {
- try_or_fail!(self, call_policy.trust_me(self, global_variables))
- }
- }
+ self.p = CodePtr::BuiltInClause(ct, self.p.local());
}
+ */
- pub(super) fn execute_cut_instr(
- &mut self,
- instr: &CutInstruction,
- cut_policy: &mut Box<dyn CutPolicy>,
- ) {
- match instr {
- &CutInstruction::NeckCut => {
- let b = self.b;
- let b0 = self.b0;
+ pub fn deallocate(&mut self) {
+ let e = self.e;
+ let frame = self.stack.index_and_frame(e);
- if b > b0 {
- self.b = b0;
+ self.cp = frame.prelude.cp;
+ self.e = frame.prelude.e;
- if b > self.e {
- self.stack.truncate(b);
- }
- }
+ if e > self.b {
+ self.stack.truncate(e);
+ }
- self.p += 1;
- }
- &CutInstruction::GetLevel(r) => {
- let b0 = self.b0;
+ self.p += 1;
+ }
- self[r] = Addr::CutPoint(b0);
- self.p += 1;
- }
- &CutInstruction::GetLevelAndUnify(r) => {
- let b0 = self[perm_v!(1)];
- let a = self[r];
+ pub fn throw_interrupt_exception(&mut self) {
+ let err = self.interrupt_error();
+ let src = functor_stub(atom!("repl"), 0);
+ let err = self.error_form(err, src);
- (self.unify_fn)(self, a, b0);
- self.p += 1;
- }
- &CutInstruction::Cut(r) => {
- if !cut_policy.cut(self, r) {
- self.p += 1;
- }
- }
- }
+ self.throw_exception(err);
}
}
diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs
new file mode 100644
index 00000000..0b4923da
--- /dev/null
+++ b/src/machine/mock_wam.rs
@@ -0,0 +1,851 @@
+pub use crate::arena::*;
+pub use crate::atom_table::*;
+use crate::heap_print::*;
+pub use crate::machine::heap::*;
+pub use crate::machine::*;
+pub use crate::machine::machine_state::*;
+pub use crate::machine::stack::*;
+pub use crate::machine::streams::*;
+pub use crate::macros::*;
+pub use crate::parser::ast::*;
+use crate::read::*;
+pub use crate::types::*;
+
+#[cfg(test)]
+use crate::machine::copier::CopierTarget;
+
+#[cfg(test)]
+use std::ops::{Deref, DerefMut, Index, IndexMut};
+
+// a mini-WAM for test purposes.
+
+pub struct MockWAM {
+ pub machine_st: MachineState,
+ pub op_dir: OpDir,
+ pub flags: MachineFlags,
+}
+
+impl MockWAM {
+ pub fn new() -> Self {
+ let op_dir = default_op_dir();
+
+ Self {
+ machine_st: MachineState::new(),
+ op_dir,
+ flags: MachineFlags::default(),
+ }
+ }
+
+ pub fn write_parsed_term_to_heap(
+ &mut self,
+ input_stream: Stream,
+ ) -> Result<TermWriteResult, ParserError> {
+ self.machine_st.read(input_stream, &self.op_dir)
+ }
+
+ pub fn parse_and_write_parsed_term_to_heap(
+ &mut self,
+ term_string: &'static str,
+ ) -> Result<TermWriteResult, ParserError> {
+ let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
+ self.write_parsed_term_to_heap(stream)
+ }
+
+ pub fn parse_and_print_term(
+ &mut self,
+ term_string: &'static str,
+ ) -> Result<String, ParserError> {
+ let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
+
+ print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
+
+ let mut printer = HCPrinter::new(
+ &mut self.machine_st.heap,
+ &mut self.machine_st.arena,
+ &self.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(term_write_result.heap_loc),
+ );
+
+ printer.var_names = term_write_result
+ .var_dict
+ .into_iter()
+ .map(|(var, cell)| (cell, var))
+ .collect();
+
+ Ok(printer.print().result())
+ }
+}
+
+#[cfg(test)]
+pub struct TermCopyingMockWAM<'a> {
+ pub wam: &'a mut MockWAM,
+}
+
+#[cfg(test)]
+impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
+ type Output = HeapCellValue;
+
+ fn index(&self, index: usize) -> &HeapCellValue {
+ &self.wam.machine_st.heap[index]
+ }
+}
+
+#[cfg(test)]
+impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
+ #[inline]
+ fn index_mut(&mut self, index: usize) -> &mut HeapCellValue {
+ &mut self.wam.machine_st.heap[index]
+ }
+}
+
+#[cfg(test)]
+impl<'a> Deref for TermCopyingMockWAM<'a> {
+ type Target = MockWAM;
+
+ fn deref(&self) -> &Self::Target {
+ &self.wam
+ }
+}
+
+#[cfg(test)]
+impl<'a> DerefMut for TermCopyingMockWAM<'a> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.wam
+ }
+}
+
+#[cfg(test)]
+impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
+ fn store(&self, val: HeapCellValue) -> HeapCellValue {
+ read_heap_cell!(val,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ self.wam.machine_st.heap[h]
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.wam.machine_st.stack[s]
+ }
+ _ => {
+ val
+ }
+ )
+ }
+
+ fn deref(&self, mut val: HeapCellValue) -> HeapCellValue {
+ loop {
+ let value = self.store(val);
+
+ if value.is_var() && value != val {
+ val = value;
+ continue;
+ }
+
+ return val;
+ }
+ }
+
+ fn push(&mut self, val: HeapCellValue) {
+ self.wam.machine_st.heap.push(val);
+ }
+
+ fn stack(&mut self) -> &mut Stack {
+ &mut self.wam.machine_st.stack
+ }
+
+ fn threshold(&self) -> usize {
+ self.wam.machine_st.heap.len()
+ }
+}
+
+#[cfg(test)]
+pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
+ for (idx, cell) in heap.iter().enumerate() {
+ assert_eq!(
+ cell.get_mark_bit(),
+ true,
+ "cell {:?} at index {} is not marked",
+ cell,
+ idx
+ );
+ assert!(
+ cell.get_forwarding_bit() != Some(true),
+ "cell {:?} at index {} is forwarded",
+ cell,
+ idx
+ );
+ }
+}
+
+#[cfg(test)]
+pub fn all_cells_unmarked(heap: &Heap) {
+ for (idx, cell) in heap.iter().enumerate() {
+ assert!(
+ !cell.get_mark_bit(),
+ "cell {:?} at index {} is still marked",
+ cell,
+ idx
+ );
+
+ assert!(
+ cell.get_forwarding_bit() != Some(true),
+ "cell {:?} at index {} is still forwarded",
+ cell,
+ idx
+ );
+ }
+}
+
+#[cfg(test)]
+pub(crate) fn write_parsed_term_to_heap(
+ machine_st: &mut MachineState,
+ input_stream: Stream,
+ op_dir: &OpDir,
+) -> Result<TermWriteResult, ParserError> {
+ machine_st.read(input_stream, op_dir)
+}
+
+#[cfg(test)]
+pub(crate) fn parse_and_write_parsed_term_to_heap(
+ machine_st: &mut MachineState,
+ term_string: &'static str,
+ op_dir: &OpDir,
+) -> Result<TermWriteResult, ParserError> {
+ let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
+ write_parsed_term_to_heap(machine_st, stream, op_dir)
+}
+
+impl Machine {
+ pub fn with_test_streams() -> Self {
+ use ref_thread_local::RefThreadLocal;
+
+ let mut machine_st = MachineState::new();
+
+ let user_input = Stream::Null(StreamOptions::default());
+ let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
+ let user_error = Stream::stderr(&mut machine_st.arena);
+
+ let mut wam = Machine {
+ machine_st,
+ indices: IndexStore::new(),
+ code: Code::new(),
+ user_input,
+ user_output,
+ user_error,
+ load_contexts: vec![],
+ };
+
+ let mut lib_path = current_dir();
+
+ lib_path.pop();
+ lib_path.push("lib");
+
+ wam.add_impls_to_indices();
+
+ bootstrapping_compile(
+ Stream::from_static_string(
+ LIBRARIES.borrow()["ops_and_meta_predicates"],
+ &mut wam.machine_st.arena,
+ ),
+ &mut wam,
+ ListingSource::from_file_and_path(
+ atom!("ops_and_meta_predicates.pl"),
+ lib_path.clone(),
+ ),
+ )
+ .unwrap();
+
+ bootstrapping_compile(
+ Stream::from_static_string(
+ LIBRARIES.borrow()["builtins"],
+ &mut wam.machine_st.arena,
+ ),
+ &mut wam,
+ ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
+ )
+ .unwrap();
+
+ if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
+ load_module(
+ &mut wam.indices.code_dir,
+ &mut wam.indices.op_dir,
+ &mut wam.indices.meta_predicates,
+ &CompilationTarget::User,
+ builtins,
+ );
+
+ import_builtin_impls(&wam.indices.code_dir, builtins);
+ } else {
+ unreachable!()
+ }
+
+ lib_path.pop(); // remove the "lib" at the end
+
+ bootstrapping_compile(
+ Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
+ &mut wam,
+ ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
+ )
+ .unwrap();
+
+ wam.configure_modules();
+
+ if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
+ load_module(
+ &mut wam.indices.code_dir,
+ &mut wam.indices.op_dir,
+ &mut wam.indices.meta_predicates,
+ &CompilationTarget::User,
+ loader,
+ );
+ } else {
+ unreachable!()
+ }
+
+ wam.load_special_forms();
+ wam.load_top_level();
+ wam.configure_streams();
+
+ wam
+ }
+
+ pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
+ use std::io::Read;
+
+ let stream = Stream::from_owned_string(
+ std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
+ &mut self.machine_st.arena,
+ );
+
+ self.load_file(file.into(), stream);
+ self.user_output.bytes().map(|b| b.unwrap()).collect()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn unify_tests() {
+ let mut wam = MachineState::new();
+ let mut op_dir = default_op_dir();
+
+ op_dir.insert(
+ (atom!("+"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("*"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("/"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("="), Fixity::In),
+ OpDesc::build_with(700, XFX as u8),
+ );
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(b,a).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ str_loc_as_cell!(0),
+ str_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ str_loc_as_cell!(1),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
+
+ all_cells_unmarked(&wam.heap);
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(pstr_as_cell!(atom!("this is a string")));
+ wam.heap.push(heap_loc_as_cell!(1));
+
+ wam.heap.push(pstr_as_cell!(atom!("this is a string")));
+ wam.heap.push(pstr_loc_as_cell!(4));
+
+ wam.heap.push(pstr_offset_as_cell!(0));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
+
+ unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
+
+ assert!(!wam.fail);
+
+ assert_eq!(wam.heap[1], pstr_loc_as_cell!(4));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ wam.heap.push(list_loc_as_cell!(6));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(5));
+
+ unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
+ assert!(!wam.fail);
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ wam.heap.push(list_loc_as_cell!(6));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(atom_as_cell!(atom!("c")));
+ wam.heap.push(heap_loc_as_cell!(5));
+
+ unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
+ assert!(wam.fail);
+
+ wam.fail = false;
+ all_cells_unmarked(&wam.heap);
+ wam.heap.clear();
+
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(5));
+
+ wam.heap.push(list_loc_as_cell!(6));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
+ assert!(!wam.fail);
+ all_cells_unmarked(&wam.heap);
+ wam.heap.clear();
+
+ {
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
+
+ print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc);
+
+ unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
+
+ assert_eq!(wam.heap[2], str_loc_as_cell!(4));
+ }
+ }
+
+ #[test]
+ fn test_unify_with_occurs_check() {
+ let mut wam = MachineState::new();
+ let mut op_dir = default_op_dir();
+
+ op_dir.insert(
+ (atom!("+"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("*"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("/"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
+
+ all_cells_unmarked(&wam.heap);
+
+ unify_with_occurs_check!(
+ wam,
+ str_loc_as_cell!(0),
+ str_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(wam.fail);
+ }
+ }
+
+ #[test]
+ fn test_term_compare() {
+ use ordered_float::OrderedFloat;
+ use std::cmp::Ordering;
+
+ let mut wam = MachineState::new();
+
+ wam.heap.push(heap_loc_as_cell!(0));
+ wam.heap.push(heap_loc_as_cell!(1));
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[0], wam.heap[1]),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[1], wam.heap[0]),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[0], wam.heap[0]),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[1], wam.heap[1]),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ atom_as_cstr_cell!(atom!("string"))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ atom_as_cell!(atom!("atom"))
+ ),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ atom_as_cell!(atom!("aaa"))
+ ),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ fixnum_as_cell!(Fixnum::build_with(6)),
+ heap_loc_as_cell!(1)
+ ),
+ Some(Ordering::Greater)
+ );
+
+ wam.heap.clear();
+
+ wam.heap.push(atom_as_cell!(atom!("f"), 1));
+ wam.heap.push(heap_loc_as_cell!(1));
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(0)
+ ),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(0),
+ atom_as_cell!(atom!("a"))
+ ),
+ Some(Ordering::Greater)
+ );
+
+ wam.heap.clear();
+
+ // [1,2,3]
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+ wam.heap.push(list_loc_as_cell!(5));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
+ wam.heap.push(empty_list_as_cell!());
+
+ // [1,2]
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
+ wam.heap.push(list_loc_as_cell!(10));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+ wam.heap.push(empty_list_as_cell!());
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(7),
+ heap_loc_as_cell!(7)
+ ),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(7)
+ ),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ heap_loc_as_cell!(7)
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ fixnum_as_cell!(Fixnum::build_with(1))
+ ),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ atom_as_cstr_cell!(atom!("string"))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ atom_as_cell!(atom!("atom"))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ empty_list_as_cell!()
+ ),
+ Some(Ordering::Greater)
+ );
+
+ let one_p_one = typed_arena_ptr_as_cell!(
+ arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ one_p_one,
+ fixnum_as_cell!(Fixnum::build_with(1))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ fixnum_as_cell!(Fixnum::build_with(1)),
+ one_p_one
+ ),
+ Some(Ordering::Greater)
+ );
+ }
+
+ #[test]
+ fn is_cyclic_term_tests() {
+ let mut wam = MachineState::new();
+
+ assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f"))));
+ assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555))));
+
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+ wam.heap.clear();
+
+ wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
+
+ assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+
+ assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
+
+ all_cells_unmarked(&wam.heap);
+
+ assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap[2] = str_loc_as_cell!(0);
+
+ print_heap_terms(wam.heap.iter(), 0);
+
+ assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap[2] = atom_as_cell!(atom!("b"));
+ wam.heap[1] = str_loc_as_cell!(0);
+
+ assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+
+ assert!(wam.is_cyclic_term(heap_loc_as_cell!(1)));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(pstr_as_cell!(atom!("a string")));
+ wam.heap.push(empty_list_as_cell!());
+
+ assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0)));
+ }
+}
diff --git a/src/machine/mod.rs b/src/machine/mod.rs
index 1f7ef41a..19e6d5a1 100644
--- a/src/machine/mod.rs
+++ b/src/machine/mod.rs
@@ -1,89 +1,72 @@
-use prolog_parser::ast::*;
-use prolog_parser::tabled_rc::*;
-use prolog_parser::{clause_name, temp_v};
-
-use lazy_static::lazy_static;
-
-use crate::clause_types::*;
+pub mod arithmetic_ops;
+pub mod attributed_variables;
+pub mod code_walker;
+#[macro_use]
+pub mod loader;
+pub mod compile;
+pub mod copier;
+pub mod dispatch;
+pub mod gc;
+pub mod heap;
+pub mod load_state;
+pub mod machine_errors;
+pub mod machine_indices;
+pub mod machine_state;
+pub mod machine_state_impl;
+pub mod mock_wam;
+pub mod partial_string;
+pub mod preprocessor;
+pub mod stack;
+pub mod streams;
+pub mod system_calls;
+pub mod term_stream;
+
+use crate::arithmetic::*;
+use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
-use crate::machine::loader::*;
-use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream};
-use crate::read::*;
-
-mod attributed_variables;
-pub(super) mod code_repo;
-pub(crate) mod code_walker;
-#[macro_use]
-pub(crate) mod loader;
-mod compile;
-mod copier;
-pub(crate) mod heap;
-mod load_state;
-pub(crate) mod machine_errors;
-pub(crate) mod machine_indices;
-pub(super) mod machine_state;
-pub(crate) mod partial_string;
-mod preprocessor;
-mod raw_block;
-mod stack;
-pub(crate) mod streams;
-mod term_stream;
-
-#[macro_use]
-mod arithmetic_ops;
-#[macro_use]
-mod machine_state_impl;
-mod system_calls;
-
-use crate::machine::code_repo::*;
use crate::machine::compile::*;
+use crate::machine::copier::*;
+use crate::machine::heap::*;
+use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
-pub use crate::machine::streams::Stream;
+use crate::machine::stack::*;
+use crate::machine::streams::*;
+use crate::parser::ast::*;
+use crate::parser::rug::{Integer, Rational};
+use crate::types::*;
use indexmap::IndexMap;
+use lazy_static::lazy_static;
+use ordered_float::OrderedFloat;
-//use std::convert::TryFrom;
-use prolog_parser::ast::ClauseName;
-use std::fs::File;
-use std::mem;
+use std::cmp::Ordering;
+use std::env;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
-#[derive(Debug)]
-pub(crate) struct MachinePolicies {
- call_policy: Box<dyn CallPolicy>,
- cut_policy: Box<dyn CutPolicy>,
-}
-
lazy_static! {
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
}
-impl MachinePolicies {
- #[inline]
- fn new() -> Self {
- MachinePolicies {
- call_policy: Box::new(DefaultCallPolicy {}),
- cut_policy: Box::new(DefaultCutPolicy {}),
- }
- }
-}
-
-impl Default for MachinePolicies {
- #[inline]
- fn default() -> Self {
- MachinePolicies::new()
- }
+#[derive(Debug)]
+pub struct Machine {
+ pub(super) machine_st: MachineState,
+ pub(super) indices: IndexStore,
+ pub(super) code: Code,
+ pub(super) user_input: Stream,
+ pub(super) user_output: Stream,
+ pub(super) user_error: Stream,
+ pub(super) load_contexts: Vec<LoadContext>,
}
#[derive(Debug)]
-pub(super) struct LoadContext {
+pub struct LoadContext {
pub(super) path: PathBuf,
pub(super) stream: Stream,
- pub(super) module: ClauseName,
+ pub(super) module: Atom,
}
impl LoadContext {
@@ -100,67 +83,138 @@ impl LoadContext {
LoadContext {
path: path_buf,
stream,
- module: clause_name!("user"),
+ module: atom!("user"),
}
}
}
-#[derive(Debug)]
-pub struct Machine {
- pub(super) machine_st: MachineState,
- pub(super) policies: MachinePolicies,
- pub(super) indices: IndexStore,
- pub(super) code_repo: CodeRepo,
- pub(super) user_input: Stream,
- pub(super) user_output: Stream,
- pub(super) user_error: Stream,
- pub(super) load_contexts: Vec<LoadContext>,
-}
-
#[inline]
fn current_dir() -> PathBuf {
- std::env::current_dir().unwrap_or(PathBuf::from("./"))
+ env::current_dir().unwrap_or(PathBuf::from("./"))
}
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
+pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0;
+pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1;
+pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 2;
+
+pub struct MachinePreludeView<'a> {
+ pub indices: &'a mut IndexStore,
+ pub code: &'a mut Code,
+ pub load_contexts: &'a mut Vec<LoadContext>,
+}
+
+pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
+ let keys = [
+ (atom!("@>"), 2),
+ (atom!("@<"), 2),
+ (atom!("@>="), 2),
+ (atom!("@=<"), 2),
+ (atom!("=="), 2),
+ (atom!("\\=="), 2),
+ (atom!(">"), 2),
+ (atom!("<"), 2),
+ (atom!(">="), 2),
+ (atom!("=<"), 2),
+ (atom!("=:="), 2),
+ (atom!("=\\="), 2),
+ (atom!("is"), 2),
+ (atom!("acyclic_term"), 1),
+ (atom!("arg"), 3),
+ (atom!("compare"), 3),
+ (atom!("copy_term"), 2),
+ (atom!("functor"), 3),
+ (atom!("ground"), 1),
+ (atom!("keysort"), 2),
+ (atom!("read"), 1),
+ (atom!("sort"), 2),
+ (atom!("$call"), 1),
+ (atom!("$call"), 2),
+ (atom!("$call"), 3),
+ (atom!("$call"), 4),
+ (atom!("$call"), 5),
+ (atom!("$call"), 6),
+ (atom!("$call"), 7),
+ (atom!("$call"), 8),
+ (atom!("$call"), 9),
+ (atom!("atom"), 1),
+ (atom!("atomic"), 1),
+ (atom!("compound"), 1),
+ (atom!("integer"), 1),
+ (atom!("number"), 1),
+ (atom!("rational"), 1),
+ (atom!("float"), 1),
+ (atom!("nonvar"), 1),
+ (atom!("var"), 1),
+ ];
+
+ for key in keys {
+ let idx = code_dir.get(&key).unwrap();
+ builtins.code_dir.insert(key, idx.clone());
+ builtins.module_decl.exports.push(ModuleExport::PredicateKey(key));
+ }
+}
+
impl Machine {
- fn run_module_predicate(&mut self, module_name: ClauseName, key: PredicateKey) {
+ #[inline]
+ pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
+ (
+ MachinePreludeView {
+ indices: &mut self.indices,
+ code: &mut self.code,
+ load_contexts: &mut self.load_contexts,
+ },
+ &mut self.machine_st
+ )
+ }
+
+ pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
+ let err = self.machine_st.session_error(err);
+ let stub = functor_stub(key.0, key.1);
+ let err = self.machine_st.error_form(err, stub);
+
+ self.machine_st.throw_exception(err);
+ }
+
+ fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) {
if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(ref code_index) = module.code_dir.get(&key) {
let p = code_index.local().unwrap();
- self.machine_st.cp = LocalCodePtr::Halt;
- self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+ self.machine_st.cp = BREAK_FROM_DISPATCH_LOOP_LOC;
+ self.machine_st.p = p;
- return self.run_query();
+ return self.dispatch_loop();
}
}
unreachable!();
}
- pub fn load_file(&mut self, path: String, stream: Stream) {
- self.machine_st[temp_v!(1)] =
- Addr::Stream(self.machine_st.heap.push(HeapCellValue::Stream(stream)));
-
- self.machine_st[temp_v!(2)] = Addr::Con(self.machine_st.heap.push(HeapCellValue::Atom(
- clause_name!(path, self.machine_st.atom_tbl),
- None,
- )));
+ pub fn load_file(&mut self, path: &str, stream: Stream) {
+ self.machine_st.registers[1] = stream_as_cell!(stream);
+ self.machine_st.registers[2] = atom_as_cell!(
+ self.machine_st.atom_tbl.build_with(path)
+ );
- self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2));
+ self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2));
}
fn load_top_level(&mut self) {
let mut path_buf = current_dir();
- path_buf.push("toplevel.pl");
- let path = path_buf.to_str().unwrap().to_string();
+ path_buf.push("src/toplevel.pl");
+
+ let path = path_buf.to_str().unwrap();
+ let toplevel_stream = Stream::from_static_string(
+ include_str!("../toplevel.pl"),
+ &mut self.machine_st.arena,
+ );
- self.load_file(path, Stream::from(include_str!("../toplevel.pl")));
+ self.load_file(path, toplevel_stream);
- if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) {
+ if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) {
load_module(
&mut self.indices.code_dir,
&mut self.indices.op_dir,
@@ -178,9 +232,15 @@ impl Machine {
path_buf.push("machine/attributed_variables.pl");
bootstrapping_compile(
- Stream::from(include_str!("attributed_variables.pl")),
+ Stream::from_static_string(
+ include_str!("attributed_variables.pl"),
+ &mut self.machine_st.arena,
+ ),
self,
- ListingSource::from_file_and_path(clause_name!("attributed_variables"), path_buf),
+ ListingSource::from_file_and_path(
+ atom!("attributed_variables"),
+ path_buf,
+ ),
)
.unwrap();
@@ -188,44 +248,49 @@ impl Machine {
path_buf.push("machine/project_attributes.pl");
bootstrapping_compile(
- Stream::from(include_str!("project_attributes.pl")),
+ Stream::from_static_string(
+ include_str!("project_attributes.pl"),
+ &mut self.machine_st.arena,
+ ),
self,
- ListingSource::from_file_and_path(clause_name!("project_attributes"), path_buf),
+ ListingSource::from_file_and_path(atom!("project_attributes"), path_buf),
)
.unwrap();
- if let Some(module) = self.indices.modules.get(&clause_name!("$atts")) {
- if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) {
+ if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
+ if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap();
}
}
}
pub fn run_top_level(&mut self) {
- use std::env;
-
let mut arg_pstrs = vec![];
for arg in env::args() {
- arg_pstrs.push(self.machine_st.heap.put_complete_string(&arg));
+ arg_pstrs.push(put_complete_string(
+ &mut self.machine_st.heap,
+ &arg,
+ &mut self.machine_st.atom_tbl,
+ ));
}
- let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter()));
-
- self.machine_st[temp_v!(1)] = list_addr;
+ self.machine_st.registers[1] = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, arg_pstrs.into_iter())
+ );
- self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1));
+ self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1));
}
pub(crate) fn configure_modules(&mut self) {
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) {
for arity in 1..66 {
- let key = (clause_name!("call"), arity);
+ let key = (atom!("call"), arity);
match loader.code_dir.get(&key) {
Some(src_code_index) => {
let target_code_index = target_code_dir
- .entry(key.clone())
+ .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined));
target_code_index.set(src_code_index.get());
@@ -237,15 +302,15 @@ impl Machine {
}
}
- if let Some(loader) = self.indices.modules.swap_remove(&clause_name!("loader")) {
- if let Some(builtins) = self.indices.modules.get_mut(&clause_name!("builtins")) {
+ if let Some(loader) = self.indices.modules.swap_remove(&atom!("loader")) {
+ if let Some(builtins) = self.indices.modules.get_mut(&atom!("builtins")) {
// Import loader's exports into the builtins module so they will be
// implicitly included in every further module.
load_module(
&mut builtins.code_dir,
&mut builtins.op_dir,
&mut builtins.meta_predicates,
- &CompilationTarget::Module(clause_name!("builtins")),
+ &CompilationTarget::Module(atom!("builtins")),
&loader,
);
@@ -257,7 +322,7 @@ impl Machine {
builtins
.module_decl
.exports
- .push(ModuleExport::PredicateKey((clause_name!("call"), arity)));
+ .push(ModuleExport::PredicateKey((atom!("call"), arity)));
}
}
@@ -267,20 +332,80 @@ impl Machine {
update_call_n_indices(&loader, &mut self.indices.code_dir);
- self.indices.modules.insert(clause_name!("loader"), loader);
+ self.indices.modules.insert(atom!("loader"), loader);
} else {
unreachable!()
}
}
- pub fn new(user_input: Stream, user_output: Stream, user_error: Stream) -> Self {
+ pub(crate) fn add_impls_to_indices(&mut self) {
+ let impls_offset = self.code.len() + 3;
+
+ self.code.extend(vec![
+ Instruction::BreakFromDispatchLoop,
+ Instruction::InstallVerifyAttr,
+ Instruction::VerifyAttrInterrupt,
+ Instruction::ExecuteTermGreaterThan(0),
+ Instruction::ExecuteTermLessThan(0),
+ Instruction::ExecuteTermGreaterThanOrEqual(0),
+ Instruction::ExecuteTermLessThanOrEqual(0),
+ Instruction::ExecuteTermEqual(0),
+ Instruction::ExecuteTermNotEqual(0),
+ Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+ Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+ Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+ Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+ Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+ Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+ Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2)), 0),
+ Instruction::ExecuteAcyclicTerm(0),
+ Instruction::ExecuteArg(0),
+ Instruction::ExecuteCompare(0),
+ Instruction::ExecuteCopyTerm(0),
+ Instruction::ExecuteFunctor(0),
+ Instruction::ExecuteGround(0),
+ Instruction::ExecuteKeySort(0),
+ Instruction::ExecuteRead(0),
+ Instruction::ExecuteSort(0),
+ Instruction::ExecuteN(1, 0),
+ Instruction::ExecuteN(2, 0),
+ Instruction::ExecuteN(3, 0),
+ Instruction::ExecuteN(4, 0),
+ Instruction::ExecuteN(5, 0),
+ Instruction::ExecuteN(6, 0),
+ Instruction::ExecuteN(7, 0),
+ Instruction::ExecuteN(8, 0),
+ Instruction::ExecuteN(9, 0),
+ Instruction::ExecuteIsAtom(temp_v!(1), 0),
+ Instruction::ExecuteIsAtomic(temp_v!(1), 0),
+ Instruction::ExecuteIsCompound(temp_v!(1), 0),
+ Instruction::ExecuteIsInteger(temp_v!(1), 0),
+ Instruction::ExecuteIsNumber(temp_v!(1), 0),
+ Instruction::ExecuteIsRational(temp_v!(1), 0),
+ Instruction::ExecuteIsFloat(temp_v!(1), 0),
+ Instruction::ExecuteIsNonVar(temp_v!(1), 0),
+ Instruction::ExecuteIsVar(temp_v!(1), 0)
+ ].into_iter());
+
+ for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
+ let key = instr.to_name_and_arity();
+ self.indices.code_dir.insert(key, CodeIndex::new(IndexPtr::Index(p + impls_offset)));
+ }
+ }
+
+ pub fn new() -> Self {
use ref_thread_local::RefThreadLocal;
+ let mut machine_st = MachineState::new();
+
+ let user_input = Stream::stdin(&mut machine_st.arena);
+ let user_output = Stream::stdout(&mut machine_st.arena);
+ let user_error = Stream::stderr(&mut machine_st.arena);
+
let mut wam = Machine {
- machine_st: MachineState::new(),
- policies: MachinePolicies::new(),
+ machine_st,
indices: IndexStore::new(),
- code_repo: CodeRepo::new(),
+ code: vec![],
user_input,
user_output,
user_error,
@@ -292,24 +417,32 @@ impl Machine {
lib_path.pop();
lib_path.push("lib");
+ wam.add_impls_to_indices();
+
bootstrapping_compile(
- Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]),
+ Stream::from_static_string(
+ LIBRARIES.borrow()["ops_and_meta_predicates"],
+ &mut wam.machine_st.arena,
+ ),
&mut wam,
ListingSource::from_file_and_path(
- clause_name!("ops_and_meta_predicates.pl"),
+ atom!("ops_and_meta_predicates.pl"),
lib_path.clone(),
),
)
.unwrap();
bootstrapping_compile(
- Stream::from(LIBRARIES.borrow()["builtins"]),
+ Stream::from_static_string(
+ LIBRARIES.borrow()["builtins"],
+ &mut wam.machine_st.arena,
+ ),
&mut wam,
- ListingSource::from_file_and_path(clause_name!("builtins.pl"), lib_path.clone()),
+ ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
)
.unwrap();
- if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) {
+ if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
load_module(
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
@@ -317,6 +450,8 @@ impl Machine {
&CompilationTarget::User,
builtins,
);
+
+ import_builtin_impls(&wam.indices.code_dir, builtins);
} else {
unreachable!()
}
@@ -324,15 +459,15 @@ impl Machine {
lib_path.pop(); // remove the "lib" at the end
bootstrapping_compile(
- Stream::from(include_str!("../loader.pl")),
+ Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
&mut wam,
- ListingSource::from_file_and_path(clause_name!("loader.pl"), lib_path.clone()),
+ ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
)
.unwrap();
wam.configure_modules();
- if let Some(loader) = wam.indices.modules.get(&clause_name!("loader")) {
+ if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module(
&mut wam.indices.code_dir,
&mut wam.indices.op_dir,
@@ -352,369 +487,372 @@ impl Machine {
}
pub(crate) fn configure_streams(&mut self) {
- self.user_input.options_mut().alias = Some(clause_name!("user_input"));
+ self.user_input.options_mut().set_alias_to_atom_opt(Some(atom!("user_input")));
self.indices
.stream_aliases
- .insert(clause_name!("user_input"), self.user_input.clone());
+ .insert(atom!("user_input"), self.user_input);
- self.indices.streams.insert(self.user_input.clone());
+ self.indices.streams.insert(self.user_input);
- self.user_output.options_mut().alias = Some(clause_name!("user_output"));
+ self.user_output.options_mut().set_alias_to_atom_opt(Some(atom!("user_output")));
self.indices
.stream_aliases
- .insert(clause_name!("user_output"), self.user_output.clone());
+ .insert(atom!("user_output"), self.user_output);
- self.user_error.options_mut().alias = Some(clause_name!("user_error"));
+ self.indices.streams.insert(self.user_output);
self.indices
.stream_aliases
- .insert(clause_name!("user_error"), self.user_error.clone());
+ .insert(atom!("user_error"), self.user_error);
- self.indices.streams.insert(self.user_output.clone());
+ self.indices.streams.insert(self.user_error);
}
- fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
- let h = self.machine_st.heap.h();
+ #[inline(always)]
+ pub(crate) fn run_verify_attr_interrupt(&mut self, arity: usize) {
+ let p = self.machine_st.attr_var_init.verify_attrs_loc;
+ self.machine_st.verify_attr_interrupt(p, arity);
+ }
- let err = MachineError::session_error(h, err);
- let stub = MachineError::functor_stub(key.0, key.1);
- let err = self.machine_st.error_form(err, stub);
+ #[inline(always)]
+ fn retry_me_else(&mut self, offset: usize) {
+ let b = self.machine_st.b;
+ let or_frame = self.machine_st.stack.index_or_frame_mut(b);
+ let n = or_frame.prelude.univ_prelude.num_cells;
- self.machine_st.throw_exception(err);
- return;
+ for i in 0..n {
+ self.machine_st.registers[i + 1] = or_frame[i];
+ }
+
+ self.machine_st.num_of_args = n;
+ self.machine_st.e = or_frame.prelude.e;
+ self.machine_st.cp = or_frame.prelude.cp;
+
+ or_frame.prelude.bp = self.machine_st.p + offset;
+
+ let old_tr = or_frame.prelude.tr;
+ let curr_tr = self.machine_st.tr;
+ let target_h = or_frame.prelude.h;
+
+ self.machine_st.tr = or_frame.prelude.tr;
+
+ self.reset_attr_var_state();
+ self.machine_st.hb = target_h;
+
+ self.unwind_trail(old_tr, curr_tr);
+
+ self.machine_st.trail.truncate(self.machine_st.tr);
+ self.machine_st.heap.truncate(target_h);
+
+ self.machine_st.p += 1;
}
- fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
- match code_ptr {
- REPLCodePtr::AddDiscontiguousPredicate => {
- self.add_discontiguous_predicate();
- }
- REPLCodePtr::AddDynamicPredicate => {
- self.add_dynamic_predicate();
- }
- REPLCodePtr::AddMultifilePredicate => {
- self.add_multifile_predicate();
- }
- REPLCodePtr::AddGoalExpansionClause => {
- self.add_goal_expansion_clause();
- }
- REPLCodePtr::AddTermExpansionClause => {
- self.add_term_expansion_clause();
- }
- REPLCodePtr::AddInSituFilenameModule => {
- self.add_in_situ_filename_module();
- }
- REPLCodePtr::ClauseToEvacuable => {
- self.clause_to_evacuable();
- }
- REPLCodePtr::ScopedClauseToEvacuable => {
- self.scoped_clause_to_evacuable();
- }
- REPLCodePtr::ConcludeLoad => {
- self.conclude_load();
- }
- REPLCodePtr::PopLoadContext => {
- self.pop_load_context();
- }
- REPLCodePtr::PushLoadContext => {
- self.push_load_context();
- }
- REPLCodePtr::PopLoadStatePayload => {
- self.pop_load_state_payload();
- }
- REPLCodePtr::UseModule => {
- self.use_module();
- }
- REPLCodePtr::LoadCompiledLibrary => {
- self.load_compiled_library();
- }
- REPLCodePtr::DeclareModule => {
- self.declare_module();
- }
- REPLCodePtr::PushLoadStatePayload => {
- self.push_load_state_payload();
- }
- REPLCodePtr::LoadContextSource => {
- self.load_context_source();
- }
- REPLCodePtr::LoadContextFile => {
- self.load_context_file();
- }
- REPLCodePtr::LoadContextDirectory => {
- self.load_context_directory();
- }
- REPLCodePtr::LoadContextModule => {
- self.load_context_module();
- }
- REPLCodePtr::LoadContextStream => {
- self.load_context_stream();
- }
- REPLCodePtr::MetaPredicateProperty => {
- self.meta_predicate_property();
- }
- REPLCodePtr::BuiltInProperty => {
- self.builtin_property();
- }
- REPLCodePtr::MultifileProperty => {
- self.multifile_property();
- }
- REPLCodePtr::DiscontiguousProperty => {
- self.discontiguous_property();
- }
- REPLCodePtr::DynamicProperty => {
- self.dynamic_property();
- }
- REPLCodePtr::Assertz => {
- self.compile_assert(AppendOrPrepend::Append);
+ #[inline(always)]
+ fn retry(&mut self, offset: usize) {
+ let b = self.machine_st.b;
+ let or_frame = self.machine_st.stack.index_or_frame_mut(b);
+ let n = or_frame.prelude.univ_prelude.num_cells;
+
+ for i in 0..n {
+ self.machine_st.registers[i+1] = or_frame[i];
+ }
+
+ self.machine_st.num_of_args = n;
+ self.machine_st.e = or_frame.prelude.e;
+ self.machine_st.cp = or_frame.prelude.cp;
+
+ or_frame.prelude.biip += 1;
+
+ let old_tr = or_frame.prelude.tr;
+ let curr_tr = self.machine_st.tr;
+ let target_h = or_frame.prelude.h;
+
+ self.machine_st.tr = or_frame.prelude.tr;
+ self.reset_attr_var_state();
+
+ self.machine_st.hb = target_h;
+ self.machine_st.p = self.machine_st.p + offset;
+
+ self.unwind_trail(old_tr, curr_tr);
+
+ self.machine_st.trail.truncate(self.machine_st.tr);
+ self.machine_st.heap.truncate(target_h);
+
+ self.machine_st.oip = 0;
+ self.machine_st.iip = 0;
+ }
+
+ #[inline(always)]
+ fn trust(&mut self, offset: usize) {
+ let b = self.machine_st.b;
+ let or_frame = self.machine_st.stack.index_or_frame(b);
+ let n = or_frame.prelude.univ_prelude.num_cells;
+
+ for i in 0..n {
+ self.machine_st.registers[i+1] = or_frame[i];
+ }
+
+ self.machine_st.num_of_args = n;
+ self.machine_st.e = or_frame.prelude.e;
+ self.machine_st.cp = or_frame.prelude.cp;
+
+ let old_tr = or_frame.prelude.tr;
+ let curr_tr = self.machine_st.tr;
+ let target_h = or_frame.prelude.h;
+
+ self.machine_st.tr = or_frame.prelude.tr;
+ self.machine_st.b = or_frame.prelude.b;
+
+ self.reset_attr_var_state();
+
+ self.machine_st.hb = target_h;
+ self.machine_st.p = self.machine_st.p + offset;
+
+ self.unwind_trail(old_tr, curr_tr);
+
+ self.machine_st.trail.truncate(self.machine_st.tr);
+ self.machine_st.stack.truncate(b);
+ self.machine_st.heap.truncate(target_h);
+
+ self.machine_st.oip = 0;
+ self.machine_st.iip = 0;
+ }
+
+ #[inline(always)]
+ fn trust_me(&mut self) {
+ let b = self.machine_st.b;
+ let or_frame = self.machine_st.stack.index_or_frame(b);
+ let n = or_frame.prelude.univ_prelude.num_cells;
+
+ for i in 0..n {
+ self.machine_st.registers[i+1] = or_frame[i];
+ }
+
+ self.machine_st.num_of_args = n;
+ self.machine_st.e = or_frame.prelude.e;
+ self.machine_st.cp = or_frame.prelude.cp;
+
+ let old_tr = or_frame.prelude.tr;
+ let curr_tr = self.machine_st.tr;
+ let target_h = or_frame.prelude.h;
+
+ self.machine_st.tr = or_frame.prelude.tr;
+ self.machine_st.b = or_frame.prelude.b;
+
+ self.reset_attr_var_state();
+
+ self.machine_st.hb = target_h;
+ self.machine_st.p += 1;
+
+ self.unwind_trail(old_tr, curr_tr);
+
+ self.machine_st.trail.truncate(self.machine_st.tr);
+ self.machine_st.stack.truncate(b);
+ self.machine_st.heap.truncate(target_h);
+ }
+
+ #[inline(always)]
+ fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
+ match idx {
+ IndexPtr::DynamicUndefined => {
+ self.machine_st.fail = true;
}
- REPLCodePtr::Asserta => {
- self.compile_assert(AppendOrPrepend::Prepend);
+ IndexPtr::Undefined => {
+ return Err(self.machine_st.throw_undefined_error(name, arity));
}
- REPLCodePtr::Retract => {
- self.retract_clause();
+ IndexPtr::DynamicIndex(compiled_tl_index) => {
+ self.machine_st.dynamic_mode = FirstOrNext::First;
+ self.machine_st.call_at_index(arity, compiled_tl_index);
}
- REPLCodePtr::AbolishClause => {
- self.abolish_clause();
+ IndexPtr::Index(compiled_tl_index) => {
+ self.machine_st.call_at_index(arity, compiled_tl_index);
}
- REPLCodePtr::IsConsistentWithTermQueue => {
- self.is_consistent_with_term_queue();
+ }
+
+ Ok(())
+ }
+
+ #[inline(always)]
+ fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
+ match idx {
+ IndexPtr::DynamicUndefined => {
+ self.machine_st.fail = true;
}
- REPLCodePtr::FlushTermQueue => {
- self.flush_term_queue();
+ IndexPtr::Undefined => {
+ return Err(self.machine_st.throw_undefined_error(name, arity));
}
- REPLCodePtr::RemoveModuleExports => {
- self.remove_module_exports();
+ IndexPtr::DynamicIndex(compiled_tl_index) => {
+ self.machine_st.dynamic_mode = FirstOrNext::First;
+ self.machine_st.execute_at_index(arity, compiled_tl_index);
}
- REPLCodePtr::AddNonCountedBacktracking => {
- self.add_non_counted_backtracking();
+ IndexPtr::Index(compiled_tl_index) => {
+ self.machine_st.execute_at_index(arity, compiled_tl_index)
}
}
- self.machine_st.p = CodePtr::Local(p);
+ Ok(())
}
- pub(crate) fn run_query(&mut self) {
- while !self.machine_st.p.is_halt() {
- self.machine_st.query_stepper(
- &mut self.indices,
- &mut self.policies,
- &mut self.code_repo,
- &mut self.user_input,
- &mut self.user_output,
- );
-
- match self.machine_st.p {
- CodePtr::REPL(code_ptr, p) => {
- self.handle_toplevel_command(code_ptr, p);
+ #[inline(always)]
+ fn call_clause(&mut self, module_name: Atom, key: PredicateKey) -> CallResult {
+ let (name, arity) = key;
- if self.machine_st.fail {
- self.machine_st.backtrack();
- }
- }
- _ => {
- break;
+ if module_name == atom!("user") {
+ if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
+ self.try_call(name, arity, idx.get())
+ } else {
+ Err(self.machine_st.throw_undefined_error(name, arity))
+ }
+ } else {
+ if let Some(module) = self.indices.modules.get(&module_name) {
+ if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
+ self.try_call(name, arity, idx.get())
+ } else {
+ Err(self.machine_st.throw_undefined_error(name, arity))
}
- };
+ } else {
+ let stub = functor_stub(name, arity);
+ let err = self.machine_st.module_resolution_error(module_name, name, arity);
+
+ Err(self.machine_st.error_form(err, stub))
+ }
}
}
-}
-impl MachineState {
- fn dispatch_instr(
- &mut self,
- instr: &Line,
- indices: &mut IndexStore,
- policies: &mut MachinePolicies,
- code_repo: &CodeRepo,
- user_input: &mut Stream,
- user_output: &mut Stream,
- ) {
- match instr {
- &Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
- &Line::Choice(ref choice_instr) => self.execute_choice_instr(
- choice_instr,
- code_repo,
- &mut policies.call_policy,
- &mut indices.global_variables,
- ),
- &Line::Cut(ref cut_instr) => {
- self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
- }
- &Line::Control(ref control_instr) => self.execute_ctrl_instr(
- indices,
- code_repo,
- &mut policies.call_policy,
- &mut policies.cut_policy,
- user_input,
- user_output,
- control_instr,
- ),
- &Line::Fact(ref fact_instr) => {
- self.execute_fact_instr(&fact_instr);
- self.p += 1;
- }
- &Line::IndexingCode(ref indexing_lines) => {
- self.execute_indexing_instr(indexing_lines, code_repo)
+ #[inline(always)]
+ fn execute_clause(&mut self, module_name: Atom, key: PredicateKey) -> CallResult {
+ let (name, arity) = key;
+
+ if module_name == atom!("user") {
+ if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
+ self.try_execute(name, arity, idx.get())
+ } else {
+ Err(self.machine_st.throw_undefined_error(name, arity))
}
- &Line::IndexedChoice(ref choice_instr) => self.execute_indexed_choice_instr(
- choice_instr,
- &mut policies.call_policy,
- &mut indices.global_variables,
- ),
- &Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr(
- code_repo,
- &mut policies.call_policy,
- &mut indices.global_variables,
- ),
- &Line::Query(ref query_instr) => {
- self.execute_query_instr(&query_instr);
- self.p += 1;
+ } else {
+ if let Some(module) = self.indices.modules.get(&module_name) {
+ if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
+ self.try_execute(name, arity, idx.get())
+ } else {
+ Err(self.machine_st.throw_undefined_error(name, arity))
+ }
+ } else {
+ let stub = functor_stub(name, arity);
+ let err = self.machine_st.module_resolution_error(module_name, name, arity);
+
+ Err(self.machine_st.error_form(err, stub))
}
}
}
- fn execute_instr(
- &mut self,
- indices: &mut IndexStore,
- policies: &mut MachinePolicies,
- code_repo: &CodeRepo,
- user_input: &mut Stream,
- user_output: &mut Stream,
- ) {
- let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
- Some(instr) => instr,
- None => return,
- };
+ #[inline(always)]
+ fn call_n(&mut self, module_name: Atom, arity: usize) -> CallResult {
+ let key = self.machine_st.setup_call_n(arity)?;
+ self.call_clause(module_name, key)
+ }
- self.dispatch_instr(
- instr.as_ref(),
- indices,
- policies,
- code_repo,
- user_input,
- user_output,
- );
+ #[inline(always)]
+ fn execute_n(&mut self, module_name: Atom, arity: usize) -> CallResult {
+ let key = self.machine_st.setup_call_n(arity)?;
+ self.execute_clause(module_name, key)
}
- fn backtrack(&mut self) {
- let b = self.b;
+ #[inline(always)]
+ fn run_cleaners(&mut self) -> bool {
+ use std::sync::Once;
- self.b0 = self.stack.index_or_frame(b).prelude.b0;
- self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp);
+ static CLEANER_INIT: Once = Once::new();
- self.fail = false;
- }
+ static mut RCWH: usize = 0;
+ static mut RCWOH: usize = 0;
- fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool {
- match self.p {
- CodePtr::Local(LocalCodePtr::DirEntry(p))
- | CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..))
- if p < code_repo.code.len() => {}
- CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => {
- return false;
- }
- _ => {}
- }
+ let (r_c_w_h, r_c_wo_h) = unsafe {
+ CLEANER_INIT.call_once(|| {
+ let r_c_w_h_atom = atom!("run_cleaners_with_handling");
+ let r_c_wo_h_atom = atom!("run_cleaners_without_handling");
+ let iso_ext = atom!("iso_ext");
- true
- }
+ RCWH = self.indices.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
+ .and_then(|item| item.local())
+ .unwrap();
+ RCWOH = self.indices.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
+ .and_then(|item| item.local())
+ .unwrap();
+ });
- // return true iff verify_attr_interrupt is called.
- fn verify_attr_stepper(
- &mut self,
- indices: &mut IndexStore,
- policies: &mut MachinePolicies,
- code_repo: &mut CodeRepo,
- user_input: &mut Stream,
- user_output: &mut Stream,
- ) -> bool {
- loop {
- let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
- Some(instr) => {
- if instr.as_ref().is_head_instr() {
- instr
- } else {
- let cp = self.p.local();
- self.run_verify_attr_interrupt(cp);
- return true;
- }
- }
- None => return false,
- };
-
- self.dispatch_instr(
- instr.as_ref(),
- indices,
- policies,
- code_repo,
- user_input,
- user_output,
- );
+ (RCWH, RCWOH)
+ };
- if self.fail {
- self.backtrack();
- }
+ if let Some(&(_, b_cutoff, prev_block)) = self.machine_st.cont_pts.last() {
+ if self.machine_st.b < b_cutoff {
+ let (idx, arity) = if self.machine_st.block > prev_block {
+ (r_c_w_h, 0)
+ } else {
+ self.machine_st.registers[1] = fixnum_as_cell!(
+ Fixnum::build_with(b_cutoff as i64)
+ );
- if !self.check_machine_index(code_repo) {
- return false;
+ (r_c_wo_h, 1)
+ };
+
+ self.machine_st.call_at_index(arity, idx);
+ return true;
}
}
+
+ false
}
- fn run_verify_attr_interrupt(&mut self, cp: LocalCodePtr) {
- let p = self.attr_var_init.verify_attrs_loc;
+ pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) {
+ // the sequence is reversed to respect the chronology of trail
+ // additions now that deleted attributes can be undeleted by
+ // backtracking.
+ for i in (a1..a2).rev() {
+ let h = self.machine_st.trail[i].get_value() as usize;
- self.attr_var_init.cp = cp;
- self.verify_attr_interrupt(p);
- }
+ match self.machine_st.trail[i].get_tag() {
+ TrailEntryTag::TrailedHeapVar => {
+ self.machine_st.heap[h] = heap_loc_as_cell!(h);
+ }
+ TrailEntryTag::TrailedStackVar => {
+ self.machine_st.stack[h] = stack_loc_as_cell!(h);
+ }
+ TrailEntryTag::TrailedAttrVar => {
+ self.machine_st.heap[h] = attr_var_as_cell!(h);
+ }
+ TrailEntryTag::TrailedAttrVarHeapLink => {
+ self.machine_st.heap[h] = heap_loc_as_cell!(h);
+ }
+ TrailEntryTag::TrailedAttrVarListLink => {
+ let value = HeapCellValue::from_bytes(
+ self.machine_st.trail[i + 1].into_bytes()
+ );
- fn query_stepper(
- &mut self,
- indices: &mut IndexStore,
- policies: &mut MachinePolicies,
- code_repo: &mut CodeRepo,
- user_input: &mut Stream,
- user_output: &mut Stream,
- ) {
- loop {
- self.execute_instr(indices, policies, code_repo, user_input, user_output);
-
- if self.fail {
- self.backtrack();
- }
+ if value.get_value() < self.machine_st.hb {
+ self.machine_st.heap[h] = value;
+ }
+ }
+ TrailEntryTag::TrailedBlackboardEntry => {
+ let key = Atom::from(h);
- match self.p {
- CodePtr::VerifyAttrInterrupt(_) => {
- self.p = CodePtr::Local(self.attr_var_init.cp);
-
- let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p);
- let instigating_instr = code_repo.lookup_instr(false, &instigating_p).unwrap();
-
- 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,
- user_input,
- user_output,
- ) {
- if self.fail {
- break;
- }
-
- let cp = self.p.local();
- self.run_verify_attr_interrupt(cp);
+ match self.indices.global_variables.get_mut(&key) {
+ Some((_, ref mut loc)) => *loc = None,
+ None => unreachable!(),
}
}
- _ => {
- if !self.check_machine_index(code_repo) {
- break;
+ TrailEntryTag::TrailedBlackboardOffset => {
+ let key = Atom::from(h);
+ let value_cell = HeapCellValue::from(u64::from(self.machine_st.trail[i + 1]));
+
+ match self.indices.global_variables.get_mut(&key) {
+ Some((_, ref mut loc)) => *loc = Some(value_cell),
+ None => unreachable!(),
}
}
+ TrailEntryTag::TrailedAttachedValue => {
+ }
}
}
}
diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs
index 79354874..0e25d7b5 100644
--- a/src/machine/partial_string.rs
+++ b/src/machine/partial_string.rs
@@ -1,43 +1,17 @@
-use crate::machine::machine_indices::*;
-use crate::machine::*;
+use crate::atom_table::*;
+use crate::parser::ast::*;
-use core::marker::PhantomData;
+use crate::machine::heap::*;
+use crate::machine::machine_errors::CycleSearchResult;
+use crate::machine::system_calls::BrentAlgState;
+use crate::types::*;
-use std::alloc;
use std::cmp::Ordering;
-use std::mem;
-use std::ops::RangeFrom;
-use std::ptr;
-use std::slice;
+use std::ops::Deref;
use std::str;
-use indexmap::IndexSet;
-
-#[derive(Debug)]
-pub(crate) struct PartialString {
- buf: *const u8,
- len: usize,
- _marker: PhantomData<[u8]>,
-}
-
-impl Drop for PartialString {
- fn drop(&mut self) {
- unsafe {
- let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::<u8>());
- alloc::dealloc(self.buf as *mut u8, layout);
-
- self.buf = ptr::null();
- self.len = 0;
- }
- }
-}
-
-impl Clone for PartialString {
- #[inline]
- fn clone(&self) -> Self {
- self.clone_from_offset(0)
- }
-}
+#[derive(Copy, Clone, Debug)]
+pub struct PartialString(Atom);
fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
let mut terminator_idx = 0;
@@ -53,432 +27,1096 @@ fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
terminator_idx
}
-#[derive(Debug)]
-pub(crate) struct PStrIter {
- buf: *const u8,
- len: usize,
-}
-
-impl PStrIter {
+impl From<Atom> for PartialString {
#[inline]
- fn from(buf: *const u8, len: usize, idx: usize) -> Self {
- PStrIter {
- buf: (buf as usize + idx) as *const _,
- len: len - idx,
- }
+ fn from(buf: Atom) -> PartialString {
+ PartialString(buf)
}
}
-impl Iterator for PStrIter {
- type Item = char;
-
- fn next(&mut self) -> Option<Self::Item> {
- unsafe {
- let slice = slice::from_raw_parts(self.buf, self.len);
- let s = str::from_utf8(slice).unwrap();
-
- if let Some(c) = s.chars().next() {
- self.buf = self.buf.offset(c.len_utf8() as isize);
- self.len -= c.len_utf8();
-
- Some(c)
- } else {
- None
- }
- }
+impl Into<Atom> for PartialString {
+ #[inline]
+ fn into(self: Self) -> Atom {
+ self.0
}
}
impl PartialString {
#[inline]
- pub(super) fn new(src: &str) -> Option<(Self, &str)> {
- let pstr = PartialString {
- buf: ptr::null_mut(),
- len: 0,
- _marker: PhantomData,
- };
+ pub(super) fn new<'a>(src: &'a str, atom_tbl: &mut AtomTable) -> Option<(Self, &'a str)> {
+ let terminator_idx = scan_for_terminator(src.chars());
+ let pstr = PartialString(atom_tbl.build_with(&src[.. terminator_idx]));
- unsafe { pstr.append_chars(src) }
+ Some(if terminator_idx < src.as_bytes().len() {
+ (pstr, &src[terminator_idx + 1..])
+ } else {
+ (pstr, "")
+ })
}
- unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
- let terminator_idx = scan_for_terminator(src.chars());
+ #[inline(always)]
+ pub(crate) fn as_str_from(&self, n: usize) -> &str {
+ &self.0.as_str()[n..]
+ }
+}
- let layout = alloc::Layout::from_size_align_unchecked(
- terminator_idx + '\u{0}'.len_utf8(),
- mem::align_of::<u8>(),
- );
+#[derive(Clone, Copy)]
+pub struct HeapPStrIter<'a> {
+ pub heap: &'a [HeapCellValue],
+ pub focus: HeapCellValue,
+ orig_focus: usize,
+ brent_st: BrentAlgState,
+ stepper: fn(&mut HeapPStrIter<'a>) -> Option<PStrIteratee>,
+}
+
+#[derive(Debug)]
+pub struct PStrPrefixCmpResult {
+ pub focus: usize,
+ pub offset: usize,
+ pub prefix_len: usize,
+}
- self.buf = alloc::alloc(layout) as *const _;
- self.len = terminator_idx + '\u{0}'.len_utf8();
+struct PStrIterStep {
+ iteratee: PStrIteratee,
+ next_hare: usize,
+}
- ptr::copy(src.as_ptr(), self.buf as *mut _, terminator_idx);
+impl<'a> HeapPStrIter<'a> {
+ pub fn new(heap: &'a [HeapCellValue], h: usize) -> Self {
+ let value = heap[h];
+
+ Self {
+ heap,
+ focus: value,
+ orig_focus: h,
+ brent_st: BrentAlgState::new(h),
+ stepper: HeapPStrIter::pre_cycle_discovery_stepper,
+ }
+ }
- self.write_terminator_at(terminator_idx);
+ #[inline(always)]
+ pub fn focus(&self) -> usize {
+ self.brent_st.hare
+ }
- Some(if terminator_idx != src.as_bytes().len() {
- (self, &src[terminator_idx..])
- } else {
- (self, "")
- })
+ #[inline(always)]
+ pub fn at_string_terminator(&self) -> bool {
+ self.focus.is_string_terminator(self.heap)
}
- 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
- };
+ #[inline(always)]
+ pub fn num_steps(&self) -> usize {
+ self.brent_st.num_steps()
+ }
- let mut pstr = PartialString {
- buf: ptr::null_mut(),
- len: len + '\u{0}'.len_utf8(),
- _marker: PhantomData,
+ pub fn compare_pstr_to_string(&mut self, s: &str) -> Option<PStrPrefixCmpResult> {
+ let mut result = PStrPrefixCmpResult {
+ focus: self.brent_st.hare,
+ offset: 0,
+ prefix_len: 0,
};
- unsafe {
- let layout = alloc::Layout::from_size_align_unchecked(
- len + '\u{0}'.len_utf8(),
- mem::align_of::<u8>(),
- );
+ while let Some(iteratee) = self.next() {
+ result.focus = iteratee.focus();
+ result.offset = iteratee.offset();
- pstr.buf = alloc::alloc(layout);
+ match iteratee {
+ PStrIteratee::Char(_, c1) => {
+ if let Some(c2) = s[result.prefix_len..].chars().next() {
+ if c1 != c2 {
+ return None;
+ } else {
+ result.prefix_len += c1.len_utf8();
+ result.offset += c1.len_utf8();
+ }
+ } else {
+ return Some(result);
+ }
+ }
+ PStrIteratee::PStrSegment(_, pstr_atom, n) => {
+ let pstr = PartialString::from(pstr_atom);
+ let t = pstr.as_str_from(n);
+ let s = &s[result.prefix_len..];
- if len > 0 {
- ptr::copy(
- (self.buf as usize + n) as *const u8,
- pstr.buf as *mut _,
- len,
- );
+ if s.len() >= t.len() {
+ if s.starts_with(t) {
+ result.prefix_len += t.len();
+ result.offset += t.len();
+ } else {
+ return None;
+ }
+ } else if t.starts_with(&s) {
+ result.prefix_len += s.len();
+ result.offset += s.len();
+
+ return Some(result);
+ } else {
+ return None;
+ }
+ }
}
- pstr.write_terminator_at(len);
+ if s.len() == result.prefix_len {
+ return Some(result);
+ }
}
- pstr
+ Some(result)
}
#[inline]
- pub(super) fn write_terminator_at(&mut self, index: usize) {
- unsafe {
- ptr::write((self.buf as usize + index) as *mut u8, 0u8);
+ pub fn chars(mut self) -> PStrCharsIter<'a> {
+ let item = self.next();
+ PStrCharsIter { iter: self, item }
+ }
+
+ fn walk_hare_to_cycle_end(&mut self) {
+ // walk_hare_to_cycle_end assumes a cycle has been found,
+ // so it is always safe to unwrap self.step()
+
+ let orig_hare = self.brent_st.hare;
+
+ self.brent_st.hare = self.orig_focus;
+ self.brent_st.tortoise = self.orig_focus;
+
+ for _ in 0 .. self.brent_st.lam {
+ self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare;
+ }
+
+ while self.brent_st.hare != self.brent_st.tortoise {
+ self.brent_st.tortoise = self.step(self.brent_st.tortoise).unwrap().next_hare;
+ self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare;
}
+
+ self.focus = self.heap[orig_hare];
+ self.brent_st.hare = orig_hare;
}
- #[inline]
- pub(crate) fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
- if self.len >= '\u{0}'.len_utf8() {
- PStrIter::from(self.buf, self.len - '\u{0}'.len_utf8(), index.start)
- } else {
- PStrIter::from(self.buf, 0, 0)
+ pub fn to_string(&mut self) -> String {
+ let mut buf = String::with_capacity(32);
+
+ while let Some(iteratee) = self.next() {
+ match iteratee {
+ PStrIteratee::Char(_, c) => {
+ buf.push(c);
+ }
+ PStrIteratee::PStrSegment(_, pstr_atom, n) => {
+ let pstr = PartialString::from(pstr_atom);
+ buf += pstr.as_str_from(n);
+ }
+ }
}
+
+ buf
}
#[inline]
- pub(crate) fn at_end(&self, end_n: usize) -> bool {
- end_n + 1 == self.len
+ pub fn is_continuable(&self) -> bool {
+ let mut focus = self.focus;
+
+ loop {
+ read_heap_cell!(focus,
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
+ return true;
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here?
+ return name == atom!(".") && arity == 2;
+ }
+ (HeapCellValueTag::Lis, h) => {
+ return read_heap_cell!(self.heap[h],
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ arity == 0 && name.as_char().is_some()
+ }
+ (HeapCellValueTag::Char) => {
+ true
+ }
+ _ => {
+ false
+ }
+ );
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if focus == self.heap[h] {
+ return false;
+ }
+
+ focus = self.heap[h];
+ }
+ _ => {
+ return false;
+ }
+ );
+ }
}
- #[inline]
- pub(crate) fn as_str_from(&self, n: usize) -> &str {
- unsafe {
- let slice = slice::from_raw_parts(self.buf, self.len - '\u{0}'.len_utf8());
+ #[inline(always)]
+ pub fn cycle_detected(&self) -> bool {
+ self.stepper as usize == HeapPStrIter::post_cycle_discovery_stepper as usize
+ }
+
+ fn step(&self, mut curr_hare: usize) -> Option<PStrIterStep> {
+ loop {
+ read_heap_cell!(self.heap[curr_hare],
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ return if self.focus == empty_list_as_cell!() {
+ None
+ } else {
+ Some(PStrIterStep {
+ iteratee: PStrIteratee::PStrSegment(curr_hare, cstr_atom, 0),
+ next_hare: curr_hare,
+ })
+ }
+ }
+ (HeapCellValueTag::PStrLoc, h) => {
+ curr_hare = h;
+ }
+ (HeapCellValueTag::PStr, pstr_atom) => {
+ return Some(PStrIterStep {
+ iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, 0),
+ next_hare: curr_hare+1,
+ });
+ }
+ (HeapCellValueTag::PStrOffset, pstr_offset) => {
+ if self.focus == empty_list_as_cell!() {
+ return None;
+ }
+
+ let pstr_atom = cell_as_atom!(self.heap[pstr_offset]);
+ let n = cell_as_fixnum!(self.heap[curr_hare+1]).get_num() as usize;
+
+ return if self.heap[pstr_offset].get_tag() == HeapCellValueTag::CStr {
+ Some(PStrIterStep {
+ iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n),
+ next_hare: pstr_offset,
+ })
+ } else {
+ Some(PStrIterStep {
+ iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n),
+ next_hare: pstr_offset+1,
+ })
+ };
+ }
+ (HeapCellValueTag::Lis, h) => {
+ let value = heap_bound_store(
+ self.heap,
+ heap_bound_deref(self.heap, self.heap[h]),
+ );
+
+ return if let Some(c) = value.as_char() {
+ Some(PStrIterStep {
+ iteratee: PStrIteratee::Char(curr_hare, c),
+ next_hare: h+1,
+ })
+ } else {
+ None
+ }
+ }
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[s])
+ .get_name_and_arity();
+
+ return if name == atom!(".") && arity == 2 {
+ let value = heap_bound_store(
+ self.heap,
+ heap_bound_deref(self.heap, self.heap[s+1]),
+ );
+
+ if let Some(c) = value.as_char() {
+ Some(PStrIterStep {
+ iteratee: PStrIteratee::Char(curr_hare, c),
+ next_hare: s+2,
+ })
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ debug_assert!(arity == 0);
+ return None;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h == curr_hare {
+ return None;
+ }
+
+ curr_hare = h;
+ }
+ _ => {
+ return None;
+ }
+ );
+ }
+ }
+
+ fn pre_cycle_discovery_stepper(&mut self) -> Option<PStrIteratee> {
+ let PStrIterStep { iteratee, next_hare } =
+ match self.step(self.brent_st.hare) {
+ Some(results) => results,
+ None => {
+ return None;
+ }
+ };
+
+ self.focus = self.heap[iteratee.focus()];
+
+ if self.focus.is_string_terminator(self.heap) {
+ self.focus = empty_list_as_cell!();
+ self.brent_st.hare = iteratee.focus();
+
+ return Some(iteratee);
+ }
+
+ match self.brent_st.step(next_hare) {
+ Some(cycle_result) => {
+ debug_assert!(match cycle_result {
+ CycleSearchResult::Cyclic(..) => true,
+ _ => false,
+ });
- let s = str::from_utf8(slice).unwrap();
+ self.walk_hare_to_cycle_end();
+ self.stepper = HeapPStrIter::post_cycle_discovery_stepper;
+ }
+ None => {
+ self.focus = self.heap[next_hare];
+ }
+ }
- &s[n..]
+ Some(iteratee)
+ }
+
+ fn post_cycle_discovery_stepper(&mut self) -> Option<PStrIteratee> {
+ if self.brent_st.hare == self.brent_st.tortoise {
+ return None;
}
+
+ let PStrIterStep { iteratee, next_hare } =
+ match self.step(self.brent_st.hare) {
+ Some(results) => results,
+ None => {
+ return None;
+ }
+ };
+
+ self.focus = self.heap[next_hare];
+ self.brent_st.hare = next_hare;
+
+ Some(iteratee)
}
}
-#[derive(Debug)]
-pub(crate) struct HeapPStrIter<'a> {
- focus: Addr,
- machine_st: &'a MachineState,
- seen: IndexSet<Addr>,
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PStrIteratee {
+ Char(usize, char),
+ PStrSegment(usize, Atom, usize),
}
-impl<'a> HeapPStrIter<'a> {
+impl PStrIteratee {
#[inline]
- pub(super) fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
- HeapPStrIter {
- focus,
- machine_st,
- seen: IndexSet::new(),
+ fn offset(&self) -> usize {
+ match self {
+ PStrIteratee::Char(_, _) => 0,
+ PStrIteratee::PStrSegment(_, _, n) => *n,
}
}
#[inline]
- pub(crate) fn focus(&self) -> Addr {
- self.machine_st.store(self.machine_st.deref(self.focus))
+ fn focus(&self) -> usize {
+ match self {
+ PStrIteratee::Char(focus, _) => *focus,
+ PStrIteratee::PStrSegment(focus, _, _) => *focus,
+ }
}
+}
- #[inline]
- pub(crate) fn to_string(&mut self) -> String {
- let mut buf = String::new();
+impl<'a> Iterator for HeapPStrIter<'a> {
+ type Item = PStrIteratee;
- while let Some(iteratee) = self.next() {
+ #[inline(always)]
+ fn next(&mut self) -> Option<Self::Item> {
+ (self.stepper)(self)
+ }
+}
+
+pub struct PStrCharsIter<'a> {
+ pub iter: HeapPStrIter<'a>,
+ pub item: Option<PStrIteratee>,
+}
+
+impl<'a> PStrCharsIter<'a> {
+ pub fn peek(&self) -> Option<char> {
+ if let Some(iteratee) = self.item {
match iteratee {
- PStrIteratee::Char(c) => {
- buf.push(c);
+ PStrIteratee::Char(_, c) => {
+ return Some(c);
+ }
+ PStrIteratee::PStrSegment(_, pstr_atom, n) => {
+ let pstr = PartialString::from(pstr_atom);
+ return pstr.as_str_from(n).chars().next();
}
- PStrIteratee::PStrSegment(h, n) => match &self.machine_st.heap[h] {
- HeapCellValue::PartialString(ref pstr, _) => {
- buf += pstr.as_str_from(n);
- }
- _ => {
- unreachable!()
- }
- },
}
}
- buf
+ None
}
}
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum PStrIteratee {
- Char(char),
- PStrSegment(usize, usize),
+impl<'a> Deref for PStrCharsIter<'a> {
+ type Target = HeapPStrIter<'a>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.iter
+ }
}
-impl<'a> Iterator for HeapPStrIter<'a> {
- type Item = PStrIteratee;
+impl<'a> Iterator for PStrCharsIter<'a> {
+ type Item = char;
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!()
+ while let Some(item) = self.item {
+ match item {
+ PStrIteratee::Char(_, c) => {
+ self.item = self.iter.next();
+ return Some(c);
}
- }
- 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() {
- atom.as_str().chars().next()
- } else {
- None
- }
- } else {
- unreachable!()
+ PStrIteratee::PStrSegment(f1, pstr_atom, n) => {
+ let pstr = PartialString::from(pstr_atom);
+
+ match pstr.as_str_from(n).chars().next() {
+ Some(c) => {
+ self.item = Some(PStrIteratee::PStrSegment(
+ f1,
+ pstr_atom,
+ n + c.len_utf8(),
+ ));
+
+ return Some(c);
+ }
+ None => {
+ self.item = self.iter.next();
}
}
- 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;
- }
+ }
+
+ None
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PStrCmpResult {
+ Ordered(Ordering),
+ FirstIterContinuable(PStrIteratee),
+ SecondIterContinuable(PStrIteratee),
+ Unordered,
+}
+
+impl PStrCmpResult {
+ #[inline]
+ pub fn is_second_iter(&self) -> bool {
+ if let PStrCmpResult::SecondIterContinuable(_) = self {
+ true
+ } else {
+ false
}
}
}
#[inline]
-pub(super) fn compare_pstr_prefixes<'a>(
+pub fn compare_pstr_prefixes<'a>(
i1: &mut HeapPStrIter<'a>,
i2: &mut HeapPStrIter<'a>,
-) -> Option<Ordering> {
- let mut r1 = i1.next();
- let mut r2 = i2.next();
+) -> PStrCmpResult {
+ #[inline(always)]
+ fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
+ let result = iter.step(hare);
+
+ iter.focus = iter.heap[hare];
+
+ if iter.focus.is_string_terminator(iter.heap) {
+ iter.focus = empty_list_as_cell!();
+ }
+
+ result
+ }
+
+ #[inline(always)]
+ fn cycle_detection_step(i1: &mut HeapPStrIter, i2: &HeapPStrIter, step: &PStrIterStep) -> bool {
+ if i1.cycle_detected() {
+ i1.brent_st.hare = step.next_hare;
+ i2.cycle_detected()
+ } else if i1.brent_st.step(step.next_hare).is_some() {
+ i1.stepper = HeapPStrIter::post_cycle_discovery_stepper;
+ i2.cycle_detected()
+ } else {
+ false
+ }
+ }
+
+ let mut r1 = step(i1, i1.brent_st.hare);
+ let mut r2 = step(i2, i2.brent_st.hare);
loop {
- if let Some(r1i) = r1 {
- if let Some(r2i) = r2 {
- match (r1i, r2i) {
- (PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => {
+ if let Some(step_1) = r1.as_mut() {
+ if let Some(step_2) = r2.as_mut() {
+ match (step_1.iteratee, step_2.iteratee) {
+ (PStrIteratee::Char(_, c1), PStrIteratee::Char(_, c2)) => {
if c1 != c2 {
- return c1.partial_cmp(&c2);
+ return PStrCmpResult::Ordered(c1.cmp(&c2));
+ }
+
+ cycle_detection_step(i1, i2, &step_1);
+ let both_cyclic = cycle_detection_step(i2, i1, &step_2);
+
+ r1 = step(i1, i1.brent_st.hare);
+ r2 = step(i2, i2.brent_st.hare);
+
+ if !both_cyclic {
+ continue;
}
}
- (PStrIteratee::Char(c1), PStrIteratee::PStrSegment(h, n)) => {
- if let &HeapCellValue::PartialString(ref pstr, _) = &i2.machine_st.heap[h] {
- if let Some(c2) = pstr.as_str_from(n).chars().next() {
- if c1 != c2 {
- return c1.partial_cmp(&c2);
- } else {
- r1 = i1.next();
- r2 = Some(PStrIteratee::PStrSegment(h, n + c2.len_utf8()));
+ (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => {
+ let pstr = PartialString::from(pstr_atom);
+
+ if let Some(c2) = pstr.as_str_from(n).chars().next() {
+ if c1 != c2 {
+ return PStrCmpResult::Ordered(c1.cmp(&c2));
+ }
+
+ let n1 = n + c2.len_utf8();
+ if n1 < pstr_atom.len() {
+ step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1);
+
+ let c1_result = cycle_detection_step(i1, i2, &step_1);
+ r1 = step(i1, i1.brent_st.hare);
+
+ if !c1_result {
continue;
}
} else {
- r2 = i2.next();
- continue;
+ cycle_detection_step(i1, i2, &step_1);
+ let both_cyclic = cycle_detection_step(i2, i1, &step_2);
+
+ r1 = step(i1, i1.brent_st.hare);
+ r2 = step(i2, i2.brent_st.hare);
+
+ if !both_cyclic {
+ continue;
+ }
}
} else {
- unreachable!()
+ let c2_result = cycle_detection_step(i2, i1, &step_2);
+ r2 = step(i2, i2.brent_st.hare);
+
+ if !c2_result {
+ continue;
+ }
}
}
- (PStrIteratee::PStrSegment(h, n), PStrIteratee::Char(c2)) => {
- if let &HeapCellValue::PartialString(ref pstr, _) = &i1.machine_st.heap[h] {
- if let Some(c1) = pstr.as_str_from(n).chars().next() {
- if c1 != c2 {
- return c2.partial_cmp(&c1);
- } else {
- r1 = i1.next();
- r2 = Some(PStrIteratee::PStrSegment(h, n + c1.len_utf8()));
+ (PStrIteratee::PStrSegment(f1, pstr_atom, n), PStrIteratee::Char(_, c2)) => {
+ let pstr = PartialString::from(pstr_atom);
+
+ if let Some(c1) = pstr.as_str_from(n).chars().next() {
+ if c1 != c2 {
+ return PStrCmpResult::Ordered(c2.cmp(&c1));
+ }
+
+ let n1 = n + c1.len_utf8();
+ if n1 < pstr_atom.len() {
+ step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1);
+
+ let c2_result = cycle_detection_step(i2, i1, &step_2);
+ r2 = step(i2, step_2.next_hare);
+
+ if !c2_result {
continue;
}
} else {
- r1 = i1.next();
- continue;
+ cycle_detection_step(i1, i2, &step_1);
+ let both_cyclic = cycle_detection_step(i2, i1, &step_2);
+
+ r1 = step(i1, i1.brent_st.hare);
+ r2 = step(i2, i2.brent_st.hare);
+
+ if !both_cyclic {
+ continue;
+ }
}
} else {
- unreachable!()
+ let c1_result = cycle_detection_step(i1, i2, &step_1);
+ r1 = step(i1, i1.brent_st.hare);
+
+ if !c1_result {
+ continue;
+ }
}
}
- (PStrIteratee::PStrSegment(h1, n1), PStrIteratee::PStrSegment(h2, n2)) => {
- match (&i1.machine_st.heap[h1], &i2.machine_st.heap[h2]) {
- (
- &HeapCellValue::PartialString(ref pstr1, _),
- &HeapCellValue::PartialString(ref pstr2, _),
- ) => {
- let str1 = pstr1.as_str_from(n1);
- let str2 = pstr2.as_str_from(n2);
-
- if str1.starts_with(str2) {
- r1 = Some(PStrIteratee::PStrSegment(h1, n1 + str2.len()));
- r2 = i2.next();
+ (PStrIteratee::PStrSegment(f1, pstr1_atom, n1),
+ PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => {
+ if pstr1_atom == pstr2_atom && n1 == n2 {
+ cycle_detection_step(i1, i2, &step_1);
+ let both_cyclic = cycle_detection_step(i2, i1, &step_2);
+
+ r1 = step(i1, i1.brent_st.hare);
+ r2 = step(i2, i2.brent_st.hare);
+
+ if !both_cyclic {
+ continue;
+ }
+
+ break;
+ }
+
+ let pstr1 = PartialString::from(pstr1_atom);
+ let pstr2 = PartialString::from(pstr2_atom);
+
+ let str1 = pstr1.as_str_from(n1);
+ let str2 = pstr2.as_str_from(n2);
+
+ match str1.len().cmp(&str2.len()) {
+ Ordering::Equal if str1 == str2 => {
+ cycle_detection_step(i1, i2, &step_1);
+ let both_cyclic = cycle_detection_step(i2, i1, &step_2);
+
+ r1 = step(i1, i1.brent_st.hare);
+ r2 = step(i2, i2.brent_st.hare);
+ if !both_cyclic {
continue;
- } else if str2.starts_with(str1) {
- r1 = i1.next();
- r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len()));
+ }
+ }
+ Ordering::Less if str2.starts_with(str1) => {
+ step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len());
+ let c1_result = cycle_detection_step(i1, i2, &step_1);
+ r1 = step(i1, i1.brent_st.hare);
+
+ if !c1_result {
+ continue;
+ }
+ }
+ Ordering::Greater if str1.starts_with(str2) => {
+ step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len());
+ let c2_result = cycle_detection_step(i2, i1, &step_2);
+ r2 = step(i2, i2.brent_st.hare);
+ if !c2_result {
continue;
- } else {
- return str1.partial_cmp(str2);
}
}
_ => {
- unreachable!()
+ return PStrCmpResult::Ordered(str1.cmp(str2));
}
}
}
}
-
- r1 = i1.next();
- r2 = i2.next();
-
- continue;
}
}
- let ordering = if r1.is_none() {
- mem::swap(&mut r1, &mut r2);
- Ordering::Less
+ break;
+ }
+
+ // to have a cyclic term, the cell at i1.focus must be:
+ //
+ // 1) 'continuable' as a cell in a string traversal, and,
+ // 2) matchable by compare_pstr_prefixes to the cell at i2.focus.
+ //
+ // If both cells are continuable they must have been encountered
+ // and thus matched by the compare_pstr_prefixes loop previously,
+ // so here it suffices to check if they are both continuable.
+
+ let r1_at_end = r1.is_none();
+ let r2_at_end = r2.is_none();
+
+ if r1_at_end && r2_at_end {
+ if i1.focus == i2.focus {
+ PStrCmpResult::Ordered(Ordering::Equal)
} else {
- Ordering::Greater
- };
+ PStrCmpResult::Unordered
+ }
+ } else if r1_at_end {
+ if i1.focus == empty_list_as_cell!() {
+ PStrCmpResult::Ordered(Ordering::Less)
+ } else {
+ PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee)
+ }
+ } else if r2_at_end {
+ if i2.focus == empty_list_as_cell!() {
+ PStrCmpResult::Ordered(Ordering::Greater)
+ } else {
+ PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee)
+ }
+ } else {
+ if i1.is_continuable() && i2.is_continuable() {
+ PStrCmpResult::Ordered(Ordering::Equal)
+ } else {
+ PStrCmpResult::Unordered
+ }
+ }
+}
- let machine_st = i1.machine_st;
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::machine::mock_wam::*;
- let check_focuses = || match (i1.focus(), i2.focus()) {
- (Addr::EmptyList, Addr::EmptyList) => Some(Ordering::Equal),
- (Addr::EmptyList, _) => Some(Ordering::Less),
- (_, Addr::EmptyList) => Some(Ordering::Greater),
- _ => None,
- };
+ #[test]
+ fn pstr_iter_tests() {
+ let mut wam = MockWAM::new();
- return match r1 {
- Some(PStrIteratee::PStrSegment(h, n)) => {
- if let &HeapCellValue::PartialString(ref pstr, _) = &machine_st.heap[h] {
- if pstr.as_str_from(n).chars().next().is_some() {
- Some(ordering)
- } else {
- check_focuses()
- }
- } else {
- unreachable!()
- }
- }
- Some(PStrIteratee::Char(_)) => Some(ordering),
- None => check_focuses(),
- };
- }
-}
+ let pstr_var_cell = put_partial_string(
+ &mut wam.machine_st.heap,
+ "abc ",
+ &mut wam.machine_st.atom_tbl,
+ );
-#[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 Some(s_offset);
- }
- }
- PStrIteratee::PStrSegment(h, n) => match heap_pstr_iter.machine_st.heap[h] {
- HeapCellValue::PartialString(ref pstr, _) => {
- let t = pstr.as_str_from(n);
+ let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
- 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());
+ {
+ let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
- s_offset += s[s_offset..].len();
- return Some(s_offset);
- } else {
- return None;
- }
- }
- _ => {
- unreachable!()
- }
- },
+ assert_eq!(
+ iter.next(),
+ Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0))
+ );
+ assert_eq!(iter.next(), None);
+
+ assert!(!iter.at_string_terminator());
}
- if s[s_offset..].is_empty() {
- return Some(s_offset);
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+
+ let pstr_second_var_cell = put_partial_string(
+ &mut wam.machine_st.heap,
+ "def",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+
+ {
+ let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
+
+ assert_eq!(
+ iter.next(),
+ Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0))
+ );
+ assert_eq!(
+ iter.next(),
+ Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0))
+ );
+
+ assert_eq!(iter.next(), None);
+ assert!(!iter.at_string_terminator());
+ }
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ {
+ let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
+
+ assert_eq!(
+ iter.next(),
+ Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0))
+ );
+ assert_eq!(
+ iter.next(),
+ Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0))
+ );
+
+ assert_eq!(iter.next(), None);
+ assert!(iter.at_string_terminator());
+ }
+
+ wam.machine_st.heap.pop();
+ wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
+
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0)));
+
+ {
+ let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
+
+ while let Some(_) = iter.next() {}
+
+ assert!(!iter.at_string_terminator());
+ }
+
+ {
+ let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0);
+ let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 0);
+
+ assert_eq!(
+ compare_pstr_prefixes(&mut iter1, &mut iter2),
+ PStrCmpResult::Ordered(Ordering::Equal)
+ );
}
- }
- Some(s_offset)
+ {
+ let second_h = wam.machine_st.heap.len();
+
+ // construct a structurally similar but different cyclic partial string
+ // matching the one beginning at wam.machine_st.heap[0].
+
+ put_partial_string(
+ &mut wam.machine_st.heap,
+ "ab",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ wam.machine_st.heap.pop();
+
+ wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+2));
+
+ put_partial_string(
+ &mut wam.machine_st.heap,
+ "c ",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ wam.machine_st.heap.pop();
+
+ wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+4));
+
+ wam.machine_st.heap.push(pstr_second_cell);
+ wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+6));
+
+ wam.machine_st.heap.push(pstr_offset_as_cell!(second_h));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0)));
+
+ let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0);
+ let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h);
+
+ assert_eq!(
+ compare_pstr_prefixes(&mut iter1, &mut iter2),
+ PStrCmpResult::Ordered(Ordering::Equal)
+ );
+ }
+
+ wam.machine_st.heap.clear();
+
+ put_partial_string(
+ &mut wam.machine_st.heap,
+ "abc ",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ let pstr_cell = wam.machine_st.heap[0];
+
+ wam.machine_st.heap[1] = list_loc_as_cell!(2);
+
+ wam.machine_st.heap.push(char_as_cell!('a'));
+ wam.machine_st.heap.push(list_loc_as_cell!(4));
+ wam.machine_st.heap.push(char_as_cell!('b'));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ wam.machine_st.heap.push(pstr_cell);
+ wam.machine_st.heap.push(heap_loc_as_cell!(7));
+
+ {
+ let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0);
+ let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 6);
+
+ assert_eq!(
+ compare_pstr_prefixes(&mut iter1, &mut iter2),
+ PStrCmpResult::FirstIterContinuable(PStrIteratee::Char(1, 'a')),
+ );
+
+ assert_eq!(iter2.focus, heap_loc_as_cell!(7));
+ }
+
+ // test "abc" = [X,Y,Z].
+
+ wam.machine_st.heap.clear();
+
+ let cstr_var_cell = put_complete_string(
+ &mut wam.machine_st.heap,
+ "abc",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ wam.machine_st.heap.push(list_loc_as_cell!(2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(2));
+
+ wam.machine_st.heap.push(list_loc_as_cell!(4));
+ wam.machine_st.heap.push(heap_loc_as_cell!(4));
+
+ wam.machine_st.heap.push(list_loc_as_cell!(6));
+ wam.machine_st.heap.push(heap_loc_as_cell!(6));
+
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
+
+ assert_eq!(
+ wam.machine_st.heap[2],
+ char_as_cell!('a'),
+ );
+
+ assert_eq!(
+ wam.machine_st.heap[4],
+ char_as_cell!('b'),
+ );
+
+ assert_eq!(
+ wam.machine_st.heap[6],
+ char_as_cell!('c'),
+ );
+
+ // test "abc" = [X,Y,Z|D].
+
+ wam.machine_st.heap.clear();
+
+ let cstr_var_cell = put_complete_string(
+ &mut wam.machine_st.heap,
+ "abc",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ wam.machine_st.heap.push(list_loc_as_cell!(2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X
+
+ wam.machine_st.heap.push(list_loc_as_cell!(4));
+ wam.machine_st.heap.push(heap_loc_as_cell!(4)); // Y
+
+ wam.machine_st.heap.push(list_loc_as_cell!(6));
+ wam.machine_st.heap.push(heap_loc_as_cell!(6)); // Z
+
+ wam.machine_st.heap.push(heap_loc_as_cell!(7)); // D
+
+ unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
+
+ assert_eq!(wam.machine_st.fail, false);
+
+ assert_eq!(
+ wam.machine_st.heap[2],
+ char_as_cell!('a'),
+ );
+
+ assert_eq!(
+ wam.machine_st.heap[4],
+ char_as_cell!('b'),
+ );
+
+ assert_eq!(
+ wam.machine_st.heap[6],
+ char_as_cell!('c'),
+ );
+
+ assert_eq!(
+ wam.machine_st.heap[7],
+ empty_list_as_cell!(),
+ );
+
+ // test "d" = [d].
+
+ wam.machine_st.heap.clear();
+
+ let cstr_var_cell = put_complete_string(
+ &mut wam.machine_st.heap,
+ "d",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ wam.machine_st.heap.push(list_loc_as_cell!(2));
+ wam.machine_st.heap.push(char_as_cell!('d'));
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
+
+ assert_eq!(wam.machine_st.fail, false);
+
+ // test "abc" = [X,b,Z].
+
+ wam.machine_st.heap.clear();
+
+ let cstr_var_cell = put_complete_string(
+ &mut wam.machine_st.heap,
+ "abc",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ wam.machine_st.heap.push(list_loc_as_cell!(2));
+ wam.machine_st.heap.push(heap_loc_as_cell!(2));
+
+ wam.machine_st.heap.push(list_loc_as_cell!(4));
+ wam.machine_st.heap.push(char_as_cell!('b'));
+
+ wam.machine_st.heap.push(list_loc_as_cell!(6));
+ wam.machine_st.heap.push(heap_loc_as_cell!(6));
+
+ wam.machine_st.heap.push(empty_list_as_cell!());
+
+ unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
+
+ assert_eq!(wam.machine_st.fail, false);
+
+ assert_eq!(
+ wam.machine_st.heap[2],
+ char_as_cell!('a'),
+ );
+
+ assert_eq!(
+ wam.machine_st.heap[4],
+ char_as_cell!('b'),
+ );
+
+ assert_eq!(
+ wam.machine_st.heap[6],
+ char_as_cell!('c'),
+ );
+
+ // test "abcdef" = [a,b,c|X].
+
+ wam.machine_st.heap.clear();
+
+ put_complete_string(
+ &mut wam.machine_st.heap,
+ "abcdef",
+ &mut wam.machine_st.atom_tbl,
+ );
+
+ wam.machine_st.heap.push(pstr_as_cell!(atom!("abc")));
+ wam.machine_st.heap.push(heap_loc_as_cell!(2));
+
+ unify!(wam.machine_st, heap_loc_as_cell!(0), pstr_loc_as_cell!(1));
+
+ print_heap_terms(wam.machine_st.heap.iter(), 0);
+
+ assert_eq!(wam.machine_st.fail, false);
+
+ assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(5));
+ assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1));
+ assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef")));
+ assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4));
+ assert_eq!(wam.machine_st.heap[6], fixnum_as_cell!(Fixnum::build_with("abc".len() as i64)));
+
+ // test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset.
+
+ wam.machine_st.heap.clear();
+
+ wam.machine_st.heap.push(pstr_as_cell!(atom!("abc")));
+ wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+ wam.machine_st.heap.push(pstr_offset_as_cell!(0));
+ wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
+
+ {
+ let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2);
+
+ assert_eq!(
+ iter.next(),
+ Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1))
+ );
+
+ // assert!(iter.next().is_none());
+
+ while let Some(_) = iter.next() {}
+ }
+ }
}
diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs
index b93f270e..50a46947 100644
--- a/src/machine/preprocessor.rs
+++ b/src/machine/preprocessor.rs
@@ -1,12 +1,10 @@
-use prolog_parser::ast::*;
-use prolog_parser::tabled_rc::*;
-use prolog_parser::{atom, clause_name, rc_atom};
-
+use crate::atom_table::*;
use crate::forms::*;
+use crate::instructions::*;
use crate::iterators::*;
-use crate::machine::load_state::*;
+use crate::machine::loader::*;
use crate::machine::machine_errors::*;
-use crate::machine::*;
+use crate::parser::ast::*;
use indexmap::IndexSet;
@@ -30,89 +28,81 @@ pub(crate) enum CutContext {
HasCutVariable,
}
-pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
+pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
- term = Term::Clause(
- Cell::default(),
- sym.clone(),
- vec![Box::new(prec), Box::new(term)],
- None,
- );
+ term = Term::Clause(Cell::default(), sym, vec![prec, term]);
}
term
}
pub(crate) fn to_op_decl(
- prec: usize,
- spec: &str,
- name: ClauseName,
+ prec: u16,
+ spec: Atom,
+ name: Atom,
) -> Result<OpDecl, CompilationError> {
match spec {
- "xfx" => Ok(OpDecl::new(prec, XFX, name)),
- "xfy" => Ok(OpDecl::new(prec, XFY, name)),
- "yfx" => Ok(OpDecl::new(prec, YFX, name)),
- "fx" => Ok(OpDecl::new(prec, FX, name)),
- "fy" => Ok(OpDecl::new(prec, FY, name)),
- "xf" => Ok(OpDecl::new(prec, XF, name)),
- "yf" => Ok(OpDecl::new(prec, YF, name)),
+ atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)),
+ atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)),
+ atom!("yfx") => Ok(OpDecl::new(OpDesc::build_with(prec, YFX as u8), name)),
+ atom!("fx") => Ok(OpDecl::new(OpDesc::build_with(prec, FX as u8), name)),
+ atom!("fy") => Ok(OpDecl::new(OpDesc::build_with(prec, FY as u8), name)),
+ atom!("xf") => Ok(OpDecl::new(OpDesc::build_with(prec, XF as u8), name)),
+ atom!("yf") => Ok(OpDecl::new(OpDesc::build_with(prec, YF as u8), name)),
_ => Err(CompilationError::InconsistentEntry),
}
}
fn setup_op_decl(
- mut terms: Vec<Box<Term>>,
- atom_tbl: TabledData<Atom>,
+ mut terms: Vec<Term>,
+ atom_tbl: &mut AtomTable,
) -> Result<OpDecl, CompilationError> {
- let name = match *terms.pop().unwrap() {
- Term::Constant(_, Constant::Atom(name, _)) => name,
- Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
+ let name = match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => name,
+ Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
_ => return Err(CompilationError::InconsistentEntry),
};
- let spec = match *terms.pop().unwrap() {
- Term::Constant(_, Constant::Atom(name, _)) => name,
- Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
+ let spec = match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => name,
+ Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
_ => return Err(CompilationError::InconsistentEntry),
};
- let prec = match *terms.pop().unwrap() {
- Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
+ let prec = match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
Ok(n) if n <= 1200 => n,
_ => return Err(CompilationError::InconsistentEntry),
},
_ => return Err(CompilationError::InconsistentEntry),
};
- to_op_decl(prec, spec.as_str(), name)
+ to_op_decl(prec, spec, name)
}
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
match term {
- Term::Clause(_, ref slash, ref mut terms, Some(_))
- if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
+ Term::Clause(_, slash, ref mut terms)
+ if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
{
- let arity = *terms.pop().unwrap();
- let name = *terms.pop().unwrap();
-
- let arity = arity
- .into_constant()
- .and_then(|c| match c {
- Constant::Integer(n) => n.to_usize(),
- Constant::Fixnum(n) => usize::try_from(n).ok(),
- _ => None,
- })
- .ok_or(CompilationError::InvalidModuleExport)?;
+ let arity = terms.pop().unwrap();
+ let name = terms.pop().unwrap();
- let name = name
- .into_constant()
- .and_then(|c| c.to_atom())
- .ok_or(CompilationError::InvalidModuleExport)?;
+ let arity = match arity {
+ Term::Literal(_, Literal::Integer(n)) => n.to_usize(),
+ Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+ _ => None,
+ }.ok_or(CompilationError::InvalidModuleExport)?;
- if slash.as_str() == "/" {
+ let name = match name {
+ Term::Literal(_, Literal::Atom(name)) => Some(name),
+ _ => None,
+ }.ok_or(CompilationError::InvalidModuleExport)?;
+
+ if *slash == atom!("/") {
Ok((name, arity))
} else {
Ok((name, arity + 2))
@@ -148,13 +138,13 @@ fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKe
fn setup_module_export(
mut term: Term,
- atom_tbl: TabledData<Atom>,
+ atom_tbl: &mut AtomTable,
) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey)
.or_else(|_| {
- if let Term::Clause(_, name, terms, _) = term {
- if terms.len() == 3 && name.as_str() == "op" {
+ if let Term::Clause(_, name, terms) = term {
+ if terms.len() == 3 && name == atom!("op") {
Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
} else {
Err(CompilationError::InvalidModuleDecl)
@@ -167,18 +157,18 @@ fn setup_module_export(
pub(super) fn setup_module_export_list(
mut export_list: Term,
- atom_tbl: TabledData<Atom>,
+ atom_tbl: &mut AtomTable,
) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![];
while let Term::Cons(_, t1, t2) = export_list {
- let module_export = setup_module_export(*t1, atom_tbl.clone())?;
+ let module_export = setup_module_export(*t1, atom_tbl)?;
exports.push(module_export);
export_list = *t2;
}
- if let Term::Constant(_, Constant::EmptyList) = export_list {
+ if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok(exports)
} else {
Err(CompilationError::InvalidModuleDecl)
@@ -186,98 +176,65 @@ pub(super) fn setup_module_export_list(
}
fn setup_module_decl(
- mut terms: Vec<Box<Term>>,
- atom_tbl: TabledData<Atom>,
+ mut terms: Vec<Term>,
+ atom_tbl: &mut AtomTable,
) -> Result<ModuleDecl, CompilationError> {
- let export_list = *terms.pop().unwrap();
- let name = terms
- .pop()
- .unwrap()
- .into_constant()
- .and_then(|c| c.to_atom())
- .ok_or(CompilationError::InvalidModuleDecl)?;
+ let export_list = terms.pop().unwrap();
+ let name = terms.pop().unwrap();
+
+ let name = match name {
+ Term::Literal(_, Literal::Atom(name)) => Some(name),
+ _ => None,
+ }.ok_or(CompilationError::InvalidModuleDecl)?;
let exports = setup_module_export_list(export_list, atom_tbl)?;
+
Ok(ModuleDecl { name, exports })
}
-fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, CompilationError> {
- match *terms.pop().unwrap() {
- Term::Clause(_, ref name, ref mut terms, None)
- if name.as_str() == "library" && terms.len() == 1 =>
+fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
+ match terms.pop().unwrap() {
+ Term::Clause(_, name, mut terms)
+ if name == atom!("library") && terms.len() == 1 =>
{
- terms
- .pop()
- .unwrap()
- .into_constant()
- .and_then(|c| c.to_atom())
- .map(|c| ModuleSource::Library(c))
- .ok_or(CompilationError::InvalidUseModuleDecl)
+ match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
+ _ => Err(CompilationError::InvalidModuleDecl),
+ }
}
- Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
_ => Err(CompilationError::InvalidUseModuleDecl),
}
}
-/*
-fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, CompilationError> {
- 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(CompilationError::InvalidDoubleQuotesDecl),
- }
- }
- _ => {
- Err(CompilationError::InvalidDoubleQuotesDecl)
- }
- }
- },
- _ => {
- Err(CompilationError::InvalidDoubleQuotesDecl)
- }
- }
-}
- */
-
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import(
- mut terms: Vec<Box<Term>>,
- atom_tbl: TabledData<Atom>,
+ mut terms: Vec<Term>,
+ atom_tbl: &mut AtomTable,
) -> Result<UseModuleExport, CompilationError> {
- let mut export_list = *terms.pop().unwrap();
- let module_src = match *terms.pop().unwrap() {
- Term::Clause(_, ref name, ref mut terms, None)
- if name.as_str() == "library" && terms.len() == 1 =>
+ let mut export_list = terms.pop().unwrap();
+ let module_src = match terms.pop().unwrap() {
+ Term::Clause(_, name, mut terms)
+ if name == atom!("library") && terms.len() == 1 =>
{
- terms
- .pop()
- .unwrap()
- .into_constant()
- .and_then(|c| c.to_atom())
- .map(|c| ModuleSource::Library(c))
- .ok_or(CompilationError::InvalidUseModuleDecl)
+ match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
+ _ => Err(CompilationError::InvalidModuleDecl),
+ }
}
- Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
_ => Err(CompilationError::InvalidUseModuleDecl),
}?;
let mut exports = IndexSet::new();
while let Term::Cons(_, t1, t2) = export_list {
- exports.insert(setup_module_export(*t1, atom_tbl.clone())?);
+ exports.insert(setup_module_export(*t1, atom_tbl)?);
export_list = *t2;
}
- if let Term::Constant(_, Constant::EmptyList) = export_list {
+ if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok((module_src, exports))
} else {
Err(CompilationError::InvalidModuleDecl)
@@ -322,29 +279,29 @@ fn setup_qualified_import(
* -
* ?
*/
-fn setup_meta_predicate<'a>(
- mut terms: Vec<Box<Term>>,
- load_state: &LoadState<'a>,
-) -> Result<(ClauseName, ClauseName, Vec<MetaSpec>), CompilationError> {
+fn setup_meta_predicate<'a, LS: LoadState<'a>>(
+ mut terms: Vec<Term>,
+ loader: &mut Loader<'a, LS>,
+) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
fn get_name_and_meta_specs(
- name: ClauseName,
- terms: &mut [Box<Term>],
- ) -> Result<(ClauseName, Vec<MetaSpec>), CompilationError> {
+ name: Atom,
+ terms: &mut [Term],
+ ) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
let mut meta_specs = vec![];
for meta_spec in terms.into_iter() {
- match &**meta_spec {
- Term::Constant(_, Constant::Atom(meta_spec, _)) => {
- let meta_spec = match meta_spec.as_str() {
- "+" => MetaSpec::Plus,
- "-" => MetaSpec::Minus,
- "?" => MetaSpec::Either,
+ match meta_spec {
+ Term::Literal(_, Literal::Atom(meta_spec)) => {
+ let meta_spec = match meta_spec {
+ atom!("+") => MetaSpec::Plus,
+ atom!("-") => MetaSpec::Minus,
+ atom!("?") => MetaSpec::Either,
_ => return Err(CompilationError::InvalidMetaPredicateDecl),
};
meta_specs.push(meta_spec);
}
- Term::Constant(_, Constant::Fixnum(n)) => match usize::try_from(*n) {
+ Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
Ok(n) if n <= MAX_ARITY => {
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
}
@@ -361,16 +318,15 @@ fn setup_meta_predicate<'a>(
Ok((name, meta_specs))
}
- match *terms.pop().unwrap() {
- Term::Clause(_, name, mut terms, _) if name.as_str() == ":" && terms.len() == 2 => {
- let spec = *terms.pop().unwrap();
- let module_name = *terms.pop().unwrap();
+ match terms.pop().unwrap() {
+ Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
+ let spec = terms.pop().unwrap();
+ let module_name = terms.pop().unwrap();
match module_name {
- Term::Constant(_, Constant::Atom(module_name, _)) => match spec {
- Term::Clause(_, name, mut terms, _) => {
+ Term::Literal(_, Literal::Atom(module_name)) => match spec {
+ Term::Clause(_, name, mut terms) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
-
Ok((module_name, name, meta_specs))
}
_ => Err(CompilationError::InvalidMetaPredicateDecl),
@@ -378,10 +334,10 @@ fn setup_meta_predicate<'a>(
_ => Err(CompilationError::InvalidMetaPredicateDecl),
}
}
- Term::Clause(_, name, mut terms, _) => {
+ Term::Clause(_, name, mut terms) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
Ok((
- load_state.compilation_target.module_name(),
+ loader.payload.compilation_target.module_name(),
name,
meta_specs,
))
@@ -420,11 +376,11 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationEr
}
}
-fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
+fn mark_cut_variables_as(terms: &mut Vec<Term>, name: Atom) {
for term in terms.iter_mut() {
match term {
- &mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => {
- *var = name.clone()
+ &mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => {
+ *var = name;
}
_ => {}
}
@@ -433,12 +389,12 @@ fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
fn mark_cut_variable(term: &mut Term) -> bool {
let cut_var_found = match term {
- &mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true,
+ &mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true,
_ => false,
};
if cut_var_found {
- *term = Term::Var(Cell::default(), rc_atom!("!"));
+ *term = Term::Var(Cell::default(), Rc::new(String::from("!")));
true
} else {
false
@@ -463,21 +419,21 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
return;
}
- if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() {
- if name.as_str() != "->" || subterms.len() != 2 {
+ if let Some(Term::Clause(_, name, ref subterms)) = terms.last() {
+ if *name != atom!("->") || subterms.len() != 2 {
return;
}
} else {
return;
}
- if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() {
- let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
- let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
+ if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() {
+ let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
+ let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
- conq_terms.push_front(Term::Constant(
+ conq_terms.push_front(Term::Literal(
Cell::default(),
- Constant::Atom(clause_name!("blocked_!"), None),
+ Literal::Atom(atom!("blocked_!")),
));
while let Some(term) = pre_cut_terms.pop_back() {
@@ -489,37 +445,44 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
terms.push(fold_by_str(
conq_terms.into_iter(),
tail_term,
- clause_name!(","),
+ atom!(","),
));
}
}
-pub(super) fn setup_declaration<'a>(
- load_state: &LoadState<'a>,
- mut terms: Vec<Box<Term>>,
+pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
+ loader: &mut Loader<'a, LS>,
+ mut terms: Vec<Term>,
) -> Result<Declaration, CompilationError> {
- let term = *terms.pop().unwrap();
- let atom_tbl = load_state.wam.machine_st.atom_tbl.clone();
+ let term = terms.pop().unwrap();
match term {
- Term::Clause(_, name, mut terms, _) => match (name.as_str(), terms.len()) {
- ("dynamic", 1) => {
- let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
+ Term::Clause(_, name, mut terms) => match (name, terms.len()) {
+ (atom!("dynamic"), 1) => {
+ let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
Ok(Declaration::Dynamic(name, arity))
}
- ("module", 2) => Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)),
- ("op", 3) => Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)),
- ("non_counted_backtracking", 1) => {
- let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
+ (atom!("module"), 2) => {
+ let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
+ Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?))
+ }
+ (atom!("op"), 3) => {
+ let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
+ Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?))
+ }
+ (atom!("non_counted_backtracking"), 1) => {
+ let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
Ok(Declaration::NonCountedBacktracking(name, arity))
}
- ("use_module", 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
- ("use_module", 2) => {
+ (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
+ (atom!("use_module"), 2) => {
+ let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
+
Ok(Declaration::UseQualifiedModule(name, exports))
}
- ("meta_predicate", 1) => {
- let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?;
+ (atom!("meta_predicate"), 1) => {
+ let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
}
_ => Err(CompilationError::InconsistentEntry),
@@ -529,25 +492,23 @@ pub(super) fn setup_declaration<'a>(
}
#[inline]
-fn clause_to_query_term<'a>(
- load_state: &mut LoadState<'a>,
- name: ClauseName,
- terms: Vec<Box<Term>>,
- fixity: Option<SharedOpDesc>,
+fn clause_to_query_term<'a, LS: LoadState<'a>>(
+ loader: &mut Loader<'a, LS>,
+ name: Atom,
+ terms: Vec<Term>,
) -> QueryTerm {
- let ct = load_state.get_clause_type(name, terms.len(), fixity);
+ let ct = loader.get_clause_type(name, terms.len());
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
#[inline]
-fn qualified_clause_to_query_term<'a>(
- load_state: &mut LoadState<'a>,
- module_name: ClauseName,
- name: ClauseName,
- terms: Vec<Box<Term>>,
- fixity: Option<SharedOpDesc>,
+fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
+ loader: &mut Loader<'a, LS>,
+ module_name: Atom,
+ name: Atom,
+ terms: Vec<Term>,
) -> QueryTerm {
- let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity);
+ let ct = loader.get_qualified_clause_type(module_name, name, terms.len());
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
@@ -565,7 +526,7 @@ impl Preprocessor {
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
match term {
- Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term),
+ Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
_ => Err(CompilationError::InadmissibleFact),
}
}
@@ -579,20 +540,17 @@ impl Preprocessor {
}
}
- vars.insert(rc_atom!("!"));
+ vars.insert(Rc::new(String::from("!")));
vars.into_iter()
.map(|v| Term::Var(Cell::default(), v))
.collect()
}
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
- let vars_of_head = vars.iter().cloned().map(Box::new).collect();
- let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None);
-
- let rule = vec![Box::new(head_term), Box::new(body_term)];
- let turnstile = clause_name!(":-");
+ let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone());
+ let rule = vec![head_term, body_term];
- Term::Clause(Cell::default(), turnstile, rule, None)
+ Term::Clause(Cell::default(), atom!(":-"), rule)
}
// the terms form the body of the rule. We create a head, by
@@ -609,16 +567,16 @@ impl Preprocessor {
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = self.compute_head(&body_term);
- let results = unfold_by_str(body_term, ";")
+ let results = unfold_by_str(body_term, atom!(";"))
.into_iter()
.map(|term| {
- let mut subterms = unfold_by_str(term, ",");
+ let mut subterms = unfold_by_str(term, atom!(","));
mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap();
- let clause = fold_by_str(subterms.into_iter(), term, clause_name!(","));
+ let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
self.fabricate_rule_body(&vars, clause)
})
@@ -628,80 +586,78 @@ impl Preprocessor {
}
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
- let mut prec_seq = unfold_by_str(prec, ",");
- let comma_sym = clause_name!(",");
- let cut_sym = atom!("!");
+ let mut prec_seq = unfold_by_str(prec, atom!(","));
+ let comma_sym = atom!(",");
+ let cut_sym = Literal::Atom(atom!("!"));
- prec_seq.push(Term::Constant(Cell::default(), cut_sym));
+ prec_seq.push(Term::Literal(Cell::default(), cut_sym));
- mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!"));
+ mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
- let mut conq_seq = unfold_by_str(conq, ",");
+ let mut conq_seq = unfold_by_str(conq, atom!(","));
mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter());
- let back_term = Box::new(prec_seq.pop().unwrap());
- let front_term = Box::new(prec_seq.pop().unwrap());
+ let back_term = prec_seq.pop().unwrap();
+ let front_term = prec_seq.pop().unwrap();
let body_term = Term::Clause(
Cell::default(),
- comma_sym.clone(),
+ comma_sym,
vec![front_term, back_term],
- None,
);
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
- fn to_query_term<'a>(
+ fn to_query_term<'a, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
+ loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
- Term::Constant(_, Constant::Atom(name, fixity)) => {
- if name.as_str() == "!" || name.as_str() == "blocked_!" {
+ Term::Literal(_, Literal::Atom(name)) => {
+ if name == atom!("!") || name == atom!("blocked_!") {
Ok(QueryTerm::BlockedCut)
} else {
- Ok(clause_to_query_term(load_state, name, vec![], fixity))
+ Ok(clause_to_query_term(loader, name, vec![]))
}
}
- Term::Constant(_, Constant::Char('!')) => Ok(QueryTerm::BlockedCut),
+ Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
Term::Var(_, ref v) if v.as_str() == "!" => {
Ok(QueryTerm::UnblockedCut(Cell::default()))
}
- Term::Clause(r, name, mut terms, fixity) => match (name.as_str(), terms.len()) {
- (";", 2) => {
- let term = Term::Clause(r, name.clone(), terms, fixity);
+ Term::Clause(r, name, mut terms) => match (name, terms.len()) {
+ (atom!(";"), 2) => {
+ let term = Term::Clause(r, name, terms);
let (stub, clauses) = self.fabricate_disjunct(term);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
- ("->", 2) => {
- let conq = *terms.pop().unwrap();
- let prec = *terms.pop().unwrap();
+ (atom!("->"), 2) => {
+ let conq = terms.pop().unwrap();
+ let prec = terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
- ("\\+", 1) => {
- terms.push(Box::new(Term::Constant(
+ (atom!("\\+"), 1) => {
+ terms.push(Term::Literal(
Cell::default(),
- Constant::Atom(clause_name!("$fail"), None),
- )));
+ Literal::Atom(atom!("$fail")),
+ ));
- let conq =
- Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None));
+ let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
- let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
- let terms = vec![Box::new(prec), Box::new(conq)];
+ let prec = Term::Clause(Cell::default(), atom!("->"), terms);
+ let terms = vec![prec, conq];
- let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
+ let term = Term::Clause(Cell::default(), atom!(";"), terms);
let (stub, clauses) = self.fabricate_disjunct(term);
debug_assert!(clauses.len() > 0);
@@ -709,104 +665,102 @@ impl Preprocessor {
Ok(QueryTerm::Jump(stub))
}
- ("$get_level", 1) => {
- if let Term::Var(_, ref var) = *terms[0] {
+ (atom!("$get_level"), 1) => {
+ if let Term::Var(_, ref var) = &terms[0] {
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
} else {
Err(CompilationError::InadmissibleQueryTerm)
}
}
- (":", 2) => {
- let predicate_name = *terms.pop().unwrap();
- let module_name = *terms.pop().unwrap();
+ (atom!(":"), 2) => {
+ let predicate_name = terms.pop().unwrap();
+ let module_name = terms.pop().unwrap();
match (module_name, predicate_name) {
(
- Term::Constant(_, Constant::Atom(module_name, _)),
- Term::Constant(_, Constant::Atom(predicate_name, fixity)),
+ Term::Literal(_, Literal::Atom(module_name)),
+ Term::Literal(_, Literal::Atom(predicate_name)),
) => Ok(qualified_clause_to_query_term(
- load_state,
+ loader,
module_name,
predicate_name,
vec![],
- fixity,
)),
(
- Term::Constant(_, Constant::Atom(module_name, _)),
- Term::Clause(_, name, terms, fixity),
+ Term::Literal(_, Literal::Atom(module_name)),
+ Term::Clause(_, name, terms),
) => Ok(qualified_clause_to_query_term(
- load_state,
+ loader,
module_name,
name,
terms,
- fixity,
)),
(module_name, predicate_name) => {
- terms.push(Box::new(module_name));
- terms.push(Box::new(predicate_name));
+ terms.push(module_name);
+ terms.push(predicate_name);
- Ok(clause_to_query_term(load_state, name, terms, fixity))
+ Ok(clause_to_query_term(loader, name, terms))
}
}
}
- _ => Ok(clause_to_query_term(load_state, name, terms, fixity)),
+ _ => Ok(clause_to_query_term(loader, name, terms)),
},
Term::Var(..) => Ok(QueryTerm::Clause(
Cell::default(),
- ClauseType::CallN,
- vec![Box::new(term)],
+ ClauseType::CallN(1),
+ vec![term],
false,
)),
_ => Err(CompilationError::InadmissibleQueryTerm),
}
}
- fn pre_query_term<'a>(
+ fn pre_query_term<'a, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
+ loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
- Term::Clause(r, name, mut subterms, fixity) => {
- if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
- self.to_query_term(load_state, *subterms.pop().unwrap())
+ Term::Clause(r, name, mut subterms) => {
+ if subterms.len() == 1 && name == atom!("$call_with_default_policy") {
+ self.to_query_term(loader, subterms.pop().unwrap())
.map(|mut query_term| {
query_term.set_default_caller();
query_term
})
} else {
- let clause = Term::Clause(r, name, subterms, fixity);
- self.to_query_term(load_state, clause)
+ let clause = Term::Clause(r, name, subterms);
+ self.to_query_term(loader, clause)
}
}
- _ => self.to_query_term(load_state, term),
+ _ => self.to_query_term(loader, term),
}
}
- fn setup_query<'a>(
+ fn setup_query<'a, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
- terms: Vec<Box<Term>>,
+ loader: &mut Loader<'a, LS>,
+ terms: Vec<Term>,
cut_context: CutContext,
) -> Result<Vec<QueryTerm>, CompilationError> {
let mut query_terms = vec![];
let mut work_queue = VecDeque::from(terms);
while let Some(term) = work_queue.pop_front() {
- let mut term = *term;
+ let mut term = term;
- if let Term::Clause(cell, name, terms, op_spec) = term {
- if name.as_str() == "," && terms.len() == 2 {
- let term = Term::Clause(cell, name, terms, op_spec);
- let mut subterms = unfold_by_str(term, ",");
+ if let Term::Clause(cell, name, terms) = term {
+ if name == atom!(",") && terms.len() == 2 {
+ let term = Term::Clause(cell, name, terms);
+ let mut subterms = unfold_by_str(term, atom!(","));
while let Some(subterm) = subterms.pop() {
- work_queue.push_front(Box::new(subterm));
+ work_queue.push_front(subterm);
}
continue;
} else {
- term = Term::Clause(cell, name, terms, op_spec);
+ term = Term::Clause(cell, name, terms);
}
}
@@ -814,30 +768,30 @@ impl Preprocessor {
mark_cut_variable(&mut term);
}
- query_terms.push(self.pre_query_term(load_state, term)?);
+ query_terms.push(self.pre_query_term(loader, term)?);
}
Ok(query_terms)
}
- fn setup_rule<'a>(
+ fn setup_rule<'a, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
- mut terms: Vec<Box<Term>>,
+ loader: &mut Loader<'a, LS>,
+ mut terms: Vec<Term>,
cut_context: CutContext,
) -> Result<Rule, CompilationError> {
let post_head_terms: Vec<_> = terms.drain(1..).collect();
- let mut query_terms = self.setup_query(load_state, post_head_terms, cut_context)?;
+ let mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?;
let clauses = query_terms.drain(1..).collect();
let qt = query_terms.pop().unwrap();
- match *terms.pop().unwrap() {
- Term::Clause(_, name, terms, _) => Ok(Rule {
+ match terms.pop().unwrap() {
+ Term::Clause(_, name, terms) => Ok(Rule {
head: (name, terms, qt),
clauses,
}),
- Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule {
+ Term::Literal(_, Literal::Atom(name)) => Ok(Rule {
head: (name, vec![], qt),
clauses,
}),
@@ -845,37 +799,37 @@ impl Preprocessor {
}
}
- fn try_term_to_query<'a>(
+ fn try_term_to_query<'a, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
- terms: Vec<Box<Term>>,
+ loader: &mut Loader<'a, LS>,
+ terms: Vec<Term>,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
Ok(TopLevel::Query(self.setup_query(
- load_state,
+ loader,
terms,
cut_context,
)?))
}
- pub(super) fn try_term_to_tl<'a>(
+ pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
+ loader: &mut Loader<'a, LS>,
term: Term,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
match term {
- Term::Clause(r, name, terms, fixity) => {
- if name.as_str() == "?-" {
- self.try_term_to_query(load_state, terms, cut_context)
- } else if name.as_str() == ":-" && terms.len() == 2 {
+ Term::Clause(r, name, terms) => {
+ if name == atom!("?-") {
+ self.try_term_to_query(loader, terms, cut_context)
+ } else if name == atom!(":-") && terms.len() == 2 {
Ok(TopLevel::Rule(self.setup_rule(
- load_state,
+ loader,
terms,
cut_context,
)?))
} else {
- let term = Term::Clause(r, name, terms, fixity);
+ let term = Term::Clause(r, name, terms);
Ok(TopLevel::Fact(self.setup_fact(term)?))
}
}
@@ -883,30 +837,30 @@ impl Preprocessor {
}
}
- fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>>(
+ fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
+ loader: &mut Loader<'a, LS>,
terms: I,
cut_context: CutContext,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut results = VecDeque::new();
for term in terms.into_iter() {
- results.push_back(self.try_term_to_tl(load_state, term, cut_context)?);
+ results.push_back(self.try_term_to_tl(loader, term, cut_context)?);
}
Ok(results)
}
- pub(super) fn parse_queue<'a>(
+ pub(super) fn parse_queue<'a, LS: LoadState<'a>>(
&mut self,
- load_state: &mut LoadState<'a>,
+ loader: &mut Loader<'a, LS>,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut queue = VecDeque::new();
while let Some(terms) = self.queue.pop_front() {
let clauses = merge_clauses(&mut self.try_terms_to_tls(
- load_state,
+ loader,
terms,
CutContext::HasCutVariable,
)?)?;
diff --git a/src/machine/stack.rs b/src/machine/stack.rs
index a3c91713..388c3008 100644
--- a/src/machine/stack.rs
+++ b/src/machine/stack.rs
@@ -1,16 +1,13 @@
use core::marker::PhantomData;
-use crate::machine::machine_indices::*;
-use crate::machine::raw_block::*;
+use crate::raw_block::*;
+use crate::types::*;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
-#[derive(Debug)]
-struct StackTraits {}
-
-impl RawBlockTraits for StackTraits {
+impl RawBlockTraits for Stack {
#[inline]
fn init_size() -> usize {
10 * 1024 * 1024
@@ -18,31 +15,23 @@ impl RawBlockTraits for StackTraits {
#[inline]
fn align() -> usize {
- mem::align_of::<Addr>()
- }
-
- #[inline]
- fn base_offset(base: *const u8) -> *const u8 {
- unsafe { base.offset(Self::align() as isize) }
+ mem::align_of::<HeapCellValue>()
}
}
-const fn prelude_size<Prelude>() -> usize {
- let size = mem::size_of::<Prelude>();
- let align = mem::align_of::<Addr>();
-
- (size & !(align - 1)) + align
+#[inline(always)]
+pub const fn prelude_size<Prelude>() -> usize {
+ mem::size_of::<Prelude>()
}
#[derive(Debug)]
-pub(crate) struct Stack {
- buf: RawBlock<StackTraits>,
- _marker: PhantomData<Addr>,
+pub struct Stack {
+ buf: RawBlock<Stack>,
+ _marker: PhantomData<HeapCellValue>,
}
impl Drop for Stack {
fn drop(&mut self) {
- self.drop_in_place();
self.buf.deallocate();
}
}
@@ -56,8 +45,7 @@ pub(crate) struct FramePrelude {
pub(crate) struct AndFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize,
- pub(crate) cp: LocalCodePtr,
- pub(crate) interrupt_cp: LocalCodePtr,
+ pub(crate) cp: usize,
}
#[derive(Debug)]
@@ -67,22 +55,22 @@ pub(crate) struct AndFrame {
impl AndFrame {
pub(crate) fn size_of(num_cells: usize) -> usize {
- prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<Addr>()
+ prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<HeapCellValue>()
}
}
impl Index<usize> for AndFrame {
- type Output = Addr;
+ type Output = HeapCellValue;
fn index(&self, index: usize) -> &Self::Output {
let prelude_offset = prelude_size::<AndFramePrelude>();
- let index_offset = (index - 1) * mem::size_of::<Addr>();
+ let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&AndFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
- &*(ptr as *const Addr)
+ &*(ptr as *const HeapCellValue)
}
}
}
@@ -90,13 +78,35 @@ impl Index<usize> for AndFrame {
impl IndexMut<usize> for AndFrame {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let prelude_offset = prelude_size::<AndFramePrelude>();
- let index_offset = (index - 1) * mem::size_of::<Addr>();
+ let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
- &mut *(ptr as *mut Addr)
+ &mut *(ptr as *mut HeapCellValue)
+ }
+ }
+}
+
+impl Index<usize> for Stack {
+ type Output = HeapCellValue;
+
+ #[inline]
+ fn index(&self, index: usize) -> &Self::Output {
+ unsafe {
+ let ptr = self.buf.base as usize + index;
+ &*(ptr as *const HeapCellValue)
+ }
+ }
+}
+
+impl IndexMut<usize> for Stack {
+ #[inline]
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ unsafe {
+ let ptr = self.buf.base as usize + index;
+ &mut *(ptr as *mut HeapCellValue)
}
}
}
@@ -105,9 +115,11 @@ impl IndexMut<usize> for AndFrame {
pub(crate) struct OrFramePrelude {
pub(crate) univ_prelude: FramePrelude,
pub(crate) e: usize,
- pub(crate) cp: LocalCodePtr,
+ pub(crate) cp: usize,
pub(crate) b: usize,
- pub(crate) bp: LocalCodePtr,
+ pub(crate) bp: usize,
+ pub(crate) boip: u32,
+ pub(crate) biip: u32,
pub(crate) tr: usize,
pub(crate) h: usize,
pub(crate) b0: usize,
@@ -119,18 +131,18 @@ pub(crate) struct OrFrame {
}
impl Index<usize> for OrFrame {
- type Output = Addr;
+ type Output = HeapCellValue;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>();
- let index_offset = index * mem::size_of::<Addr>();
+ let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
- &*(ptr as *const Addr)
+ &*(ptr as *const HeapCellValue)
}
}
}
@@ -139,20 +151,20 @@ impl IndexMut<usize> for OrFrame {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let prelude_offset = prelude_size::<OrFramePrelude>();
- let index_offset = index * mem::size_of::<Addr>();
+ let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
let ptr = ptr as usize + prelude_offset + index_offset;
- &mut *(ptr as *mut Addr)
+ &mut *(ptr as *mut HeapCellValue)
}
}
}
impl OrFrame {
pub(crate) fn size_of(num_cells: usize) -> usize {
- prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
+ prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<HeapCellValue>()
}
}
@@ -164,26 +176,39 @@ impl Stack {
}
}
+ #[inline(always)]
+ unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
+ loop {
+ let ptr = self.buf.alloc(frame_size);
+
+ if ptr.is_null() {
+ self.buf.grow();
+ } else {
+ return ptr;
+ }
+ }
+ }
+
pub(crate) fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
let frame_size = AndFrame::size_of(num_cells);
unsafe {
- let new_top = self.buf.new_block(frame_size);
- let e = self.buf.top as usize - self.buf.base as usize;
+ let e = self.buf.ptr as usize - self.buf.base as usize;
+ let new_ptr = self.alloc(frame_size);
+ let mut offset = prelude_size::<AndFramePrelude>();
for idx in 0..num_cells {
- let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
- (self.buf.top as usize + offset) as *mut Addr,
- Addr::StackCell(e, idx + 1),
+ (new_ptr as usize + offset) as *mut HeapCellValue,
+ stack_loc_as_cell!(AndFrame, e, idx + 1),
);
+
+ offset += mem::size_of::<HeapCellValue>();
}
- let and_frame = &mut *(self.buf.top as *mut AndFrame);
+ let and_frame = &mut *(new_ptr as *mut AndFrame);
and_frame.prelude.univ_prelude.num_cells = num_cells;
- self.buf.top = new_top;
-
e
}
}
@@ -192,27 +217,27 @@ impl Stack {
let frame_size = OrFrame::size_of(num_cells);
unsafe {
- let new_top = self.buf.new_block(frame_size);
- let b = self.buf.top as usize - self.buf.base as usize;
+ let b = self.buf.ptr as usize - self.buf.base as usize;
+ let new_ptr = self.alloc(frame_size);
+ let mut offset = prelude_size::<OrFramePrelude>();
for idx in 0..num_cells {
- let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
ptr::write(
- (self.buf.top as usize + offset) as *mut Addr,
- Addr::StackCell(b, idx),
+ (new_ptr as usize + offset) as *mut HeapCellValue,
+ stack_loc_as_cell!(OrFrame, b, idx),
);
+
+ offset += mem::size_of::<HeapCellValue>();
}
- let or_frame = &mut *(self.buf.top as *mut OrFrame);
+ let or_frame = &mut *(new_ptr as *mut OrFrame);
or_frame.prelude.univ_prelude.num_cells = num_cells;
- self.buf.top = new_top;
-
b
}
}
- #[inline]
+ #[inline(always)]
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
unsafe {
let ptr = self.buf.base as usize + e;
@@ -220,7 +245,7 @@ impl Stack {
}
}
- #[inline]
+ #[inline(always)]
pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
unsafe {
let ptr = self.buf.base as usize + e;
@@ -228,7 +253,7 @@ impl Stack {
}
}
- #[inline]
+ #[inline(always)]
pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
@@ -236,7 +261,7 @@ impl Stack {
}
}
- #[inline]
+ #[inline(always)]
pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
@@ -244,31 +269,65 @@ impl Stack {
}
}
- #[inline]
+ #[inline(always)]
pub(crate) fn truncate(&mut self, b: usize) {
- if b == 0 {
- self.inner_truncate(mem::align_of::<Addr>());
- } else {
- self.inner_truncate(b);
+ let base = self.buf.base as usize + b;
+
+ if base < self.buf.ptr as usize {
+ self.buf.ptr = base as *mut _;
}
}
+}
- #[inline]
- fn inner_truncate(&mut self, b: usize) {
- let base = b + self.buf.base as usize;
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::machine::mock_wam::*;
+
+ #[test]
+ fn stack_tests() {
+ let mut wam = MockWAM::new();
- if base < self.buf.top as usize {
- self.buf.top = base as *const _;
+ let e = wam.machine_st.stack.allocate_and_frame(10); // create an AND frame!
+ let and_frame = wam.machine_st.stack.index_and_frame_mut(e);
+
+ assert_eq!(
+ e,
+ 0// 10 * mem::size_of::<HeapCellValue>() + prelude_size::<AndFrame>()
+ );
+
+ assert_eq!(and_frame.prelude.univ_prelude.num_cells, 10);
+
+ for idx in 0..10 {
+ assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, e, idx + 1));
+ }
+
+ and_frame[5] = empty_list_as_cell!();
+
+ assert_eq!(and_frame[5], empty_list_as_cell!());
+
+ let b = wam.machine_st.stack.allocate_or_frame(5);
+
+ let or_frame = wam.machine_st.stack.index_or_frame_mut(b);
+
+ for idx in 0..5 {
+ assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx));
+ }
+
+ let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame!
+ let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e);
+
+ for idx in 0..9 {
+ assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1));
}
- }
- pub(crate) fn drop_in_place(&mut self) {
- self.truncate(mem::align_of::<Addr>());
+ let and_frame = wam.machine_st.stack.index_and_frame(e);
+ assert_eq!(and_frame[5], empty_list_as_cell!());
- debug_assert!(if self.buf.top.is_null() {
- self.buf.top == self.buf.base
- } else {
- self.buf.top as usize == self.buf.base as usize + mem::align_of::<Addr>()
- });
+ assert_eq!(
+ wam.machine_st.stack[stack_loc!(AndFrame, e, 5)],
+ empty_list_as_cell!()
+ );
}
}
diff --git a/src/machine/streams.rs b/src/machine/streams.rs
index 69f66022..9d76c898 100644
--- a/src/machine/streams.rs
+++ b/src/machine/streams.rs
@@ -1,47 +1,52 @@
-use prolog_parser::ast::*;
-use prolog_parser::clause_name;
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::parser::ast::*;
+use crate::parser::char_reader::*;
+use crate::read::*;
+use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
-use crate::read::readline::*;
-use crate::read::PrologStream;
+use crate::types::*;
+
+pub use modular_bitfield::prelude::*;
-use std::cell::RefCell;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
-use std::fs::File;
-use std::hash::{Hash, Hasher};
+use std::fs::{File, OpenOptions};
+use std::hash::{Hash};
use std::io;
-use std::io::{stderr, stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
+use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
use std::mem;
-use std::net::{Shutdown, TcpStream};
-use std::ops::DerefMut;
-use std::rc::Rc;
+use std::net::{TcpStream, Shutdown};
+use std::ops::{Deref, DerefMut};
+use std::ptr;
use native_tls::TlsStream;
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) enum StreamType {
+#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
+#[bits = 1]
+pub enum StreamType {
Binary,
Text,
}
impl StreamType {
#[inline]
- pub(crate) fn as_str(&self) -> &'static str {
+ pub(crate) fn as_atom(&self) -> Atom {
match self {
- StreamType::Binary => "binary_stream",
- StreamType::Text => "text_stream",
+ StreamType::Binary => atom!("binary_stream"),
+ StreamType::Text => atom!("text_stream"),
}
}
#[inline]
- pub(crate) fn as_property_str(&self) -> &'static str {
+ pub(crate) fn as_property_atom(&self) -> Atom {
match self {
- StreamType::Binary => "binary",
- StreamType::Text => "text",
+ StreamType::Binary => atom!("binary"),
+ StreamType::Text => atom!("text"),
}
}
@@ -54,14 +59,16 @@ impl StreamType {
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) enum EOFAction {
+#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
+#[bits = 2]
+pub enum EOFAction {
EOFCode,
Error,
Reset,
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, BitfieldSpecifier, Copy, Clone, PartialEq)]
+#[bits = 2]
pub(crate) enum AtEndOfStream {
Not,
At,
@@ -70,165 +77,633 @@ pub(crate) enum AtEndOfStream {
impl AtEndOfStream {
#[inline]
- pub(crate) fn as_str(&self) -> &'static str {
+ pub(crate) fn as_atom(&self) -> Atom {
match self {
- AtEndOfStream::Not => "not",
- AtEndOfStream::Past => "past",
- AtEndOfStream::At => "at",
+ AtEndOfStream::Not => atom!("not"),
+ AtEndOfStream::Past => atom!("past"),
+ AtEndOfStream::At => atom!("at"),
}
}
}
impl EOFAction {
#[inline]
- pub(crate) fn as_str(&self) -> &'static str {
+ pub(crate) fn as_atom(&self) -> Atom {
match self {
- EOFAction::EOFCode => "eof_code",
- EOFAction::Error => "error",
- EOFAction::Reset => "reset",
+ EOFAction::EOFCode => atom!("eof_code"),
+ EOFAction::Error => atom!("error"),
+ EOFAction::Reset => atom!("reset"),
}
}
}
-fn parser_top_to_bytes(mut buf: Vec<io::Result<char>>) -> io::Result<Vec<u8>> {
- let mut str_buf = String::new();
+#[derive(Debug)]
+pub struct ByteStream(Cursor<Vec<u8>>);
+
+impl Read for ByteStream {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ self.0.read(buf)
+ }
+}
+
+impl Write for ByteStream {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ let pos = self.0.position();
- while let Some(c) = buf.pop() {
- str_buf.push(c?);
+ self.0.seek(SeekFrom::End(0))?;
+ let result = self.0.write(buf);
+ self.0.seek(SeekFrom::Start(pos))?;
+
+ result
}
- unsafe {
- let array = str_buf.as_bytes_mut();
- array.reverse();
- Ok(Vec::from(array))
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ self.0.flush()
}
}
-/* all these streams are closed automatically when the instance is
- * dropped. */
-enum StreamInstance {
- Bytes(Cursor<Vec<u8>>),
- InputFile(ClauseName, File),
- OutputFile(ClauseName, File, bool), // File, append.
- Null,
- PausedPrologStream(Vec<u8>, Box<StreamInstance>),
- ReadlineStream(ReadlineStream),
- StaticStr(Cursor<&'static str>),
- Stderr,
- Stdout,
- TcpStream(ClauseName, TcpStream),
- TlsStream(ClauseName, TlsStream<Stream>),
+#[derive(Debug)]
+pub struct InputFileStream {
+ file_name: Atom,
+ file: File,
}
-impl StreamInstance {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- match self {
- StreamInstance::PausedPrologStream(ref mut put_back, ref mut stream) => {
- let mut index = 0;
+impl Read for InputFileStream {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ self.file.read(buf)
+ }
+}
- while index < buf.len() {
- if let Some(b) = put_back.pop() {
- buf[index] = b;
- index += 1;
- } else {
- break;
- }
- }
+#[derive(Debug)]
+pub struct OutputFileStream {
+ file_name: Atom,
+ file: File,
+ is_append: bool,
+}
- if index == buf.len() {
- Ok(buf.len())
- } else {
- stream
- .read(&mut buf[index..])
- .map(|bytes_read| bytes_read + index)
+impl Write for OutputFileStream {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ self.file.write(buf)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ self.file.flush()
+ }
+}
+
+#[derive(Debug)]
+pub struct StaticStringStream {
+ stream: Cursor<&'static str>,
+}
+
+impl Read for StaticStringStream {
+ #[inline(always)]
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ self.stream.read(buf)
+ }
+}
+
+impl CharRead for StaticStringStream {
+ #[inline(always)]
+ fn peek_char(&mut self) -> Option<std::io::Result<char>> {
+ let pos = self.stream.position() as usize;
+ self.stream.get_ref()[pos ..].chars().next().map(Ok)
+ }
+
+ #[inline(always)]
+ fn consume(&mut self, nread: usize) {
+ self.stream.seek(SeekFrom::Current(nread as i64)).unwrap();
+ }
+
+ #[inline(always)]
+ fn put_back_char(&mut self, c: char) {
+ self.stream.seek(SeekFrom::Current(- (c.len_utf8() as i64))).unwrap();
+ }
+}
+
+#[derive(Debug)]
+pub struct NamedTcpStream {
+ address: Atom,
+ tcp_stream: TcpStream,
+}
+
+impl Read for NamedTcpStream {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ self.tcp_stream.read(buf)
+ }
+}
+
+impl Write for NamedTcpStream {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ self.tcp_stream.write(buf)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ self.tcp_stream.flush()
+ }
+}
+
+#[derive(Debug)]
+pub struct NamedTlsStream {
+ address: Atom,
+ tls_stream: TlsStream<Stream>,
+}
+
+impl Read for NamedTlsStream {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ self.tls_stream.read(buf)
+ }
+}
+
+impl Write for NamedTlsStream {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ self.tls_stream.write(buf)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ self.tls_stream.flush()
+ }
+}
+
+#[derive(Debug)]
+pub struct StandardOutputStream {}
+
+impl Write for StandardOutputStream {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ io::stdout().write(buf)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ io::stdout().flush()
+ }
+}
+
+#[derive(Debug)]
+pub struct StandardErrorStream {}
+
+impl Write for StandardErrorStream {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ io::stderr().write(buf)
+ }
+
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ io::stderr().flush()
+ }
+}
+
+#[bitfield]
+#[repr(u64)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct StreamOptions {
+ pub stream_type: StreamType,
+ pub reposition: bool,
+ pub eof_action: EOFAction,
+ pub has_alias: bool,
+ pub alias: B59,
+}
+
+impl StreamOptions {
+ #[inline]
+ pub fn get_alias(self) -> Option<Atom> {
+ if self.has_alias() {
+ Some(Atom::from((self.alias() << 3) as usize))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn set_alias_to_atom_opt(&mut self, alias: Option<Atom>) {
+ self.set_has_alias(alias.is_some());
+
+ if let Some(alias) = alias {
+ self.set_alias(alias.flat_index());
+ }
+ }
+}
+
+impl Default for StreamOptions {
+ #[inline]
+ fn default() -> Self {
+ StreamOptions::new()
+ .with_stream_type(StreamType::Text)
+ .with_reposition(false)
+ .with_eof_action(EOFAction::EOFCode)
+ .with_has_alias(false)
+ .with_alias(0)
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct StreamLayout<T> {
+ pub options: StreamOptions,
+ pub lines_read: usize,
+ past_end_of_stream: bool,
+ stream: T,
+}
+
+impl<T> StreamLayout<T> {
+ #[inline]
+ pub fn new(stream: T) -> Self {
+ Self {
+ options: StreamOptions::default(),
+ lines_read: 0,
+ past_end_of_stream: false,
+ stream,
+ }
+ }
+}
+
+impl<T> Deref for StreamLayout<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.stream
+ }
+}
+
+impl<T> DerefMut for StreamLayout<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.stream
+ }
+}
+
+macro_rules! arena_allocated_impl_for_stream {
+ ($stream_type:ty, $stream_tag:ident) => {
+ impl ArenaAllocated for StreamLayout<$stream_type> {
+ type PtrToAllocated = TypedArenaPtr<StreamLayout<$stream_type>>;
+
+ #[inline]
+ fn tag() -> ArenaHeaderTag {
+ ArenaHeaderTag::$stream_tag
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ mem::size_of::<StreamLayout<$stream_type>>()
+ }
+
+ #[inline]
+ fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
+ unsafe {
+ ptr::write(dst, self);
+ TypedArenaPtr::new(dst as *mut Self)
}
}
- StreamInstance::InputFile(_, ref mut file) => file.read(buf),
- StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.read(buf),
- StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.read(buf),
- StreamInstance::ReadlineStream(ref mut rl_stream) => rl_stream.read(buf),
- StreamInstance::StaticStr(ref mut src) => src.read(buf),
- StreamInstance::Bytes(ref mut cursor) => cursor.read(buf),
- StreamInstance::OutputFile(..)
- | StreamInstance::Stderr
- | StreamInstance::Stdout
- | StreamInstance::Null => Err(std::io::Error::new(
- ErrorKind::PermissionDenied,
- StreamError::ReadFromOutputStream,
- )),
}
+ };
+}
+
+arena_allocated_impl_for_stream!(CharReader<ByteStream>, ByteStream);
+arena_allocated_impl_for_stream!(CharReader<InputFileStream>, InputFileStream);
+arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream);
+arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream);
+arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream);
+arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream);
+arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream);
+arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
+arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream);
+
+#[derive(Debug, Copy, Clone)]
+pub enum Stream {
+ Byte(TypedArenaPtr<StreamLayout<CharReader<ByteStream>>>),
+ InputFile(TypedArenaPtr<StreamLayout<CharReader<InputFileStream>>>),
+ OutputFile(TypedArenaPtr<StreamLayout<OutputFileStream>>),
+ StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
+ NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
+ NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
+ Null(StreamOptions),
+ Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
+ StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>),
+ StandardError(TypedArenaPtr<StreamLayout<StandardErrorStream>>),
+}
+
+impl From<TypedArenaPtr<StreamLayout<ReadlineStream>>> for Stream {
+ #[inline]
+ fn from(stream: TypedArenaPtr<StreamLayout<ReadlineStream>>) -> Stream {
+ Stream::Readline(stream)
}
}
-impl fmt::Debug for StreamInstance {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &StreamInstance::Bytes(ref bytes) => write!(fmt, "Bytes({:?})", bytes),
- &StreamInstance::StaticStr(_) => write!(fmt, "StaticStr(_)"), // Hacky solution.
- &StreamInstance::InputFile(_, ref file) => write!(fmt, "InputFile({:?})", file),
- &StreamInstance::OutputFile(_, ref file, _) => write!(fmt, "OutputFile({:?})", file),
- &StreamInstance::Null => write!(fmt, "Null"),
- &StreamInstance::PausedPrologStream(ref put_back, ref stream) => {
- write!(fmt, "PausedPrologStream({:?}, {:?})", put_back, stream)
+impl Stream {
+ #[inline]
+ pub fn from_readline_stream(stream: ReadlineStream, arena: &mut Arena) -> Stream {
+ Stream::Readline(arena_alloc!(StreamLayout::new(stream), arena))
+ }
+
+ #[inline]
+ pub fn from_owned_string(string: String, arena: &mut Arena) -> Stream {
+ Stream::Byte(arena_alloc!(
+ StreamLayout::new(CharReader::new(ByteStream(Cursor::new(string.into_bytes())))),
+ arena
+ ))
+ }
+
+ #[inline]
+ pub fn from_static_string(src: &'static str, arena: &mut Arena) -> Stream {
+ Stream::StaticString(arena_alloc!(
+ StreamLayout::new(StaticStringStream {
+ stream: Cursor::new(src)
+ }),
+ arena
+ ))
+ }
+
+ #[inline]
+ pub fn stdin(arena: &mut Arena) -> Stream {
+ Stream::Readline(arena_alloc!(
+ StreamLayout::new(ReadlineStream::new("")),
+ arena
+ ))
+ }
+
+ pub fn from_tag(tag: ArenaHeaderTag, ptr: *const u8) -> Self {
+ match tag {
+ ArenaHeaderTag::ByteStream => Stream::Byte(TypedArenaPtr::new(ptr as *mut _)),
+ ArenaHeaderTag::InputFileStream => Stream::InputFile(TypedArenaPtr::new(ptr as *mut _)),
+ ArenaHeaderTag::OutputFileStream => {
+ Stream::OutputFile(TypedArenaPtr::new(ptr as *mut _))
}
- &StreamInstance::ReadlineStream(ref readline_stream) => {
- write!(fmt, "ReadlineStream({:?})", readline_stream)
+ ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
+ ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
+ ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
+ ArenaHeaderTag::StaticStringStream => {
+ Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
}
- &StreamInstance::Stderr => write!(fmt, "Stderr"),
- &StreamInstance::Stdout => write!(fmt, "Stdout"),
- &StreamInstance::TcpStream(_, ref tcp_stream) => {
- write!(fmt, "TcpStream({:?})", tcp_stream)
+ ArenaHeaderTag::StandardOutputStream => {
+ Stream::StandardOutput(TypedArenaPtr::new(ptr as *mut _))
}
- &StreamInstance::TlsStream(_, ref tls_stream) => {
- write!(fmt, "TlsStream({:?})", tls_stream)
+ ArenaHeaderTag::StandardErrorStream => {
+ Stream::StandardError(TypedArenaPtr::new(ptr as *mut _))
}
+ ArenaHeaderTag::NullStream => Stream::Null(StreamOptions::default()),
+ _ => unreachable!(),
}
}
-}
-#[derive(Debug)]
-pub(crate) struct InnerStream {
- options: StreamOptions,
- stream_inst: StreamInstance,
- past_end_of_stream: bool,
- lines_read: usize,
-}
+ #[inline]
+ pub fn is_stderr(&self) -> bool {
+ if let Stream::StandardError(_) = self {
+ true
+ } else {
+ false
+ }
+ }
-#[derive(Debug, Clone)]
-struct WrappedStreamInstance(Rc<RefCell<InnerStream>>);
+ #[inline]
+ pub fn is_stdout(&self) -> bool {
+ if let Stream::StandardOutput(_) = self {
+ true
+ } else {
+ false
+ }
+ }
-impl WrappedStreamInstance {
#[inline]
- fn new(stream_inst: StreamInstance, past_end_of_stream: bool) -> Self {
- WrappedStreamInstance(Rc::new(RefCell::new(InnerStream {
- options: StreamOptions::default(),
- stream_inst,
- past_end_of_stream,
- lines_read: 0,
- })))
+ pub fn is_stdin(&self) -> bool {
+ if let Stream::Readline(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn as_ptr(&self) -> *const ArenaHeader {
+ match self {
+ Stream::Byte(ptr) => ptr.header_ptr(),
+ Stream::InputFile(ptr) => ptr.header_ptr(),
+ Stream::OutputFile(ptr) => ptr.header_ptr(),
+ Stream::StaticString(ptr) => ptr.header_ptr(),
+ Stream::NamedTcp(ptr) => ptr.header_ptr(),
+ Stream::NamedTls(ptr) => ptr.header_ptr(),
+ Stream::Null(_) => ptr::null(),
+ Stream::Readline(ptr) => ptr.header_ptr(),
+ Stream::StandardOutput(ptr) => ptr.header_ptr(),
+ Stream::StandardError(ptr) => ptr.header_ptr(),
+ }
+ }
+
+ pub fn options(&self) -> &StreamOptions {
+ match self {
+ Stream::Byte(ref ptr) => &ptr.options,
+ Stream::InputFile(ref ptr) => &ptr.options,
+ Stream::OutputFile(ref ptr) => &ptr.options,
+ Stream::StaticString(ref ptr) => &ptr.options,
+ Stream::NamedTcp(ref ptr) => &ptr.options,
+ Stream::NamedTls(ref ptr) => &ptr.options,
+ Stream::Null(ref options) => options,
+ Stream::Readline(ref ptr) => &ptr.options,
+ Stream::StandardOutput(ref ptr) => &ptr.options,
+ Stream::StandardError(ref ptr) => &ptr.options,
+ }
+ }
+
+ pub fn options_mut(&mut self) -> &mut StreamOptions {
+ match self {
+ Stream::Byte(ref mut ptr) => &mut ptr.options,
+ Stream::InputFile(ref mut ptr) => &mut ptr.options,
+ Stream::OutputFile(ref mut ptr) => &mut ptr.options,
+ Stream::StaticString(ref mut ptr) => &mut ptr.options,
+ Stream::NamedTcp(ref mut ptr) => &mut ptr.options,
+ Stream::NamedTls(ref mut ptr) => &mut ptr.options,
+ Stream::Null(ref mut options) => options,
+ Stream::Readline(ref mut ptr) => &mut ptr.options,
+ Stream::StandardOutput(ref mut ptr) => &mut ptr.options,
+ Stream::StandardError(ref mut ptr) => &mut ptr.options,
+ }
}
-}
-impl PartialEq for WrappedStreamInstance {
#[inline]
- fn eq(&self, other: &Self) -> bool {
- Rc::ptr_eq(&self.0, &other.0)
+ pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) {
+ match self {
+ Stream::Byte(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::InputFile(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::OutputFile(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::Null(_) => {}
+ Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read,
+ Stream::StandardError(ptr) => ptr.lines_read += incr_num_lines_read,
+ }
+ }
+
+ #[inline]
+ pub(crate) fn set_lines_read(&mut self, value: usize) {
+ match self {
+ Stream::Byte(ptr) => ptr.lines_read = value,
+ Stream::InputFile(ptr) => ptr.lines_read = value,
+ Stream::OutputFile(ptr) => ptr.lines_read = value,
+ Stream::StaticString(ptr) => ptr.lines_read = value,
+ Stream::NamedTcp(ptr) => ptr.lines_read = value,
+ Stream::NamedTls(ptr) => ptr.lines_read = value,
+ Stream::Null(_) => {}
+ Stream::Readline(ptr) => ptr.lines_read = value,
+ Stream::StandardOutput(ptr) => ptr.lines_read = value,
+ Stream::StandardError(ptr) => ptr.lines_read = value,
+ }
+ }
+
+ #[inline]
+ pub(crate) fn lines_read(&self) -> usize {
+ match self {
+ Stream::Byte(ptr) => ptr.lines_read,
+ Stream::InputFile(ptr) => ptr.lines_read,
+ Stream::OutputFile(ptr) => ptr.lines_read,
+ Stream::StaticString(ptr) => ptr.lines_read,
+ Stream::NamedTcp(ptr) => ptr.lines_read,
+ Stream::NamedTls(ptr) => ptr.lines_read,
+ Stream::Null(_) => 0,
+ Stream::Readline(ptr) => ptr.lines_read,
+ Stream::StandardOutput(ptr) => ptr.lines_read,
+ Stream::StandardError(ptr) => ptr.lines_read,
+ }
}
}
-impl Eq for WrappedStreamInstance {}
+impl CharRead for Stream {
+ fn peek_char(&mut self) -> Option<std::io::Result<char>> {
+ match self {
+ Stream::InputFile(file) => (*file).peek_char(),
+ Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(),
+ Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(),
+ Stream::Readline(rl_stream) => (*rl_stream).peek_char(),
+ Stream::StaticString(src) => (*src).peek_char(),
+ Stream::Byte(cursor) => (*cursor).peek_char(),
+ Stream::OutputFile(_) |
+ Stream::StandardError(_) |
+ Stream::StandardOutput(_) |
+ Stream::Null(_) => Some(Err(std::io::Error::new(
+ ErrorKind::PermissionDenied,
+ StreamError::ReadFromOutputStream,
+ ))),
+ }
+ }
-impl Hash for WrappedStreamInstance {
- fn hash<H: Hasher>(&self, state: &mut H) {
- let rc = &self.0;
- let ptr = Rc::into_raw(rc.clone());
+ fn read_char(&mut self) -> Option<std::io::Result<char>> {
+ match self {
+ Stream::InputFile(file) => (*file).read_char(),
+ Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(),
+ Stream::NamedTls(tls_stream) => (*tls_stream).read_char(),
+ Stream::Readline(rl_stream) => (*rl_stream).read_char(),
+ Stream::StaticString(src) => (*src).read_char(),
+ Stream::Byte(cursor) => (*cursor).read_char(),
+ Stream::OutputFile(_) |
+ Stream::StandardError(_) |
+ Stream::StandardOutput(_) |
+ Stream::Null(_) => Some(Err(std::io::Error::new(
+ ErrorKind::PermissionDenied,
+ StreamError::ReadFromOutputStream,
+ ))),
+ }
+ }
+
+ fn put_back_char(&mut self, c: char) {
+ match self {
+ Stream::InputFile(file) => file.put_back_char(c),
+ Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c),
+ Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c),
+ Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
+ Stream::StaticString(src) => src.put_back_char(c),
+ Stream::Byte(cursor) => cursor.put_back_char(c),
+ Stream::OutputFile(_) |
+ Stream::StandardError(_) |
+ Stream::StandardOutput(_) |
+ Stream::Null(_) => {}
+ }
+ }
- state.write_usize(ptr as usize);
+ fn consume(&mut self, nread: usize) {
+ match self {
+ Stream::InputFile(ref mut file) => file.consume(nread),
+ Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread),
+ Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread),
+ Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread),
+ Stream::StaticString(ref mut src) => src.consume(nread),
+ Stream::Byte(ref mut cursor) => cursor.consume(nread),
+ Stream::OutputFile(_) |
+ Stream::StandardError(_) |
+ Stream::StandardOutput(_) |
+ Stream::Null(_) => {}
+ }
+ }
+}
- unsafe {
- // necessary to avoid memory leak.
- let _ = Rc::from_raw(ptr);
+impl Read for Stream {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ let bytes_read = match self {
+ Stream::InputFile(file) => (*file).read(buf),
+ Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf),
+ Stream::NamedTls(tls_stream) => (*tls_stream).read(buf),
+ Stream::Readline(rl_stream) => (*rl_stream).read(buf),
+ Stream::StaticString(src) => (*src).read(buf),
+ Stream::Byte(cursor) => (*cursor).read(buf),
+ Stream::OutputFile(_)
+ | Stream::StandardError(_)
+ | Stream::StandardOutput(_)
+ | Stream::Null(_) => Err(std::io::Error::new(
+ ErrorKind::PermissionDenied,
+ StreamError::ReadFromOutputStream,
+ )),
};
+
+ bytes_read
+ }
+}
+
+impl Write for Stream {
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ match self {
+ Stream::OutputFile(ref mut file) => file.write(buf),
+ Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.get_mut().write(buf),
+ Stream::NamedTls(ref mut tls_stream) => tls_stream.get_mut().write(buf),
+ Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
+ Stream::StandardOutput(stream) => stream.write(buf),
+ Stream::StandardError(stream) => stream.write(buf),
+ Stream::StaticString(_) |
+ Stream::Readline(_) |
+ Stream::InputFile(..) |
+ Stream::Null(_) => Err(std::io::Error::new(
+ ErrorKind::PermissionDenied,
+ StreamError::WriteToInputStream,
+ )),
+ }
+ }
+
+ fn flush(&mut self) -> std::io::Result<()> {
+ match self {
+ Stream::OutputFile(ref mut file) => file.stream.flush(),
+ Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.stream.get_mut().flush(),
+ Stream::NamedTls(ref mut tls_stream) => tls_stream.stream.get_mut().flush(),
+ Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
+ Stream::StandardError(stream) => stream.stream.flush(),
+ Stream::StandardOutput(stream) => stream.stream.flush(),
+ Stream::StaticString(_) |
+ Stream::Readline(_) |
+ Stream::InputFile(_) |
+ Stream::Null(_) => Err(std::io::Error::new(
+ ErrorKind::PermissionDenied,
+ StreamError::FlushToInputStream,
+ )),
+ }
}
}
@@ -236,8 +711,8 @@ impl Hash for WrappedStreamInstance {
enum StreamError {
PeekByteFailed,
PeekByteFromNonPeekableStream,
- PeekCharFailed,
- PeekCharFromNonPeekableStream,
+ #[allow(unused)] PeekCharFailed,
+ #[allow(unused)] PeekCharFromNonPeekableStream,
ReadFromOutputStream,
WriteToInputStream,
FlushToInputStream,
@@ -273,31 +748,6 @@ impl fmt::Display for StreamError {
impl Error for StreamError {}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub(crate) struct StreamOptions {
- pub(crate) stream_type: StreamType,
- pub(crate) reposition: bool,
- pub(crate) alias: Option<ClauseName>,
- pub(crate) 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(Debug, Clone, Hash)]
-pub struct Stream {
- stream_inst: WrappedStreamInstance,
-}
-
impl PartialOrd for Stream {
#[inline]
fn partial_cmp(&self, other: &Stream) -> Option<Ordering> {
@@ -315,123 +765,44 @@ impl Ord for Stream {
impl PartialEq for Stream {
#[inline]
fn eq(&self, other: &Self) -> bool {
- self.stream_inst == other.stream_inst
+ self.as_ptr() == other.as_ptr()
}
}
impl Eq for Stream {}
-impl From<String> for Stream {
- fn from(string: String) -> Self {
- Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes())))
- }
-}
-
-impl From<ReadlineStream> for Stream {
- fn from(rl_stream: ReadlineStream) -> Self {
- Stream::from_inst(StreamInstance::ReadlineStream(rl_stream))
- }
-}
-
-impl From<&'static str> for Stream {
- fn from(src: &'static str) -> Stream {
- Stream::from_inst(StreamInstance::StaticStr(Cursor::new(src)))
- }
-}
-
impl Stream {
#[inline]
- pub(crate) fn as_ptr(&self) -> *const u8 {
- 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 as *const u8
- }
-
- pub fn bytes(&self) -> Option<std::cell::Ref<Vec<u8>>> {
- /*
- // Replacement of workaround for when we have stable https://github.com/rust-lang/rust/issues/81061
- std::cell::Ref::filter_map(
- self.stream_inst.0.borrow(),
- |inner_stream| match inner_stream.stream_inst {
- StreamInstance::Bytes(cursor) => Some(cursor.get_ref()),
- _ => None,
- },
- )
- .ok()
- */
- let val = std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| {
- &inner_stream.stream_inst
- });
- match std::ops::Deref::deref(&val) {
- StreamInstance::Bytes(_) => Some(std::cell::Ref::map(
- std::cell::Ref::clone(&val),
- |instance| match instance {
- StreamInstance::Bytes(cursor) => cursor.get_ref(),
- _ => unreachable!(),
- },
- )),
- _ => None,
- }
- }
-
- #[inline]
- pub(crate) fn lines_read(&mut self) -> usize {
- self.stream_inst.0.borrow_mut().lines_read
- }
-
- #[inline]
- pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) {
- self.stream_inst.0.borrow_mut().lines_read += incr_num_lines_read;
- }
-
- #[inline]
- pub(crate) fn options(&self) -> std::cell::Ref<'_, StreamOptions> {
- std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| {
- &inner_stream.options
- })
- }
-
- #[inline]
- pub(crate) fn options_mut(&mut self) -> std::cell::RefMut<'_, StreamOptions> {
- std::cell::RefMut::map(self.stream_inst.0.borrow_mut(), |inner_stream| {
- &mut inner_stream.options
- })
- }
-
- #[inline]
pub(crate) fn position(&mut self) -> Option<(u64, usize)> {
// returns lines_read, position.
- let result = match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::InputFile(_, ref mut file) => file.seek(SeekFrom::Current(0)).ok(),
- StreamInstance::TcpStream(..)
- | StreamInstance::TlsStream(..)
- | StreamInstance::ReadlineStream(..)
- | StreamInstance::StaticStr(..)
- | StreamInstance::PausedPrologStream(..)
- | StreamInstance::Bytes(..) => Some(0),
+ let result = match self {
+ Stream::InputFile(ref mut file_stream) => {
+ file_stream.get_mut().file.seek(SeekFrom::Current(0)).ok()
+ }
+ Stream::NamedTcp(..)
+ | Stream::NamedTls(..)
+ | Stream::Readline(..)
+ | Stream::StaticString(..)
+ | Stream::Byte(..) => Some(0),
_ => None,
};
- result.map(|position| (position, self.stream_inst.0.borrow().lines_read))
+ result.map(|position| (position, self.lines_read()))
}
#[inline]
pub(crate) fn set_position(&mut self, position: u64) {
- match self.stream_inst.0.borrow_mut().deref_mut() {
- InnerStream {
- past_end_of_stream,
- stream_inst: StreamInstance::InputFile(_, ref mut file),
- ..
- } => {
- file.seek(SeekFrom::Start(position)).unwrap();
+ match self {
+ Stream::InputFile(stream_layout) => {
+ let StreamLayout {
+ past_end_of_stream,
+ stream,
+ ..
+ } = &mut **stream_layout;
+
+ stream.get_mut().file.seek(SeekFrom::Start(position)).unwrap();
- if let Ok(metadata) = file.metadata() {
+ if let Ok(metadata) = stream.get_ref().file.metadata() {
*past_end_of_stream = position > metadata.len();
}
}
@@ -441,7 +812,19 @@ impl Stream {
#[inline]
pub(crate) fn past_end_of_stream(&self) -> bool {
- self.stream_inst.0.borrow_mut().past_end_of_stream
+ match self {
+ Stream::Byte(stream) => stream.past_end_of_stream,
+ Stream::InputFile(stream) => stream.past_end_of_stream,
+ Stream::OutputFile(stream) => stream.past_end_of_stream,
+ // Stream::PausedProlog(stream) => stream.paused_stream.past_end_of_stream(),
+ Stream::StaticString(stream) => stream.past_end_of_stream,
+ Stream::NamedTcp(stream) => stream.past_end_of_stream,
+ Stream::NamedTls(stream) => stream.past_end_of_stream,
+ Stream::Null(_) => false,
+ Stream::Readline(stream) => stream.past_end_of_stream,
+ Stream::StandardOutput(stream) => stream.past_end_of_stream,
+ Stream::StandardError(stream) => stream.past_end_of_stream,
+ }
}
#[inline]
@@ -450,8 +833,19 @@ impl Stream {
}
#[inline]
- pub(crate) fn set_past_end_of_stream(&mut self) {
- self.stream_inst.0.borrow_mut().past_end_of_stream = true;
+ pub(crate) fn set_past_end_of_stream(&mut self, value: bool) {
+ match self {
+ Stream::Byte(stream) => stream.past_end_of_stream = value,
+ Stream::InputFile(stream) => stream.past_end_of_stream = value,
+ Stream::OutputFile(stream) => stream.past_end_of_stream = value,
+ Stream::StaticString(stream) => stream.past_end_of_stream = value,
+ Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
+ Stream::NamedTls(stream) => stream.past_end_of_stream = value,
+ Stream::Null(_) => {}
+ Stream::Readline(stream) => stream.past_end_of_stream = value,
+ Stream::StandardOutput(stream) => stream.past_end_of_stream = value,
+ Stream::StandardError(stream) => stream.past_end_of_stream = value,
+ }
}
#[inline]
@@ -460,14 +854,16 @@ impl Stream {
return AtEndOfStream::Past;
}
- match self.stream_inst.0.borrow_mut().deref_mut() {
- InnerStream {
+ if let Stream::InputFile(stream_layout) = self {
+ let StreamLayout {
past_end_of_stream,
- stream_inst: StreamInstance::InputFile(_, ref mut file),
+ stream,
..
- } => match file.metadata() {
+ } = &mut **stream_layout;
+
+ match stream.get_ref().file.metadata() {
Ok(metadata) => {
- if let Ok(position) = file.seek(SeekFrom::Current(0)) {
+ if let Ok(position) = stream.get_mut().file.seek(SeekFrom::Current(0)) {
return match position.cmp(&metadata.len()) {
Ordering::Equal => AtEndOfStream::At,
Ordering::Less => AtEndOfStream::Not,
@@ -485,120 +881,130 @@ impl Stream {
*past_end_of_stream = true;
AtEndOfStream::Past
}
- },
- _ => AtEndOfStream::Not,
+ }
+ } else {
+ AtEndOfStream::Not
}
}
#[inline]
- pub(crate) fn file_name(&self) -> Option<ClauseName> {
- match self.stream_inst.0.borrow().stream_inst {
- StreamInstance::InputFile(ref name, _) => Some(name.clone()),
- StreamInstance::OutputFile(ref name, ..) => Some(name.clone()),
- StreamInstance::TcpStream(ref name, _) => Some(name.clone()),
+ pub(crate) fn file_name(&self) -> Option<Atom> {
+ match self {
+ Stream::InputFile(file) => Some(file.stream.get_ref().file_name),
+ Stream::OutputFile(file) => Some(file.stream.file_name),
+ Stream::NamedTcp(tcp) => Some(tcp.stream.get_ref().address),
+ Stream::NamedTls(tls) => Some(tls.stream.get_ref().address),
_ => None,
}
}
#[inline]
- pub(crate) fn mode(&self) -> &'static str {
- match self.stream_inst.0.borrow().stream_inst {
- StreamInstance::Bytes(_)
- | StreamInstance::PausedPrologStream(..)
- | StreamInstance::ReadlineStream(_)
- | StreamInstance::StaticStr(_)
- | StreamInstance::InputFile(..) => "read",
- StreamInstance::TcpStream(..) | StreamInstance::TlsStream(..) => "read_append",
- StreamInstance::OutputFile(_, _, true) => "append",
- StreamInstance::Stderr
- | StreamInstance::Stdout
- | StreamInstance::OutputFile(_, _, false) => "write",
- StreamInstance::Null => "",
- }
- }
-
- #[inline]
- fn from_inst(stream_inst: StreamInstance) -> Self {
- Stream {
- stream_inst: WrappedStreamInstance::new(stream_inst, false),
+ pub(crate) fn mode(&self) -> Atom {
+ match self {
+ Stream::Byte(_)
+ | Stream::Readline(_)
+ | Stream::StaticString(_)
+ | Stream::InputFile(..) => atom!("read"),
+ Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
+ Stream::OutputFile(file) if file.is_append => atom!("append"),
+ Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"),
+ Stream::Null(_) => atom!(""),
}
}
#[inline]
- pub fn stdout() -> Self {
- Stream::from_inst(StreamInstance::Stdout)
+ pub fn stdout(arena: &mut Arena) -> Self {
+ Stream::StandardOutput(arena_alloc!(
+ StreamLayout::new(StandardOutputStream {}),
+ arena
+ ))
}
#[inline]
- pub fn stderr() -> Self {
- Stream::from_inst(StreamInstance::Stderr)
+ pub fn stderr(arena: &mut Arena) -> Self {
+ Stream::StandardError(arena_alloc!(
+ StreamLayout::new(StandardErrorStream {}),
+ arena
+ ))
}
#[inline]
- pub(crate) fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self {
+ pub(crate) fn from_tcp_stream(
+ address: Atom,
+ tcp_stream: TcpStream,
+ arena: &mut Arena,
+ ) -> Self {
tcp_stream.set_read_timeout(None).unwrap();
tcp_stream.set_write_timeout(None).unwrap();
- Stream::from_inst(StreamInstance::TcpStream(address, tcp_stream))
+ Stream::NamedTcp(arena_alloc!(
+ StreamLayout::new(CharReader::new(NamedTcpStream {
+ address,
+ tcp_stream
+ })),
+ arena
+ ))
}
#[inline]
- pub(crate) fn from_tls_stream(address: ClauseName, tls_stream: TlsStream<Stream>) -> Self {
- Stream::from_inst(StreamInstance::TlsStream(address, tls_stream))
+ pub(crate) fn from_tls_stream(
+ address: Atom,
+ tls_stream: TlsStream<Stream>,
+ arena: &mut Arena,
+ ) -> Self {
+ Stream::NamedTls(arena_alloc!(
+ StreamLayout::new(CharReader::new(NamedTlsStream {
+ address,
+ tls_stream
+ })),
+ arena
+ ))
}
#[inline]
- pub(crate) fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self {
- Stream::from_inst(StreamInstance::OutputFile(name, file, in_append_mode))
+ pub(crate) fn from_file_as_output(
+ file_name: Atom,
+ file: File,
+ is_append: bool,
+ arena: &mut Arena,
+ ) -> Self {
+ Stream::OutputFile(arena_alloc!(
+ StreamLayout::new(OutputFileStream {
+ file_name,
+ file,
+ is_append
+ }),
+ arena
+ ))
}
#[inline]
- pub(crate) fn from_file_as_input(name: ClauseName, file: File) -> Self {
- Stream::from_inst(StreamInstance::InputFile(name, file))
- }
-
- #[inline]
- pub(crate) fn is_stderr(&self) -> bool {
- match self.stream_inst.0.borrow().stream_inst {
- StreamInstance::Stderr => true,
- _ => false,
- }
- }
-
- #[inline]
- pub(crate) fn is_stdout(&self) -> bool {
- match self.stream_inst.0.borrow().stream_inst {
- StreamInstance::Stdout => true,
- _ => false,
- }
- }
-
- #[inline]
- pub(crate) fn is_stdin(&self) -> bool {
- match self.stream_inst.0.borrow().stream_inst {
- StreamInstance::ReadlineStream(_) => true,
- _ => false,
- }
+ pub(crate) fn from_file_as_input(file_name: Atom, file: File, arena: &mut Arena) -> Self {
+ Stream::InputFile(arena_alloc!(
+ StreamLayout::new(CharReader::new(InputFileStream { file_name, file })),
+ arena
+ ))
}
#[inline]
pub(crate) fn close(&mut self) -> Result<(), std::io::Error> {
- let result = match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::TcpStream(_, ref mut tcp_stream) => {
- tcp_stream.shutdown(Shutdown::Both)
+ let result = match self {
+ Stream::NamedTcp(ref mut tcp_stream) => {
+ tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both)
},
- StreamInstance::TlsStream(_, ref mut tls_stream) => {
- tls_stream.shutdown()
+ Stream::NamedTls(ref mut tls_stream) => {
+ tls_stream.inner_mut().tls_stream.shutdown()
}
_ => Ok(())
};
- self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::Null;
+
+ *self = Stream::Null(StreamOptions::default());
result
}
#[inline]
pub(crate) fn is_null_stream(&self) -> bool {
- if let StreamInstance::Null = self.stream_inst.0.borrow().stream_inst {
+ if let Stream::Null(_) = self {
true
} else {
false
@@ -607,98 +1013,78 @@ impl Stream {
#[inline]
pub(crate) fn is_input_stream(&self) -> bool {
- match self.stream_inst.0.borrow().stream_inst {
- StreamInstance::TcpStream(..)
- | StreamInstance::TlsStream(..)
- | StreamInstance::Bytes(_)
- | StreamInstance::PausedPrologStream(..)
- | StreamInstance::ReadlineStream(_)
- | StreamInstance::StaticStr(_)
- | StreamInstance::InputFile(..) => true,
+ match self {
+ Stream::NamedTcp(..)
+ | Stream::NamedTls(..)
+ | Stream::Byte(_)
+ | Stream::Readline(_)
+ | Stream::StaticString(_)
+ | Stream::InputFile(..) => true,
_ => false,
}
}
#[inline]
pub(crate) fn is_output_stream(&self) -> bool {
- match self.stream_inst.0.borrow().stream_inst {
- StreamInstance::Stderr
- | StreamInstance::Stdout
- | StreamInstance::TcpStream(..)
- | StreamInstance::TlsStream(..)
- | StreamInstance::Bytes(_)
- | StreamInstance::OutputFile(..) => true,
+ match self {
+ Stream::StandardError(_)
+ | Stream::StandardOutput(_)
+ | Stream::NamedTcp(..)
+ | Stream::NamedTls(..)
+ | Stream::Byte(_)
+ | Stream::OutputFile(..) => true,
_ => false,
}
}
- fn unpause_stream(&mut self) {
- let stream_inst = match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::PausedPrologStream(ref put_back, ref mut stream_inst)
- if put_back.is_empty() =>
- {
- mem::replace(&mut **stream_inst, StreamInstance::Null)
- }
- _ => {
- return;
- }
- };
-
- self.stream_inst.0.borrow_mut().stream_inst = stream_inst;
- }
-
// returns true on success.
#[inline]
pub(super) fn reset(&mut self) -> bool {
- self.stream_inst.0.borrow_mut().lines_read = 0;
- self.stream_inst.0.borrow_mut().past_end_of_stream = false;
+ self.set_lines_read(0);
+ self.set_past_end_of_stream(false);
loop {
- match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::Bytes(ref mut cursor) => {
- cursor.set_position(0);
+ match self {
+ Stream::Byte(ref mut cursor) => {
+ cursor.stream.get_mut().0.set_position(0);
return true;
}
- StreamInstance::InputFile(_, ref mut file) => {
- file.seek(SeekFrom::Start(0)).unwrap();
+ Stream::InputFile(ref mut file_stream) => {
+ file_stream.stream.get_mut().file.seek(SeekFrom::Start(0)).unwrap();
return true;
}
- StreamInstance::PausedPrologStream(ref mut put_back, _) => {
- put_back.clear();
- }
- StreamInstance::ReadlineStream(_) => {
+ Stream::Readline(ref mut readline_stream) => {
+ readline_stream.reset();
return true;
}
_ => {
return false;
}
}
-
- self.unpause_stream();
}
}
#[inline]
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
- match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::Bytes(ref mut cursor) => {
+ match self {
+ Stream::Byte(ref mut cursor) => {
let mut b = [0u8; 1];
- let pos = cursor.position();
+ let pos = cursor.stream.get_mut().0.position();
match cursor.read(&mut b)? {
1 => {
- cursor.set_position(pos);
+ cursor.stream.get_mut().0.set_position(pos);
Ok(b[0])
}
_ => Err(std::io::Error::new(ErrorKind::UnexpectedEof, "end of file")),
}
}
- StreamInstance::InputFile(_, ref mut file) => {
+ Stream::InputFile(ref mut file) => {
let mut b = [0u8; 1];
match file.read(&mut b)? {
1 => {
- file.seek(SeekFrom::Current(-1))?;
+ file.stream.get_mut().file.seek(SeekFrom::Current(-1))?;
Ok(b[0])
}
_ => Err(std::io::Error::new(
@@ -707,10 +1093,10 @@ impl Stream {
)),
}
}
- StreamInstance::ReadlineStream(ref mut stream) => stream.peek_byte(),
- StreamInstance::TcpStream(_, ref mut tcp_stream) => {
+ Stream::Readline(ref mut stream) => stream.stream.peek_byte(),
+ Stream::NamedTcp(ref mut stream) => {
let mut b = [0u8; 1];
- tcp_stream.peek(&mut b)?;
+ stream.stream.get_mut().tcp_stream.peek(&mut b)?;
Ok(b[0])
}
_ => Err(std::io::Error::new(
@@ -719,113 +1105,37 @@ impl Stream {
)),
}
}
-
- #[inline]
- pub(crate) fn peek_char(&mut self) -> std::io::Result<char> {
- use unicode_reader::CodePoints;
-
- match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::InputFile(_, ref mut file) => {
- let c = {
- let mut iter = CodePoints::from(&*file);
-
- if let Some(Ok(c)) = iter.next() {
- c
- } else {
- return Err(std::io::Error::new(
- ErrorKind::UnexpectedEof,
- StreamError::PeekCharFailed,
- ));
- }
- };
-
- file.seek(SeekFrom::Current(-(c.len_utf8() as i64)))?;
-
- Ok(c)
- }
- StreamInstance::ReadlineStream(ref mut stream) => stream.peek_char(),
- StreamInstance::TcpStream(_, ref tcp_stream) => {
- let c = {
- let mut buf = [0u8; 8];
- tcp_stream.peek(&mut buf)?;
-
- let mut iter = CodePoints::from(buf.bytes());
-
- if let Some(Ok(c)) = iter.next() {
- c
- } else {
- return Err(std::io::Error::new(
- ErrorKind::UnexpectedEof,
- StreamError::PeekCharFailed,
- ));
- }
- };
-
- Ok(c)
- }
- _ => Err(std::io::Error::new(
- ErrorKind::PermissionDenied,
- StreamError::PeekCharFromNonPeekableStream,
- )),
- }
- }
-
- #[inline]
- pub(crate) fn pause_stream(&mut self, buf: Vec<io::Result<char>>) -> io::Result<()> {
- match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::PausedPrologStream(ref mut inner_buf, _) => {
- inner_buf.extend(parser_top_to_bytes(buf)?.into_iter());
- return Ok(());
- }
- _ => {}
- }
-
- if !buf.is_empty() {
- let stream_inst = mem::replace(
- &mut self.stream_inst.0.borrow_mut().stream_inst,
- StreamInstance::Null,
- );
-
- self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::PausedPrologStream(
- parser_top_to_bytes(buf)?,
- Box::new(stream_inst),
- );
- }
-
- Ok(())
- }
}
impl MachineState {
#[inline]
pub(crate) fn eof_action(
&mut self,
- result: Addr,
- stream: &mut Stream,
- caller: ClauseName,
+ result: HeapCellValue,
+ mut stream: Stream,
+ caller: Atom,
arity: usize,
) -> CallResult {
- let eof_action = stream.options().eof_action;
+ let eof_action = stream.options().eof_action();
match eof_action {
EOFAction::Error => {
- stream.set_past_end_of_stream();
- return Err(self.open_past_eos_error(stream.clone(), caller, arity));
+ stream.set_past_end_of_stream(true);
+ return Err(self.open_past_eos_error(stream, caller, arity));
}
EOFAction::EOFCode => {
- let end_of_stream = if stream.options().stream_type == StreamType::Binary {
- Addr::Fixnum(-1)
+ let end_of_stream = if stream.options().stream_type() == StreamType::Binary {
+ fixnum_as_cell!(Fixnum::build_with(-1))
} else {
- self.heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("end_of_file"), None))
+ atom_as_cell!(atom!("end_of_file"))
};
- stream.set_past_end_of_stream();
- Ok(self.unify(result, end_of_stream))
+ stream.set_past_end_of_stream(true);
+ Ok(unify!(self, result, end_of_stream))
}
EOFAction::Reset => {
if !stream.reset() {
- stream.set_past_end_of_stream();
+ stream.set_past_end_of_stream(true);
}
Ok(self.fail = stream.past_end_of_stream())
@@ -834,182 +1144,179 @@ impl MachineState {
}
pub(crate) fn to_stream_options(
- &self,
- alias: Addr,
- eof_action: Addr,
- reposition: Addr,
- stream_type: Addr,
+ &mut self,
+ alias: HeapCellValue,
+ eof_action: HeapCellValue,
+ reposition: HeapCellValue,
+ stream_type: HeapCellValue,
) -> StreamOptions {
- let alias = match self.store(self.deref(alias)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- Some(name.clone())
+ let alias = read_heap_cell!(self.store(MachineState::deref(self, alias)),
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+
+ if name != atom!("[]") {
+ Some(name)
} else {
- unreachable!()
+ None
}
}
- _ => None,
- };
+ _ => {
+ None
+ }
+ );
- let eof_action = match self.store(self.deref(eof_action)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- match name.as_str() {
- "eof_code" => EOFAction::EOFCode,
- "error" => EOFAction::Error,
- "reset" => EOFAction::Reset,
- _ => unreachable!(),
- }
- } else {
- unreachable!()
+ let eof_action = read_heap_cell!(self.store(MachineState::deref(self, eof_action)),
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+
+ match name {
+ atom!("eof_code") => EOFAction::EOFCode,
+ atom!("error") => EOFAction::Error,
+ atom!("reset") => EOFAction::Reset,
+ _ => unreachable!(),
}
}
_ => {
unreachable!()
}
- };
+ );
- let reposition = match self.store(self.deref(reposition)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- name.as_str() == "true"
- } else {
- unreachable!()
- }
+ let reposition = read_heap_cell!(self.store(MachineState::deref(self, reposition)),
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+ name == atom!("true")
}
_ => {
unreachable!()
}
- };
+ );
- let stream_type = match self.store(self.deref(stream_type)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- match name.as_str() {
- "text" => StreamType::Text,
- "binary" => StreamType::Binary,
- _ => unreachable!(),
- }
- } else {
- unreachable!()
+ let stream_type = read_heap_cell!(self.store(MachineState::deref(self, stream_type)),
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+ match name {
+ atom!("text") => StreamType::Text,
+ atom!("binary") => StreamType::Binary,
+ _ => unreachable!(),
}
}
_ => {
unreachable!()
}
- };
+ );
let mut options = StreamOptions::default();
- options.stream_type = stream_type;
- options.reposition = reposition;
- options.alias = alias;
- options.eof_action = eof_action;
+ options.set_stream_type(stream_type);
+ options.set_reposition(reposition);
+ options.set_alias_to_atom_opt(alias);
+ options.set_eof_action(eof_action);
options
}
pub(crate) fn get_stream_or_alias(
&mut self,
- addr: Addr,
+ addr: HeapCellValue,
stream_aliases: &StreamAliasDir,
- caller: &'static str,
+ caller: Atom,
arity: usize,
) -> Result<Stream, MachineStub> {
- Ok(match self.store(self.deref(addr)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) {
- match stream_aliases.get(atom) {
- Some(stream) if !stream.is_null_stream() => stream.clone(),
- _ => {
- let stub = MachineError::functor_stub(clause_name!(caller), arity);
-
- let addr = self
- .heap
- .to_unifiable(HeapCellValue::Atom(atom.clone(), spec.clone()));
-
- return Err(self.error_form(
- MachineError::existence_error(
- self.heap.h(),
- ExistenceError::Stream(addr),
- ),
- stub,
- ));
- }
+ let addr = self.store(MachineState::deref(self, addr));
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+
+ return match stream_aliases.get(&name) {
+ Some(stream) if !stream.is_null_stream() => Ok(*stream),
+ _ => {
+ let stub = functor_stub(caller, arity);
+ let addr = atom_as_cell!(name);
+
+ let existence_error = self.existence_error(ExistenceError::Stream(addr));
+
+ Err(self.error_form(existence_error, stub))
}
- } else {
- unreachable!()
- }
+ };
}
- Addr::Stream(h) => {
- if let HeapCellValue::Stream(ref stream) = &self.heap[h] {
- if stream.is_null_stream() {
- return Err(self.open_permission_error(Addr::Stream(h), caller, arity));
- } else {
- stream.clone()
- }
- } else {
- unreachable!()
- }
+ (HeapCellValueTag::Cons, ptr) => {
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Stream, stream) => {
+ return if stream.is_null_stream() {
+ Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
+ } else {
+ Ok(stream)
+ };
+ }
+ _ => {
+ }
+ );
}
- addr => {
- let stub = MachineError::functor_stub(clause_name!(caller), arity);
-
- if addr.is_ref() {
- return Err(self.error_form(MachineError::instantiation_error(), stub));
- } else {
- return Err(self.error_form(
- MachineError::domain_error(DomainErrorType::StreamOrAlias, addr),
- stub,
- ));
- }
+ _ => {
}
- })
+ );
+
+ let stub = functor_stub(caller, arity);
+
+ if addr.is_var() {
+ let instantiation_error = self.instantiation_error();
+ Err(self.error_form(instantiation_error, stub))
+ } else {
+ let domain_error = self.domain_error(DomainErrorType::StreamOrAlias, addr);
+ Err(self.error_form(domain_error, stub))
+ }
}
pub(crate) fn open_parsing_stream(
- &self,
- stream: Stream,
- stub_name: &'static str,
+ &mut self,
+ mut stream: Stream,
+ stub_name: Atom,
stub_arity: usize,
- ) -> Result<PrologStream, MachineStub> {
- match parsing_stream(stream) {
- Ok(parsing_stream) => Ok(parsing_stream),
- Err(e) => {
- let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity);
- let err = MachineError::session_error(self.heap.h(), SessionError::from(e));
+ ) -> Result<Stream, MachineStub> {
+ match stream.peek_char() {
+ None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
+ Some(Err(e)) => {
+ let err = self.session_error(SessionError::from(e));
+ let stub = functor_stub(stub_name, stub_arity);
Err(self.error_form(err, stub))
}
+ Some(Ok(c)) => {
+ if c == '\u{feff}' {
+ // skip UTF-8 BOM
+ stream.consume(c.len_utf8());
+ }
+
+ Ok(stream)
+ }
}
}
pub(crate) fn stream_permission_error(
- &self,
+ &mut self,
perm: Permission,
- err_string: &'static str,
+ err_atom: Atom,
stream: Stream,
- caller: ClauseName,
+ caller: Atom,
arity: usize,
) -> MachineStub {
- let stub = MachineError::functor_stub(caller, arity);
- let payload = vec![HeapCellValue::Stream(stream)];
-
- let err = MachineError::permission_error(self.heap.h(), perm, err_string, payload);
+ let stub = functor_stub(caller, arity);
+ let err = self.permission_error(perm, err_atom, stream_as_cell!(stream));
return self.error_form(err, stub);
}
#[inline]
pub(crate) fn open_past_eos_error(
- &self,
+ &mut self,
stream: Stream,
- caller: ClauseName,
+ caller: Atom,
arity: usize,
) -> MachineStub {
self.stream_permission_error(
Permission::InputStream,
- "past_end_of_stream",
+ atom!("past_end_of_stream"),
stream,
caller,
arity,
@@ -1017,67 +1324,58 @@ impl MachineState {
}
pub(crate) fn open_permission_error<T: PermissionError>(
- &self,
+ &mut self,
culprit: T,
- stub_name: &'static str,
+ stub_name: Atom,
stub_arity: usize,
) -> MachineStub {
- let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity);
- let err =
- MachineError::permission_error(self.heap.h(), Permission::Open, "source_sink", culprit);
+ let stub = functor_stub(stub_name, stub_arity);
+ let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit);
return self.error_form(err, stub);
}
pub(crate) fn occupied_alias_permission_error(
- &self,
- alias: ClauseName,
- stub_name: &'static str,
+ &mut self,
+ alias: Atom,
+ stub_name: Atom,
stub_arity: usize,
) -> MachineStub {
- let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity);
- let err = MachineError::permission_error(
- self.heap.h(),
+ let stub = functor_stub(stub_name, stub_arity);
+ let alias_name = atom!("alias");
+
+ let err = self.permission_error(
Permission::Open,
- "source_sink",
- functor!("alias", [clause_name(alias)]),
+ atom!("source_sink"),
+ functor!(alias_name, [atom(alias)]),
);
return self.error_form(err, stub);
}
- pub(crate) fn reposition_error(
- &self,
- stub_name: &'static str,
- stub_arity: usize,
- ) -> MachineStub {
- let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity);
- let rep_stub = functor!("reposition", [atom("true")]);
+ pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
+ let stub = functor_stub(stub_name, stub_arity);
- let err = MachineError::permission_error(
- self.heap.h(),
- Permission::Open,
- "source_sink",
- rep_stub,
- );
+ let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
+ let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
return self.error_form(err, stub);
}
pub(crate) fn check_stream_properties(
&mut self,
- stream: &mut Stream,
+ stream: Stream,
expected_type: StreamType,
- input: Option<Addr>,
- caller: ClauseName,
+ input: Option<HeapCellValue>,
+ caller: Atom,
arity: usize,
) -> CallResult {
let opt_err = if input.is_some() && !stream.is_input_stream() {
- Some("stream") // 8.14.2.3 g)
+ Some(atom!("stream")) // 8.14.2.3 g)
} else if input.is_none() && !stream.is_output_stream() {
- Some("stream") // 8.14.2.3 g)
- } else if stream.options().stream_type != expected_type {
- Some(expected_type.other().as_str()) // 8.14.2.3 h)
+ Some(atom!("stream")) // 8.14.2.3 g)
+ } else if stream.options().stream_type() != expected_type {
+ Some(expected_type.other().as_atom()) // 8.14.2.3 h)
} else {
None
};
@@ -1088,14 +1386,8 @@ impl MachineState {
Permission::OutputStream
};
- if let Some(err_string) = opt_err {
- return Err(self.stream_permission_error(
- permission,
- err_string,
- stream.clone(),
- caller,
- arity,
- ));
+ if let Some(err_atom) = opt_err {
+ return Err(self.stream_permission_error(permission, err_atom, stream, caller, arity));
}
if let Some(input) = input {
@@ -1106,53 +1398,96 @@ impl MachineState {
Ok(())
}
-}
-impl Read for Stream {
- #[inline]
- fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- let bytes_read = self.stream_inst.0.borrow_mut().stream_inst.read(buf)?;
- self.unpause_stream();
- Ok(bytes_read)
- }
-}
+ pub(crate) fn stream_from_file_spec(
+ &mut self,
+ file_spec: Atom,
+ indices: &mut IndexStore,
+ options: &StreamOptions,
+ ) -> Result<Stream, MachineStub> {
+ if file_spec == atom!("") {
+ let stub = functor_stub(atom!("open"), 4);
+ let err = self.domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]);
-impl Write for Stream {
- fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
- match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::OutputFile(_, ref mut file, _) => file.write(buf),
- StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.write(buf),
- StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.write(buf),
- StreamInstance::Bytes(ref mut cursor) => cursor.write(buf),
- StreamInstance::Stdout => stdout().write(buf),
- StreamInstance::Stderr => stderr().write(buf),
- StreamInstance::PausedPrologStream(..)
- | StreamInstance::StaticStr(_)
- | StreamInstance::ReadlineStream(_)
- | StreamInstance::InputFile(..)
- | StreamInstance::Null => Err(std::io::Error::new(
- ErrorKind::PermissionDenied,
- StreamError::WriteToInputStream,
- )),
+ return Err(self.error_form(err, stub));
}
- }
- fn flush(&mut self) -> std::io::Result<()> {
- match self.stream_inst.0.borrow_mut().stream_inst {
- StreamInstance::OutputFile(_, ref mut file, _) => file.flush(),
- StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.flush(),
- StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.flush(),
- StreamInstance::Bytes(ref mut cursor) => cursor.flush(),
- StreamInstance::Stderr => stderr().flush(),
- StreamInstance::Stdout => stdout().flush(),
- StreamInstance::PausedPrologStream(..)
- | StreamInstance::StaticStr(_)
- | StreamInstance::ReadlineStream(_)
- | StreamInstance::InputFile(..)
- | StreamInstance::Null => Err(std::io::Error::new(
- ErrorKind::PermissionDenied,
- StreamError::FlushToInputStream,
- )),
+ // 8.11.5.3l)
+ if let Some(alias) = options.get_alias() {
+ if indices.stream_aliases.contains_key(&alias) {
+ return Err(self.occupied_alias_permission_error(alias, atom!("open"), 4));
+ }
}
+
+ let mode = MachineState::deref(self, self[temp_v!(2)]);
+ let mode = cell_as_atom!(self.store(mode));
+
+ let mut open_options = OpenOptions::new();
+
+ let (is_input_file, in_append_mode) = match mode {
+ atom!("read") => {
+ open_options.read(true).write(false).create(false);
+ (true, false)
+ }
+ atom!("write") => {
+ open_options
+ .read(false)
+ .write(true)
+ .truncate(true)
+ .create(true);
+
+ (false, false)
+ }
+ atom!("append") => {
+ open_options
+ .read(false)
+ .write(true)
+ .create(true)
+ .append(true);
+
+ (false, true)
+ }
+ _ => {
+ let stub = functor_stub(atom!("open"), 4);
+ let err = self.domain_error(DomainErrorType::IOMode, self[temp_v!(2)]);
+
+ // 8.11.5.3h)
+ return Err(self.error_form(err, stub));
+ }
+ };
+
+ let file = match open_options.open(file_spec.as_str()) {
+ Ok(file) => file,
+ Err(err) => {
+ match err.kind() {
+ ErrorKind::NotFound => {
+ // 8.11.5.3j)
+ let stub = functor_stub(atom!("open"), 4);
+
+ let err = self.existence_error(
+ ExistenceError::SourceSink(self[temp_v!(1)]),
+ );
+
+ return Err(self.error_form(err, stub));
+ }
+ ErrorKind::PermissionDenied => {
+ // 8.11.5.3k)
+ return Err(self.open_permission_error(self[temp_v!(1)], atom!("open"), 4));
+ }
+ _ => {
+ let stub = functor_stub(atom!("open"), 4);
+ let err = self.syntax_error(ParserError::IO(err));
+
+ return Err(self.error_form(err, stub));
+ }
+ }
+ }
+ };
+
+ Ok(if is_input_file {
+ Stream::from_file_as_input(file_spec, file, &mut self.arena)
+ } else {
+ Stream::from_file_as_output(file_spec, file, in_append_mode, &mut self.arena)
+ })
}
}
diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs
index 0505e138..b8bd9063 100644
--- a/src/machine/system_calls.rs
+++ b/src/machine/system_calls.rs
@@ -1,35 +1,37 @@
-use prolog_parser::ast::*;
-use prolog_parser::parser::*;
-use prolog_parser::{
- alpha_char, alpha_numeric_char, binary_digit_char, clause_name, decimal_digit_char,
- exponent_char, graphic_char, graphic_token_char, hexadecimal_digit_char, layout_char,
- meta_char, new_line_char, octal_digit_char, octet_char, prolog_char, sign_char, solo_char,
- symbolic_control_char, symbolic_hexadecimal_char, temp_v,
-};
+use crate::parser::ast::*;
+use crate::parser::parser::*;
use lazy_static::lazy_static;
-use crate::clause_types::*;
+use crate::arena::*;
+use crate::atom_table::*;
use crate::forms::*;
+use crate::heap_iter::*;
use crate::heap_print::*;
use crate::instructions::*;
use crate::machine;
-use crate::machine::code_repo::CodeRepo;
+use crate::machine::{Machine, VERIFY_ATTR_INTERRUPT_LOC};
use crate::machine::code_walker::*;
use crate::machine::copier::*;
+use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
+use crate::machine::partial_string::*;
use crate::machine::preprocessor::to_op_decl;
+use crate::machine::stack::*;
use crate::machine::streams::*;
+use crate::parser::char_reader::*;
+use crate::parser::rug::Integer;
+use crate::parser::rug::rand::RandState;
+use crate::read::*;
+use crate::types::*;
-use crate::read::readline;
-use crate::rug::Integer;
use ordered_float::OrderedFloat;
use indexmap::IndexSet;
-use ref_thread_local::RefThreadLocal;
+use ref_thread_local::{RefThreadLocal, ref_thread_local};
use std::collections::BTreeSet;
use std::convert::TryFrom;
@@ -37,10 +39,10 @@ use std::env;
use std::fs;
use std::io::{ErrorKind, Read, Write};
use std::iter::{once, FromIterator};
+use std::mem;
use std::net::{TcpListener, TcpStream};
use std::num::NonZeroU32;
use std::ops::Sub;
-use std::rc::Rc;
use std::process;
use chrono::{offset::Local, DateTime};
@@ -71,6 +73,10 @@ use base64;
use roxmltree;
use select;
+ref_thread_local! {
+ pub(crate) static managed RANDOM_STATE: RandState<'static> = RandState::new();
+}
+
pub(crate) fn get_key() -> KeyEvent {
let key;
enable_raw_mode().expect("failed to enable raw mode");
@@ -92,503 +98,610 @@ pub(crate) fn get_key() -> KeyEvent {
key
}
-#[derive(Debug)]
-struct BrentAlgState {
- hare: Addr,
- tortoise: Addr,
- power: usize,
- steps: usize,
+#[derive(Debug, Clone, Copy)]
+pub struct BrentAlgState {
+ pub hare: usize,
+ pub tortoise: usize,
+ pub power: usize,
+ pub lam: usize,
+ pub pstr_chars: usize,
}
impl BrentAlgState {
- fn new(hare: Addr) -> Self {
- BrentAlgState {
- hare: hare,
+ pub fn new(hare: usize) -> Self {
+ Self {
+ hare,
tortoise: hare,
- power: 2,
- steps: 0,
+ power: 1,
+ lam: 0,
+ pstr_chars: 0,
}
}
- #[inline]
- fn conclude_or_move_tortoise(&mut self) -> Option<CycleSearchResult> {
- if self.tortoise == self.hare {
- return Some(CycleSearchResult::NotList);
- } else if self.steps == self.power {
+ #[inline(always)]
+ pub fn teleport_tortoise(&mut self) {
+ if self.lam == self.power {
self.tortoise = self.hare;
self.power <<= 1;
+ self.lam = 0;
+ }
+ }
+
+ #[inline(always)]
+ pub fn step(&mut self, hare: usize) -> Option<CycleSearchResult> {
+ self.hare = hare;
+ self.lam += 1;
+
+ if self.tortoise == self.hare {
+ return Some(CycleSearchResult::Cyclic(self.lam));
+ } else {
+ self.teleport_tortoise();
}
None
}
- #[inline]
- fn step(&mut self, hare: Addr) -> Option<CycleSearchResult> {
- self.hare = hare;
- self.steps += 1;
+ #[inline(always)]
+ pub fn num_steps(&self) -> usize {
+ return self.lam + self.pstr_chars + self.power - 1;
+ }
- self.conclude_or_move_tortoise()
+ pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult {
+ if let Some(var) = heap[self.hare].as_var() {
+ return CycleSearchResult::PartialList(self.num_steps(), var);
+ }
+
+ read_heap_cell!(heap[self.hare],
+ (HeapCellValueTag::PStrOffset) => {
+ let n = cell_as_fixnum!(heap[self.hare+1]).get_num() as usize;
+
+ let pstr = cell_as_string!(heap[self.hare]);
+ self.pstr_chars += pstr.as_str_from(n).chars().count();
+
+ return CycleSearchResult::PStrLocation(self.num_steps(), n);
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ return if name == atom!("[]") && arity == 0 {
+ CycleSearchResult::ProperList(self.num_steps())
+ } else {
+ CycleSearchResult::NotList(self.num_steps(), heap[self.hare])
+ };
+ }
+ (HeapCellValueTag::Lis, l) => {
+ return CycleSearchResult::UntouchedList(self.num_steps(), l);
+ }
+ _ => {
+ return CycleSearchResult::NotList(self.num_steps(), heap[self.hare]);
+ }
+ );
}
- fn to_result(self) -> CycleSearchResult {
- match self.hare {
- addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => {
- CycleSearchResult::PartialList(self.steps, addr.as_var().unwrap())
+ fn add_pstr_chars_and_step(&mut self, heap: &[HeapCellValue], h: usize) -> Option<CycleSearchResult> {
+ read_heap_cell!(heap[h],
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ let cstr = PartialString::from(cstr_atom);
+
+ self.pstr_chars += cstr.as_str_from(0).chars().count();
+ Some(CycleSearchResult::ProperList(self.num_steps()))
}
- Addr::PStrLocation(h, n) => CycleSearchResult::PStrLocation(self.steps, h, n),
- Addr::EmptyList => CycleSearchResult::ProperList(self.steps),
- _ => CycleSearchResult::NotList,
- }
+ (HeapCellValueTag::PStr, pstr_atom) => {
+ let pstr = PartialString::from(pstr_atom);
+
+ self.pstr_chars += pstr.as_str_from(0).chars().count() - 1;
+ self.step(h+1)
+ }
+ (HeapCellValueTag::PStrOffset, offset) => {
+ let pstr = cell_as_string!(heap[offset]);
+ let n = cell_as_fixnum!(heap[h+1]).get_num() as usize;
+
+ self.pstr_chars += pstr.as_str_from(n).chars().count();
+
+ if let HeapCellValueTag::PStr = heap[offset].get_tag() {
+ self.pstr_chars -= 1;
+ self.step(offset+1)
+ } else {
+ debug_assert!(heap[offset].get_tag() == HeapCellValueTag::CStr);
+ Some(CycleSearchResult::ProperList(self.num_steps()))
+ }
+ }
+ _ => {
+ unreachable!()
+ }
+ )
}
-}
-fn is_builtin_predicate(name: &ClauseName) -> bool {
- let in_builtins = name.owning_module().as_str() == "builtins";
- let hidden_name = name.as_str().starts_with("$");
+ #[inline(always)]
+ fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option<CycleSearchResult> {
+ loop {
+ let value = heap[self.hare];
+
+ read_heap_cell!(value,
+ (HeapCellValueTag::PStrLoc, h) => {
+ return self.add_pstr_chars_and_step(&heap, h);
+ }
+ (HeapCellValueTag::CStr | HeapCellValueTag::PStrOffset) => {
+ return self.add_pstr_chars_and_step(&heap, self.hare);
+ }
+ (HeapCellValueTag::Lis, h) => {
+ return self.step(h+1);
+ }
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
- in_builtins || hidden_name
-}
+ return if name == atom!(".") && arity == 2 {
+ self.step(s+2)
+ } else {
+ Some(CycleSearchResult::NotList(self.num_steps(), value))
+ };
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert!(arity == 0);
-impl MachineState {
- // a step in Brent's algorithm.
- fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult> {
- match self.store(self.deref(brent_st.hare)) {
- Addr::EmptyList => Some(CycleSearchResult::ProperList(brent_st.steps)),
- addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => {
- Some(CycleSearchResult::PartialList(
- brent_st.steps,
- addr.as_var().unwrap(),
- ))
- }
- Addr::PStrLocation(h, n) => match &self.heap[h] {
- HeapCellValue::PartialString(ref pstr, _) => {
- if let Some(c) = pstr.range_from(n..).next() {
- brent_st.step(Addr::PStrLocation(h, n + c.len_utf8()))
+ return if name == atom!("[]") {
+ Some(CycleSearchResult::ProperList(self.num_steps()))
} else {
- unreachable!()
+ Some(CycleSearchResult::NotList(self.num_steps(), value))
+ };
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if self.hare == h {
+ let r = value.as_var().unwrap();
+ return Some(CycleSearchResult::PartialList(self.num_steps(), r));
}
+
+ self.hare = h;
}
_ => {
- unreachable!()
+ return Some(CycleSearchResult::NotList(self.num_steps(), value));
}
- },
- Addr::Lis(l) => brent_st.step(Addr::HeapCell(l + 1)),
- _ => Some(CycleSearchResult::NotList),
+ );
}
}
- pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult {
- let hare = match self.store(self.deref(addr)) {
- Addr::Lis(offset) if max_steps > 0 => Addr::Lis(offset),
- Addr::Lis(offset) => {
- return CycleSearchResult::UntouchedList(offset);
+ pub fn detect_cycles(heap: &[HeapCellValue], value: HeapCellValue) -> CycleSearchResult {
+ let mut pstr_chars = 0;
+
+ let hare = read_heap_cell!(value,
+ (HeapCellValueTag::Lis, offset) => {
+ offset+1
+ }
+ (HeapCellValueTag::PStrLoc, h) => {
+ let (h_offset, n) = pstr_loc_and_offset(&heap, h);
+ let n = n.get_num() as usize;
+ let pstr = cell_as_string!(heap[h_offset]);
+
+ pstr_chars = pstr.as_str_from(n).chars().count() - 1;
+
+ if heap[h].get_tag() == HeapCellValueTag::PStrOffset {
+ debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset);
+
+ if heap[h_offset].get_tag() == HeapCellValueTag::CStr {
+ return CycleSearchResult::ProperList(pstr_chars + 1);
+ }
+ }
+
+ h_offset+1
}
- Addr::PStrLocation(h, n) if max_steps > 0 => Addr::PStrLocation(h, n),
- Addr::PStrLocation(h, _) => {
- return CycleSearchResult::UntouchedList(h);
+ (HeapCellValueTag::PStrOffset) => {
+ unreachable!()
}
- Addr::EmptyList => {
- return CycleSearchResult::EmptyList;
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ let cstr = PartialString::from(cstr_atom);
+ return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count());
}
- Addr::Con(h) if max_steps > 0 => {
- if let HeapCellValue::PartialString(..) = &self.heap[h] {
- Addr::PStrLocation(h, 0)
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(heap[s])
+ .get_name_and_arity();
+
+ if name == atom!("[]") && arity == 0 {
+ return CycleSearchResult::EmptyList;
+ } else if name == atom!(".") && arity == 2 {
+ s + 2
} else {
- return CycleSearchResult::NotList;
+ return CycleSearchResult::NotList(0, value);
}
}
- Addr::Con(h) => {
- if let HeapCellValue::PartialString(..) = &self.heap[h] {
- return CycleSearchResult::UntouchedList(h);
- }
-
- return CycleSearchResult::NotList;
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ return if name == atom!("[]") && arity == 0 {
+ CycleSearchResult::EmptyList
+ } else {
+ CycleSearchResult::NotList(0, value)
+ };
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
+ return CycleSearchResult::PartialList(0, value.as_var().unwrap());
}
_ => {
- return CycleSearchResult::NotList;
+ return CycleSearchResult::NotList(0, value);
}
- };
+ );
let mut brent_st = BrentAlgState::new(hare);
- loop {
- if brent_st.steps == max_steps {
- return brent_st.to_result();
- }
+ brent_st.power += 1; // advance a step.
+ brent_st.pstr_chars = pstr_chars;
- if let Some(result) = self.brents_alg_step(&mut brent_st) {
+ loop {
+ if let Some(result) = brent_st.cycle_step(heap) {
return result;
}
}
}
- pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult {
- let addr = self.store(self.deref(addr));
- let hare = match addr {
- Addr::Lis(offset) => Addr::Lis(offset),
- Addr::EmptyList => {
- return CycleSearchResult::EmptyList;
+ pub fn detect_cycles_with_max(
+ heap: &[HeapCellValue],
+ max_steps: usize,
+ value: HeapCellValue,
+ ) -> CycleSearchResult {
+ let mut pstr_chars = 0;
+
+ let hare = read_heap_cell!(value,
+ (HeapCellValueTag::Lis, offset) => {
+ if max_steps > 0 {
+ offset+1
+ } else {
+ return CycleSearchResult::UntouchedList(0, offset);
+ }
+ }
+ (HeapCellValueTag::PStrLoc, h) => {
+ let (h_offset, n) = pstr_loc_and_offset(&heap, h);
+ let n = n.get_num() as usize;
+ let pstr = cell_as_string!(heap[h_offset]);
+
+ pstr_chars = pstr.as_str_from(n).chars().count() - 1;
+
+ if heap[h].get_tag() == HeapCellValueTag::PStrOffset {
+ debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset);
+
+ if heap[h_offset].get_tag() == HeapCellValueTag::CStr {
+ return if pstr_chars + 1 <= max_steps {
+ CycleSearchResult::ProperList(pstr_chars + 1)
+ } else {
+ CycleSearchResult::UntouchedCStr(pstr.into(), max_steps)
+ };
+ }
+ }
+
+ if pstr_chars + 1 > max_steps {
+ return CycleSearchResult::PStrLocation(max_steps, h_offset);
+ }
+
+ h_offset+1
+ }
+ (HeapCellValueTag::PStrOffset) => {
+ unreachable!()
+ }
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ return if max_steps > 0 {
+ let cstr = PartialString::from(cstr_atom);
+ let pstr_chars = cstr.as_str_from(0).chars().count();
+
+ if pstr_chars <= max_steps {
+ CycleSearchResult::ProperList(pstr_chars)
+ } else {
+ CycleSearchResult::UntouchedCStr(cstr_atom, max_steps)
+ }
+ } else {
+ CycleSearchResult::UntouchedCStr(cstr_atom, 0)
+ };
}
- Addr::PStrLocation(h, n) => Addr::PStrLocation(h, n),
- Addr::Con(h) => {
- if let HeapCellValue::PartialString(..) = &self.heap[h] {
- Addr::PStrLocation(h, 0)
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
+
+ if name == atom!("[]") && arity == 0 {
+ return CycleSearchResult::EmptyList;
+ } else if name == atom!(".") && arity == 2 {
+ if max_steps > 0 {
+ s + 2
+ } else {
+ return CycleSearchResult::UntouchedList(0, s + 1);
+ }
} else {
- return CycleSearchResult::NotList;
+ return CycleSearchResult::NotList(0, value);
}
}
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ return if name == atom!("[]") && arity == 0 {
+ CycleSearchResult::EmptyList
+ } else {
+ CycleSearchResult::NotList(0, value)
+ };
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
+ return CycleSearchResult::PartialList(0, value.as_var().unwrap());
+ }
_ => {
- return CycleSearchResult::NotList;
+ return CycleSearchResult::NotList(0, value);
}
- };
+ );
let mut brent_st = BrentAlgState::new(hare);
+ brent_st.power += 1; // advance a step.
+ brent_st.pstr_chars = pstr_chars;
+
loop {
- if let Some(result) = self.brents_alg_step(&mut brent_st) {
+ if brent_st.num_steps() >= max_steps {
+ return brent_st.to_result(&heap);
+ }
+
+ if let Some(result) = brent_st.cycle_step(heap) {
return result;
}
}
}
+}
+
+impl MachineState {
+ fn skip_max_list_cycle(&mut self, lam: usize) {
+ fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize {
+ loop {
+ read_heap_cell!(value,
+ (HeapCellValueTag::PStrLoc, h) => {
+ let (h_offset, _) = pstr_loc_and_offset(&heap, h);
+ return h_offset+1;
+ }
+ (HeapCellValueTag::Lis, h) => {
+ return h+1;
+ }
+ (HeapCellValueTag::Str, s) => {
+ return s+2;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ value = heap[h];
+ }
+ _ => {
+ unreachable!();
+ }
+ );
+ }
+ }
+
+ let h = self.heap.len();
+ self.heap.push(self.registers[3]);
+
+ let mut hare = h;
+ let mut tortoise = hare;
+
+ for _ in 0 .. lam {
+ hare = step(&self.heap, self.heap[hare]);
+ }
+
+ let mut prev_hare = hare;
+
+ while hare != tortoise {
+ prev_hare = hare;
+ hare = step(&self.heap, self.heap[hare]);
+ tortoise = step(&self.heap, self.heap[tortoise]);
+ }
+
+ // now compute the num_steps of the list prefix until hare is
+ // reached in the fashion of a C do-while loop since hare
+ // may point to the beginning of a cycle.
+
+ let mut brent_st = BrentAlgState::new(h);
+
+ brent_st.cycle_step(&self.heap);
+
+ while prev_hare != brent_st.hare {
+ brent_st.cycle_step(&self.heap);
+ }
+
+ self.heap.pop();
+
+ let target_n = self.store(self.deref(self.registers[1]));
+ self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n);
+
+ if !self.fail {
+ unify!(self, self.registers[4], self.heap[prev_hare]);
+ }
+ }
- fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) {
- let target_n = self[temp_v!(1)];
- self.unify(Addr::Usize(n), target_n);
+ fn finalize_skip_max_list(&mut self, n: i64, value: HeapCellValue) {
+ let target_n = self.store(self.deref(self.registers[1]));
+ self.unify_fixnum(Fixnum::build_with(n), target_n);
if !self.fail {
- let xs = self[temp_v!(4)];
- self.unify(addr, xs);
+ let xs = self.registers[4];
+ unify!(self, value, xs);
}
}
- fn skip_max_list_result(&mut self, max_steps: Option<isize>) {
- let search_result = if let Some(max_steps) = max_steps {
- if max_steps == -1 {
- self.detect_cycles(self[temp_v!(3)])
- } else {
- self.detect_cycles_with_max(max_steps as usize, self[temp_v!(3)])
- }
+ fn skip_max_list_result(&mut self, max_steps: i64) {
+ let search_result = if max_steps == -1 {
+ BrentAlgState::detect_cycles(
+ &self.heap,
+ self.store(self.deref(self.registers[3])),
+ )
} else {
- self.detect_cycles(self[temp_v!(3)])
+ BrentAlgState::detect_cycles_with_max(
+ &self.heap,
+ max_steps as usize,
+ self.store(self.deref(self.registers[3])),
+ )
};
match search_result {
- CycleSearchResult::PStrLocation(steps, h, n) => {
- self.finalize_skip_max_list(steps, Addr::PStrLocation(h, n));
+ CycleSearchResult::PStrLocation(steps, pstr_loc) => {
+ self.finalize_skip_max_list(steps as i64, pstr_loc_as_cell!(pstr_loc));
+ }
+ CycleSearchResult::UntouchedList(n, l) => {
+ self.finalize_skip_max_list(n as i64, list_loc_as_cell!(l));
+ }
+ CycleSearchResult::UntouchedCStr(cstr_atom, n) => {
+ self.finalize_skip_max_list(n as i64, string_as_cstr_cell!(cstr_atom));
+ }
+ CycleSearchResult::EmptyList => {
+ self.finalize_skip_max_list(0, empty_list_as_cell!());
+ }
+ CycleSearchResult::PartialList(n, r) => {
+ self.finalize_skip_max_list(n as i64, r.as_heap_cell_value());
}
- CycleSearchResult::UntouchedList(l) => self.finalize_skip_max_list(0, Addr::Lis(l)),
- CycleSearchResult::EmptyList => self.finalize_skip_max_list(0, Addr::EmptyList),
- CycleSearchResult::PartialList(n, r) => self.finalize_skip_max_list(n, r.as_addr()),
CycleSearchResult::ProperList(steps) => {
- self.finalize_skip_max_list(steps, Addr::EmptyList)
+ self.finalize_skip_max_list(steps as i64, empty_list_as_cell!())
}
- CycleSearchResult::NotList => {
- let xs0 = self[temp_v!(3)];
- self.finalize_skip_max_list(0, xs0);
+ CycleSearchResult::NotList(n, value) => {
+ self.finalize_skip_max_list(n as i64, value);
+ }
+ CycleSearchResult::Cyclic(lam) => {
+ self.skip_max_list_cycle(lam);
}
};
}
- pub(super) fn skip_max_list(&mut self) -> CallResult {
- let max_steps = self.store(self.deref(self[temp_v!(2)]));
-
- match max_steps {
- Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => {
- let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4);
- return Err(self.error_form(MachineError::instantiation_error(), stub));
- }
- addr => {
- let max_steps_n = match Number::try_from((max_steps, &self.heap)) {
- Ok(Number::Integer(n)) => n.to_isize(),
- Ok(Number::Fixnum(n)) => Some(n),
- _ => None,
- };
+ pub fn skip_max_list(&mut self) -> CallResult {
+ let max_steps = self.store(self.deref(self.registers[2]));
+ let mut max_old = -1i64;
- if max_steps_n.map(|i| i >= -1).unwrap_or(false) {
- let n = self.store(self.deref(self[temp_v!(1)]));
+ if !max_steps.is_var() {
+ let max_steps = Number::try_from(max_steps);
- match Number::try_from((n, &self.heap)) {
- Ok(Number::Integer(n)) => {
- if n.as_ref() == &0 {
- let xs0 = self[temp_v!(3)];
- let xs = self[temp_v!(4)];
+ let max_steps_n = match max_steps {
+ Ok(Number::Fixnum(n)) => Some(n.get_num()),
+ Ok(Number::Integer(n)) => n.to_i64(),
+ _ => None,
+ };
- self.unify(xs0, xs);
- } else {
- self.skip_max_list_result(max_steps_n);
- }
- }
- Ok(Number::Fixnum(n)) => {
- if n == 0 {
- let xs0 = self[temp_v!(3)];
- let xs = self[temp_v!(4)];
-
- self.unify(xs0, xs);
- } else {
- self.skip_max_list_result(max_steps_n);
- }
- }
- _ => {
- self.skip_max_list_result(max_steps_n);
- }
+ if let Some(max_steps) = max_steps_n {
+ if max_steps.abs() as usize <= 1 << 63 {
+ if max_steps >= 0 {
+ max_old = max_steps;
+ } else {
+ self.fail = true;
+ return Ok(());
}
- } else {
- let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4);
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, addr),
- stub,
- ));
+ } else if max_steps < 0 {
+ self.fail = true;
+ return Ok(());
}
+ } else if !max_steps.map(|n| n.is_integer()).unwrap_or(false) {
+ self.fail = true;
+ return Ok(());
}
}
+ self.skip_max_list_result(max_old);
Ok(())
}
- fn stream_from_file_spec(
- &self,
- file_spec: ClauseName,
- indices: &mut IndexStore,
- options: &StreamOptions,
- ) -> Result<Stream, MachineStub> {
- if file_spec.as_str().is_empty() {
- let stub = MachineError::functor_stub(clause_name!("open"), 4);
- let err = MachineError::domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]);
-
- return Err(self.error_form(err, stub));
- }
-
- // 8.11.5.3l)
- if let Some(ref alias) = &options.alias {
- if indices.stream_aliases.contains_key(alias) {
- return Err(self.occupied_alias_permission_error(alias.clone(), "open", 4));
- }
- }
-
- let mode = atom_from!(self, self.store(self.deref(self[temp_v!(2)])));
- let mut open_options = fs::OpenOptions::new();
-
- let (is_input_file, in_append_mode) = match mode.as_str() {
- "read" => {
- open_options.read(true).write(false).create(false);
- (true, false)
- }
- "write" => {
- open_options
- .read(false)
- .write(true)
- .truncate(true)
- .create(true);
- (false, false)
- }
- "append" => {
- open_options
- .read(false)
- .write(true)
- .create(true)
- .append(true);
- (false, true)
- }
- _ => {
- let stub = MachineError::functor_stub(clause_name!("open"), 4);
- let err = MachineError::domain_error(DomainErrorType::IOMode, self[temp_v!(2)]);
-
- // 8.11.5.3h)
- return Err(self.error_form(err, stub));
- }
- };
-
- let file = match open_options.open(file_spec.as_str()) {
- Ok(file) => file,
- Err(err) => {
- match err.kind() {
- ErrorKind::NotFound => {
- // 8.11.5.3j)
- let stub = MachineError::functor_stub(clause_name!("open"), 4);
+ fn term_variables_under_max_depth(
+ &mut self,
+ term: HeapCellValue,
+ max_depth: usize,
+ list_of_vars: HeapCellValue,
+ ) {
+ let mut seen_set = IndexSet::new();
- let err = MachineError::existence_error(
- self.heap.h(),
- ExistenceError::SourceSink(self[temp_v!(1)]),
- );
+ {
+ let mut iter = stackful_post_order_iter(&mut self.heap, term);
- return Err(self.error_form(err, stub));
- }
- ErrorKind::PermissionDenied => {
- // 8.11.5.3k)
- return Err(self.open_permission_error(self[temp_v!(1)], "open", 4));
- }
- _ => {
- let stub = MachineError::functor_stub(clause_name!("open"), 4);
+ while let Some(value) = iter.next() {
+ if iter.parent_stack_len() >= max_depth {
+ iter.pop_stack();
+ continue;
+ }
- let err = MachineError::syntax_error(self.heap.h(), ParserError::IO(err));
+ let value = unmark_cell_bits!(value);
- return Err(self.error_form(err, stub));
- }
+ if value.is_var() && !seen_set.contains(&value) {
+ seen_set.insert(value);
}
}
- };
+ }
- Ok(if is_input_file {
- Stream::from_file_as_input(file_spec, file)
- } else {
- Stream::from_file_as_output(file_spec, file, in_append_mode)
- })
+ let outcome = heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.heap,
+ seen_set.into_iter(),
+ )
+ );
+
+ unify_fn!(*self, list_of_vars, outcome);
}
#[inline]
- fn install_new_block(&mut self, r: RegType) -> usize {
+ pub(crate) fn install_new_block(&mut self, value: HeapCellValue) -> usize {
self.block = self.b;
+ self.unify_fixnum(Fixnum::build_with(self.block as i64), value);
- let c = Constant::Usize(self.block);
- let addr = self[r];
-
- self.write_constant_to_var(addr, &c);
self.block
}
- fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: Addr) -> usize {
- let threshold = self.lifted_heap.h() - lh_offset;
+ pub(crate) fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: HeapCellValue) -> usize {
+ let threshold = self.lifted_heap.len() - lh_offset;
let mut copy_ball_term =
CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.lifted_heap);
- copy_ball_term.push(HeapCellValue::Addr(Addr::Lis(threshold + 1)));
- copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 3)));
- copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2)));
+ copy_ball_term.push(list_loc_as_cell!(threshold + 1));
+ copy_ball_term.push(heap_loc_as_cell!(threshold + 3));
+ copy_ball_term.push(heap_loc_as_cell!(threshold + 2));
copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy);
threshold + lh_offset + 2
}
- fn repl_redirect(&mut self, repl_code_ptr: REPLCodePtr) -> CallResult {
- let p = if self.last_call {
- self.cp
- } else {
- self.p.local() + 1
- };
-
- Ok(self.p = CodePtr::REPL(repl_code_ptr, p))
- }
+ #[inline(always)]
+ pub(crate) fn truncate_if_no_lifted_heap_diff(
+ &mut self,
+ addr_constr: impl Fn(usize) -> HeapCellValue,
+ ) {
+ read_heap_cell!(self.store(self.deref(self.registers[1])),
+ (HeapCellValueTag::Fixnum, n) => {
+ let lh_offset = n.get_num() as usize;
- fn truncate_if_no_lifted_heap_diff<AddrConstr>(&mut self, addr_constr: AddrConstr)
- where
- AddrConstr: Fn(usize) -> Addr,
- {
- match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Usize(lh_offset) => {
- if lh_offset >= self.lifted_heap.h() {
+ if lh_offset >= self.lifted_heap.len() {
self.lifted_heap.truncate(lh_offset);
} else {
- let threshold = self.lifted_heap.h() - lh_offset;
- self.lifted_heap
- .push(HeapCellValue::Addr(addr_constr(threshold)));
+ let threshold = self.lifted_heap.len() - lh_offset;
+ self.lifted_heap.push(addr_constr(threshold));
}
}
- _ => self.fail = true,
- }
+ _ => {
+ self.fail = true;
+ }
+ );
}
- fn get_next_db_ref(&mut self, indices: &IndexStore, db_ref: &DBRef) {
+ pub(crate) fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option<DBRef> {
match db_ref {
- &DBRef::NamedPred(ref name, arity, _) => {
- let key = (name.clone(), arity);
- let mut iter = indices.code_dir.range(key..).skip(1);
-
- while let Some(((name, arity), idx)) = iter.next() {
- if idx.is_undefined() {
- self.fail = true;
- return;
- }
-
- if is_builtin_predicate(&name) {
- continue;
- }
-
- let a2 = self[temp_v!(2)];
+ DBRef::NamedPred(name, arity) => {
+ let key = (*name, *arity);
- if let Some(r) = a2.as_var() {
- let spec = get_clause_spec(
- name.clone(),
- *arity,
- &CompositeOpDir::new(&indices.op_dir, None),
- );
+ if let Some((last_idx, _, _)) = indices.code_dir.get_full(&key) {
+ for idx in last_idx + 1 .. indices.code_dir.len() {
+ let ((name, arity), idx) = indices.code_dir.get_index(idx).unwrap();
- let addr = self
- .heap
- .to_unifiable(HeapCellValue::DBRef(DBRef::NamedPred(
- name.clone(),
- *arity,
- spec,
- )));
-
- self.bind(r, addr);
+ if idx.is_undefined() {
+ return None;
+ }
- return;
+ return Some(DBRef::NamedPred(*name, *arity));
}
}
-
- self.fail = true;
}
- &DBRef::Op(_, spec, ref name, ref op_dir, _) => {
- let fixity = match spec {
- XF | YF => Fixity::Post,
- FX | FY => Fixity::Pre,
- _ => Fixity::In,
- };
-
- let key = OrderedOpDirKey(name.clone(), fixity);
-
- match op_dir.range(key..).skip(1).next() {
- Some((OrderedOpDirKey(name, _), (priority, spec))) => {
- let a2 = self[temp_v!(2)];
+ DBRef::Op(name, fixity, op_dir) => {
+ let key = (*name, *fixity);
- if let Some(r) = a2.as_var() {
- let addr = self.heap.to_unifiable(HeapCellValue::DBRef(DBRef::Op(
- *priority,
- *spec,
- name.clone(),
- op_dir.clone(),
- SharedOpDesc::new(*priority, *spec),
- )));
-
- self.bind(r, addr);
- } else {
- self.fail = true;
- }
+ if let Some((last_idx, _, _)) = op_dir.get_full(&key) {
+ if let Some(((name, fixity), _)) = op_dir.get_index(last_idx+1) {
+ return Some(DBRef::Op(*name, *fixity, *op_dir));
}
- None => self.fail = true,
}
}
}
- }
-
- fn int_to_char(
- &self,
- n: &Integer,
- stub: &'static str,
- arity: usize,
- ) -> Result<char, MachineStub> {
- let c = n.to_u32().and_then(std::char::from_u32);
-
- if let Some(c) = c {
- Ok(c)
- } else {
- let stub = MachineError::functor_stub(clause_name!(stub), arity);
- let err = MachineError::representation_error(RepFlag::CharacterCode);
- let err = self.error_form(err, stub);
- Err(err)
- }
+ None
}
- fn parse_number_from_string(
+ pub(crate) fn parse_number_from_string(
&mut self,
mut string: String,
indices: &IndexStore,
- stub: MachineStub,
+ stub_gen: impl Fn() -> FunctorStub,
) -> CallResult {
- let nx = self[temp_v!(2)];
+ let nx = self.registers[2];
if let Some(c) = string.chars().last() {
if layout_char!(c) {
@@ -600,5190 +713,5356 @@ impl MachineState {
}
});
let err = ParserError::UnexpectedChar(c, line_num, col_num);
+ let err = self.syntax_error(err);
- let h = self.heap.h();
- let err = MachineError::syntax_error(h, err);
-
- return Err(self.error_form(err, stub));
+ return Err(self.error_form(err, stub_gen()));
}
}
string.push('.');
- let mut stream = match parsing_stream(std::io::Cursor::new(string)) {
- Ok(stream) => stream,
- Err(e) => {
- let err = MachineError::session_error(self.heap.h(), SessionError::from(e));
-
- return Err(self.error_form(err, stub));
- }
- };
-
- let mut parser = Parser::new(&mut stream, self.atom_tbl.clone(), self.machine_flags());
+ let stream = CharReader::new(std::io::Cursor::new(string));
+ let mut parser = Parser::new(stream, self);
match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) {
Err(err) => {
- let h = self.heap.h();
- let err = MachineError::syntax_error(h, err);
-
- return Err(self.error_form(err, stub));
+ let err = self.syntax_error(err);
+ return Err(self.error_form(err, stub_gen()));
}
- Ok(Term::Constant(_, Constant::Rational(n))) => {
- let addr = self.heap.put_constant(Constant::Rational(n));
- (self.unify_fn)(self, nx, addr);
+ Ok(Term::Literal(_, Literal::Rational(n))) => {
+ self.unify_rational(n, nx);
}
- Ok(Term::Constant(_, Constant::Float(n))) => {
- let addr = self.heap.put_constant(Constant::Float(n));
- (self.unify_fn)(self, nx, addr);
+ Ok(Term::Literal(_, Literal::Float(n))) => {
+ self.unify_f64(n, nx);
}
- Ok(Term::Constant(_, Constant::Integer(n))) => {
- let addr = self.heap.put_constant(Constant::Integer(n));
- (self.unify_fn)(self, nx, addr);
+ Ok(Term::Literal(_, Literal::Integer(n))) => {
+ self.unify_big_int(n, nx);
}
- Ok(Term::Constant(_, Constant::Fixnum(n))) => {
- let addr = self.heap.put_constant(Constant::Fixnum(n));
- (self.unify_fn)(self, nx, addr);
+ Ok(Term::Literal(_, Literal::Fixnum(n))) => {
+ self.unify_fixnum(n, nx);
}
_ => {
let err = ParserError::ParseBigInt(0, 0);
+ let err = self.syntax_error(err);
- let h = self.heap.h();
- let err = MachineError::syntax_error(h, err);
-
- return Err(self.error_form(err, stub));
+ return Err(self.error_form(err, stub_gen()));
}
}
Ok(())
}
- fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr {
+ pub(crate) fn call_continuation_chunk(&mut self, chunk: HeapCellValue, return_p: usize) -> usize {
let chunk = self.store(self.deref(chunk));
- match chunk {
- Addr::Str(s) => {
- match &self.heap[s] {
- HeapCellValue::NamedStr(arity, ..) => {
- let num_cells = arity - 1;
- let p_functor = self.heap[s + 1].as_addr(s + 1);
+ let s = chunk.get_value();
+ let arity = cell_as_atom_cell!(self.heap[s]).get_arity();
- let cp = self.heap.to_local_code_ptr(&p_functor).unwrap();
- let prev_e = self.e;
+ let num_cells = arity - 1;
+ let p_functor = self.heap[s + 1];
- let e = self.stack.allocate_and_frame(num_cells);
- let and_frame = self.stack.index_and_frame_mut(e);
+ let cp = to_local_code_ptr(&self.heap, p_functor).unwrap();
+ let prev_e = self.e;
- and_frame.prelude.e = prev_e;
- and_frame.prelude.cp = return_p;
+ let e = self.stack.allocate_and_frame(num_cells);
+ let and_frame = self.stack.index_and_frame_mut(e);
- self.p = CodePtr::Local(cp + 1);
+ and_frame.prelude.e = prev_e;
+ and_frame.prelude.cp = return_p;
- // adjust cut point to occur after call_continuation.
- if num_cells > 0 {
- if let Addr::CutPoint(_) = self.heap[s + 2].as_addr(s + 2) {
- and_frame[1] = Addr::CutPoint(self.b);
- } else {
- and_frame[1] = self.heap[s + 2].as_addr(s + 2);
- }
- }
+ self.p = cp + 1;
- for index in s + 3..s + 2 + num_cells {
- and_frame[index - (s + 1)] = self.heap[index].as_addr(index);
- }
+ // adjust cut point to occur after call_continuation.
+ if num_cells > 0 {
+ if let HeapCellValueTag::Fixnum = self.heap[s + 2].get_tag() {
+ and_frame[1] = fixnum_as_cell!(Fixnum::build_with(self.b as i64));
+ } else {
+ and_frame[1] = self.heap[s + 2];
+ }
+ }
- self.e = e;
+ for index in s + 3..s + 2 + num_cells {
+ and_frame[index - (s + 1)] = self.heap[index];
+ }
- self.p.local()
- }
- _ => unreachable!(),
+ self.e = e;
+ self.p
+ }
+
+ pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option<AtomOrString> {
+ read_heap_cell!(value,
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ // avoid allocating a String if possible:
+ // We must be careful to preserve the string "[]" as is,
+ // instead of turning it into the atom [], i.e., "".
+ if cstr_atom == atom!("[]") {
+ Some(AtomOrString::String("[]".to_string()))
+ } else {
+ Some(AtomOrString::Atom(cstr_atom))
}
}
- _ => unreachable!(),
- }
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ if arity == 0 {
+ // ... likewise.
+ Some(AtomOrString::Atom(atom))
+ } else {
+ None
+ }
+ }
+ (HeapCellValueTag::Char, c) => {
+ Some(AtomOrString::Atom(self.atom_tbl.build_with(&c.to_string())))
+ }
+ _ => {
+ if value.is_constant() {
+ return None;
+ }
+
+ let h = self.heap.len();
+ self.heap.push(value);
+
+ let mut iter = HeapPStrIter::new(&self.heap, h);
+ let string = iter.to_string();
+ let at_terminator = iter.at_string_terminator();
+
+ self.heap.pop();
+
+ // if the iteration doesn't terminate like a string
+ // (i.e. with the [] atom or a CStr), it is not
+ // "str_like" so return None.
+ if at_terminator {
+ Some(AtomOrString::String(string))
+ } else {
+ None
+ }
+ }
+ )
}
- pub(super) fn system_call(
+ pub(crate) fn codes_to_string(
&mut self,
- ct: &SystemClauseType,
- code_repo: &CodeRepo,
- indices: &mut IndexStore,
- call_policy: &mut Box<dyn CallPolicy>,
- cut_policy: &mut Box<dyn CutPolicy>,
- current_input_stream: &mut Stream,
- current_output_stream: &mut Stream,
- ) -> CallResult {
- match ct {
- &SystemClauseType::BindFromRegister => {
- let reg = self.store(self.deref(self[temp_v!(2)]));
- let n = match Number::try_from((reg, &self.heap)) {
- Ok(Number::Integer(n)) => n.to_usize(),
- Ok(Number::Fixnum(n)) => usize::try_from(n).ok(),
- _ => {
- unreachable!()
+ addrs: impl Iterator<Item = HeapCellValue>,
+ stub_gen: impl Fn() -> FunctorStub,
+ ) -> Result<String, MachineStub> {
+ let mut string = String::new();
+
+ for addr in addrs {
+ match Number::try_from(addr) {
+ Ok(Number::Fixnum(n)) => {
+ match u32::try_from(n.get_num()) {
+ Ok(n) => {
+ if let Some(c) = std::char::from_u32(n) {
+ string.push(c);
+ continue;
+ }
+ }
+ _ => {}
}
- };
-
- if let Some(n) = n {
- if n <= MAX_ARITY {
- let target = self[temp_v!(n)];
- let addr = self[temp_v!(1)];
-
- (self.unify_fn)(self, addr, target);
- return return_from_clause!(self.last_call, self);
+ }
+ Ok(Number::Integer(n)) => {
+ if let Some(c) = n.to_u32().and_then(std::char::from_u32) {
+ string.push(c);
+ continue;
}
}
+ _ => {
+ let err = self.type_error(ValidType::Integer, addr);
+ return Err(self.error_form(err, stub_gen()));
+ }
+ }
- self.fail = true;
+ let err = self.representation_error(RepFlag::CharacterCode);
+ return Err(self.error_form(err, stub_gen()));
+ }
+
+ Ok(string)
+ }
+}
+
+impl Machine {
+ #[inline(always)]
+ pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool {
+ match &self.code[p] {
+ &Instruction::CallResetContinuationMarker(_) |
+ &Instruction::ExecuteResetContinuationMarker(_) => true,
+ _ => false
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn bind_from_register(&mut self) {
+ let reg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+ let n = match Number::try_from(reg) {
+ Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+ Ok(Number::Integer(n)) => n.to_usize(),
+ _ => {
+ unreachable!()
}
- &SystemClauseType::CurrentHostname => {
- match hostname::get().ok() {
- Some(host) => match host.into_string().ok() {
- Some(host) => {
- let hostname = self.heap.to_unifiable(HeapCellValue::Atom(
- clause_name!(host, self.atom_tbl),
- None,
- ));
-
- (self.unify_fn)(self, self[temp_v!(1)], hostname);
- return return_from_clause!(self.last_call, self);
- }
- None => {}
- },
- None => {}
- }
+ };
- self.fail = true;
- return Ok(());
+ if let Some(n) = n {
+ if n <= MAX_ARITY {
+ let target = self.machine_st.registers[n];
+ let addr = self.machine_st.registers[1];
+
+ unify_fn!(self.machine_st, addr, target);
+ return;
}
- &SystemClauseType::CurrentInput => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
+ }
- let stream = current_input_stream.clone();
+ self.machine_st.fail = true;
+ }
- match addr {
- addr if addr.is_ref() => {
- let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
- (self.unify_fn)(self, stream, addr);
- }
- Addr::Stream(other_stream) => {
- if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] {
- self.fail = current_input_stream != other_stream;
- } else {
- unreachable!()
- }
- }
- addr => {
- let stub = MachineError::functor_stub(clause_name!("current_input"), 1);
+ #[inline(always)]
+ pub(crate) fn current_hostname(&mut self) {
+ match hostname::get().ok() {
+ Some(host) => match host.to_str() {
+ Some(host) => {
+ let hostname = self.machine_st.atom_tbl.build_with(host);
- let err = MachineError::domain_error(DomainErrorType::Stream, addr);
+ self.machine_st.unify_atom(
+ hostname,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+ );
- return Err(self.error_form(err, stub));
- }
+ return;
}
- }
- &SystemClauseType::CurrentOutput => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
- let stream = current_output_stream.clone();
+ None => {}
+ },
+ None => {}
+ }
+
+ self.machine_st.fail = true;
+ }
+
+ #[inline(always)]
+ pub(crate) fn current_input(&mut self) -> CallResult {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let stream = self.user_input;
- match addr {
- addr if addr.is_ref() => {
- let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
- (self.unify_fn)(self, stream, addr);
+ if let Some(var) = addr.as_var() {
+ self.machine_st.bind(var, stream_as_cell!(stream));
+ return Ok(());
+ }
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Stream, other_stream) => {
+ self.machine_st.fail = stream != other_stream;
}
- Addr::Stream(other_stream) => {
- if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] {
- self.fail = current_output_stream != other_stream;
- } else {
- unreachable!()
- }
+ _ => {
+ let stub = functor_stub(atom!("current_input"), 1);
+ let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
+
+ return Err(self.machine_st.error_form(err, stub));
}
- addr => {
- let stub = MachineError::functor_stub(clause_name!("current_input"), 1);
+ );
+ }
+ _ => {
+ let stub = functor_stub(atom!("current_input"), 1);
+ let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
+ );
+
+ Ok(())
+ }
- let err = MachineError::domain_error(DomainErrorType::Stream, addr);
+ #[inline(always)]
+ pub(crate) fn current_output(&mut self) -> CallResult {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let stream = self.user_output;
- return Err(self.error_form(err, stub));
+ if let Some(var) = addr.as_var() {
+ self.machine_st.bind(var, stream_as_cell!(stream));
+ return Ok(());
+ }
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Stream, other_stream) => {
+ self.machine_st.fail = stream != other_stream;
}
- }
+ _ => {
+ let stub = functor_stub(atom!("current_output"), 1);
+ let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
+ );
+ }
+ _ => {
+ let stub = functor_stub(atom!("current_output"), 1);
+ let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
+
+ return Err(self.machine_st.error_form(err, stub));
}
- &SystemClauseType::DirectoryFiles => {
- let dir = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- let path = std::path::Path::new(&dir);
- let mut files = Vec::new();
+ );
- if let Ok(entries) = fs::read_dir(path) {
- for entry in entries {
- if let Ok(entry) = entry {
- match entry.file_name().into_string() {
- Ok(name) => {
- files.push(self.heap.put_complete_string(&name));
- }
- _ => {
- let stub = MachineError::functor_stub(
- clause_name!("directory_files"),
- 2,
- );
- let err =
- MachineError::representation_error(RepFlag::Character);
- let err = self.error_form(err, stub);
-
- return Err(err);
- }
- }
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn directory_files(&mut self) -> CallResult {
+ if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let path = std::path::Path::new(dir.as_str());
+ let mut files = Vec::new();
+
+ if let Ok(entries) = fs::read_dir(path) {
+ for entry in entries {
+ if let Ok(entry) = entry {
+ if let Some(name) = entry.file_name().to_str() {
+ let name = self.machine_st.atom_tbl.build_with(name);
+ files.push(atom_as_cstr_cell!(name));
+
+ continue;
}
}
+
+ let stub = functor_stub(atom!("directory_files"), 2);
+ let err = self.machine_st.representation_error(RepFlag::Character);
+ let err = self.machine_st.error_form(err, stub);
+
+ return Err(err);
}
- let files_list = Addr::HeapCell(self.heap.to_list(files.into_iter()));
- (self.unify_fn)(self, self[temp_v!(2)], files_list);
+ let files_list = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, files.into_iter())
+ );
+
+ unify!(self.machine_st, self.machine_st.registers[2], files_list);
+ return Ok(());
+ }
+ }
+
+ self.machine_st.fail = true;
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn file_size(&mut self) {
+ if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let len = Number::arena_from(
+ fs::metadata(file.as_str()).unwrap().len(),
+ &mut self.machine_st.arena,
+ );
+
+ match len {
+ Number::Fixnum(n) => self.machine_st.unify_fixnum(n, self.machine_st.registers[2]),
+ Number::Integer(n) => self.machine_st.unify_big_int(n, self.machine_st.registers[2]),
+ _ => unreachable!(),
}
- &SystemClauseType::FileSize => {
- let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- let len = Integer::from(fs::metadata(&file).unwrap().len());
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
- let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len)));
+ #[inline(always)]
+ pub(crate) fn file_exists(&mut self) {
+ if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let file_str = file.as_str();
- (self.unify_fn)(self, self[temp_v!(2)], len);
+ if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() {
+ self.machine_st.fail = true;
}
- &SystemClauseType::FileExists => {
- let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- if !std::path::Path::new(&file).exists() || !fs::metadata(&file).unwrap().is_file()
- {
- self.fail = true;
- return Ok(());
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn directory_exists(&mut self) {
+ if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let dir_str = dir.as_str();
+
+ if !std::path::Path::new(dir_str).exists() || !fs::metadata(dir_str).unwrap().is_dir() {
+ self.machine_st.fail = true;
+ }
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn file_time(&mut self) {
+ if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let which = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2]
+ )));
+
+ if let Ok(md) = fs::metadata(file.as_str()) {
+ if let Ok(time) = match which {
+ atom!("modification") => md.modified(),
+ atom!("access") => md.accessed(),
+ atom!("creation") => md.created(),
+ _ => {
+ unreachable!()
+ }
+ } {
+ let chars_atom = self.systemtime_to_timestamp(time);
+
+ self.machine_st.unify_complete_string(
+ chars_atom,
+ self.machine_st.registers[3],
+ );
+
+ return;
}
}
- &SystemClauseType::DirectoryExists => {
- let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- if !std::path::Path::new(&directory).exists()
- || !fs::metadata(&directory).unwrap().is_dir()
- {
- self.fail = true;
- return Ok(());
+ }
+
+ self.machine_st.fail = true;
+ }
+
+ #[inline(always)]
+ pub(crate) fn directory_separator(&mut self) {
+ self.machine_st.unify_char(std::path::MAIN_SEPARATOR, self.machine_st.registers[1]);
+ }
+
+ #[inline(always)]
+ pub(crate) fn make_directory(&mut self) {
+ if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ match fs::create_dir(dir.as_str()) {
+ Ok(_) => {}
+ _ => {
+ self.machine_st.fail = true;
}
}
- &SystemClauseType::DirectorySeparator => {
- let addr = self
- .heap
- .put_constant(Constant::Char(std::path::MAIN_SEPARATOR));
- (self.unify_fn)(self, self[temp_v!(1)], addr);
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn make_directory_path(&mut self) {
+ if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+
+ match fs::create_dir_all(dir.as_str()) {
+ Ok(_) => {}
+ _ => {
+ self.machine_st.fail = true;
+ }
}
- &SystemClauseType::MakeDirectory => {
- let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
- match fs::create_dir(directory) {
- Ok(_) => {}
- _ => {
- self.fail = true;
- return Ok(());
- }
+ #[inline(always)]
+ pub(crate) fn delete_file(&mut self) {
+ if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ match fs::remove_file(file.as_str()) {
+ Ok(_) => {}
+ _ => {
+ self.machine_st.fail = true;
}
}
- &SystemClauseType::MakeDirectoryPath => {
- let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
+ }
+ }
- match fs::create_dir_all(directory) {
- Ok(_) => {}
- _ => {
- self.fail = true;
- return Ok(());
- }
+ #[inline(always)]
+ pub(crate) fn rename_file(&mut self) {
+ if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ if let Some(renamed) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
+ if fs::rename(file.as_str(), renamed.as_str()).is_ok() {
+ return;
}
}
- &SystemClauseType::DeleteFile => {
- let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
+ }
- match fs::remove_file(file) {
- Ok(_) => {}
- _ => {
- self.fail = true;
- return Ok(());
- }
+ self.machine_st.fail = true;
+ }
+
+ #[inline(always)]
+ pub(crate) fn delete_directory(&mut self) {
+ if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ match fs::remove_dir(dir.as_str()) {
+ Ok(_) => {}
+ _ => {
+ self.machine_st.fail = true;
}
}
- &SystemClauseType::RenameFile => {
- let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- let renamed = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
+ }
+ }
- match fs::rename(file, renamed) {
- Ok(_) => {}
- _ => {
- self.fail = true;
- return Ok(());
- }
+ #[inline(always)]
+ pub(crate) fn working_directory(&mut self) -> CallResult {
+ if let Ok(dir) = env::current_dir() {
+ let current = match dir.to_str() {
+ Some(d) => d,
+ _ => {
+ let stub = functor_stub(atom!("working_directory"), 2);
+ let err = self.machine_st.representation_error(RepFlag::Character);
+ let err = self.machine_st.error_form(err, stub);
+
+ return Err(err);
}
+ };
+
+ let current_atom = self.machine_st.atom_tbl.build_with(&current);
+
+ self.machine_st.unify_complete_string(
+ current_atom,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
+ );
+
+ if self.machine_st.fail {
+ return Ok(());
}
- &SystemClauseType::DeleteDirectory => {
- let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- match fs::remove_dir(directory) {
- Ok(_) => {}
- _ => {
- self.fail = true;
- return Ok(());
- }
+ let target = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ if let Some(next) = self.machine_st.value_to_str_like(target) {
+ if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() {
+ return Ok(());
}
}
- &SystemClauseType::WorkingDirectory => {
- if let Ok(dir) = env::current_dir() {
- let current = match dir.to_str() {
- Some(d) => d,
+ }
+
+ self.machine_st.fail = true;
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn path_canonical(&mut self) -> CallResult {
+ if let Some(path) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ match fs::canonicalize(path.as_str()) {
+ Ok(canonical) => {
+ let cs = match canonical.to_str() {
+ Some(s) => s,
_ => {
- let stub =
- MachineError::functor_stub(clause_name!("working_directory"), 2);
- let err = MachineError::representation_error(RepFlag::Character);
- let err = self.error_form(err, stub);
+ let stub = functor_stub(atom!("path_canonical"), 2);
+ let err = self.machine_st.representation_error(RepFlag::Character);
+ let err = self.machine_st.error_form(err, stub);
return Err(err);
}
};
- let chars = self.heap.put_complete_string(current);
- (self.unify_fn)(self, self[temp_v!(1)], chars);
+ let canonical_atom = self.machine_st.atom_tbl.build_with(cs);
- let next = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
+ self.machine_st.unify_complete_string(
+ canonical_atom,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
- match env::set_current_dir(std::path::Path::new(&next)) {
- Ok(_) => {}
- _ => {
- self.fail = true;
- return Ok(());
- }
- }
- } else {
- self.fail = true;
return Ok(());
}
+ _ => {
+ }
}
- &SystemClauseType::PathCanonical => {
- let path = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
+ }
- match fs::canonicalize(path) {
- Ok(canonical) => {
- let cs = match canonical.to_str() {
- Some(s) => s,
- _ => {
- let stub =
- MachineError::functor_stub(clause_name!("path_canonical"), 2);
- let err = MachineError::representation_error(RepFlag::Character);
- let err = self.error_form(err, stub);
+ self.machine_st.fail = true;
+ Ok(())
+ }
- return Err(err);
- }
- };
- let chars = self.heap.put_complete_string(cs);
- (self.unify_fn)(self, self[temp_v!(2)], chars);
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
+ #[inline(always)]
+ pub(crate) fn atom_chars(&mut self) {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ read_heap_cell!(a1,
+ (HeapCellValueTag::Char) => {
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(a1);
+ self.machine_st.heap.push(empty_list_as_cell!());
+
+ unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h));
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ self.machine_st.unify_complete_string(
+ name,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
+ } else {
+ self.machine_st.fail = true;
}
}
- &SystemClauseType::FileTime => {
- let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- let which = match self.store(self.deref(self[temp_v!(2)])) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
- atom.as_str()
- } else {
- unreachable!()
+ if let Some(str_like) = self.machine_st.value_to_str_like(a2) {
+ let atom = match str_like {
+ AtomOrString::Atom(atom) => {
+ atom
}
- }
- _ => {
- unreachable!()
- }
- };
-
- if let Ok(md) = fs::metadata(file) {
- if let Ok(time) = match which {
- "modification" => md.modified(),
- "access" => md.accessed(),
- "creation" => md.created(),
- _ => {
- unreachable!()
+ AtomOrString::String(string) => {
+ self.machine_st.atom_tbl.build_with(&string)
}
- } {
- let chars = self.systemtime_to_timestamp(time);
- (self.unify_fn)(self, self[temp_v!(3)], chars);
- } else {
- self.fail = true;
- return Ok(());
- }
- } else {
- self.fail = true;
- return Ok(());
+ };
+
+ self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
+ return;
}
+
+ self.machine_st.fail = true;
}
- &SystemClauseType::AtomChars => {
- let a1 = self[temp_v!(1)];
+ _ => {
+ unreachable!();
+ }
+ );
+ }
- match self.store(self.deref(a1)) {
- Addr::Char(c) => {
- let iter = once(Addr::Char(c));
- let list_of_chars = Addr::HeapCell(self.heap.to_list(iter));
+ #[inline(always)]
+ pub(crate) fn atom_codes(&mut self) -> CallResult {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- let a2 = self[temp_v!(2)];
- (self.unify_fn)(self, a2, list_of_chars);
- }
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
- let s = self.heap.put_complete_string(name.as_str());
- let a2 = self[temp_v!(2)];
+ read_heap_cell!(a1,
+ (HeapCellValueTag::Char, c) => {
+ let h = self.machine_st.heap.len();
- (self.unify_fn)(self, s, a2);
- } else {
- unreachable!()
- }
- }
- Addr::EmptyList => {
- let a2 = self[temp_v!(2)];
- let chars = vec![Addr::Char('['), Addr::Char(']')];
+ self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
+ self.machine_st.heap.push(empty_list_as_cell!());
- let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter()));
+ unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]);
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ let iter = name.chars()
+ .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+
+ let h = iter_to_heap_list(&mut self.machine_st.heap, iter);
+ unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]);
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ let stub_gen = || functor_stub(atom!("atom_codes"), 2);
- (self.unify_fn)(self, a2, list_of_chars);
+ match self.machine_st.try_from_list(self.machine_st.registers[2], stub_gen) {
+ Ok(addrs) => {
+ let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
+ let atom = self.machine_st.atom_tbl.build_with(&string);
+
+ self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
}
- addr if addr.is_ref() => {
- let mut iter = self.heap_pstr_iter(self[temp_v!(2)]);
- let string = iter.to_string();
-
- match iter.focus() {
- Addr::EmptyList => {
- if &string == "[]" {
- (self.unify_fn)(self, addr, Addr::EmptyList);
- } else {
- let chars = clause_name!(string, self.atom_tbl);
- let atom =
- self.heap.to_unifiable(HeapCellValue::Atom(chars, None));
-
- (self.unify_fn)(self, addr, atom);
- }
- }
- focus => {
- if let Addr::Lis(l) = focus {
- let stub =
- MachineError::functor_stub(clause_name!("atom_chars"), 2);
-
- let err = MachineError::type_error(
- self.heap.h(),
- ValidType::Character,
- Addr::HeapCell(l),
- );
-
- return Err(self.error_form(err, stub));
- } else {
- unreachable!()
- }
- }
- }
+ Err(e) => {
+ return Err(e);
}
- _ => unreachable!(),
- };
+ }
+ }
+ _ => {
+ unreachable!();
}
- &SystemClauseType::AtomCodes => {
- let a1 = self[temp_v!(1)];
+ );
- match self.store(self.deref(a1)) {
- Addr::Char(c) => {
- let iter = once(Addr::Fixnum(c as isize));
- let list_of_codes = Addr::HeapCell(self.heap.to_list(iter));
+ Ok(())
+ }
- let a2 = self[temp_v!(2)];
- (self.unify_fn)(self, a2, list_of_codes);
- }
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
- let a2 = self.store(self.deref(self[temp_v!(2)]));
+ #[inline(always)]
+ pub(crate) fn atom_length(&mut self) {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- let iter = name.as_str().chars().map(|c| Addr::Fixnum(c as isize));
+ let len: i64 = read_heap_cell!(a1,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ name.chars().count() as i64
+ } else {
+ self.machine_st.fail = true;
+ return;
+ }
+ }
+ (HeapCellValueTag::Char) => {
+ 1
+ }
+ _ => {
+ unreachable!()
+ }
+ );
- let list_of_codes = Addr::HeapCell(self.heap.to_list(iter));
+ self.machine_st.unify_fixnum(
+ Fixnum::build_with(len),
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
+ }
- (self.unify_fn)(self, a2, list_of_codes);
- } else {
- unreachable!()
- }
- }
- Addr::EmptyList => {
- let chars = vec![Addr::Fixnum('[' as isize), Addr::Fixnum(']' as isize)];
+ #[inline(always)]
+ pub(crate) fn call_continuation(&mut self, last_call: bool) -> CallResult {
+ let stub_gen = || functor_stub(atom!("call_continuation"), 1);
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter()));
- let a2 = self[temp_v!(2)];
+ match self.machine_st.try_from_list(a1, stub_gen) {
+ Err(e) => Err(e),
+ Ok(cont_chunks) => {
+ let mut return_p = if last_call {
+ self.machine_st.cp
+ } else {
+ self.machine_st.p + 1
+ };
- (self.unify_fn)(self, a2, list_of_codes);
- }
- addr if addr.is_ref() => {
- let stub = MachineError::functor_stub(clause_name!("atom_codes"), 2);
-
- match self.try_from_list(temp_v!(2), stub) {
- Err(e) => return Err(e),
- Ok(addrs) => {
- let mut chars = String::new();
-
- for addr in addrs {
- let addr = self.store(self.deref(addr));
-
- match Number::try_from((addr, &self.heap)) {
- Ok(Number::Fixnum(n)) => {
- let c = self.int_to_char(
- &Integer::from(n),
- "atom_codes",
- 2,
- )?;
-
- chars.push(c);
- continue;
- }
- Ok(Number::Integer(n)) => {
- let c = self.int_to_char(&n, "atom_codes", 2)?;
- chars.push(c);
-
- continue;
- }
- _ => {
- let stub = MachineError::functor_stub(
- clause_name!("atom_codes"),
- 2,
- );
-
- let err = MachineError::type_error(
- self.heap.h(),
- ValidType::Integer,
- addr,
- );
-
- return Err(self.error_form(err, stub));
- }
- }
- }
+ self.machine_st.p = return_p;
- let string = self.heap.to_unifiable(HeapCellValue::Atom(
- clause_name!(chars, self.atom_tbl),
- None,
- ));
+ for chunk in cont_chunks.into_iter().rev() {
+ return_p = self.machine_st.call_continuation_chunk(chunk, return_p);
+ }
- self.bind(addr.as_var().unwrap(), string);
- }
- }
- }
- _ => {
- unreachable!()
- }
- };
+ Ok(())
}
- &SystemClauseType::AtomLength => {
- let a1 = self.store(self.deref(self[temp_v!(1)]));
+ }
+ }
- let atom = match self.store(self.deref(a1)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- name.clone()
- } else {
- unreachable!()
- }
- }
- Addr::EmptyList => {
- clause_name!("[]")
- }
- Addr::Char(c) => {
- clause_name!(c.to_string(), self.atom_tbl)
- }
- _ => {
- unreachable!()
- }
- };
+ #[inline(always)]
+ pub(crate) fn chars_to_number(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("number_chars"), 2);
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ if let Some(atom_or_string) = self.machine_st.value_to_str_like(a1) {
+ self.machine_st.parse_number_from_string(
+ atom_or_string.to_string(),
+ &self.indices,
+ stub_gen,
+ )?;
+ } else {
+ // a1 is a ground list at the call site within
+ // number_chars/2, so failure of value_to_str_like
+ // means the list contains a non-character.
+ let err = self.machine_st.type_error(ValidType::Character, a1);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+
+ Ok(())
+ }
- let len = Integer::from(atom.as_str().chars().count());
- let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len)));
+ #[inline(always)]
+ pub(crate) fn create_partial_string(&mut self) {
+ let atom = cell_as_atom!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+ );
- let a2 = self[temp_v!(2)];
+ if atom == atom!("") {
+ self.machine_st.fail = true;
+ return;
+ }
- (self.unify_fn)(self, a2, len);
- }
- &SystemClauseType::CallContinuation => {
- let stub = MachineError::functor_stub(clause_name!("call_continuation"), 1);
+ let pstr_h = self.machine_st.heap.len();
- match self.try_from_list(temp_v!(1), stub) {
- Err(e) => return Err(e),
- Ok(cont_chunks) => {
- let mut return_p = if self.last_call {
- self.cp
- } else {
- self.p.local() + 1
- };
+ self.machine_st.heap.push(pstr_as_cell!(atom));
+ self.machine_st.heap.push(heap_loc_as_cell!(pstr_h+1));
- self.p = CodePtr::Local(return_p);
+ unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_as_cell!(pstr_h));
- for chunk in cont_chunks.into_iter().rev() {
- return_p = self.call_continuation_chunk(chunk, return_p);
- }
- }
+ if !self.machine_st.fail {
+ self.machine_st.bind(Ref::heap_cell(pstr_h+1), self.machine_st.registers[3]);
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn is_partial_string(&mut self) {
+ let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.push(value);
+
+ let mut iter = HeapPStrIter::new(&self.machine_st.heap, h);
+
+ while let Some(_) = iter.next() {}
+
+ let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator();
+ self.machine_st.fail = !at_end_of_pstr;
+
+ self.machine_st.heap.pop();
+ }
+
+ #[inline(always)]
+ pub(crate) fn partial_string_tail(&mut self) {
+ let pstr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ read_heap_cell!(pstr,
+ (HeapCellValueTag::PStrLoc, h) => {
+ let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h);
+
+ if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() {
+ self.machine_st.unify_atom(
+ atom!("[]"),
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+ );
+ } else {
+ unify_fn!(
+ self.machine_st,
+ heap_loc_as_cell!(h+1),
+ self.machine_st.registers[2]
+ );
}
+ }
+ (HeapCellValueTag::CStr) => {
+ self.machine_st.unify_atom(
+ atom!("[]"),
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+ );
+ }
+ (HeapCellValueTag::Lis, h) => {
+ unify_fn!(
+ self.machine_st,
+ heap_loc_as_cell!(h+1),
+ self.machine_st.registers[2]
+ );
+ }
+ _ => {
+ self.machine_st.fail = true;
+ }
+ );
+ }
+ #[inline(always)]
+ pub(crate) fn peek_byte(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("peek_byte"), 2);
+
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("peek_byte"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Binary,
+ Some(self.machine_st.registers[2]),
+ atom!("peek_byte"),
+ 2,
+ )?;
+
+ if stream.past_end_of_stream() {
+ if EOFAction::Reset != stream.options().eof_action() {
+ return Ok(());
+ } else if self.machine_st.fail {
return Ok(());
}
- &SystemClauseType::CharsToNumber => {
- let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
+ }
- match self.try_from_list(temp_v!(1), stub) {
- Err(e) => {
- return Err(e);
- }
- Ok(addrs) => match self.try_char_list(addrs) {
- Ok(string) => {
- let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
- self.parse_number_from_string(string, indices, stub)?;
- }
- Err(err) => {
- let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
+ if stream.at_end_of_stream() {
+ stream.set_past_end_of_stream(true);
- return Err(self.error_form(err, stub));
- }
- },
- }
- }
- &SystemClauseType::CreatePartialString => {
- let atom = match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Con(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- name.clone()
- } else {
- unreachable!()
- }
+ self.machine_st.unify_fixnum(
+ Fixnum::build_with(-1),
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
+
+ return Ok(());
+ }
+
+ let addr = match self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) {
+ addr if addr.is_var() => addr,
+ addr => match Number::try_from(addr) {
+ Ok(Number::Integer(n)) => {
+ if let Some(nb) = n.to_u8() {
+ fixnum_as_cell!(Fixnum::build_with(nb as i64))
+ } else {
+ let err = self.machine_st.type_error(ValidType::InByte, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
- _ => {
- unreachable!()
+ }
+ Ok(Number::Fixnum(n)) => {
+ if let Ok(nb) = u8::try_from(n.get_num()) {
+ fixnum_as_cell!(Fixnum::build_with(nb as i64))
+ } else {
+ let err = self.machine_st.type_error(ValidType::InByte, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
- };
+ }
+ _ => {
+ let err = self.machine_st.type_error(ValidType::InByte, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ },
+ };
- if atom.as_str().is_empty() {
- self.fail = true;
- return Ok(());
+ loop {
+ match stream.peek_byte().map_err(|e| e.kind()) {
+ Ok(b) => {
+ self.machine_st.unify_fixnum(Fixnum::build_with(b as i64), addr);
+ }
+ Err(ErrorKind::PermissionDenied) => {
+ self.machine_st.fail = true;
+ break;
}
+ _ => {
+ self.machine_st.eof_action(
+ self.machine_st.registers[2],
+ stream,
+ atom!("peek_byte"),
+ 2,
+ )?;
- let pstr = self.heap.allocate_pstr(atom.as_str());
- (self.unify_fn)(self, self[temp_v!(2)], pstr);
+ if EOFAction::Reset != stream.options().eof_action() {
+ break;
+ } else if self.machine_st.fail {
+ break;
+ }
+ }
+ }
+ }
- if !self.fail {
- let h = self.heap.h();
- let pstr_tail = self.heap[h - 1].as_addr(h - 1);
+ Ok(())
+ }
- (self.unify_fn)(self, self[temp_v!(3)], pstr_tail);
- }
+ #[inline(always)]
+ pub(crate) fn peek_char(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("peek_char"), 2);
+
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("peek_char"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Text,
+ Some(self.machine_st.registers[2]),
+ atom!("peek_char"),
+ 2,
+ )?;
+
+ if stream.past_end_of_stream() {
+ if EOFAction::Reset != stream.options().eof_action() {
+ return Ok(());
+ } else if self.machine_st.fail {
+ return Ok(());
}
- &SystemClauseType::IsPartialString => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
+ }
- match addr {
- Addr::EmptyList => {
- return return_from_clause!(self.last_call, self);
- }
- Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => {
- self.fail = true;
- return Ok(());
+ if stream.at_end_of_stream() {
+ let end_of_file = atom!("end_of_file");
+ stream.set_past_end_of_stream(true);
+
+ self.machine_st.unify_atom(
+ end_of_file,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
+
+ return Ok(());
+ }
+
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ let a2 = read_heap_cell!(a2,
+ (HeapCellValueTag::Char) => {
+ a2
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ if let Some(c) = name.as_char() {
+ char_as_cell!(c)
+ } else {
+ let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
- _ => {}
+ } else {
+ let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
+ a2
+ }
+ _ => {
+ let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ );
+
+ loop {
+ match stream.peek_char().map(|result| result.map_err(|e| e.kind())) {
+ Some(Ok(d)) => {
+ self.machine_st.unify_char(d, a2);
+ break;
+ }
+ Some(Err(ErrorKind::PermissionDenied)) => {
+ self.machine_st.fail = true;
+ break;
}
+ _ => {
+ self.machine_st.eof_action(
+ self.machine_st.registers[2],
+ stream,
+ atom!("peek_char"),
+ 2,
+ )?;
- let mut heap_pstr_iter = self.heap_pstr_iter(addr);
+ if EOFAction::Reset != stream.options().eof_action() {
+ break;
+ } else if self.machine_st.fail {
+ break;
+ }
+ }
+ }
+ }
- while let Some(_) = heap_pstr_iter.next() {}
+ Ok(())
+ }
- self.fail = match heap_pstr_iter.focus() {
- Addr::AttrVar(_)
- | Addr::HeapCell(_)
- | Addr::StackCell(..)
- | Addr::EmptyList => false,
- _ => true,
- };
+ #[inline(always)]
+ pub(crate) fn peek_code(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("peek_code"), 2);
+
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("peek_code"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Text,
+ Some(self.machine_st.registers[2]),
+ atom!("peek_code"),
+ 2,
+ )?;
+
+ if stream.past_end_of_stream() {
+ if EOFAction::Reset != stream.options().eof_action() {
+ return Ok(());
+ } else if self.machine_st.fail {
+ return Ok(());
}
- &SystemClauseType::PartialStringTail => {
- let pstr = self.store(self.deref(self[temp_v!(1)]));
+ }
+
+ if stream.at_end_of_stream() {
+ let end_of_file = atom!("end_of_file");
+ stream.set_past_end_of_stream(true);
- match pstr {
- Addr::PStrLocation(h, _) => {
- if let HeapCellValue::PartialString(_, true) = &self.heap[h] {
- let tail = self.heap[h + 1].as_addr(h + 1);
- let target = self[temp_v!(2)];
+ self.machine_st.unify_atom(
+ end_of_file,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
- (self.unify_fn)(self, tail, target);
+ return Ok(());
+ }
+
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ let addr = read_heap_cell!(a2,
+ (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
+ a2
+ }
+ _ => {
+ match Number::try_from(a2) {
+ Ok(Number::Integer(n)) => {
+ let n = n
+ .to_u32()
+ .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
+
+ if let Some(n) = n {
+ fixnum_as_cell!(Fixnum::build_with(n as i64))
} else {
- self.fail = true;
- return Ok(());
+ let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
}
- Addr::Lis(h) => {
- (self.unify_fn)(self, Addr::HeapCell(h + 1), self[temp_v!(2)]);
- }
- Addr::EmptyList => {
- self.fail = true;
- return Ok(());
+ Ok(Number::Fixnum(n)) => {
+ let n = u32::try_from(n.get_num())
+ .ok()
+ .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
+
+ if let Some(n) = n {
+ fixnum_as_cell!(Fixnum::build_with(n as i64))
+ } else {
+ let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
}
_ => {
- unreachable!()
+ let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
}
}
- &SystemClauseType::PeekByte => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "peek_byte",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Binary,
- Some(self[temp_v!(2)]),
- clause_name!("peek_byte"),
- 2,
- )?;
-
- if stream.past_end_of_stream() {
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
- }
+ );
- if stream.at_end_of_stream() {
- stream.set_past_end_of_stream();
- (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1));
- return return_from_clause!(self.last_call, self);
- }
-
- let addr = match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => addr,
- addr => match Number::try_from((addr, &self.heap)) {
- Ok(Number::Integer(n)) => {
- if let Some(nb) = n.to_u8() {
- Addr::Usize(nb as usize)
- } else {
- return Err(self.type_error(
- ValidType::InByte,
- addr,
- clause_name!("peek_byte"),
- 2,
- ));
- }
- }
- Ok(Number::Fixnum(n)) => {
- if let Ok(nb) = u8::try_from(n) {
- Addr::Usize(nb as usize)
- } else {
- return Err(self.type_error(
- ValidType::InByte,
- addr,
- clause_name!("peek_byte"),
- 2,
- ));
- }
- }
- _ => {
- return Err(self.type_error(
- ValidType::InByte,
- addr,
- clause_name!("peek_byte"),
- 2,
- ));
- }
- },
- };
+ loop {
+ let result = stream.peek_char();
- loop {
- match stream.peek_byte().map_err(|e| e.kind()) {
- Ok(b) => {
- if let Some(var) = addr.as_var() {
- self.bind(var, Addr::Usize(b as usize));
- break;
- } else if addr == Addr::Usize(b as usize) {
- break;
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- Err(ErrorKind::PermissionDenied) => {
- self.fail = true;
- break;
- }
- _ => {
- self.eof_action(
- self[temp_v!(2)],
- &mut stream,
- clause_name!("peek_byte"),
- 2,
- )?;
-
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
- }
- }
+ match result.map(|result| result.map_err(|e| e.kind())) {
+ Some(Ok(c)) => {
+ self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
+ break;
}
- }
- &SystemClauseType::PeekChar => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "peek_char",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Text,
- Some(self[temp_v!(2)]),
- clause_name!("peek_char"),
- 2,
- )?;
-
- if stream.past_end_of_stream() {
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
+ Some(Err(ErrorKind::PermissionDenied)) => {
+ self.machine_st.fail = true;
+ break;
+ }
+ _ => {
+ self.machine_st.eof_action(
+ self.machine_st.registers[2],
+ stream,
+ atom!("peek_code"),
+ 2,
+ )?;
+
+ if EOFAction::Reset != stream.options().eof_action() {
+ break;
+ } else if self.machine_st.fail {
+ break;
}
}
+ }
+ }
- if stream.at_end_of_stream() {
- let end_of_file = clause_name!("end_of_file");
- let end_of_file = self
- .heap
- .to_unifiable(HeapCellValue::Atom(end_of_file, None));
+ return Ok(());
+ }
- stream.set_past_end_of_stream();
+ #[inline(always)]
+ pub(crate) fn number_to_chars(&mut self) {
+ let n = self.machine_st.registers[1];
+ let chs = self.machine_st.registers[2];
- (self.unify_fn)(self, self[temp_v!(2)], end_of_file);
- return return_from_clause!(self.last_call, self);
- }
+ let n = self.machine_st.store(self.machine_st.deref(n));
- let addr = match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => addr,
- Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] {
- HeapCellValue::Atom(ref atom, _) if atom.is_char() => {
- if let Some(c) = atom.as_str().chars().next() {
- Addr::Char(c)
- } else {
- unreachable!()
- }
- }
- culprit => {
- return Err(self.type_error(
- ValidType::InCharacter,
- culprit.as_addr(h),
- clause_name!("peek_char"),
- 2,
- ));
- }
- },
- Addr::Char(d) => Addr::Char(d),
- culprit => {
- return Err(self.type_error(
- ValidType::InCharacter,
- culprit,
- clause_name!("peek_char"),
- 2,
- ));
- }
- };
+ let string = match Number::try_from(n) {
+ Ok(Number::Float(OrderedFloat(n))) => {
+ format!("{0:<20?}", n)
+ }
+ Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+ Ok(Number::Integer(n)) => n.to_string(),
+ Ok(Number::Rational(r)) => {
+ // n has already been confirmed as an integer, and
+ // internally, Rational is assumed reduced, so its denominator
+ // must be 1.
+ r.numer().to_string()
+ }
+ _ => {
+ unreachable!()
+ }
+ };
- loop {
- match stream.peek_char().map_err(|e| e.kind()) {
- Ok(d) => {
- if let Some(var) = addr.as_var() {
- self.bind(var, Addr::Char(d));
- break;
- } else if addr == Addr::Char(d) {
- break;
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- Err(ErrorKind::PermissionDenied) => {
- self.fail = true;
- break;
- }
- _ => {
- self.eof_action(
- self[temp_v!(2)],
- &mut stream,
- clause_name!("peek_char"),
- 2,
- )?;
-
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
- } /*
- _ => {
- let stub = MachineError::functor_stub(clause_name!("peek_char"), 2);
- let err = MachineError::representation_error(RepFlag::Character);
- let err = self.error_form(err, stub);
-
- return Err(err);
- }*/
- }
- }
+ let chars_atom = self.machine_st.atom_tbl.build_with(&string.trim());
+ self.machine_st.unify_complete_string(chars_atom, self.machine_st.store(self.machine_st.deref(chs)));
+ }
+
+ #[inline(always)]
+ pub(crate) fn number_to_codes(&mut self) {
+ let n = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let chs = self.machine_st.registers[2];
+
+ let string = match Number::try_from(n) {
+ Ok(Number::Float(OrderedFloat(n))) => {
+ format!("{0:<20?}", n)
}
- &SystemClauseType::PeekCode => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "peek_code",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Text,
- Some(self[temp_v!(2)]),
- clause_name!("peek_code"),
- 2,
- )?;
-
- if stream.past_end_of_stream() {
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
- }
+ Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+ Ok(Number::Integer(n)) => n.to_string(),
+ Ok(Number::Rational(r)) => {
+ // n has already been confirmed as an integer, and
+ // internally, Rational is assumed reduced, so its
+ // denominator must be 1.
+ r.numer().to_string()
+ }
+ _ => {
+ unreachable!()
+ }
+ };
- if stream.at_end_of_stream() {
- let end_of_file = clause_name!("end_of_file");
- let end_of_file = self
- .heap
- .to_unifiable(HeapCellValue::Atom(end_of_file, None));
+ let codes = string.trim().chars().map(|c| {
+ fixnum_as_cell!(Fixnum::build_with(c as i64))
+ });
- stream.set_past_end_of_stream();
+ let h = iter_to_heap_list(&mut self.machine_st.heap, codes);
+ unify!(self.machine_st, heap_loc_as_cell!(h), chs);
+ }
- (self.unify_fn)(self, self[temp_v!(2)], end_of_file);
- return return_from_clause!(self.last_call, self);
- }
+ #[inline(always)]
+ pub(crate) fn codes_to_number(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("number_codes"), 2);
- let addr = match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => addr,
- addr => match Number::try_from((addr, &self.heap)) {
- Ok(Number::Integer(n)) => {
- let n = n
- .to_u32()
- .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
+ match self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen) {
+ Err(e) => {
+ return Err(e);
+ }
+ Ok(addrs) => {
+ let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
+ self.machine_st.parse_number_from_string(string, &self.indices, stub_gen)?;
+ }
+ }
- if let Some(n) = n {
- Addr::Fixnum(n as isize)
- } else {
- return Err(self.representation_error(
- RepFlag::InCharacterCode,
- clause_name!("peek_code"),
- 2,
- ));
- }
- }
- Ok(Number::Fixnum(n)) => {
- let n = u32::try_from(n)
- .ok()
- .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
-
- if let Some(n) = n {
- Addr::Fixnum(n as isize)
- } else {
- return Err(self.representation_error(
- RepFlag::InCharacterCode,
- clause_name!("peek_code"),
- 2,
- ));
- }
- }
- _ => {
- return Err(self.type_error(
- ValidType::Integer,
- self[temp_v!(2)],
- clause_name!("peek_code"),
- 2,
- ));
- }
- },
- };
+ Ok(())
+ }
- loop {
- let result = stream.peek_char();
-
- match result.map_err(|e| e.kind()) {
- Ok(c) => {
- if let Some(var) = addr.as_var() {
- self.bind(var, Addr::Fixnum(c as isize));
- break;
- } else if addr == Addr::Fixnum(c as isize) {
- break;
- } else {
- self.fail = true;
- return Ok(());
+ #[inline(always)]
+ pub(crate) fn lifted_heap_length(&mut self) {
+ let a1 = self.machine_st.registers[1];
+ let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64);
+
+ self.machine_st.unify_fixnum(lh_len, a1);
+ }
+
+ #[inline(always)]
+ pub(crate) fn char_code(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("char_code"), 2);
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ let c = read_heap_cell!(a1,
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ name.as_char().unwrap()
+ }
+ (HeapCellValueTag::Char, c) => {
+ c
+ }
+ _ => {
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ match Number::try_from(a2) {
+ Ok(Number::Integer(n)) => {
+ let c = match n.to_u32().and_then(std::char::from_u32) {
+ Some(c) => c,
+ _ => {
+ let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
- }
- Err(ErrorKind::PermissionDenied) => {
- self.fail = true;
- break;
- }
- _ => {
- self.eof_action(
- self[temp_v!(2)],
- &mut stream,
- clause_name!("peek_code"),
- 2,
- )?;
-
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
+ };
+
+ self.machine_st.unify_char(c, a1);
+ return Ok(());
+ }
+ Ok(Number::Fixnum(n)) => {
+ match u32::try_from(n.get_num()) {
+ Ok(n) => {
+ if let Some(c) = std::char::from_u32(n) {
+ self.machine_st.unify_char(c, a1);
+ return Ok(());
+ }
}
+ _ => {}
}
+
+ let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ _ => {
+ self.machine_st.fail = true;
+ return Ok(());
}
}
}
- &SystemClauseType::NumberToChars => {
- let n = self[temp_v!(1)];
- let chs = self[temp_v!(2)];
+ );
- let n = self.store(self.deref(n));
+ self.machine_st.unify_fixnum(
+ Fixnum::build_with(c as i64),
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
- let string = match Number::try_from((n, &self.heap)) {
- Ok(Number::Float(OrderedFloat(n))) => {
- format!("{0:<20?}", n)
- }
- Ok(Number::Fixnum(n)) => n.to_string(),
- Ok(Number::Integer(n)) => n.to_string(),
- Ok(Number::Rational(r)) => {
- // n has already been confirmed as an integer, and
- // internally, Rational is assumed reduced, so its denominator
- // must be 1.
- r.numer().to_string()
- }
- _ => {
- unreachable!()
- }
- };
+ Ok(())
+ }
- let chars = string.trim().chars().map(|c| Addr::Char(c));
- let char_list = Addr::HeapCell(self.heap.to_list(chars));
+ #[inline(always)]
+ pub(crate) fn char_type(&mut self) {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- (self.unify_fn)(self, char_list, chs);
+ let c = read_heap_cell!(a1,
+ (HeapCellValueTag::Char, c) => {
+ c
+ }
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ name.as_char().unwrap()
+ }
+ _ => {
+ unreachable!()
}
- &SystemClauseType::NumberToCodes => {
- let n = self[temp_v!(1)];
- let chs = self[temp_v!(2)];
+ );
- let string = match Number::try_from((n, &self.heap)) {
- Ok(Number::Float(OrderedFloat(n))) => {
- format!("{0:<20?}", n)
- }
- Ok(Number::Fixnum(n)) => n.to_string(),
- Ok(Number::Integer(n)) => n.to_string(),
- Ok(Number::Rational(r)) => {
- // n has already been confirmed as an integer, and
- // internally, Rational is assumed reduced, so its
- // denominator must be 1.
- r.numer().to_string()
- }
- _ => {
- unreachable!()
- }
- };
+ let chars = cell_as_atom!(a2);
+ self.machine_st.fail = true; // This predicate fails by default.
- let codes = string.trim().chars().map(|c| Addr::Fixnum(c as isize));
+ macro_rules! macro_check {
+ ($id:ident, $name:expr) => {
+ if $id!(c) && chars == $name {
+ self.machine_st.fail = false;
+ return;
+ }
+ };
+ }
- let codes_list = Addr::HeapCell(self.heap.to_list(codes));
+ macro_rules! method_check {
+ ($id:ident, $name:expr) => {
+ if c.$id() && chars == $name {
+ self.machine_st.fail = false;
+ return;
+ }
+ };
+ }
- (self.unify_fn)(self, codes_list, chs);
- }
- &SystemClauseType::CodesToNumber => {
- let stub = MachineError::functor_stub(clause_name!("number_codes"), 2);
+ macro_check!(alpha_char, atom!("alpha"));
+ method_check!(is_alphabetic, atom!("alphabetic"));
+ method_check!(is_alphanumeric, atom!("alphanumeric"));
+ macro_check!(alpha_numeric_char, atom!("alnum"));
+ method_check!(is_ascii, atom!("ascii"));
+ method_check!(is_ascii_punctuation, atom!("ascii_ponctuaction"));
+ method_check!(is_ascii_graphic, atom!("ascii_graphic"));
+ // macro_check!(backslash_char, atom!("backslash"));
+ // macro_check!(back_quote_char, atom!("back_quote"));
+ macro_check!(binary_digit_char, atom!("binary_digit"));
+ // macro_check!(capital_letter_char, atom!("upper"));
+ // macro_check!(comment_1_char, "comment_1");
+ // macro_check!(comment_2_char, "comment_2");
+ method_check!(is_control, atom!("control"));
+ // macro_check!(cut_char, atom!("cut"));
+ macro_check!(decimal_digit_char, atom!("decimal_digit"));
+ // macro_check!(decimal_point_char, atom!("decimal_point"));
+ // macro_check!(double_quote_char, atom!("double_quote"));
+ macro_check!(exponent_char, atom!("exponent"));
+ macro_check!(graphic_char, atom!("graphic"));
+ macro_check!(graphic_token_char, atom!("graphic_token"));
+ macro_check!(hexadecimal_digit_char, atom!("hexadecimal_digit"));
+ macro_check!(layout_char, atom!("layout"));
+ method_check!(is_lowercase, atom!("lower"));
+ macro_check!(meta_char, atom!("meta"));
+ // macro_check!(new_line_char, atom!("new_line"));
+ method_check!(is_numeric, atom!("numeric"));
+ macro_check!(octal_digit_char, atom!("octal_digit"));
+ macro_check!(octet_char, atom!("octet"));
+ macro_check!(prolog_char, atom!("prolog"));
+ // macro_check!(semicolon_char, atom!("semicolon"));
+ macro_check!(sign_char, atom!("sign"));
+ // macro_check!(single_quote_char, atom!("single_quote"));
+ // macro_check!(small_letter_char, atom!("lower"));
+ macro_check!(solo_char, atom!("solo"));
+ // macro_check!(space_char, atom!("space"));
+ macro_check!(symbolic_hexadecimal_char, atom!("symbolic_hexadecimal"));
+ macro_check!(symbolic_control_char, atom!("symbolic_control"));
+ method_check!(is_uppercase, atom!("upper"));
+ // macro_check!(variable_indicator_char, atom!("variable_indicator"));
+ method_check!(is_whitespace, atom!("whitespace"));
+ }
- match self.try_from_list(temp_v!(1), stub) {
- Err(e) => {
- return Err(e);
- }
- Ok(addrs) => match self.try_char_list(addrs) {
- Ok(chars) => {
- let stub = MachineError::functor_stub(clause_name!("number_codes"), 2);
- self.parse_number_from_string(chars, indices, stub)?;
- }
- Err(err) => {
- let stub = MachineError::functor_stub(clause_name!("number_codes"), 2);
+ #[inline(always)]
+ pub(crate) fn check_cut_point(&mut self) {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let old_b = cell_as_fixnum!(addr).get_num() as usize;
- return Err(self.error_form(err, stub));
- }
- },
+ let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
+ let prev_b = self.machine_st.stack.index_or_frame(prev_b).prelude.b;
+
+ if prev_b > old_b {
+ self.machine_st.fail = true;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn copy_term_without_attr_vars(&mut self) {
+ self.machine_st.copy_term(AttrVarPolicy::StripAttributes);
+ }
+
+ #[inline(always)]
+ pub(crate) fn fetch_global_var(&mut self) {
+ let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+ let addr = self.machine_st.registers[2];
+
+ match self.indices.global_variables.get_mut(&key) {
+ Some((ref ball, ref mut loc)) => match loc {
+ Some(value_loc) => {
+ unify_fn!(self.machine_st, addr, *value_loc);
}
- }
- &SystemClauseType::LiftedHeapLength => {
- let a1 = self[temp_v!(1)];
- let lh_len = Addr::Usize(self.lifted_heap.h());
+ None if !ball.stub.is_empty() => {
+ let h = self.machine_st.heap.len();
+ let stub = ball.copy_and_align(h);
- (self.unify_fn)(self, a1, lh_len);
- }
- &SystemClauseType::CharCode => {
- let a1 = self[temp_v!(1)];
+ self.machine_st.heap.extend(stub.into_iter());
- match self.store(self.deref(a1)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- let c = if let HeapCellValue::Atom(name, _) = &self.heap[h] {
- if name.is_char() {
- name.as_str().chars().next().unwrap()
- } else {
- self.fail = true;
- return Ok(());
- }
- } else {
- unreachable!()
- };
+ unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h));
- let a2 = self[temp_v!(2)];
- (self.unify_fn)(self, Addr::Fixnum(c as isize), a2);
+ if !self.machine_st.fail {
+ *loc = Some(heap_loc_as_cell!(h));
+ self.machine_st.trail(TrailRef::BlackboardEntry(key));
}
- Addr::Char(c) => {
- let a2 = self[temp_v!(2)];
- (self.unify_fn)(self, Addr::Fixnum(c as isize), a2);
- }
- addr if addr.is_ref() => {
- let a2 = self[temp_v!(2)];
- let a2 = self.store(self.deref(a2));
-
- let c = match Number::try_from((a2, &self.heap)) {
- Ok(Number::Integer(n)) => self.int_to_char(&n, "char_code", 2)?,
- Ok(Number::Fixnum(n)) => {
- self.int_to_char(&Integer::from(n), "char_code", 2)?
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
+ }
+ _ => self.machine_st.fail = true,
+ },
+ None => self.machine_st.fail = true,
+ };
+ }
- (self.unify_fn)(self, Addr::Char(c), addr);
+ #[inline(always)]
+ pub(crate) fn put_code(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("put_code"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Text,
+ None,
+ atom!("put_code"),
+ 2,
+ )?;
+
+ let stub_gen = || functor_stub(atom!("put_code"), 2);
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ if addr.is_var() {
+ let err = self.machine_st.instantiation_error();
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ } else {
+ match Number::try_from(addr) {
+ Ok(Number::Integer(n)) => {
+ if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) {
+ write!(&mut stream, "{}", c).unwrap();
+ return Ok(());
}
- _ => {
- unreachable!();
+ }
+ Ok(Number::Fixnum(n)) => {
+ let n = n.get_num();
+
+ if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) {
+ write!(&mut stream, "{}", c).unwrap();
+ return Ok(());
}
- };
+ }
+ _ => {
+ let err = self.machine_st.type_error(ValidType::Integer, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
}
- &SystemClauseType::CharType => {
- let a1 = self.store(self.deref(self[temp_v!(1)]));
- let a2 = self.store(self.deref(self[temp_v!(2)]));
- let c = match a1 {
- Addr::Char(c) => c,
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(name, _) = &self.heap[h] {
- name.as_str().chars().next().unwrap()
- } else {
- unreachable!()
- }
- }
- _ => unreachable!(),
- };
- let chars = match a2 {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(name, _) = &self.heap[h] {
- name.as_str().to_string()
- } else {
- unreachable!()
- }
- }
- Addr::Char(c) => c.to_string(),
- _ => unreachable!(),
- };
- self.fail = true; // This predicate fails by default.
- macro_rules! macro_check {
- ($id:ident, $name:tt) => {
- if $id!(c) && chars == $name {
- self.fail = false;
+ let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ }
- return return_from_clause!(self.last_call, self);
- }
- };
+ #[inline(always)]
+ pub(crate) fn put_char(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("put_char"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Text,
+ None,
+ atom!("put_char"),
+ 2,
+ )?;
+
+ let stub_gen = || functor_stub(atom!("put_char"), 2);
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ if addr.is_var() {
+ let err = self.machine_st.instantiation_error();
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ } else {
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ let c = name.as_char().unwrap();
+ write!(&mut stream, "{}", c).unwrap();
+ return Ok(());
}
- macro_rules! method_check {
- ($id:ident, $name:tt) => {
- if c.$id() && chars == $name {
- self.fail = false;
-
- return return_from_clause!(self.last_call, self);
- }
- };
+ (HeapCellValueTag::Char, c) => {
+ write!(&mut stream, "{}", c).unwrap();
+ return Ok(());
}
- macro_check!(alpha_char, "alpha");
- method_check!(is_alphabetic, "alphabetic");
- method_check!(is_alphanumeric, "alphanumeric");
- macro_check!(alpha_numeric_char, "alnum");
- method_check!(is_ascii, "ascii");
- method_check!(is_ascii_punctuation, "ascii_ponctuaction");
- method_check!(is_ascii_graphic, "ascii_graphic");
- // macro_check!(backslash_char, "backslash");
- // macro_check!(back_quote_char, "back_quote");
- macro_check!(binary_digit_char, "binary_digit");
- // macro_check!(capital_letter_char, "upper");
- // macro_check!(comment_1_char, "comment_1");
- // macro_check!(comment_2_char, "comment_2");
- method_check!(is_control, "control");
- // macro_check!(cut_char, "cut");
- macro_check!(decimal_digit_char, "decimal_digit");
- // macro_check!(decimal_point_char, "decimal_point");
- // macro_check!(double_quote_char, "double_quote");
- macro_check!(exponent_char, "exponent");
- macro_check!(graphic_char, "graphic");
- macro_check!(graphic_token_char, "graphic_token");
- macro_check!(hexadecimal_digit_char, "hexadecimal_digit");
- macro_check!(layout_char, "layout");
- method_check!(is_lowercase, "lower");
- macro_check!(meta_char, "meta");
- // macro_check!(new_line_char, "new_line");
- method_check!(is_numeric, "numeric");
- macro_check!(octal_digit_char, "octal_digit");
- macro_check!(octet_char, "octet");
- macro_check!(prolog_char, "prolog");
- // macro_check!(semicolon_char, "semicolon");
- macro_check!(sign_char, "sign");
- // macro_check!(single_quote_char, "single_quote");
- // macro_check!(small_letter_char, "lower");
- macro_check!(solo_char, "solo");
- // macro_check!(space_char, "space");
- macro_check!(symbolic_hexadecimal_char, "symbolic_hexadecimal");
- macro_check!(symbolic_control_char, "symbolic_control");
- method_check!(is_uppercase, "upper");
- // macro_check!(variable_indicator_char, "variable_indicator");
- method_check!(is_whitespace, "whitespace");
- }
- &SystemClauseType::CheckCutPoint => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
-
- match addr {
- Addr::Usize(old_b) | Addr::CutPoint(old_b) => {
- let prev_b = self.stack.index_or_frame(self.b).prelude.b;
- let prev_b = self.stack.index_or_frame(prev_b).prelude.b;
-
- if prev_b > old_b {
- self.fail = true;
- }
+ _ => {
+ }
+ );
+
+ let err = self.machine_st.type_error(ValidType::Character, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn put_chars(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("$put_chars"),
+ 2,
+ )?;
+
+ let mut bytes = Vec::new();
+ let stub_gen = || functor_stub(atom!("$put_chars"), 2);
+
+ if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
+ if stream.options().stream_type() == StreamType::Binary {
+ for c in string.as_str().chars() {
+ if c as u32 > 255 {
+ let err = self.machine_st.type_error(ValidType::Byte, char_as_cell!(c));
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
- _ => self.fail = true,
- };
- }
- &SystemClauseType::CopyTermWithoutAttrVars => {
- self.copy_term(AttrVarPolicy::StripAttributes);
+
+ bytes.push(c as u8);
+ }
+ } else {
+ bytes = string.as_str().bytes().collect();
}
- &SystemClauseType::FetchGlobalVar => {
- let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
- (h, atom.clone())
- } else {
- unreachable!()
- }
- }
- _ => {
- unreachable!()
- }
- };
- let addr = self[temp_v!(2)];
+ match stream.write_all(&bytes) {
+ Ok(_) => {
+ }
+ _ => {
+ let addr = stream_as_cell!(stream);
+ let err = self.machine_st.existence_error(ExistenceError::Stream(addr));
- match indices.global_variables.get_mut(&key) {
- Some((ref ball, ref mut loc)) => match loc {
- Some(ref value_addr) => {
- (self.unify_fn)(self, addr, *value_addr);
- }
- loc @ None if !ball.stub.is_empty() => {
- let h = self.heap.h();
- let stub = ball.copy_and_align(h);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ }
+ } else {
+ self.machine_st.fail = true;
+ }
+
+ Ok(())
+ }
- self.heap.extend(stub.into_iter());
- (self.unify_fn)(self, addr, Addr::HeapCell(h));
+ #[inline(always)]
+ pub(crate) fn put_byte(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("put_byte"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Binary,
+ None,
+ atom!("put_byte"),
+ 2,
+ )?;
+
+ let stub_gen = || functor_stub(atom!("put_byte"), 2);
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ if addr.is_var() {
+ let err = self.machine_st.instantiation_error();
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ } else {
+ match Number::try_from(addr) {
+ Ok(Number::Integer(n)) => {
+ if let Some(nb) = n.to_u8() {
+ match stream.write(&mut [nb]) {
+ Ok(1) => {
+ return Ok(());
+ }
+ _ => {
+ let err = self.machine_st.existence_error(
+ ExistenceError::Stream(stream_as_cell!(stream))
+ );
- if !self.fail {
- *loc = Some(Addr::HeapCell(h));
- self.trail(TrailRef::BlackboardEntry(key_h));
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
}
- _ => self.fail = true,
- },
- None => self.fail = true,
- };
- }
- &SystemClauseType::PutCode => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "put_code",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Text,
- None,
- clause_name!("put_code"),
- 2,
- )?;
-
- match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => {
- let stub = MachineError::functor_stub(clause_name!("put_code"), 2);
- let err = MachineError::instantiation_error();
-
- return Err(self.error_form(err, stub));
}
- addr => {
- match Number::try_from((addr, &self.heap)) {
- Ok(Number::Integer(n)) => {
- if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) {
- write!(&mut stream, "{}", c).unwrap();
- return return_from_clause!(self.last_call, self);
- }
- }
- Ok(Number::Fixnum(n)) => {
- if let Some(c) =
- u32::try_from(n).ok().and_then(|c| char::try_from(c).ok())
- {
- write!(&mut stream, "{}", c).unwrap();
- return return_from_clause!(self.last_call, self);
- }
+ }
+ Ok(Number::Fixnum(n)) => {
+ if let Ok(nb) = u8::try_from(n.get_num()) {
+ match stream.write(&mut [nb]) {
+ Ok(1) => {
+ return Ok(());
}
_ => {
- let stub = MachineError::functor_stub(clause_name!("put_code"), 2);
- let err = MachineError::type_error(
- self.heap.h(),
- ValidType::Integer,
- self[temp_v!(2)],
+ let err = self.machine_st.existence_error(
+ ExistenceError::Stream(stream_as_cell!(stream))
);
- return Err(self.error_form(err, stub));
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
}
-
- let stub = MachineError::functor_stub(clause_name!("put_code"), 2);
- let err = MachineError::representation_error(RepFlag::CharacterCode);
-
- return Err(self.error_form(err, stub));
}
}
+ _ => {
+ }
}
- &SystemClauseType::PutChar => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "put_char",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Text,
- None,
- clause_name!("put_char"),
- 2,
- )?;
-
- match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => {
- let stub = MachineError::functor_stub(clause_name!("put_char"), 2);
- let err = MachineError::instantiation_error();
-
- return Err(self.error_form(err, stub));
- }
- addr => {
- match self.store(self.deref(self[temp_v!(2)])) {
- Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] {
- HeapCellValue::Atom(ref atom, _) if atom.is_char() => {
- if let Some(c) = atom.as_str().chars().next() {
- write!(&mut stream, "{}", c).unwrap();
- return return_from_clause!(self.last_call, self);
- } else {
- unreachable!()
- }
- }
- _ => {}
- },
- Addr::Char(c) => {
- write!(&mut stream, "{}", c).unwrap();
- return return_from_clause!(self.last_call, self);
- }
- _ => {}
- }
+ }
- let stub = MachineError::functor_stub(clause_name!("put_char"), 2);
- let err =
- MachineError::type_error(self.heap.h(), ValidType::Character, addr);
+ let err = self.machine_st.type_error(ValidType::Byte, self.machine_st.registers[2]);
+ Err(self.machine_st.error_form(err, stub_gen()))
+ }
- return Err(self.error_form(err, stub));
- }
- }
+ #[inline(always)]
+ pub(crate) fn get_byte(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("get_byte"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Binary,
+ Some(self.machine_st.registers[2]),
+ atom!("get_byte"),
+ 2,
+ )?;
+
+ if stream.past_end_of_stream() {
+ self.machine_st.eof_action(self.machine_st.registers[2], stream, atom!("get_byte"), 2)?;
+
+ if EOFAction::Reset != stream.options().eof_action() {
+ return Ok(());
+ } else if self.machine_st.fail {
+ return Ok(());
}
- &SystemClauseType::PutChars => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "$put_chars",
- 2,
- )?;
+ }
- let mut bytes = Vec::new();
- let string = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
+ let stub_gen = || functor_stub(atom!("get_byte"), 2);
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- if stream.options().stream_type == StreamType::Binary {
- for c in string.chars() {
- bytes.push(c as u8);
+ let addr = if addr.is_var() {
+ addr
+ } else {
+ match Number::try_from(addr) {
+ Ok(Number::Integer(n)) => {
+ if let Some(nb) = n.to_u8() {
+ fixnum_as_cell!(Fixnum::build_with(nb as i64))
+ } else {
+ let err = self.machine_st.type_error(ValidType::InByte, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
- } else {
- bytes = string.into_bytes();
}
-
- match stream.write_all(&bytes) {
- Ok(_) => {
- return return_from_clause!(self.last_call, self);
- }
- _ => {
- let stub = MachineError::functor_stub(clause_name!("$put_chars"), 2);
-
- let addr = self
- .heap
- .to_unifiable(HeapCellValue::Stream(stream.clone()));
-
- return Err(self.error_form(
- MachineError::existence_error(
- self.heap.h(),
- ExistenceError::Stream(addr),
- ),
- stub,
- ));
+ Ok(Number::Fixnum(n)) => {
+ if let Ok(nb) = u8::try_from(n.get_num()) {
+ fixnum_as_cell!(Fixnum::build_with(nb as i64))
+ } else {
+ let err = self.machine_st.type_error(ValidType::InByte, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
}
+ _ => {
+ let err = self.machine_st.type_error(ValidType::InByte, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
}
- &SystemClauseType::PutByte => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "put_byte",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Binary,
- None,
- clause_name!("put_byte"),
- 2,
- )?;
-
- match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => {
- let stub = MachineError::functor_stub(clause_name!("put_byte"), 2);
- let err = MachineError::instantiation_error();
-
- return Err(self.error_form(err, stub));
- }
- addr => {
- match Number::try_from((addr, &self.heap)) {
- Ok(Number::Integer(n)) => {
- if let Some(nb) = n.to_u8() {
- match stream.write(&mut [nb]) {
- Ok(1) => {
- return return_from_clause!(self.last_call, self);
- }
- _ => {
- let stub = MachineError::functor_stub(
- clause_name!("put_byte"),
- 2,
- );
-
- let addr = self.heap.to_unifiable(
- HeapCellValue::Stream(stream.clone()),
- );
-
- return Err(self.error_form(
- MachineError::existence_error(
- self.heap.h(),
- ExistenceError::Stream(addr),
- ),
- stub,
- ));
- }
- }
- }
- }
- Ok(Number::Fixnum(n)) => {
- if let Ok(nb) = u8::try_from(n) {
- match stream.write(&mut [nb]) {
- Ok(1) => {
- return return_from_clause!(self.last_call, self);
- }
- _ => {
- let stub = MachineError::functor_stub(
- clause_name!("put_byte"),
- 2,
- );
-
- let addr = self.heap.to_unifiable(
- HeapCellValue::Stream(stream.clone()),
- );
-
- return Err(self.error_form(
- MachineError::existence_error(
- self.heap.h(),
- ExistenceError::Stream(addr),
- ),
- stub,
- ));
- }
- }
- }
- }
- _ => {}
- }
+ };
- let stub = MachineError::functor_stub(clause_name!("put_byte"), 2);
- let err = MachineError::type_error(
- self.heap.h(),
- ValidType::Byte,
- self[temp_v!(2)],
- );
+ loop {
+ let mut b = [0u8; 1];
- return Err(self.error_form(err, stub));
- }
+ match stream.read(&mut b) {
+ Ok(1) => {
+ self.machine_st.unify_fixnum(Fixnum::build_with(b[0] as i64), addr);
+ break;
}
- }
- &SystemClauseType::GetByte => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "get_byte",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Binary,
- Some(self[temp_v!(2)]),
- clause_name!("get_byte"),
- 2,
- )?;
-
- if stream.past_end_of_stream() {
- self.eof_action(self[temp_v!(2)], &mut stream, clause_name!("get_byte"), 2)?;
-
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
+ _ => {
+ stream.set_past_end_of_stream(true);
+ self.machine_st.unify_fixnum(Fixnum::build_with(-1), self.machine_st.registers[2]);
+ break;
}
+ }
+ }
- let addr = match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => addr,
- addr => match Number::try_from((addr, &self.heap)) {
- Ok(Number::Integer(n)) => {
- if let Some(nb) = n.to_u8() {
- Addr::Usize(nb as usize)
- } else {
- return Err(self.type_error(
- ValidType::InByte,
- addr,
- clause_name!("get_byte"),
- 2,
- ));
- }
- }
- Ok(Number::Fixnum(n)) => {
- if let Ok(nb) = u8::try_from(n) {
- Addr::Usize(nb as usize)
- } else {
- return Err(self.type_error(
- ValidType::InByte,
- addr,
- clause_name!("get_byte"),
- 2,
- ));
- }
- }
- _ => {
- return Err(self.type_error(
- ValidType::InByte,
- addr,
- clause_name!("get_byte"),
- 2,
- ));
- }
- },
- };
+ Ok(())
+ }
- loop {
- let mut b = [0u8; 1];
-
- match stream.read(&mut b) {
- Ok(1) => {
- if let Some(var) = addr.as_var() {
- self.bind(var, Addr::Usize(b[0] as usize));
- break;
- } else if addr == Addr::Usize(b[0] as usize) {
- break;
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- _ => {
- stream.set_past_end_of_stream();
- (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1));
- return return_from_clause!(self.last_call, self);
- }
- }
- }
+ #[inline(always)]
+ pub(crate) fn get_char(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("get_char"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Text,
+ Some(self.machine_st.registers[2]),
+ atom!("get_char"),
+ 2,
+ )?;
+
+ if stream.past_end_of_stream() {
+ if EOFAction::Reset != stream.options().eof_action() {
+ return Ok(());
+ } else if self.machine_st.fail {
+ return Ok(());
}
- &SystemClauseType::GetChar => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "get_char",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Text,
- Some(self[temp_v!(2)]),
- clause_name!("get_char"),
- 2,
- )?;
-
- if stream.past_end_of_stream() {
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
- }
+ }
- if stream.at_end_of_stream() {
- let end_of_file = clause_name!("end_of_file");
- let end_of_file = self
- .heap
- .to_unifiable(HeapCellValue::Atom(end_of_file, None));
+ if stream.at_end_of_stream() {
+ let end_of_file = atom!("end_of_file");
+ stream.set_past_end_of_stream(true);
- stream.set_past_end_of_stream();
+ self.machine_st.unify_atom(
+ end_of_file,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+ );
- (self.unify_fn)(self, self[temp_v!(2)], end_of_file);
- return return_from_clause!(self.last_call, self);
+ return Ok(());
+ }
+
+ let stub_gen = || functor_stub(atom!("get_char"), 2);
+ let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_char"), 2)?;
+
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ let addr = if addr.is_var() {
+ addr
+ } else {
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Atom, (atom, _arity)) => {
+ char_as_cell!(atom.as_char().unwrap())
}
+ (HeapCellValueTag::Char) => {
+ addr
+ }
+ _ => {
+ let err = self.machine_st.type_error(ValidType::InCharacter, addr);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ )
+ };
- let mut iter = self.open_parsing_stream(stream.clone(), "get_char", 2)?;
+ loop {
+ let result = iter.read_char();
- let addr = match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => addr,
- Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] {
- HeapCellValue::Atom(ref atom, _) if atom.is_char() => {
- if let Some(c) = atom.as_str().chars().next() {
- Addr::Char(c)
- } else {
- unreachable!()
- }
- }
- culprit => {
- return Err(self.type_error(
- ValidType::InCharacter,
- culprit.as_addr(h),
- clause_name!("get_char"),
- 2,
- ));
- }
- },
- Addr::Char(d) => Addr::Char(d),
- culprit => {
- return Err(self.type_error(
- ValidType::InCharacter,
- culprit,
- clause_name!("get_char"),
- 2,
- ));
- }
- };
+ match result {
+ Some(Ok(c)) => {
+ self.machine_st.unify_char(c, addr);
+ break;
+ }
+ _ => {
+ self.machine_st.eof_action(
+ self.machine_st.registers[2],
+ stream,
+ atom!("get_char"),
+ 2,
+ )?;
- loop {
- let result = iter.next();
-
- match result {
- Some(Ok(d)) => {
- if let Some(var) = addr.as_var() {
- self.bind(var, Addr::Char(d));
- break;
- } else if addr == Addr::Char(d) {
- break;
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- _ => {
- self.eof_action(
- self[temp_v!(2)],
- &mut stream,
- clause_name!("get_char"),
- 2,
- )?;
-
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
- } /*
- _ => {
- let stub = MachineError::functor_stub(clause_name!("get_char"), 2);
- let err = MachineError::representation_error(RepFlag::Character);
- let err = self.error_form(err, stub);
-
- return Err(err);
- }*/
+ if EOFAction::Reset != stream.options().eof_action() {
+ break;
+ } else if self.machine_st.fail {
+ break;
}
}
}
- &SystemClauseType::GetNChars => {
- let stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "get_n_chars",
- 3,
- )?;
+ }
- let num = match Number::try_from((self[temp_v!(2)], &self.heap)) {
- Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(),
- Ok(Number::Integer(n)) => match n.to_usize() {
- Some(u) => u,
- _ => {
- self.fail = true;
- return Ok(());
- }
- },
- _ => {
- unreachable!()
- }
- };
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_n_chars(&mut self) -> CallResult {
+ let stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("get_n_chars"),
+ 3,
+ )?;
+
+ let num = match Number::try_from(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) {
+ Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
+ Ok(Number::Integer(n)) => match n.to_usize() {
+ Some(u) => u,
+ _ => {
+ self.machine_st.fail = true;
+ return Ok(());
+ }
+ },
+ _ => {
+ unreachable!()
+ }
+ };
- let mut string = String::new();
+ let mut string = String::new();
- if stream.options().stream_type == StreamType::Binary {
- let mut buf = vec![];
- let mut chunk = stream.take(num as u64);
- chunk.read_to_end(&mut buf).ok();
- for c in buf {
- string.push(c as char);
- }
- } else {
- let mut iter = self.open_parsing_stream(stream.clone(), "get_n_chars", 2)?;
+ if stream.options().stream_type() == StreamType::Binary {
+ let mut buf = vec![];
+ let mut chunk = stream.take(num as u64);
- for _ in 0..num {
- let result = iter.next();
+ chunk.read_to_end(&mut buf).ok();
- match result {
- Some(Ok(c)) => {
- string.push(c);
- }
- _ => {
- break;
- }
- }
+ for c in buf {
+ string.push(c as char);
+ }
+ } else {
+ let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_n_chars"), 2)?;
+
+ for _ in 0..num {
+ let result = iter.read_char();
+
+ match result {
+ Some(Ok(c)) => {
+ string.push(c);
}
- };
- let string = self.heap.put_complete_string(&string);
- (self.unify_fn)(self, self[temp_v!(3)], string);
- }
- &SystemClauseType::GetCode => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "get_code",
- 2,
- )?;
-
- self.check_stream_properties(
- &mut stream,
- StreamType::Text,
- Some(self[temp_v!(2)]),
- clause_name!("get_code"),
- 2,
- )?;
-
- if stream.past_end_of_stream() {
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
+ _ => {
+ break;
}
}
+ }
+ };
- if stream.at_end_of_stream() {
- let end_of_file = Integer::from(-1);
- let end_of_file = self
- .heap
- .to_unifiable(HeapCellValue::Integer(Rc::new(end_of_file)));
+ let output = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+ let atom = self.machine_st.atom_tbl.build_with(&string);
- stream.set_past_end_of_stream();
+ self.machine_st.unify_complete_string(atom, output);
+ Ok(())
+ }
- (self.unify_fn)(self, self[temp_v!(2)], end_of_file);
- return return_from_clause!(self.last_call, self);
- }
+ #[inline(always)]
+ pub(crate) fn get_code(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("get_code"),
+ 2,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Text,
+ Some(self.machine_st.registers[2]),
+ atom!("get_code"),
+ 2,
+ )?;
+
+ if stream.past_end_of_stream() {
+ if EOFAction::Reset != stream.options().eof_action() {
+ return Ok(());
+ } else if self.machine_st.fail {
+ return Ok(());
+ }
+ }
- let addr = match self.store(self.deref(self[temp_v!(2)])) {
- addr if addr.is_ref() => addr,
- addr => match Number::try_from((addr, &self.heap)) {
- Ok(Number::Integer(n)) => {
- let n = n
- .to_u32()
- .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
+ if stream.at_end_of_stream() {
+ let end_of_file = atom!("end_of_file");
+ stream.set_past_end_of_stream(true);
- if let Some(n) = n {
- Addr::Fixnum(n as isize)
- } else {
- return Err(self.representation_error(
- RepFlag::InCharacterCode,
- clause_name!("get_code"),
- 2,
- ));
- }
- }
- Ok(Number::Fixnum(n)) => {
- let n = u32::try_from(n)
- .ok()
- .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
-
- if let Some(n) = n {
- Addr::Fixnum(n as isize)
- } else {
- return Err(self.representation_error(
- RepFlag::InCharacterCode,
- clause_name!("get_code"),
- 2,
- ));
- }
- }
- _ => {
- return Err(self.type_error(
- ValidType::Integer,
- self[temp_v!(2)],
- clause_name!("get_code"),
- 2,
- ));
- }
- },
- };
+ self.machine_st.unify_atom(
+ end_of_file,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
- let mut iter = self.open_parsing_stream(stream.clone(), "get_code", 2)?;
+ return Ok(());
+ }
- loop {
- let result = iter.next();
+ let stub_gen = || functor_stub(atom!("get_code"), 2);
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- match result {
- Some(Ok(c)) => {
- if let Some(var) = addr.as_var() {
- self.bind(var, Addr::Fixnum(c as isize));
- break;
- } else if addr == Addr::Fixnum(c as isize) {
- break;
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- _ => {
- self.eof_action(
- self[temp_v!(2)],
- &mut stream,
- clause_name!("get_code"),
- 2,
- )?;
-
- if EOFAction::Reset != stream.options().eof_action {
- return return_from_clause!(self.last_call, self);
- } else if self.fail {
- return Ok(());
- }
- }
+ let addr = if addr.is_var() {
+ addr
+ } else {
+ match Number::try_from(addr) {
+ Ok(Number::Integer(n)) => {
+ let n = n
+ .to_u32()
+ .and_then(|n| std::char::from_u32(n));
+
+ if let Some(n) = n {
+ fixnum_as_cell!(Fixnum::build_with(n as i64))
+ } else {
+ let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
}
- }
- &SystemClauseType::FirstStream => {
- let mut first_stream = None;
- let mut null_streams = BTreeSet::new();
+ Ok(Number::Fixnum(n)) => {
+ let nf = u32::try_from(n.get_num())
+ .ok()
+ .and_then(|n| std::char::from_u32(n));
- for stream in indices.streams.iter().cloned() {
- if !stream.is_null_stream() {
- first_stream = Some(stream);
- break;
+ if nf.is_some() {
+ fixnum_as_cell!(n)
} else {
- null_streams.insert(stream);
+ let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+ return Err(self.machine_st.error_form(err, stub_gen()));
}
}
+ _ => {
+ let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ }
+ };
- indices.streams = indices.streams.sub(&null_streams);
+ let mut iter = self.machine_st.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?;
- if let Some(first_stream) = first_stream {
- let stream = self.heap.to_unifiable(HeapCellValue::Stream(first_stream));
+ loop {
+ let result = iter.read_char();
- let var = self.store(self.deref(self[temp_v!(1)])).as_var().unwrap();
- self.bind(var, stream);
- } else {
- self.fail = true;
- return Ok(());
+ match result {
+ Some(Ok(c)) => {
+ self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
+ break;
}
- }
- &SystemClauseType::NextStream => {
- let prev_stream = match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Stream(h) => {
- if let HeapCellValue::Stream(ref stream) = &self.heap[h] {
- stream.clone()
- } else {
- unreachable!()
- }
- }
- _ => {
- unreachable!()
- }
- };
+ _ => {
+ self.machine_st.eof_action(
+ self.machine_st.registers[2],
+ stream,
+ atom!("get_code"),
+ 2,
+ )?;
- let mut next_stream = None;
- let mut null_streams = BTreeSet::new();
-
- for stream in indices
- .streams
- .range(prev_stream.clone()..)
- .skip(1)
- .cloned()
- {
- if !stream.is_null_stream() {
- next_stream = Some(stream);
+ if EOFAction::Reset != stream.options().eof_action() {
+ break;
+ } else if self.machine_st.fail {
break;
- } else {
- null_streams.insert(stream);
}
}
+ }
+ }
- indices.streams = indices.streams.sub(&null_streams);
+ Ok(())
+ }
- if let Some(next_stream) = next_stream {
- let var = self.store(self.deref(self[temp_v!(2)])).as_var().unwrap();
- let next_stream = self.heap.to_unifiable(HeapCellValue::Stream(next_stream));
+ #[inline(always)]
+ pub(crate) fn first_stream(&mut self) {
+ let mut first_stream = None;
+ let mut null_streams = BTreeSet::new();
- self.bind(var, next_stream);
- } else {
- self.fail = true;
- return Ok(());
- }
+ for stream in self.indices.streams.iter().cloned() {
+ if !stream.is_null_stream() {
+ first_stream = Some(stream);
+ break;
+ } else {
+ null_streams.insert(stream);
}
- &SystemClauseType::FlushOutput => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "flush_output",
- 1,
- )?;
+ }
- if !stream.is_output_stream() {
- let stub = MachineError::functor_stub(clause_name!("flush_output"), 1);
+ self.indices.streams = self.indices.streams.sub(&null_streams);
- let addr = vec![HeapCellValue::Stream(stream)];
+ if let Some(first_stream) = first_stream {
+ let stream = stream_as_cell!(first_stream);
- let err = MachineError::permission_error(
- self.heap.h(),
- Permission::OutputStream,
- "stream",
- addr,
- );
+ let var = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1]
+ )).as_var().unwrap();
- return Err(self.error_form(err, stub));
- }
+ self.machine_st.bind(var, stream);
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
- stream.flush().unwrap();
+ #[inline(always)]
+ pub(crate) fn next_stream(&mut self) {
+ let prev_stream = cell_as_stream!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1]
+ )));
+
+ let mut next_stream = None;
+ let mut null_streams = BTreeSet::new();
+
+ for stream in self.indices
+ .streams
+ .range(prev_stream..)
+ .skip(1)
+ .cloned()
+ {
+ if !stream.is_null_stream() {
+ next_stream = Some(stream);
+ break;
+ } else {
+ null_streams.insert(stream);
}
- &SystemClauseType::GetSingleChar => {
- let ctrl_c = KeyEvent {
- code: KeyCode::Char('c'),
- modifiers: KeyModifiers::CONTROL,
- };
- let key = get_key();
- if key == ctrl_c {
- let stub = MachineError::functor_stub(clause_name!("get_single_char"), 1);
- let err = MachineError::interrupt_error();
- let err = self.error_form(err, stub);
+ }
- return Err(err);
- }
- let c = match key.code {
- KeyCode::Enter => '\n',
- KeyCode::Tab => '\t',
- KeyCode::Char(c) => c,
- _ => unreachable!(),
- };
+ self.indices.streams = self.indices.streams.sub(&null_streams);
+
+ if let Some(next_stream) = next_stream {
+ let var = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2]
+ )).as_var().unwrap();
+
+ let next_stream = stream_as_cell!(next_stream);
+ self.machine_st.bind(var, next_stream);
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn flush_output(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("flush_output"),
+ 1,
+ )?;
+
+ if !stream.is_output_stream() {
+ let stub = functor_stub(atom!("flush_output"), 1);
+ let addr = stream_as_cell!(stream);
+
+ let err = self.machine_st.permission_error(
+ Permission::OutputStream,
+ atom!("stream"),
+ addr,
+ );
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
+
+ stream.flush().unwrap();
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_single_char(&mut self) -> CallResult {
+ let ctrl_c = KeyEvent {
+ code: KeyCode::Char('c'),
+ modifiers: KeyModifiers::CONTROL,
+ };
+
+ let key = get_key();
+
+ if key == ctrl_c {
+ let stub = functor_stub(atom!("get_single_char"), 1);
+ let err = self.machine_st.interrupt_error();
+ let err = self.machine_st.error_form(err, stub);
+
+ return Err(err);
+ }
+
+ let c = match key.code {
+ KeyCode::Enter => '\n',
+ KeyCode::Tab => '\t',
+ KeyCode::Char(c) => c,
+ _ => unreachable!(),
+ };
+
+ self.machine_st.unify_char(
+ c,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
+ );
+
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn head_is_dynamic(&mut self) {
+ let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1])
+ ));
- let a1 = self[temp_v!(1)];
+ let (name, arity) = read_heap_cell!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ (HeapCellValueTag::Str, s) => {
+ cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity()
+ }
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ (name, 0)
+ }
+ _ => {
+ unreachable!()
+ }
+ );
+
+ self.machine_st.fail = !self.indices.is_dynamic_predicate(module_name, (name, arity));
+ }
+
+ #[inline(always)]
+ pub(crate) fn close(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("close"),
+ 2,
+ )?;
+
+ if !stream.is_input_stream() {
+ stream.flush().unwrap(); // 8.11.6.1b)
+ }
+
+ self.indices.streams.remove(&stream);
- (self.unify_fn)(self, Addr::Char(c), a1);
+ if stream == self.user_input {
+ self.user_input = self.indices
+ .stream_aliases
+ .get(&atom!("user_input"))
+ .cloned()
+ .unwrap();
+
+ self.indices.streams.insert(self.user_input);
+ } else if stream == self.user_output {
+ self.user_output = self.indices
+ .stream_aliases
+ .get(&atom!("user_output"))
+ .cloned()
+ .unwrap();
+
+ self.indices.streams.insert(self.user_output);
+ }
+
+ if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() {
+ if let Some(alias) = stream.options().get_alias() {
+ self.indices.stream_aliases.remove(&alias);
}
- &SystemClauseType::HeadIsDynamic => {
- let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)])));
- self.fail = !match self.store(self.deref(self[temp_v!(2)])) {
- Addr::Str(s) => match &self.heap[s] {
- &HeapCellValue::NamedStr(arity, ref name, ..) => {
- indices.is_dynamic_predicate(module_name, (name.clone(), arity))
- }
- _ => unreachable!(),
- },
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(name, _) = &self.heap[h] {
- indices.is_dynamic_predicate(module_name, (name.clone(), 0))
- } else {
- unreachable!()
- }
+ let close_result = stream.close();
+
+ if let Err(_) = close_result {
+ let stub = functor_stub(atom!("close"), 1);
+ let addr = stream_as_cell!(stream);
+ let err = self.machine_st.existence_error(ExistenceError::Stream(addr));
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
+ }
+
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn copy_to_lifted_heap(&mut self) {
+ let lh_offset = cell_as_fixnum!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+ ).get_num() as usize;
+
+ let copy_target = self.machine_st.registers[2];
+
+ let old_threshold = self.machine_st.copy_findall_solution(lh_offset, copy_target);
+ let new_threshold = self.machine_st.lifted_heap.len() - lh_offset;
+
+ self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold);
+
+ for addr in self.machine_st.lifted_heap[old_threshold + 1 ..].iter_mut() {
+ *addr -= self.machine_st.heap.len() + lh_offset;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn delete_attribute(&mut self) {
+ let ls0 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ if let HeapCellValueTag::Lis = ls0.get_tag() {
+ let l1 = ls0.get_value();
+ let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
+
+ if let HeapCellValueTag::Lis = ls1.get_tag() {
+ let l2 = ls1.get_value();
+
+ let old_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l1+1]));
+ let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1)));
+
+ let tail = if tail.is_var() {
+ heap_loc_as_cell!(l1 + 1)
+ } else {
+ tail
+ };
+
+ let trail_ref = read_heap_cell!(old_addr,
+ (HeapCellValueTag::Var, h) => {
+ TrailRef::AttrVarHeapLink(h)
+ }
+ (HeapCellValueTag::Lis, l) => {
+ TrailRef::AttrVarListLink(l1 + 1, l)
}
_ => {
unreachable!()
}
- };
+ );
+
+ self.machine_st.heap[l1 + 1] = tail;
+ self.machine_st.trail(trail_ref);
}
- &SystemClauseType::Close => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "close",
- 2,
- )?;
+ }
+ }
- if !stream.is_input_stream() {
- stream.flush().unwrap(); // 8.11.6.1b)
- }
+ #[inline(always)]
+ pub(crate) fn delete_head_attribute(&mut self) {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- indices.streams.remove(&stream);
+ debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
- if stream == *current_input_stream {
- *current_input_stream = indices
- .stream_aliases
- .get(&clause_name!("user_input"))
- .cloned()
- .unwrap();
+ let h = addr.get_value();
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
- indices.streams.insert(current_input_stream.clone());
- } else if stream == *current_output_stream {
- *current_output_stream = indices
- .stream_aliases
- .get(&clause_name!("user_output"))
- .cloned()
- .unwrap();
+ debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis);
- indices.streams.insert(current_output_stream.clone());
- }
+ let l = addr.get_value();
+ let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l + 1)));
- if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() {
- let close_result = stream.close();
+ let tail = if tail.is_var() {
+ self.machine_st.heap[h] = heap_loc_as_cell!(h);
+ self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
- if let Some(ref alias) = stream.options().alias {
- indices.stream_aliases.remove(alias);
- }
- if let Err(_) = close_result {
- let stub = MachineError::functor_stub(
- clause_name!("close"),
- 1,
- );
-
- let addr = self.heap.to_unifiable(
- HeapCellValue::Stream(stream.clone()),
- );
-
- return Err(self.error_form(
- MachineError::existence_error(
- self.heap.h(),
- ExistenceError::Stream(addr),
- ),
- stub,
- ));
- }
- }
- }
- &SystemClauseType::CopyToLiftedHeap => match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Usize(lh_offset) => {
- let copy_target = self[temp_v!(2)];
+ heap_loc_as_cell!(h + 1)
+ } else {
+ tail
+ };
- let old_threshold = self.copy_findall_solution(lh_offset, copy_target);
- let new_threshold = self.lifted_heap.h() - lh_offset;
+ self.machine_st.heap[h + 1] = tail;
+ self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
+ }
- self.lifted_heap[old_threshold] =
- HeapCellValue::Addr(Addr::HeapCell(new_threshold));
+ #[inline(always)]
+ pub(crate) fn dynamic_module_resolution(
+ &mut self,
+ narity: usize,
+ ) -> Result<(Atom, PredicateKey), MachineStub> {
+ let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1 + narity]
+ )));
- for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) {
- match addr {
- HeapCellValue::Addr(ref mut addr) => {
- *addr -= self.heap.h() + lh_offset;
- }
- _ => {}
- }
- }
+ let addr = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2 + narity]
+ ));
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Str, a) => {
+ let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[a])
+ .get_name_and_arity();
+
+
+ for i in (arity + 1..arity + narity + 1).rev() {
+ self.machine_st.registers[i] = self.machine_st.registers[i - arity];
}
- _ => {
- self.fail = true;
+
+ for i in 1..arity + 1 {
+ self.machine_st.registers[i] = self.machine_st.heap[a + i];
}
- },
- &SystemClauseType::DeleteAttribute => {
- let ls0 = self.store(self.deref(self[temp_v!(1)]));
- if let Addr::Lis(l1) = ls0 {
- if let Addr::Lis(l2) = self.store(self.deref(Addr::HeapCell(l1 + 1))) {
- let old_addr = self.heap[l1 + 1].as_addr(l1 + 1);
- let tail = self.store(self.deref(Addr::HeapCell(l2 + 1)));
+ Ok((module_name, (name, arity + narity)))
+ }
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ Ok((module_name, (name, narity)))
+ }
+ (HeapCellValueTag::Char, c) => {
+ let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity);
+ Ok((module_name, key))
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
+ let stub = functor_stub(atom!("call"), 1);
+ let err = self.machine_st.instantiation_error();
- let tail = if tail.is_ref() {
- Addr::HeapCell(l1 + 1)
- } else {
- tail
- };
+ Err(self.machine_st.error_form(err, stub))
+ }
+ _ => {
+ let stub = functor_stub(atom!("call"), narity);
+ let err = self.machine_st.type_error(ValidType::Callable, addr);
- let trail_ref = match old_addr {
- Addr::HeapCell(h) => TrailRef::AttrVarHeapLink(h),
- Addr::Lis(l) => TrailRef::AttrVarListLink(l1 + 1, l),
- _ => unreachable!(),
- };
+ Err(self.machine_st.error_form(err, stub))
+ }
+ )
+ }
- self.heap[l1 + 1] = HeapCellValue::Addr(tail);
- self.trail(trail_ref);
- }
- }
+ #[inline(always)]
+ pub(crate) fn enqueue_attributed_var(&mut self) {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::AttrVar, h) => {
+ self.machine_st.attr_var_init.attr_var_queue.push(h);
}
- &SystemClauseType::DeleteHeadAttribute => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
+ _ => {
+ }
+ );
+ }
- match addr {
- Addr::AttrVar(h) => {
- let addr = self.heap[h + 1].as_addr(h + 1);
- let addr = self.store(self.deref(addr));
+ #[inline(always)]
+ pub(crate) fn get_next_db_ref(&mut self) {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- match addr {
- Addr::Lis(l) => {
- let tail = self.store(self.deref(Addr::HeapCell(l + 1)));
- let tail = if tail.is_ref() {
- self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h));
- self.trail(TrailRef::Ref(Ref::AttrVar(h)));
+ if let Some(name_var) = a1.as_var() {
+ let mut iter = self.indices.code_dir.iter();
- Addr::HeapCell(h + 1)
- } else {
- tail
- };
+ while let Some(((name, arity), _)) = iter.next() {
+ let arity_var = self.machine_st.deref(self.machine_st.registers[2])
+ .as_var().unwrap();
- self.heap[h + 1] = HeapCellValue::Addr(tail);
- self.trail(TrailRef::AttrVarListLink(h + 1, l));
- }
- _ => {
- unreachable!();
- }
- }
- }
- _ => {
- unreachable!();
- }
+ self.machine_st.bind(name_var, atom_as_cell!(name));
+ self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64)));
+
+ return;
+ }
+
+ self.machine_st.fail = true;
+ } else if a1.get_tag() == HeapCellValueTag::Atom {
+ let name = cell_as_atom!(a1);
+ let arity = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2])
+ )).get_num() as usize;
+
+ match self.machine_st.get_next_db_ref(&self.indices, &DBRef::NamedPred(name, arity)) {
+ Some(DBRef::NamedPred(name, arity)) => {
+ let atom_var = self.machine_st.deref(self.machine_st.registers[3])
+ .as_var().unwrap();
+
+ let arity_var = self.machine_st.deref(self.machine_st.registers[4])
+ .as_var().unwrap();
+
+ self.machine_st.bind(atom_var, atom_as_cell!(name));
+ self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64)));
+ }
+ Some(DBRef::Op(..)) | None => {
+ self.machine_st.fail = true;
}
}
- &SystemClauseType::DynamicModuleResolution(narity) => {
- let module_name = self.store(self.deref(self[temp_v!(1 + narity)]));
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
- let module_name = match module_name {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref module_name, _) = self.heap[h] {
- module_name.clone()
- } else {
- unreachable!()
- }
+ #[inline(always)]
+ pub(crate) fn get_next_op_db_ref(&mut self) {
+ let prec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ if let Some(prec_var) = prec.as_var() {
+ let spec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+ let op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+ let orig_op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[7]));
+
+ let spec_num = if spec.get_tag() == HeapCellValueTag::Atom {
+ (match cell_as_atom!(spec) {
+ atom!("xfx") => XFX,
+ atom!("xfy") => XFY,
+ atom!("yfx") => YFX,
+ atom!("fx") => FX,
+ atom!("fy") => FY,
+ atom!("xf") => XF,
+ _ => unreachable!(),
+ }) as u8
+ } else {
+ 0
+ };
+
+ let unossified_op_dir = if !orig_op.is_var() {
+ let orig_op = read_heap_cell!(orig_op,
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ name
+ }
+ (HeapCellValueTag::Char, c) => {
+ self.machine_st.atom_tbl.build_with(&c.to_string())
}
_ => {
unreachable!()
}
- };
+ );
- match self.store(self.deref(self[temp_v!(2 + narity)])) {
- Addr::Str(a) => {
- if let HeapCellValue::NamedStr(arity, name, _) = self.heap.clone(a) {
- for i in (arity + 1..arity + narity + 1).rev() {
- self.registers[i] = self.registers[i - arity];
- }
+ let op_descs = [
+ self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)),
+ self.indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)),
+ self.indices.op_dir.get_key_value(&(orig_op, Fixity::Post)),
+ ];
- for i in 1..arity + 1 {
- self.registers[i] = self.heap[a + i].as_addr(a + i);
- }
+ let number_of_keys = op_descs[0].is_some() as usize +
+ op_descs[1].is_some() as usize +
+ op_descs[2].is_some() as usize;
- return self.module_lookup(
- indices,
- call_policy,
- (name, arity + narity),
- module_name,
- true,
- &indices.stream_aliases,
- );
- } else {
- unreachable!()
- }
+ match number_of_keys {
+ 0 => {
+ self.machine_st.fail = true;
+ return;
}
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
- return self.module_lookup(
- indices,
- call_policy,
- (name.clone(), narity),
- module_name,
- true,
- &indices.stream_aliases,
- );
- } else {
- unreachable!()
+ 1 => {
+ for op_desc in op_descs {
+ if let Some((_, op_desc)) = op_desc {
+ let (op_prec, op_spec) =
+ (op_desc.get_prec(), op_desc.get_spec());
+
+ let op_spec = match op_spec as u32 {
+ XFX => atom!("xfx"),
+ XFY => atom!("xfy"),
+ YFX => atom!("yfx"),
+ FX => atom!("fx"),
+ FY => atom!("fy"),
+ XF => atom!("xf"),
+ YF => atom!("yf"),
+ _ => unreachable!(),
+ };
+
+ let op_prec = Fixnum::build_with(op_prec as i64);
+
+ self.machine_st.unify_fixnum(op_prec, prec);
+ self.machine_st.unify_atom(op_spec, spec);
+ }
}
+
+ return;
}
- Addr::Char(c) => {
- return self.module_lookup(
- indices,
- call_policy,
- (clause_name!(c.to_string(), self.atom_tbl), narity),
- module_name,
- true,
- &indices.stream_aliases,
- );
- }
- addr => {
- let stub = MachineError::functor_stub(clause_name!("(:)"), 2);
+ _ => {
+ let mut unossified_op_dir = OssifiedOpDir::new();
- let type_error =
- MachineError::type_error(self.heap.h(), ValidType::Callable, addr);
+ for op_desc in op_descs {
+ if let Some((key, op_desc)) = op_desc {
+ let (prec, spec) = (op_desc.get_prec(), op_desc.get_spec());
+ unossified_op_dir.insert(*key, (prec as usize, spec as Specifier));
+ }
+ }
- let type_error = self.error_form(type_error, stub);
- return Err(type_error);
+ unossified_op_dir
}
}
- }
- &SystemClauseType::EnqueueAttributedVar => {
- let addr = self[temp_v!(1)];
+ } else {
+ let mut unossified_op_dir = OssifiedOpDir::new();
- match self.store(self.deref(addr)) {
- Addr::AttrVar(h) => {
- self.attr_var_init.attr_var_queue.push(h);
- }
- _ => {}
- }
- }
- &SystemClauseType::GetNextDBRef => {
- let a1 = self[temp_v!(1)];
+ unossified_op_dir.extend(self.indices.op_dir.iter().filter_map(
+ |(key, op_desc)| {
+ let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec());
+ let name = key.0;
- match self.store(self.deref(a1)) {
- addr @ Addr::HeapCell(_)
- | addr @ Addr::StackCell(..)
- | addr @ Addr::AttrVar(_) => {
- let mut iter = indices.code_dir.iter();
+ if other_prec == 0 {
+ return None;
+ }
- while let Some(((name, arity), _)) = iter.next() {
- if is_builtin_predicate(&name) {
- continue;
+ if (!orig_op.is_var() && atom_as_cell!(name) != orig_op) ||
+ (!spec.is_var() && other_spec != spec_num) {
+ return None;
}
- let spec = get_clause_spec(
- name.clone(),
- *arity,
- &CompositeOpDir::new(&indices.op_dir, None),
- );
+ Some((*key, (other_prec as usize, other_spec as Specifier)))
+ }
+ ));
- let db_ref = DBRef::NamedPred(name.clone(), *arity, spec);
- let r = addr.as_var().unwrap();
+ unossified_op_dir
+ };
+
+ let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.machine_st.arena);
+
+ match ossified_op_dir.iter().next() {
+ Some(((op_atom, _), (op_prec, op_spec))) => {
+ let ossified_op_dir_var = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[4]
+ )).as_var().unwrap();
+
+ let spec_atom = match *op_spec {
+ FX => atom!("fx"),
+ FY => atom!("fy"),
+ XF => atom!("xf"),
+ YF => atom!("yf"),
+ XFX => atom!("xfx"),
+ XFY => atom!("xfy"),
+ YFX => atom!("yfx"),
+ _ => {
+ self.machine_st.fail = true;
+ return;
+ }
+ };
- let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref));
+ let spec_var = spec.as_var().unwrap();
+ let op_var = op.as_var().unwrap();
- self.bind(r, addr);
+ self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64)));
+ self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
+ self.machine_st.bind(op_var, atom_as_cell!(op_atom));
+ self.machine_st.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir));
+ }
+ None => {
+ self.machine_st.fail = true;
+ return;
+ }
+ }
+ } else {
+ let spec = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+ let op_atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])));
+ let ossified_op_dir_cell = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
- return return_from_clause!(self.last_call, self);
- }
+ if ossified_op_dir_cell.is_var() {
+ self.machine_st.fail = true;
+ return;
+ }
- self.fail = true;
- }
- Addr::Con(h) => match self.heap.clone(h) {
- HeapCellValue::DBRef(DBRef::Op(..)) => {
- self.fail = true;
- }
- HeapCellValue::DBRef(ref db_ref) => {
- self.get_next_db_ref(indices, db_ref);
- }
+ let ossified_op_dir = cell_as_ossified_op_dir!(
+ ossified_op_dir_cell
+ );
+
+ let fixity = match spec {
+ atom!("xfy") | atom!("yfx") | atom!("xfx") => Fixity::In,
+ atom!("xf") | atom!("yf") => Fixity::Post,
+ atom!("fx") | atom!("fy") => Fixity::Pre,
+ _ => {
+ self.machine_st.fail = true;
+ return;
+ }
+ };
+
+ match self.machine_st.get_next_db_ref(
+ &self.indices,
+ &DBRef::Op(op_atom, fixity, ossified_op_dir),
+ ) {
+ Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => {
+ let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap();
+
+ let prec_var = self.machine_st.deref(self.machine_st.registers[5])
+ .as_var().unwrap();
+
+ let spec_var = self.machine_st.deref(self.machine_st.registers[6])
+ .as_var().unwrap();
+
+ let op_var = self.machine_st.deref(self.machine_st.registers[7])
+ .as_var().unwrap();
+
+ let spec_atom = match *spec {
+ FX => atom!("fx"),
+ FY => atom!("fy"),
+ XF => atom!("xf"),
+ YF => atom!("yf"),
+ XFX => atom!("xfx"),
+ XFY => atom!("xfy"),
+ YFX => atom!("yfx"),
_ => {
- self.fail = true;
+ self.machine_st.fail = true;
+ return;
}
- },
- _ => {
- self.fail = true;
- }
+ };
+
+ self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64)));
+ self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
+ self.machine_st.bind(op_var, atom_as_cell!(op_atom));
+ }
+ Some(DBRef::NamedPred(..)) | None => {
+ self.machine_st.fail = true;
}
}
- &SystemClauseType::GetNextOpDBRef => {
- let a1 = self[temp_v!(1)];
+ }
+ }
- match self.store(self.deref(a1)) {
- addr @ Addr::HeapCell(_)
- | addr @ Addr::StackCell(..)
- | addr @ Addr::AttrVar(_) => {
- let mut unossified_op_dir = OssifiedOpDir::new();
+ #[inline(always)]
+ pub(crate) fn maybe(&mut self) {
+ let result = {
+ let mut rand = RANDOM_STATE.borrow_mut();
+ rand.bits(1) == 0
+ };
- unossified_op_dir.extend(indices.op_dir.iter().filter_map(
- |(key, op_dir_val)| {
- let (name, fixity) = key.clone();
+ self.machine_st.fail = result;
+ }
- let prec = op_dir_val.shared_op_desc().prec();
+ #[inline(always)]
+ pub(crate) fn cpu_now(&mut self) {
+ let secs = ProcessTime::now().as_duration().as_secs_f64();
+ let secs = arena_alloc!(OrderedFloat(secs), &mut self.machine_st.arena);
- if prec == 0 {
- return None;
- }
+ self.machine_st.unify_f64(secs, self.machine_st.registers[1]);
+ }
- let assoc = op_dir_val.shared_op_desc().assoc();
+ #[inline(always)]
+ pub(crate) fn current_time(&mut self) {
+ let timestamp = self.systemtime_to_timestamp(SystemTime::now());
+ self.machine_st.unify_complete_string(timestamp, self.machine_st.registers[1]);
+ }
- Some((OrderedOpDirKey(name, fixity), (prec, assoc)))
- },
- ));
+ #[inline(always)]
+ pub(crate) fn open(&mut self) -> CallResult {
+ let alias = self.machine_st.registers[4];
+ let eof_action = self.machine_st.registers[5];
+ let reposition = self.machine_st.registers[6];
+ let stream_type = self.machine_st.registers[7];
- let ossified_op_dir = Rc::new(unossified_op_dir);
+ let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+ let src_sink = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- match ossified_op_dir.iter().next() {
- Some((OrderedOpDirKey(name, _), (priority, spec))) => {
- let db_ref = DBRef::Op(
- *priority,
- *spec,
- name.clone(),
- ossified_op_dir.clone(),
- SharedOpDesc::new(*priority, *spec),
- );
+ if let Some(str_like) = self.machine_st.value_to_str_like(src_sink) {
+ let file_spec = match str_like {
+ AtomOrString::Atom(atom) => {
+ atom
+ }
+ AtomOrString::String(string) => {
+ self.machine_st.atom_tbl.build_with(&string)
+ }
+ };
- let r = addr.as_var().unwrap();
- let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref));
+ let mut stream = self.machine_st.stream_from_file_spec(
+ file_spec,
+ &mut self.indices,
+ &options,
+ )?;
- self.bind(r, addr);
- }
- None => {
- self.fail = true;
- return Ok(());
- }
- }
- }
- Addr::Con(h) => match self.heap.clone(h) {
- HeapCellValue::DBRef(DBRef::NamedPred(..)) => {
- self.fail = true;
- }
- HeapCellValue::DBRef(ref db_ref) => {
- self.get_next_db_ref(indices, db_ref);
- }
- _ => {
- self.fail = true;
- }
- },
- _ => {
- self.fail = true;
- }
- }
+ *stream.options_mut() = options;
+ self.indices.streams.insert(stream);
+
+ if let Some(alias) = stream.options().get_alias() {
+ self.indices.stream_aliases.insert(alias, stream);
}
- &SystemClauseType::LookupDBRef => {
- let a1 = self[temp_v!(1)];
- match self.store(self.deref(a1)) {
- Addr::Con(h) => match self.heap.clone(h) {
- HeapCellValue::DBRef(DBRef::NamedPred(name, arity, spec)) => {
- let a2 = self[temp_v!(2)];
- let a3 = self[temp_v!(3)];
+ let stream_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+ self.machine_st.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream));
+ } else {
+ let err = self.machine_st.domain_error(DomainErrorType::SourceSink, src_sink);
+ let stub = functor_stub(atom!("open"), 4);
- let atom = self.heap.to_unifiable(HeapCellValue::Atom(name, spec));
+ return Err(self.machine_st.error_form(err, stub));
+ }
- (self.unify_fn)(self, a2, atom);
+ Ok(())
+ }
- if !self.fail {
- (self.unify_fn)(self, a3, Addr::Usize(arity));
- }
- }
- _ => {
- self.fail = true;
- }
- },
- _ => {
- self.fail = true;
- }
- }
- }
- &SystemClauseType::LookupOpDBRef => {
- let a1 = self[temp_v!(1)];
-
- match self.store(self.deref(a1)) {
- Addr::Con(h) => match self.heap.clone(h) {
- HeapCellValue::DBRef(DBRef::Op(
- priority,
- spec,
- name,
- _,
- shared_op_desc,
- )) => {
- let prec = self[temp_v!(2)];
- let specifier = self[temp_v!(3)];
- let op = self[temp_v!(4)];
-
- let spec = match spec {
- FX => "fx",
- FY => "fy",
- XF => "xf",
- YF => "yf",
- XFX => "xfx",
- XFY => "xfy",
- YFX => "yfx",
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
+ #[inline(always)]
+ pub(crate) fn op_declaration(&mut self) -> CallResult {
+ let priority = self.machine_st.registers[1];
+ let specifier = self.machine_st.registers[2];
+ let op = self.machine_st.registers[3];
- let a3 = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!(spec), None));
+ let priority = self.machine_st.store(self.machine_st.deref(priority));
- let a4 = self
- .heap
- .to_unifiable(HeapCellValue::Atom(name, Some(shared_op_desc)));
+ let priority = match Number::try_from(priority) {
+ Ok(Number::Integer(n)) => n.to_u16().unwrap(),
+ Ok(Number::Fixnum(n)) => u16::try_from(n.get_num()).unwrap(),
+ _ => {
+ unreachable!();
+ }
+ };
- (self.unify_fn)(self, Addr::Usize(priority), prec);
+ let specifier = cell_as_atom_cell!(self.machine_st.store(self.machine_st.deref(specifier)))
+ .get_name();
- if !self.fail {
- (self.unify_fn)(self, a3, specifier);
- }
+ let op = read_heap_cell!(self.machine_st.store(self.machine_st.deref(op)),
+ (HeapCellValueTag::Char) => {
+ self.machine_st.atom_tbl.build_with(&op.to_string())
+ }
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ name
+ }
+ _ => {
+ unreachable!()
+ }
+ );
- if !self.fail {
- (self.unify_fn)(self, a4, op);
- }
- }
- _ => {
- self.fail = true;
- }
- },
- _ => {
- self.fail = true;
- }
+ let result = to_op_decl(priority, specifier, op)
+ .map_err(SessionError::from)
+ .and_then(|mut op_decl| {
+ if op_decl.op_desc.get_prec() == 0 {
+ Ok(op_decl.remove(&mut self.indices.op_dir))
+ } else {
+ let spec = get_op_desc(
+ op_decl.name,
+ &CompositeOpDir::new(&self.indices.op_dir, None),
+ );
+
+ op_decl.submit(spec, &mut self.indices.op_dir)
}
+ });
+
+ match result {
+ Ok(()) => Ok(()),
+ Err(e) => {
+ // 8.14.3.3 l)
+ let err = self.machine_st.session_error(e);
+ let stub = functor_stub(atom!("op"), 3);
+
+ Err(self.machine_st.error_form(err, stub))
}
- &SystemClauseType::Maybe => {
- let result = {
- let mut rand = RANDOM_STATE.borrow_mut();
- rand.bits(1) == 0
- };
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_stream_options(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("open"),
+ 4,
+ )?;
+
+ let alias = self.machine_st.registers[2];
+ let eof_action = self.machine_st.registers[3];
+ let reposition = self.machine_st.registers[4];
+ let stream_type = self.machine_st.registers[5];
+
+ let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+ *stream.options_mut() = options;
+
+ Ok(())
+ }
- self.fail = result;
+ #[inline(always)]
+ pub(crate) fn truncate_if_no_lifted_heap_growth_diff(&mut self) {
+ self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h))
+ }
+
+ #[inline(always)]
+ pub(crate) fn truncate_if_no_lifted_heap_growth(&mut self) {
+ self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!())
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_attributed_variable_list(&mut self) {
+ let attr_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let attr_var_list = read_heap_cell!(attr_var,
+ (HeapCellValueTag::AttrVar, h) => {
+ h + 1
}
- &SystemClauseType::CpuNow => {
- let a1 = self[temp_v!(1)];
- let a2 = ProcessTime::now().as_duration().as_secs_f64();
- let addr = self.heap.put_constant(Constant::Float(OrderedFloat(a2)));
+ (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+ // create an AttrVar in the heap.
+ let h = self.machine_st.heap.len();
+
+ self.machine_st.heap.push(attr_var_as_cell!(h));
+ self.machine_st.heap.push(heap_loc_as_cell!(h+1));
- (self.unify_fn)(self, a1, addr);
+ self.machine_st.bind(Ref::attr_var(h), attr_var);
+ h + 1
}
- &SystemClauseType::CurrentTime => {
- let str = self.systemtime_to_timestamp(SystemTime::now());
- (self.unify_fn)(self, self[temp_v!(1)], str);
+ _ => {
+ self.machine_st.fail = true;
+ return;
}
- &SystemClauseType::OpDeclaration => {
- let priority = self[temp_v!(1)];
- let specifier = self[temp_v!(2)];
- let op = self[temp_v!(3)];
+ );
- let priority = self.store(self.deref(priority));
+ let list_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+ self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr);
+ }
- let priority = match Number::try_from((priority, &self.heap)) {
- Ok(Number::Integer(n)) => n.to_usize().unwrap(),
- Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(),
- _ => {
- unreachable!();
- }
- };
+ #[inline(always)]
+ pub(crate) fn get_attr_var_queue_delimiter(&mut self) {
+ let addr = self.machine_st.registers[1];
+ let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64);
- let specifier = match self.store(self.deref(specifier)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref specifier, _) = &self.heap[h] {
- specifier.clone()
- } else {
- unreachable!()
- }
- }
- _ => unreachable!(),
- };
+ self.machine_st.unify_fixnum(value, self.machine_st.store(self.machine_st.deref(addr)));
+ }
- let op = match self.store(self.deref(op)) {
- Addr::Char(c) => clause_name!(c.to_string(), self.atom_tbl),
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- name.clone()
- } else {
- unreachable!()
- }
- }
- _ => unreachable!(),
- };
+ #[inline(always)]
+ pub(crate) fn get_attr_var_queue_beyond(&mut self) {
+ let addr = self.machine_st.registers[1];
+ let addr = self.machine_st.store(self.machine_st.deref(addr));
- let result = to_op_decl(priority, specifier.as_str(), op)
- .map_err(SessionError::from)
- .and_then(|mut op_decl| {
- if op_decl.prec == 0 {
- Ok(op_decl.remove(&mut indices.op_dir))
- } else {
- let spec = get_op_desc(
- op_decl.name.clone(),
- &CompositeOpDir::new(&indices.op_dir, None),
- );
+ let b = match Number::try_from(addr) {
+ Ok(Number::Integer(n)) => n.to_usize(),
+ Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+ _ => {
+ self.machine_st.fail = true;
+ return;
+ }
+ };
- op_decl.submit(spec, &mut indices.op_dir)
- }
- });
+ if let Some(b) = b {
+ let iter = self.machine_st.gather_attr_vars_created_since(b);
- match result {
- Ok(()) => {}
- Err(e) => {
- // 8.14.3.3 l)
- let e = MachineError::session_error(self.heap.h(), e);
- let stub = MachineError::functor_stub(clause_name!("op"), 3);
- let permission_error = self.error_form(e, stub);
+ let var_list_addr = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, iter)
+ );
- return Err(permission_error);
- }
- };
- }
- &SystemClauseType::Open => {
- let alias = self[temp_v!(4)];
- let eof_action = self[temp_v!(5)];
- let reposition = self[temp_v!(6)];
- let stream_type = self[temp_v!(7)];
+ let list_addr = self.machine_st.registers[2];
+ unify!(self.machine_st, var_list_addr, list_addr);
+ }
+ }
- let options = self.to_stream_options(alias, eof_action, reposition, stream_type);
+ #[inline(always)]
+ pub(crate) fn get_continuation_chunk(&mut self) {
+ let e = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let e = cell_as_fixnum!(e).get_num() as usize;
- let mut iter = self.heap_pstr_iter(self[temp_v!(1)]);
- let file_spec = clause_name!(iter.to_string(), self.atom_tbl);
+ let p_functor = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2]
+ ));
- let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?;
+ let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap();
- *stream.options_mut() = options;
+ let num_cells = *self.code[p].perm_vars_mut().unwrap();
+ let mut addrs = vec![];
- indices.streams.insert(stream.clone());
+ for idx in 1..num_cells + 1 {
+ addrs.push(self.machine_st.stack[stack_loc!(AndFrame, e, idx)]);
+ }
- if let Some(ref alias) = &stream.options().alias {
- indices.stream_aliases.insert(alias.clone(), stream.clone());
- }
+ let chunk = str_loc_as_cell!(self.machine_st.heap.len());
- let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
- let stream_var = self.store(self.deref(self[temp_v!(3)]));
+ self.machine_st.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells));
+ self.machine_st.heap.push(p_functor);
+ self.machine_st.heap.extend(addrs);
- self.bind(stream_var.as_var().unwrap(), stream);
- }
- &SystemClauseType::SetStreamOptions => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "open",
- 4,
- )?;
+ unify!(self.machine_st, self.machine_st.registers[3], chunk);
+ }
- let alias = self[temp_v!(2)];
- let eof_action = self[temp_v!(3)];
- let reposition = self[temp_v!(4)];
- let stream_type = self[temp_v!(5)];
+ #[inline(always)]
+ pub(crate) fn get_lifted_heap_from_offset_diff(&mut self) {
+ let lh_offset = self.machine_st.registers[1];
+ let lh_offset = cell_as_fixnum!(
+ self.machine_st.store(self.machine_st.deref(lh_offset))
+ ).get_num() as usize;
- let options = self.to_stream_options(alias, eof_action, reposition, stream_type);
- *stream.options_mut() = options;
- }
- &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
- self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h))
+ if lh_offset >= self.machine_st.lifted_heap.len() {
+ let solutions = self.machine_st.registers[2];
+ let diff = self.machine_st.registers[3];
+
+ unify_fn!(self.machine_st, solutions, diff);
+ } else {
+ let h = self.machine_st.heap.len();
+ let mut last_index = h;
+
+ for value in self.machine_st.lifted_heap[lh_offset ..].iter().cloned() {
+ last_index = self.machine_st.heap.len();
+ self.machine_st.heap.push(value + h);
}
- &SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
- self.truncate_if_no_lifted_heap_diff(|_| Addr::EmptyList)
+
+ if last_index < self.machine_st.heap.len() {
+ let diff = self.machine_st.registers[3];
+ unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]);
}
- &SystemClauseType::GetAttributedVariableList => {
- let attr_var = self.store(self.deref(self[temp_v!(1)]));
- let attr_var_list = match attr_var {
- Addr::AttrVar(h) => h + 1,
- attr_var @ Addr::HeapCell(_) | attr_var @ Addr::StackCell(..) => {
- // create an AttrVar in the heap.
- let h = self.heap.h();
- self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h)));
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
+ self.machine_st.lifted_heap.truncate(lh_offset);
- self.bind(Ref::AttrVar(h), attr_var);
- h + 1
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
+ let solutions = self.machine_st.registers[2];
+ unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
+ }
+ }
- let list_addr = self[temp_v!(2)];
- self.bind(Ref::HeapCell(attr_var_list), list_addr);
- }
- &SystemClauseType::GetAttrVarQueueDelimiter => {
- let addr = self[temp_v!(1)];
- let value = Addr::Usize(self.attr_var_init.attr_var_queue.len());
+ #[inline(always)]
+ pub(crate) fn get_lifted_heap_from_offset(&mut self) {
+ let lh_offset = self.machine_st.registers[1];
+ let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(
+ lh_offset
+ ))).get_num() as usize;
- (self.unify_fn)(self, addr, value);
+ if lh_offset >= self.machine_st.lifted_heap.len() {
+ let solutions = self.machine_st.registers[2];
+ unify_fn!(self.machine_st, solutions, empty_list_as_cell!());
+ } else {
+ let h = self.machine_st.heap.len();
+
+ for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() {
+ self.machine_st.heap.push(addr + h);
}
- &SystemClauseType::GetAttrVarQueueBeyond => {
- let addr = self[temp_v!(1)];
- let addr = self.store(self.deref(addr));
- let b = match addr {
- Addr::Usize(b) => Some(b),
- _ => match Number::try_from((addr, &self.heap)) {
- Ok(Number::Integer(n)) => n.to_usize(),
- Ok(Number::Fixnum(n)) => usize::try_from(n).ok(),
- _ => {
- self.fail = true;
- return Ok(());
- }
- },
- };
+ self.machine_st.lifted_heap.truncate(lh_offset);
+
+ let solutions = self.machine_st.registers[2];
+ unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_double_quotes(&mut self) {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ self.machine_st.unify_atom(
+ match self.machine_st.flags.double_quotes {
+ DoubleQuotes::Chars => atom!("chars"),
+ DoubleQuotes::Atom => atom!("atom"),
+ DoubleQuotes::Codes => atom!("codes"),
+ },
+ a1,
+ );
+ }
- if let Some(b) = b {
- let iter = self.gather_attr_vars_created_since(b);
+ #[inline(always)]
+ pub(crate) fn get_scc_cleaner(&mut self) {
+ let dest = self.machine_st.registers[1];
- let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
- let list_addr = self[temp_v!(2)];
+ if let Some((addr, b_cutoff, prev_b)) = self.machine_st.cont_pts.pop() {
+ let b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
- (self.unify_fn)(self, var_list_addr, list_addr);
+ if b <= b_cutoff {
+ self.machine_st.block = prev_b;
+
+ if let Some(r) = dest.as_var() {
+ self.machine_st.bind(r, addr);
+ return;
}
+ } else {
+ self.machine_st.cont_pts.push((addr, b_cutoff, prev_b));
}
- &SystemClauseType::GetContinuationChunk => {
- let e = self.store(self.deref(self[temp_v!(1)]));
+ }
- let e = if let Addr::Usize(e) = e {
- e
- } else {
- self.fail = true;
- return Ok(());
- };
+ self.machine_st.fail = true;
+ }
- let p_functor = self.store(self.deref(self[temp_v!(2)]));
- let p = self.heap.to_local_code_ptr(&p_functor).unwrap();
+ #[inline(always)]
+ pub(crate) fn halt(&mut self) {
+ let code = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) {
- Some(line) => {
- let perm_vars = match line.as_ref() {
- Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(),
- _ => None,
- };
+ let code = match Number::try_from(code) {
+ Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(),
+ Ok(Number::Integer(n)) => n.to_i32().unwrap(),
+ Ok(Number::Rational(r)) => {
+ // n has already been confirmed as an integer, and
+ // internally, Rational is assumed reduced, so its
+ // denominator must be 1.
+ r.numer().to_i32().unwrap()
+ }
+ _ => {
+ unreachable!()
+ }
+ };
- perm_vars.unwrap()
- }
- _ => unreachable!(),
- };
+ std::process::exit(code);
+ }
- let mut addrs = vec![];
+ #[inline(always)]
+ pub(crate) fn install_scc_cleaner(&mut self) {
+ let addr = self.machine_st.registers[1];
+ let b = self.machine_st.b;
+ let prev_block = self.machine_st.block;
- for index in 1..num_cells + 1 {
- addrs.push(self.stack.index_and_frame(e)[index]);
- }
+ self.machine_st.run_cleaners_fn = Machine::run_cleaners;
- let chunk = Addr::HeapCell(self.heap.h());
+ self.machine_st.install_new_block(self.machine_st.registers[2]);
+ self.machine_st.cont_pts.push((addr, b, prev_block));
+ }
- self.heap.push(HeapCellValue::NamedStr(
- 1 + num_cells,
- clause_name!("cont_chunk"),
- None,
- ));
+ #[inline(always)]
+ pub(crate) fn install_inference_counter(&mut self) -> CallResult {
+ // A1 = B, A2 = L
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- self.heap.push(HeapCellValue::Addr(p_functor));
- self.heap.extend(addrs.into_iter().map(HeapCellValue::Addr));
+ let n = match Number::try_from(a2) {
+ Ok(Number::Fixnum(bp)) => bp.get_num() as usize,
+ Ok(Number::Integer(n)) => n.to_usize().unwrap(),
+ _ => {
+ let stub = functor_stub(
+ atom!("call_with_inference_limit"),
+ 3,
+ );
- (self.unify_fn)(self, self[temp_v!(3)], chunk);
+ let err = self.machine_st.type_error(ValidType::Integer, a2);
+ return Err(self.machine_st.error_form(err, stub));
}
- &SystemClauseType::GetLiftedHeapFromOffsetDiff => {
- let lh_offset = self[temp_v!(1)];
+ };
- match self.store(self.deref(lh_offset)) {
- Addr::Usize(lh_offset) => {
- if lh_offset >= self.lifted_heap.h() {
- let solutions = self[temp_v!(2)];
- let diff = self[temp_v!(3)];
+ let bp = cell_as_fixnum!(a1).get_num() as usize;
+ let count = self.machine_st.cwil.add_limit(n, bp);
+ let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
- (self.unify_fn)(self, solutions, diff);
- } else {
- let h = self.heap.h();
- let mut last_index = h;
-
- for value in self.lifted_heap.iter_from(lh_offset) {
- last_index = self.heap.h();
-
- match value {
- HeapCellValue::Addr(ref addr) => {
- self.heap.push(HeapCellValue::Addr(*addr + h));
- }
- value => {
- self.heap.push(value.context_free_clone());
- }
- }
- }
+ self.machine_st.increment_call_count_fn = MachineState::increment_call_count;
- if last_index < self.heap.h() {
- let addr_opt =
- if let HeapCellValue::Addr(ref addr) = &self.heap[last_index] {
- Some(*addr)
- } else {
- None
- };
-
- addr_opt.map(|addr| {
- let diff = self[temp_v!(3)];
- (self.unify_fn)(self, diff, addr);
- });
- }
+ let a3 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+ self.machine_st.unify_big_int(count, a3);
+
+ Ok(())
+ }
- self.lifted_heap.truncate(lh_offset);
+ #[inline(always)]
+ pub(crate) fn module_exists(&mut self) {
+ let module = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let module_name = cell_as_atom!(module);
- let solutions = self[temp_v!(2)];
- (self.unify_fn)(self, Addr::HeapCell(h), solutions);
- }
- }
- _ => {
- self.fail = true;
+ self.machine_st.fail = !self.indices.modules.contains_key(&module_name);
+ }
+
+ #[inline(always)]
+ pub(crate) fn no_such_predicate(&mut self) -> CallResult {
+ let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1]
+ )));
+
+ let head = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ self.machine_st.fail = read_heap_cell!(head,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_name_and_arity();
+
+ let ct = ClauseType::from(name, arity);
+
+ if ct.is_inlined() || ct.is_builtin() {
+ true
+ } else {
+ let index = self.indices.get_predicate_code_index(
+ name,
+ arity,
+ module_name,
+ )
+ .map(|index| index.get())
+ .unwrap_or(IndexPtr::DynamicUndefined);
+
+ match index {
+ IndexPtr::DynamicUndefined | IndexPtr::Undefined => false,
+ _ => true,
}
}
}
- &SystemClauseType::GetLiftedHeapFromOffset => {
- let lh_offset = self[temp_v!(1)];
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
- match self.store(self.deref(lh_offset)) {
- Addr::Usize(lh_offset) => {
- if lh_offset >= self.lifted_heap.h() {
- let solutions = self[temp_v!(2)];
- (self.unify_fn)(self, solutions, Addr::EmptyList);
- } else {
- let h = self.heap.h();
-
- for addr in self.lifted_heap.iter_from(lh_offset) {
- match addr {
- HeapCellValue::Addr(ref addr) => {
- self.heap.push(HeapCellValue::Addr(*addr + h));
- }
- value => {
- self.heap.push(value.context_free_clone());
- }
- }
- }
+ let ct = ClauseType::from(name, 0);
- self.lifted_heap.truncate(lh_offset);
+ if ct.is_inlined() || ct.is_builtin() {
+ true
+ } else {
+ let index = self.indices.get_predicate_code_index(
+ name,
+ 0,
+ module_name,
+ )
+ .map(|index| index.get())
+ .unwrap_or(IndexPtr::DynamicUndefined);
- let solutions = self[temp_v!(2)];
- (self.unify_fn)(self, Addr::HeapCell(h), solutions);
- }
- }
- _ => {
- self.fail = true;
+ match index {
+ IndexPtr::DynamicUndefined => false,
+ _ => true,
}
}
}
- &SystemClauseType::GetDoubleQuotes => {
- let a1 = self[temp_v!(1)];
+ _ => {
+ let err = self.machine_st.type_error(ValidType::Callable, head);
+ let stub = functor_stub(atom!("clause"), 2);
- match self.flags.double_quotes {
- DoubleQuotes::Chars => {
- let atom = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("chars"), None));
+ return Err(self.machine_st.error_form(err, stub));
+ }
+ );
- (self.unify_fn)(self, a1, atom);
- }
- DoubleQuotes::Atom => {
- let atom = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("atom"), None));
+ Ok(())
+ }
+ #[inline(always)]
+ pub(crate) fn redo_attr_var_binding(&mut self) {
+ let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- (self.unify_fn)(self, a1, atom);
- }
- DoubleQuotes::Codes => {
- let atom = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("codes"), None));
+ debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag());
+ self.machine_st.heap[var.get_value()] = value;
+ }
- (self.unify_fn)(self, a1, atom);
- }
- }
+ #[inline(always)]
+ pub(super) fn restore_instr_at_verify_attr_interrupt(&mut self) {
+ match &self.code[VERIFY_ATTR_INTERRUPT_LOC] {
+ &Instruction::VerifyAttrInterrupt => {}
+ _ => {
+ let instr = mem::replace(
+ &mut self.code[VERIFY_ATTR_INTERRUPT_LOC],
+ Instruction::VerifyAttrInterrupt,
+ );
+
+ self.code[self.machine_st.attr_var_init.cp] = instr;
}
- &SystemClauseType::GetSCCCleaner => {
- let dest = self[temp_v!(1)];
+ }
+ }
- match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
- Some(sgc_policy) => {
- if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() {
- let b = self.stack.index_or_frame(self.b).prelude.b;
+ #[inline(always)]
+ pub(crate) fn reset_attr_var_state(&mut self) {
+ self.restore_instr_at_verify_attr_interrupt();
+ self.machine_st.attr_var_init.reset();
+ }
- if b <= b_cutoff {
- self.block = prev_b;
+ #[inline(always)]
+ pub(crate) fn remove_call_policy_check(&mut self) {
+ let bp = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1]
+ ))).get_num() as usize;
- if let Some(r) = dest.as_var() {
- self.bind(r, addr);
- return return_from_clause!(self.last_call, self);
- }
- } else {
- sgc_policy.push_cont_pt(addr, b_cutoff, prev_b);
- }
- }
- }
- None => {}
- };
+ if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
+ self.machine_st.cwil.reset();
+ self.machine_st.increment_call_count_fn = |_| { Ok(()) };
+ }
+ }
- self.fail = true;
- }
- &SystemClauseType::Halt => {
- let code = self.store(self.deref(self[temp_v!(1)]));
-
- let code = match Number::try_from((code, &self.heap)) {
- Ok(Number::Fixnum(n)) => n as i32,
- Ok(Number::Integer(n)) => n.to_i32().unwrap(),
- Ok(Number::Rational(r)) => {
- // n has already been confirmed as an integer, and
- // internally, Rational is assumed reduced, so its
- // denominator must be 1.
- r.numer().to_i32().unwrap()
- }
- _ => {
- unreachable!()
- }
- };
+ #[inline(always)]
+ pub(crate) fn remove_inference_counter(&mut self) {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let bp = cell_as_fixnum!(a1).get_num() as usize;
- std::process::exit(code);
- }
- &SystemClauseType::InstallSCCCleaner => {
- let addr = self[temp_v!(1)];
- let b = self.b;
- let prev_block = self.block;
+ let count = self.machine_st.cwil.remove_limit(bp).clone();
+ let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
- if cut_policy.downcast_ref::<SCCCutPolicy>().is_err() {
- let (r_c_w_h, r_c_wo_h) = indices.get_cleaner_sites();
- *cut_policy = Box::new(SCCCutPolicy::new(r_c_w_h, r_c_wo_h));
- }
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
- Some(cut_policy) => {
- self.install_new_block(temp_v!(2));
- cut_policy.push_cont_pt(addr, b, prev_block);
- }
- None => panic!(
- "install_cleaner: should have installed \\
- SCCCutPolicy."
- ),
- };
- }
- &SystemClauseType::InstallInferenceCounter => {
- // A1 = B, A2 = L
- let a1 = self.store(self.deref(self[temp_v!(1)]));
- let a2 = self.store(self.deref(self[temp_v!(2)]));
+ self.machine_st.unify_big_int(count, a2);
+ }
- if call_policy.downcast_ref::<CWILCallPolicy>().is_err() {
- CWILCallPolicy::new_in_place(call_policy);
- }
+ #[inline(always)]
+ pub(crate) fn return_from_verify_attr(&mut self) {
+ let e = self.machine_st.e;
+ let frame_len = self.machine_st.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
- let n = match Number::try_from((a2, &self.heap)) {
- Ok(Number::Integer(n)) => Integer::from(&*n.clone()),
- Ok(Number::Fixnum(n)) => Integer::from(n),
- _ => {
- let stub = MachineError::functor_stub(
- clause_name!("call_with_inference_limit"),
- 3,
- );
+ for i in 1..frame_len - 2 {
+ self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)];
+ }
- return Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, a2),
- stub,
- ));
- }
- };
+ self.machine_st.b0 = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 2)])
+ .get_num() as usize;
- match a1 {
- Addr::Usize(bp) | Addr::CutPoint(bp) => {
- match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
- Some(call_policy) => {
- let count = call_policy.add_limit(n, bp).clone();
- let count = self
- .heap
- .to_unifiable(HeapCellValue::Integer(Rc::new(count)));
-
- let a3 = self[temp_v!(3)];
- (self.unify_fn)(self, a3, count);
- }
- None => {
- panic!(
- "install_inference_counter: should have installed \\
- CWILCallPolicy."
- )
- }
- }
- }
- _ => {
- unreachable!();
- }
- }
- }
- &SystemClauseType::ModuleExists => {
- let module = self.store(self.deref(self[temp_v!(1)]));
+ self.machine_st.num_of_args = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)])
+ .get_num() as usize;
- match module {
- Addr::Con(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- self.fail = !indices.modules.contains_key(name);
- } else {
- unreachable!()
- }
- }
- _ => {
- unreachable!()
- }
- };
- }
- &SystemClauseType::NoSuchPredicate => {
- let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)])));
-
- self.fail = match self.store(self.deref(self[temp_v!(2)])) {
- Addr::Str(s) => match &self.heap[s] {
- &HeapCellValue::NamedStr(arity, ref name, ref spec) => {
- if CLAUSE_TYPE_FORMS
- .borrow()
- .get(&(name.as_str(), arity))
- .is_some()
- {
- true
- } else {
- let index = indices
- .get_predicate_code_index(
- name.clone(),
- arity,
- module_name,
- spec.clone(),
- )
- .map(|index| index.get())
- .unwrap_or(IndexPtr::DynamicUndefined);
-
- match index {
- IndexPtr::DynamicUndefined => false,
- _ => true,
- }
- }
- }
- _ => {
- unreachable!()
- }
- },
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] {
- let spec =
- fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir);
-
- if CLAUSE_TYPE_FORMS
- .borrow()
- .get(&(name.as_str(), 0))
- .is_some()
- {
- true
- } else {
- let index = indices
- .get_predicate_code_index(
- name.clone(),
- 0,
- module_name,
- spec.clone(),
- )
- .map(|index| index.get())
- .unwrap_or(IndexPtr::DynamicUndefined);
-
- match index {
- IndexPtr::DynamicUndefined => false,
- _ => true,
- }
- }
- } else {
- unreachable!()
- }
- }
- head => {
- let err =
- MachineError::type_error(self.heap.h(), ValidType::Callable, head);
- let stub = MachineError::functor_stub(clause_name!("clause"), 2);
+ let p = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]).get_num() as usize;
- return Err(self.error_form(err, stub));
- }
- };
- }
- &SystemClauseType::RedoAttrVarBinding => {
- let var = self.store(self.deref(self[temp_v!(1)]));
- let value = self.store(self.deref(self[temp_v!(2)]));
+ self.machine_st.deallocate();
+ self.machine_st.p = p;
+ }
- match var {
- Addr::AttrVar(h) => {
- self.heap[h] = HeapCellValue::Addr(value);
- }
- _ => {
- unreachable!()
- }
- }
- }
- &SystemClauseType::ResetAttrVarState => {
- self.attr_var_init.reset();
- }
- &SystemClauseType::RemoveCallPolicyCheck => {
- let restore_default = match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
- Some(call_policy) => {
- let a1 = self.store(self.deref(self[temp_v!(1)]));
+ #[inline(always)]
+ pub(crate) fn restore_cut_policy(&mut self) {
+ if self.machine_st.cont_pts.is_empty() {
+ self.machine_st.run_cleaners_fn = |_| { false };
+ }
+ }
- match a1 {
- Addr::Usize(bp) | Addr::CutPoint(bp) => {
- if call_policy.is_empty() && bp == self.b {
- Some(call_policy.into_inner())
- } else {
- None
- }
- }
- _ => {
- panic!("remove_call_policy_check: expected Usize in A1.");
- }
- }
- }
- None => panic!(
- "remove_call_policy_check: requires \\
- CWILCallPolicy."
- ),
- };
+ #[inline(always)]
+ pub(crate) fn set_cut_point(&mut self, r: RegType) -> bool {
+ let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+ self.machine_st.cut_body(cp);
- if let Some(new_policy) = restore_default {
- *call_policy = new_policy;
- }
+ (self.machine_st.run_cleaners_fn)(self)
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_cut_point_by_default(&mut self, r: RegType) {
+ let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+ self.machine_st.cut_body(cp);
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_input(&mut self) -> CallResult {
+ let addr = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1]
+ ));
+
+ let stream = self.machine_st.get_stream_or_alias(
+ addr,
+ &self.indices.stream_aliases,
+ atom!("set_input"),
+ 1,
+ )?;
+
+ if !stream.is_input_stream() {
+ let stub = functor_stub(atom!("set_input"), 1);
+ let user_alias = atom_as_cell!(atom!("user"));
+
+ let err = self.machine_st.permission_error(
+ Permission::InputStream,
+ atom!("stream"),
+ user_alias,
+ );
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
+
+ self.user_input = stream;
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_output(&mut self) -> CallResult {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let stream = self.machine_st.get_stream_or_alias(
+ addr,
+ &self.indices.stream_aliases,
+ atom!("set_output"),
+ 1,
+ )?;
+
+ if !stream.is_output_stream() {
+ let stub = functor_stub(atom!("set_input"), 1);
+
+ let user_alias = atom_as_cell!(atom!("user"));
+ let err = self.machine_st.permission_error(
+ Permission::OutputStream,
+ atom!("stream"),
+ user_alias,
+ );
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
+
+ self.user_output = stream;
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_double_quotes(&mut self) {
+ let atom = cell_as_atom!(self.machine_st.registers[1]);
+
+ self.machine_st.flags.double_quotes = match atom {
+ atom!("atom") => DoubleQuotes::Atom,
+ atom!("chars") => DoubleQuotes::Chars,
+ atom!("codes") => DoubleQuotes::Codes,
+ _ => {
+ self.machine_st.fail = true;
+ return;
}
- &SystemClauseType::RemoveInferenceCounter => {
- match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
- Some(call_policy) => {
- let a1 = self.store(self.deref(self[temp_v!(1)]));
+ };
+ }
- match a1 {
- Addr::Usize(bp) | Addr::CutPoint(bp) => {
- let count = call_policy.remove_limit(bp).clone();
- let count = self
- .heap
- .to_unifiable(HeapCellValue::Integer(Rc::new(count)));
+ #[inline(always)]
+ pub(crate) fn inference_level(&mut self) {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- let a2 = self[temp_v!(2)];
+ let bp = cell_as_fixnum!(a2).get_num() as usize;
+ let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
- (self.unify_fn)(self, a2, count);
- }
- _ => {
- panic!("remove_inference_counter: expected Usize in A1.");
+ if prev_b <= bp {
+ self.machine_st.unify_atom(atom!("!"), a1)
+ } else {
+ self.machine_st.unify_atom(atom!("true"), a1);
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn clean_up_block(&mut self) {
+ let nb = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let nb = cell_as_fixnum!(nb).get_num() as usize;
+
+ let b = self.machine_st.b;
+
+ if nb > 0 && self.machine_st.stack.index_or_frame(b).prelude.b == nb {
+ self.machine_st.b = self.machine_st.stack.index_or_frame(nb).prelude.b;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn erase_ball(&mut self) {
+ self.machine_st.ball.reset();
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_ball(&mut self) {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let h = self.machine_st.heap.len();
+
+ if self.machine_st.ball.stub.len() > 0 {
+ let stub = self.machine_st.ball.copy_and_align(h);
+ self.machine_st.heap.extend(stub.into_iter());
+ } else {
+ self.machine_st.fail = true;
+ return;
+ }
+
+ match addr.as_var() {
+ Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]),
+ _ => self.machine_st.fail = true,
+ };
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_current_block(&mut self) {
+ let n = Fixnum::build_with(i64::try_from(self.machine_st.block).unwrap());
+ self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_b_value(&mut self) {
+ let n = Fixnum::build_with(i64::try_from(self.machine_st.b).unwrap());
+ self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_cut_point(&mut self) {
+ let n = Fixnum::build_with(i64::try_from(self.machine_st.b0).unwrap());
+ self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_staggered_cut_point(&mut self) {
+ use std::sync::Once;
+
+ let b = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0;
+ static LOC_INIT: Once = Once::new();
+
+ let semicolon_second_clause_p = unsafe {
+ LOC_INIT.call_once(|| {
+ if let Some(builtins) = self.indices.modules.get(&atom!("builtins")) {
+ match builtins.code_dir.get(&(atom!("staggered_sc"), 2)).map(|cell| cell.get()) {
+ Some(IndexPtr::Index(p)) => {
+ match &self.code[p] {
+ &Instruction::TryMeElse(o) => {
+ SEMICOLON_SECOND_BRANCH_LOC = p + o;
+ }
+ _ => {
+ unreachable!();
+ }
}
}
+ _ => {
+ unreachable!();
+ }
}
- None => panic!(
- "remove_inference_counter: requires \\
- CWILCallPolicy."
- ),
- }
- }
- &SystemClauseType::REPL(repl_code_ptr) => {
- return self.repl_redirect(repl_code_ptr);
- }
- &SystemClauseType::ReturnFromVerifyAttr => {
- let e = self.e;
- let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
-
- for i in 1..frame_len - 1 {
- self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i];
- }
-
- if let &Addr::CutPoint(b0) = &self.stack.index_and_frame(e)[frame_len - 1] {
- self.b0 = b0;
+ } else {
+ unreachable!();
}
+ });
- if let &Addr::Usize(num_of_args) = &self.stack.index_and_frame(e)[frame_len] {
- self.num_of_args = num_of_args;
- }
+ SEMICOLON_SECOND_BRANCH_LOC
+ };
- self.deallocate();
- self.p = CodePtr::Local(self.stack.index_and_frame(e).prelude.interrupt_cp);
+ let staggered_b0 = if self.machine_st.b > 0 {
+ let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b);
- return Ok(());
+ if or_frame.prelude.bp == semicolon_second_clause_p {
+ or_frame.prelude.b0
+ } else {
+ self.machine_st.b0
}
- &SystemClauseType::RestoreCutPolicy => {
- let restore_default =
- if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
- cut_policy.out_of_cont_pts()
- } else {
- false
- };
+ } else {
+ self.machine_st.b0
+ };
- if restore_default {
- *cut_policy = Box::new(DefaultCutPolicy {});
- }
- }
- &SystemClauseType::SetCutPoint(r) => {
- if cut_policy.cut(self, r) {
- return Ok(());
- }
- }
- &SystemClauseType::SetCutPointByDefault(r) => deref_cut(self, r),
- &SystemClauseType::SetInput => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
- let stream =
- self.get_stream_or_alias(addr, &indices.stream_aliases, "set_input", 1)?;
+ let staggered_b0 = integer_as_cell!(
+ Number::arena_from(staggered_b0, &mut self.machine_st.arena)
+ );
- if !stream.is_input_stream() {
- let stub = MachineError::functor_stub(clause_name!("set_input"), 1);
+ self.machine_st.bind(b.as_var().unwrap(), staggered_b0);
+ }
- let user_alias = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None));
+ #[inline(always)]
+ pub(crate) fn next_ep(&mut self) {
+ let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- let err = MachineError::permission_error(
- self.heap.h(),
- Permission::InputStream,
- "stream",
- user_alias,
- );
+ read_heap_cell!(first_arg,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(name, atom!("first"));
+ debug_assert_eq!(arity, 0);
- return Err(self.error_form(err, stub));
+ if self.machine_st.e == 0 {
+ self.machine_st.fail = true;
+ return;
}
- *current_input_stream = stream;
- }
- &SystemClauseType::SetOutput => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
- let stream =
- self.get_stream_or_alias(addr, &indices.stream_aliases, "set_output", 1)?;
+ let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e);
+ let cp = and_frame.prelude.cp - 1;
- if !stream.is_output_stream() {
- let stub = MachineError::functor_stub(clause_name!("set_input"), 1);
+ let e = and_frame.prelude.e;
+ let e = Fixnum::build_with(i64::try_from(e).unwrap());
- let user_alias = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None));
+ let p = str_loc_as_cell!(self.machine_st.heap.len());
- let err = MachineError::permission_error(
- self.heap.h(),
- Permission::OutputStream,
- "stream",
- user_alias,
- );
+ self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
+ self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
- return Err(self.error_form(err, stub));
+ if !self.machine_st.fail {
+ unify!(self.machine_st, p, self.machine_st.registers[3]);
}
-
- *current_output_stream = stream;
}
- &SystemClauseType::SetDoubleQuotes => match self[temp_v!(1)] {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
- self.flags.double_quotes = match atom.as_str() {
- "atom" => DoubleQuotes::Atom,
- "chars" => DoubleQuotes::Chars,
- "codes" => DoubleQuotes::Codes,
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
- } else {
- unreachable!()
- }
- }
- _ => {
- self.fail = true;
+ (HeapCellValueTag::Fixnum, n) => {
+ let e = n.get_num() as usize;
+
+ if e == 0 {
+ self.machine_st.fail = true;
+ return;
}
- },
- &SystemClauseType::InferenceLevel => {
- let a1 = self[temp_v!(1)];
- let a2 = self.store(self.deref(self[temp_v!(2)]));
- match a2 {
- Addr::CutPoint(bp) | Addr::Usize(bp) => {
- let prev_b = self.stack.index_or_frame(self.b).prelude.b;
+ // get the call site so that the number of
+ // active permanent variables can be read from
+ // it later.
+ let and_frame = self.machine_st.stack.index_and_frame(e);
+ let cp = and_frame.prelude.cp - 1;
- if prev_b <= bp {
- let a2 = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("!"), None));
+ let p = str_loc_as_cell!(self.machine_st.heap.len());
+ self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
- (self.unify_fn)(self, a1, a2);
- } else {
- let a2 = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("true"), None));
+ let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap());
+ self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
- (self.unify_fn)(self, a1, a2);
- }
- }
- _ => {
- self.fail = true;
- }
+ if !self.machine_st.fail {
+ unify!(self.machine_st, p, self.machine_st.registers[3]);
}
}
- &SystemClauseType::CleanUpBlock => {
- let nb = self.store(self.deref(self[temp_v!(1)]));
+ _ => {
+ unreachable!();
+ }
+ );
+ }
- match nb {
- Addr::Usize(nb) => {
- let b = self.b;
+ #[inline(always)]
+ pub(crate) fn points_to_continuation_reset_marker(&mut self) {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb {
- self.b = self.stack.index_or_frame(nb).prelude.b;
- }
- }
- _ => {
- self.fail = true;
- }
+ let p = match to_local_code_ptr(&self.machine_st.heap, addr) {
+ Some(p) => p + 1,
+ None => {
+ self.machine_st.fail = true;
+ return;
+ }
+ };
+
+ if !self.is_reset_cont_marker(p) {
+ self.machine_st.fail = true;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn quoted_token(&mut self) {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Fixnum, n) => {
+ let n = u32::try_from(n.get_num()).ok();
+ let n = n.and_then(std::char::from_u32);
+
+ self.machine_st.fail = match n {
+ Some(c) => non_quoted_token(once(c)),
+ None => true,
};
}
- &SystemClauseType::EraseBall => {
- self.ball.reset();
+ (HeapCellValueTag::Char, c) => {
+ self.machine_st.fail = non_quoted_token(once(c));
}
- &SystemClauseType::Fail => {
- self.fail = true;
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+ self.machine_st.fail = non_quoted_token(name.as_str().chars());
+ }
+ _ => {
+ self.machine_st.fail = true;
}
- &SystemClauseType::GetBall => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
- let h = self.heap.h();
+ );
+ }
- if self.ball.stub.h() > 0 {
- let stub = self.ball.copy_and_align(h);
- self.heap.extend(stub.into_iter());
- } else {
- self.fail = true;
- return Ok(());
- }
+ #[inline(always)]
+ pub(crate) fn read_query_term(&mut self) -> CallResult {
+ self.user_input.reset();
- let ball = self.heap[h].as_addr(h);
+ set_prompt(true);
+ let result = self.machine_st.read_term(self.user_input, &mut self.indices);
+ set_prompt(false);
- match addr.as_var() {
- Some(r) => self.bind(r, ball),
- _ => self.fail = true,
- };
+ match result {
+ Ok(()) => Ok(()),
+ Err(e) => {
+ self.user_input = input_stream(&mut self.machine_st.arena);
+ return Err(e);
}
- &SystemClauseType::GetCurrentBlock => {
- let c = Constant::Usize(self.block);
- let addr = self[temp_v!(1)];
+ }
+ }
- self.write_constant_to_var(addr, &c);
- }
- &SystemClauseType::GetBValue => {
- let a1 = self[temp_v!(1)];
- let a2 = Addr::Usize(self.b);
+ #[inline(always)]
+ pub(crate) fn read_term(&mut self) -> CallResult {
+ set_prompt(false);
- (self.unify_fn)(self, a1, a2);
- }
- &SystemClauseType::GetCutPoint => {
- let a1 = self[temp_v!(1)];
- let a2 = Addr::CutPoint(self.b0);
+ let stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("read_term"),
+ 3,
+ )?;
- (self.unify_fn)(self, a1, a2);
- }
- &SystemClauseType::InstallNewBlock => {
- self.install_new_block(temp_v!(1));
- }
- &SystemClauseType::NextEP => {
- let first_arg = self.store(self.deref(self[temp_v!(1)]));
+ self.machine_st.read_term(stream, &mut self.indices)
+ }
- match first_arg {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = self.heap.clone(h) {
- if name.as_str() == "first" {
- if self.e == 0 {
- self.fail = true;
- return Ok(());
- }
+ #[inline(always)]
+ pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
+ if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let chars = atom_or_string.to_string();
+ let stream = Stream::from_owned_string(chars, &mut self.machine_st.arena);
- let cp =
- (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap();
+ let term_write_result = match self.machine_st.read(stream, &self.indices.op_dir) {
+ Ok(term_write_result) => term_write_result,
+ Err(e) => {
+ let stub = functor_stub(atom!("read_term_from_chars"), 2);
+ let e = self.machine_st.session_error(SessionError::from(e));
- let e = self.stack.index_and_frame(self.e).prelude.e;
- let e = Addr::Usize(e);
+ return Err(self.machine_st.error_form(e, stub));
+ }
+ };
- let p = cp.as_functor(&mut self.heap);
+ let result = heap_loc_as_cell!(term_write_result.heap_loc);
+ let var = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2]
+ )).as_var().unwrap();
- (self.unify_fn)(self, self[temp_v!(2)], e);
+ self.machine_st.bind(var, result);
+ } else {
+ unreachable!()
+ }
- if !self.fail {
- (self.unify_fn)(self, self[temp_v!(3)], p);
- }
- } else {
- unreachable!()
- }
- } else {
- unreachable!()
- }
- }
- Addr::Usize(e) => {
- if e == 0 {
- self.fail = true;
- return Ok(());
- }
+ Ok(())
+ }
- // get the call site so that the number of active permanent variables can be read
- // from it later.
- let cp = (self.stack.index_and_frame(e).prelude.cp - 1).unwrap();
+ #[inline(always)]
+ pub(crate) fn reset_block(&mut self) {
+ let addr = self.machine_st.deref(self.machine_st.registers[1]);
+ self.machine_st.reset_block(addr);
+ }
- let p = cp.as_functor(&mut self.heap);
- let e = self.stack.index_and_frame(e).prelude.e;
+ #[inline(always)]
+ pub(crate) fn reset_continuation_marker(&mut self) {
+ let h = self.machine_st.heap.len();
- let e = Addr::Usize(e);
+ self.machine_st.registers[3] = atom_as_cell!(atom!("none"));
+ self.machine_st.registers[4] = heap_loc_as_cell!(h);
- (self.unify_fn)(self, self[temp_v!(2)], e);
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ }
- if !self.fail {
- (self.unify_fn)(self, self[temp_v!(3)], p);
- }
- }
+ #[inline(always)]
+ pub(crate) fn set_ball(&mut self) {
+ self.machine_st.set_ball();
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_seed(&mut self) {
+ let seed = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let mut rand = RANDOM_STATE.borrow_mut();
+
+ match Number::try_from(seed) {
+ Ok(Number::Fixnum(n)) => rand.seed(&Integer::from(n)),
+ Ok(Number::Integer(n)) => rand.seed(&*n),
+ Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()),
+ _ => {
+ self.machine_st.fail = true;
+ }
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn sleep(&mut self) {
+ let time = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ let time = match Number::try_from(time) {
+ Ok(Number::Float(n)) => n.into_inner(),
+ Ok(Number::Fixnum(n)) => n.get_num() as f64,
+ Ok(Number::Integer(n)) => n.to_f64(),
+ _ => {
+ unreachable!()
+ }
+ };
+
+ let duration = Duration::new(1, 0);
+ let duration = duration.mul_f64(time);
+
+ std::thread::sleep(duration);
+ }
+
+ #[inline(always)]
+ pub(crate) fn socket_client_open(&mut self) -> CallResult {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ let socket_atom = cell_as_atom!(addr);
+
+ let port = read_heap_cell!(port,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+ name
+ }
+ _ => {
+ self.machine_st.atom_tbl.build_with(&match Number::try_from(port) {
+ Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+ Ok(Number::Integer(n)) => n.to_string(),
_ => {
unreachable!()
}
- }
+ })
}
- &SystemClauseType::PointsToContinuationResetMarker => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
+ );
- let p = match self.heap.to_local_code_ptr(&addr) {
- Some(p) => p + 1,
- None => {
- self.fail = true;
- return Ok(());
- }
- };
+ let socket_addr = if socket_atom == atom!("") {
+ atom!("127.0.0.1:80")
+ } else {
+ let buffer = format!("{}:{}", socket_atom.as_str(), port.as_str());
+ self.machine_st.atom_tbl.build_with(&buffer)
+ };
- if p.is_reset_cont_marker(code_repo, self.last_call) {
- return return_from_clause!(self.last_call, self);
- }
+ let alias = self.machine_st.registers[4];
+ let eof_action = self.machine_st.registers[5];
+ let reposition = self.machine_st.registers[6];
+ let stream_type = self.machine_st.registers[7];
- self.fail = true;
- return Ok(());
- }
- &SystemClauseType::QuotedToken => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
+ let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
- match addr {
- Addr::Fixnum(n) => {
- let n = u32::try_from(n).ok();
- let n = n.and_then(std::char::from_u32);
+ if options.reposition() {
+ return Err(self.machine_st.reposition_error(atom!("socket_client_open"), 3));
+ }
- self.fail = match n {
- Some(c) => non_quoted_token(once(c)),
- None => true,
- };
- }
- Addr::Char(c) => {
- self.fail = non_quoted_token(once(c));
- }
- Addr::Con(h) => {
- if let HeapCellValue::Atom(atom, _) = &self.heap[h] {
- self.fail = non_quoted_token(atom.as_str().chars());
- }
- }
- _ => {
- self.fail = true;
- }
- }
+ if let Some(alias) = options.get_alias() {
+ if self.indices.stream_aliases.contains_key(&alias) {
+ return Err(self.machine_st.occupied_alias_permission_error(
+ alias,
+ atom!("socket_client_open"),
+ 3,
+ ));
}
- &SystemClauseType::ReadQueryTerm => {
- current_input_stream.reset();
+ }
- readline::set_prompt(true);
- let result = self.read_term(current_input_stream.clone(), indices);
- readline::set_prompt(false);
+ let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) {
+ Ok(tcp_stream) => {
+ let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.machine_st.arena);
- match result {
- Ok(()) => {}
- Err(e) => {
- *current_input_stream = readline::input_stream();
- return Err(e);
- }
+ *stream.options_mut() = options;
+
+ if let Some(alias) = stream.options().get_alias() {
+ self.indices.stream_aliases.insert(alias, stream);
}
- }
- &SystemClauseType::ReadTerm => {
- readline::set_prompt(false);
- let stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "read_term",
- 3,
- )?;
+ self.indices.streams.insert(stream);
+
+ stream_as_cell!(stream)
+ }
+ Err(ErrorKind::PermissionDenied) => {
+ return Err(self.machine_st.open_permission_error(addr, atom!("socket_client_open"), 3));
+ }
+ Err(ErrorKind::NotFound) => {
+ let stub = functor_stub(atom!("socket_client_open"), 3);
+ let err = self.machine_st.existence_error(
+ ExistenceError::SourceSink(addr),
+ );
- self.read_term(stream, indices)?;
+ return Err(self.machine_st.error_form(err, stub));
+ }
+ Err(_) => {
+ // for now, just fail. expand to meaningful error messages later.
+ self.machine_st.fail = true;
+ return Ok(());
}
- &SystemClauseType::ReadTermFromChars => {
- let mut heap_pstr_iter = self.heap_pstr_iter(self[temp_v!(1)]);
- let chars = heap_pstr_iter.to_string();
+ };
- if let Addr::EmptyList = heap_pstr_iter.focus() {
- let term_write_result = match self.read(
- Stream::from(chars),
- self.atom_tbl.clone(),
- &indices.op_dir,
- ) {
- Ok(term_write_result) => term_write_result,
- Err(e) => {
- let stub =
- MachineError::functor_stub(clause_name!("read_term_from_chars"), 2);
+ let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+ self.machine_st.bind(stream_addr.as_var().unwrap(), stream);
- let h = self.heap.h();
- let e = MachineError::session_error(h, SessionError::from(e));
+ Ok(())
+ }
- return Err(self.error_form(e, stub));
- }
- };
+ #[inline(always)]
+ pub(crate) fn socket_server_open(&mut self) -> CallResult {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let socket_atom = cell_as_atom_cell!(addr).get_name();
- let result = Addr::HeapCell(term_write_result.heap_loc);
+ let socket_atom = if socket_atom == atom!("[]") {
+ atom!("127.0.0.1")
+ } else {
+ socket_atom
+ };
- if let Some(var) = self.store(self.deref(self[temp_v!(2)])).as_var() {
- self.bind(var, result);
- } else {
- unreachable!()
- }
- } else {
+ let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ let port = if port.is_var() {
+ String::from("0")
+ } else {
+ match Number::try_from(port) {
+ Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+ Ok(Number::Integer(n)) => n.to_string(),
+ _ => {
unreachable!()
}
}
- &SystemClauseType::ResetBlock => {
- let addr = self.deref(self[temp_v!(1)]);
- self.reset_block(addr);
- }
- &SystemClauseType::ResetContinuationMarker => {
- self[temp_v!(3)] = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("none"), None));
+ };
- let h = self.heap.h();
+ let had_zero_port = &port == "0";
- self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
- self[temp_v!(4)] = Addr::HeapCell(h);
- }
- &SystemClauseType::SetBall => {
- self.set_ball();
- }
- &SystemClauseType::SetSeed => {
- let seed = self.store(self.deref(self[temp_v!(1)]));
+ let server_addr = if socket_atom == atom!("") {
+ port
+ } else {
+ format!("{}:{}", socket_atom.as_str(), port)
+ };
- let seed = match Number::try_from((seed, &self.heap)) {
- Ok(Number::Fixnum(n)) => Integer::from(n),
- Ok(Number::Integer(n)) => Integer::from(n.as_ref()),
- Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().clone(),
- _ => {
- self.fail = true;
+ let (tcp_listener, port) =
+ match TcpListener::bind(server_addr).map_err(|e| e.kind()) {
+ Ok(tcp_listener) => {
+ let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
+
+ if let Some(port) = port {
+ (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port as usize)
+ } else {
+ self.machine_st.fail = true;
return Ok(());
}
- };
-
- let mut rand = RANDOM_STATE.borrow_mut();
- rand.seed(&seed);
- }
- &SystemClauseType::SkipMaxList => {
- if let Err(err) = self.skip_max_list() {
- return Err(err);
}
- }
- &SystemClauseType::Sleep => {
- let time = self.store(self.deref(self[temp_v!(1)]));
+ Err(ErrorKind::PermissionDenied) => {
+ return Err(self.machine_st.open_permission_error(addr, atom!("socket_server_open"), 2));
+ }
+ _ => {
+ self.machine_st.fail = true;
+ return Ok(());
+ }
+ };
- let time = match Number::try_from((time, &self.heap)) {
- Ok(Number::Float(OrderedFloat(n))) => n,
- Ok(Number::Fixnum(n)) => n as f64,
- Ok(Number::Integer(n)) => n.to_f64(),
- _ => {
- unreachable!()
- }
- };
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+ self.machine_st.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener));
- let duration = Duration::new(1, 0);
- let duration = duration.mul_f64(time);
- ::std::thread::sleep(duration);
- }
- &SystemClauseType::SocketClientOpen => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
- let port = self.store(self.deref(self[temp_v!(2)]));
+ if had_zero_port {
+ self.machine_st.unify_fixnum(Fixnum::build_with(port as i64), self.machine_st.registers[2]);
+ }
- let socket_atom = match addr {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
- name.clone()
- } else {
- unreachable!()
- }
- }
- _ => {
- unreachable!()
- }
- };
+ Ok(())
+ }
- let port = match port {
- Addr::Fixnum(n) => n.to_string(),
- Addr::Usize(n) => n.to_string(),
- Addr::Con(h) => match &self.heap[h] {
- HeapCellValue::Atom(ref name, _) => name.as_str().to_string(),
- HeapCellValue::Integer(ref n) => n.to_string(),
- _ => {
- unreachable!()
- }
- },
- _ => {
- unreachable!()
- }
- };
+ #[inline(always)]
+ pub(crate) fn socket_server_accept(&mut self) -> CallResult {
+ let alias = self.machine_st.registers[4];
+ let eof_action = self.machine_st.registers[5];
+ let reposition = self.machine_st.registers[6];
+ let stream_type = self.machine_st.registers[7];
- let socket_addr = format!(
- "{}:{}",
- if socket_atom.as_str() == "" {
- "127.0.0.1"
- } else {
- socket_atom.as_str()
- },
- port,
- );
+ let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
- let alias = self[temp_v!(4)];
- let eof_action = self[temp_v!(5)];
- let reposition = self[temp_v!(6)];
- let stream_type = self[temp_v!(7)];
+ if options.reposition() {
+ return Err(self.machine_st.reposition_error(atom!("socket_server_accept"), 4));
+ }
+
+ if let Some(alias) = options.get_alias() {
+ if self.indices.stream_aliases.contains_key(&alias) {
+ return Err(self.machine_st.occupied_alias_permission_error(
+ alias,
+ atom!("socket_server_accept"),
+ 4,
+ ));
+ }
+ }
- let options = self.to_stream_options(alias, eof_action, reposition, stream_type);
+ let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ read_heap_cell!(culprit,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::TcpListener, tcp_listener) => {
+ match tcp_listener.accept().ok() {
+ Some((tcp_stream, socket_addr)) => {
+ let client = self.machine_st.atom_tbl.build_with(&socket_addr.to_string());
+
+ let mut tcp_stream = Stream::from_tcp_stream(
+ client,
+ tcp_stream,
+ &mut self.machine_st.arena,
+ );
+
+ *tcp_stream.options_mut() = options;
+
+ if let Some(alias) = &tcp_stream.options().get_alias() {
+ self.indices.stream_aliases.insert(*alias, tcp_stream);
+ }
+
+ self.indices.streams.insert(tcp_stream);
+
+ let tcp_stream = stream_as_cell!(tcp_stream);
+ let client = atom_as_cell!(client);
+
+ let client_addr = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2],
+ ));
+ let stream_addr = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[3],
+ ));
+
+ self.machine_st.bind(client_addr.as_var().unwrap(), client);
+ self.machine_st.bind(stream_addr.as_var().unwrap(), tcp_stream);
+ }
+ None => {
+ self.machine_st.fail = true;
+ }
+ }
+ }
+ _ => {
+ }
+ );
+ }
+ _ => {
+ }
+ );
- if options.reposition {
- return Err(self.reposition_error("socket_client_open", 3));
- }
+ Ok(())
+ }
- if let Some(ref alias) = &options.alias {
- if indices.stream_aliases.contains_key(alias) {
- return Err(self.occupied_alias_permission_error(
- alias.clone(),
- "socket_client_open",
+ #[inline(always)]
+ pub(crate) fn tls_client_connect(&mut self) -> CallResult {
+ if let Some(hostname) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let stream0 = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[2],
+ &self.indices.stream_aliases,
+ atom!("tls_client_negotiate"),
+ 3,
+ )?;
+
+ let connector = TlsConnector::new().unwrap();
+ let stream =
+ match connector.connect(hostname.as_str(), stream0) {
+ Ok(tls_stream) => tls_stream,
+ Err(_) => {
+ return Err(self.machine_st.open_permission_error(
+ self.machine_st.registers[1],
+ atom!("tls_client_negotiate"),
3,
));
}
- }
-
- let stream = match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) {
- Ok(tcp_stream) => {
- let socket_addr = clause_name!(socket_addr, self.atom_tbl);
+ };
- let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream);
+ let addr = atom!("TLS");
+ let stream = Stream::from_tls_stream(addr, stream, &mut self.machine_st.arena);
+ self.indices.streams.insert(stream);
- *stream.options_mut() = options;
+ self.machine_st.heap.push(stream_as_cell!(stream));
+ let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+ self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
- if let Some(ref alias) = &stream.options().alias {
- indices.stream_aliases.insert(alias.clone(), stream.clone());
- }
+ Ok(())
+ } else {
+ unreachable!();
+ }
+ }
- indices.streams.insert(stream.clone());
+ #[inline(always)]
+ pub(crate) fn tls_accept_client(&mut self) -> CallResult {
+ let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
- self.heap.to_unifiable(HeapCellValue::Stream(stream))
- }
- Err(ErrorKind::PermissionDenied) => {
- return Err(self.open_permission_error(addr, "socket_client_open", 3));
+ if let Some(password) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
+ let identity =
+ match Identity::from_pkcs12(&pkcs12, password.as_str()) {
+ Ok(identity) => identity,
+ Err(_) => {
+ return Err(self.machine_st.open_permission_error(
+ self.machine_st.registers[1],
+ atom!("tls_server_negotiate"),
+ 3,
+ ));
}
- Err(ErrorKind::NotFound) => {
- let stub =
- MachineError::functor_stub(clause_name!("socket_client_open"), 3);
+ };
- let err = MachineError::existence_error(
- self.heap.h(),
- ExistenceError::SourceSink(addr),
- );
+ let stream0 = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[3],
+ &self.indices.stream_aliases,
+ atom!("tls_server_negotiate"),
+ 3,
+ )?;
- return Err(self.error_form(err, stub));
- }
+ let acceptor = TlsAcceptor::new(identity).unwrap();
+
+ let stream =
+ match acceptor.accept(stream0) {
+ Ok(tls_stream) => tls_stream,
Err(_) => {
- // for now, just fail. expand to meaningful error messages later.
- self.fail = true;
- return Ok(());
+ return Err(self.machine_st.open_permission_error(
+ self.machine_st.registers[3],
+ atom!("tls_server_negotiate"),
+ 3,
+ ));
}
};
- let stream_addr = self.store(self.deref(self[temp_v!(3)]));
- self.bind(stream_addr.as_var().unwrap(), stream);
- }
- &SystemClauseType::SocketServerOpen => {
- let addr = self.store(self.deref(self[temp_v!(1)]));
- let socket_atom = match addr {
- Addr::EmptyList => "127.0.0.1".to_string(),
- Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] {
- HeapCellValue::Atom(ref name, _) => name.as_str().to_string(),
- _ => {
- unreachable!()
- }
- },
- _ => {
- unreachable!()
- }
- };
+ let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena);
+ self.indices.streams.insert(stream);
- let port = match self.store(self.deref(self[temp_v!(2)])) {
- Addr::Fixnum(n) => n.to_string(),
- Addr::Usize(n) => n.to_string(),
- Addr::Con(h) => match &self.heap[h] {
- HeapCellValue::Integer(ref n) => n.to_string(),
- _ => {
- unreachable!()
+ let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
+ self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
+ } else {
+ unreachable!();
+ }
+
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn socket_server_close(&mut self) -> CallResult {
+ let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ read_heap_cell!(culprit,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::TcpListener, tcp_listener) => {
+ unsafe {
+ // dropping closes the instance.
+ std::ptr::drop_in_place(&mut tcp_listener as *mut _);
}
- },
- addr if addr.is_ref() => "0".to_string(),
+
+ tcp_listener.set_tag(ArenaHeaderTag::Dropped);
+ return Ok(());
+ }
_ => {
- unreachable!()
}
- };
+ );
+ }
+ _ => {
+ }
+ );
- let had_zero_port = &port == "0";
+ let err = self.machine_st.type_error(ValidType::TcpListener, culprit);
+ let stub = functor_stub(atom!("socket_server_close"), 1);
- let server_addr = if socket_atom.is_empty() {
- port
- } else {
- format!("{}:{}", socket_atom, port)
- };
+ return Err(self.machine_st.error_form(err, stub));
+ }
- let (tcp_listener, port) =
- match TcpListener::bind(server_addr).map_err(|e| e.kind()) {
- Ok(tcp_listener) => {
- let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
-
- if let Some(port) = port {
- (
- self.heap
- .to_unifiable(HeapCellValue::TcpListener(tcp_listener)),
- port as usize,
- )
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- Err(ErrorKind::PermissionDenied) => {
- return Err(self.open_permission_error(addr, "socket_server_open", 2));
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
+ #[inline(always)]
+ pub(crate) fn set_stream_position(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("set_stream_position"),
+ 2,
+ )?;
+
+ if !stream.options().reposition() {
+ let stub = functor_stub(atom!("set_stream_position"), 2);
+
+ let err = self.machine_st.permission_error(
+ Permission::Reposition,
+ atom!("stream"),
+ vec![stream_as_cell!(stream)],
+ );
+
+ return Err(self.machine_st.error_form(err, stub));
+ }
- let addr = self.store(self.deref(self[temp_v!(3)]));
- self.bind(addr.as_var().unwrap(), tcp_listener);
+ let position = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- if had_zero_port {
- (self.unify_fn)(self, self[temp_v!(2)], Addr::Usize(port));
+ let position = match Number::try_from(position) {
+ Ok(Number::Fixnum(n)) => n.get_num() as u64,
+ Ok(Number::Integer(n)) => {
+ if let Some(n) = n.to_u64() {
+ n
+ } else {
+ self.machine_st.fail = true;
+ return Ok(());
}
}
- &SystemClauseType::SocketServerAccept => {
- let alias = self[temp_v!(4)];
- let eof_action = self[temp_v!(5)];
- let reposition = self[temp_v!(6)];
- let stream_type = self[temp_v!(7)];
+ _ => {
+ unreachable!()
+ }
+ };
- let options = self.to_stream_options(alias, eof_action, reposition, stream_type);
+ stream.set_position(position);
+ Ok(())
+ }
- if options.reposition {
- return Err(self.reposition_error("socket_server_accept", 4));
- }
+ #[inline(always)]
+ pub(crate) fn stream_property(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("stream_property"),
+ 2,
+ )?;
+
+ let atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[2]
+ )));
+
+ let property = match atom {
+ atom!("file_name") => {
+ atom_as_cell!(if let Some(file_name) = stream.file_name() {
+ file_name
+ } else {
+ self.machine_st.fail = true;
+ return Ok(());
+ })
+ }
+ atom!("mode") => atom_as_cell!(stream.mode()),
+ atom!("direction") =>
+ atom_as_cell!(if stream.is_input_stream() && stream.is_output_stream() {
+ atom!("input_output")
+ } else if stream.is_input_stream() {
+ atom!("input")
+ } else {
+ atom!("output")
+ }),
+ atom!("alias") => {
+ atom_as_cell!(if let Some(alias) = stream.options().get_alias() {
+ alias
+ } else {
+ self.machine_st.fail = true;
+ return Ok(());
+ })
+ }
+ atom!("position") => {
+ if let Some((position, lines_read)) = stream.position() {
+ let h = self.machine_st.heap.len();
- if let Some(ref alias) = &options.alias {
- if indices.stream_aliases.contains_key(alias) {
- return Err(self.occupied_alias_permission_error(
- alias.clone(),
- "socket_server_accept",
- 4,
- ));
- }
- }
+ let position_term = functor!(
+ atom!("position_and_lines_read"),
+ [integer(position, &mut self.machine_st.arena),
+ integer(lines_read, &mut self.machine_st.arena)]
+ );
- match self.store(self.deref(self[temp_v!(1)])) {
- Addr::TcpListener(h) => match &mut self.heap[h] {
- HeapCellValue::TcpListener(ref mut tcp_listener) => {
- match tcp_listener.accept().ok() {
- Some((tcp_stream, socket_addr)) => {
- let client =
- clause_name!(format!("{}", socket_addr), self.atom_tbl);
+ self.machine_st.heap.extend(position_term.into_iter());
+ str_loc_as_cell!(h)
+ } else {
+ self.machine_st.fail = true;
+ return Ok(());
+ }
+ }
+ atom!("end_of_stream") => {
+ let end_of_stream_pos = stream.position_relative_to_end();
+ atom_as_cell!(end_of_stream_pos.as_atom())
+ }
+ atom!("eof_action") => {
+ atom_as_cell!(stream.options().eof_action().as_atom())
+ }
+ atom!("reposition") =>
+ atom_as_cell!(if stream.options().reposition() {
+ atom!("true")
+ } else {
+ atom!("false")
+ }),
+ atom!("type") => {
+ atom_as_cell!(stream.options().stream_type().as_property_atom())
+ }
+ _ => {
+ unreachable!()
+ }
+ };
- let mut tcp_stream =
- Stream::from_tcp_stream(client.clone(), tcp_stream);
+ unify!(self.machine_st, property, self.machine_st.registers[3]);
+ Ok(())
+ }
- *tcp_stream.options_mut() = options;
+ #[inline(always)]
+ pub(crate) fn store_global_var(&mut self) {
+ let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
- if let Some(ref alias) = &tcp_stream.options().alias {
- indices
- .stream_aliases
- .insert(alias.clone(), tcp_stream.clone());
- }
+ let value = self.machine_st.registers[2];
+ let mut ball = Ball::new();
- indices.streams.insert(tcp_stream.clone());
+ ball.boundary = self.machine_st.heap.len();
- let tcp_stream =
- self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream));
+ copy_term(
+ CopyBallTerm::new(&mut self.machine_st.stack, &mut self.machine_st.heap, &mut ball.stub),
+ value,
+ AttrVarPolicy::DeepCopy,
+ );
- let client =
- self.heap.to_unifiable(HeapCellValue::Atom(client, None));
+ self.indices.global_variables.insert(key, (ball, None));
+ }
- let client_addr = self.store(self.deref(self[temp_v!(2)]));
- let stream_addr = self.store(self.deref(self[temp_v!(3)]));
+ #[inline(always)]
+ pub(crate) fn store_backtrackable_global_var(&mut self) {
+ let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+ let new_value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- self.bind(client_addr.as_var().unwrap(), client);
- self.bind(stream_addr.as_var().unwrap(), tcp_stream);
- }
- None => {
- self.fail = true;
- return Ok(());
- }
- }
- }
- culprit => {
- let culprit = culprit.as_addr(h);
-
- return Err(self.type_error(
- ValidType::TcpListener,
- culprit,
- clause_name!("socket_server_accept"),
- 4,
- ));
- }
- },
- culprit => {
- return Err(self.type_error(
- ValidType::TcpListener,
- culprit,
- clause_name!("socket_server_accept"),
- 4,
- ));
- }
+ match self.indices.global_variables.get_mut(&key) {
+ Some((_, ref mut loc)) => match loc {
+ Some(ref mut value) => {
+ self.machine_st.trail(TrailRef::BlackboardOffset(key, *value));
+ *value = new_value;
}
- }
- &SystemClauseType::SocketServerClose => {
- match self.store(self.deref(self[temp_v!(1)])) {
- Addr::TcpListener(h) => {
- let closed_tcp_listener = clause_name!("$closed_tcp_listener");
- self.heap[h] = HeapCellValue::Atom(closed_tcp_listener, None);
- }
- culprit => {
- return Err(self.type_error(
- ValidType::TcpListener,
- culprit,
- clause_name!("socket_server_close"),
- 1,
- ));
- }
+ loc @ None => {
+ self.machine_st.trail(TrailRef::BlackboardEntry(key));
+ *loc = Some(new_value);
}
+ },
+ None => {
+ self.machine_st.trail(TrailRef::BlackboardEntry(key));
+ self.indices
+ .global_variables
+ .insert(key, (Ball::new(), Some(new_value)));
}
- &SystemClauseType::TLSClientConnect => {
- let hostname = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
+ }
+ }
- let stream0 = self.get_stream_or_alias(
- self[temp_v!(2)],
- &indices.stream_aliases,
- "tls_client_negotiate",
- 3,
- )?;
-
- let connector = TlsConnector::new().unwrap();
- let stream =
- match connector.connect(&hostname, stream0) {
- Ok(tls_stream) => tls_stream,
- Err(_) => {
- return Err(self.open_permission_error(
- self[temp_v!(1)],
- "tls_client_negotiate",
- 3,
- ));
- }
- };
+ #[inline(always)]
+ pub(crate) fn term_attributed_variables(&mut self) {
+ if self.machine_st.registers[1].is_constant() {
+ self.machine_st.unify_atom(
+ atom!("[]"),
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+ );
- let addr = clause_name!("TLS".to_string(), self.atom_tbl);
- let stream = Stream::from_tls_stream(addr, stream);
- indices.streams.insert(stream.clone());
-
- let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
- let stream_addr = self.store(self.deref(self[temp_v!(3)]));
- self.bind(stream_addr.as_var().unwrap(), stream);
- }
- &SystemClauseType::TLSAcceptClient => {
- let pkcs12 = self.string_encoding_bytes(1, "octet");
- let password = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
- let identity =
- match Identity::from_pkcs12(&pkcs12, &password) {
- Ok(identity) => identity,
- Err(_) => {
- return Err(self.open_permission_error(
- self[temp_v!(1)],
- "tls_server_negotiate",
- 3,
- ));
- }
- };
+ return;
+ }
- let stream0 = self.get_stream_or_alias(
- self[temp_v!(3)],
- &indices.stream_aliases,
- "tls_server_negotiate",
- 3,
- )?;
-
- let acceptor = TlsAcceptor::new(identity).unwrap();
-
- let stream =
- match acceptor.accept(stream0) {
- Ok(tls_stream) => tls_stream,
- Err(_) => {
- return Err(self.open_permission_error(
- self[temp_v!(3)],
- "tls_server_negotiate",
- 3,
- ));
- }
- };
- let addr = clause_name!("TLS".to_string(), self.atom_tbl);
- let stream = Stream::from_tls_stream(addr, stream);
- indices.streams.insert(stream.clone());
-
- let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
- let stream_addr = self.store(self.deref(self[temp_v!(4)]));
- self.bind(stream_addr.as_var().unwrap(), stream);
- }
- &SystemClauseType::SetStreamPosition => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "set_stream_position",
- 2,
- )?;
-
- if !stream.options().reposition {
- let stub = MachineError::functor_stub(clause_name!("set_stream_position"), 2);
-
- let err = MachineError::permission_error(
- self.heap.h(),
- Permission::Reposition,
- "stream",
- vec![HeapCellValue::Stream(stream)],
- );
+ let seen_vars = self.machine_st.attr_vars_of_term(self.machine_st.registers[1]);
+ let outcome = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, seen_vars.into_iter())
+ );
- return Err(self.error_form(err, stub));
- }
+ unify_fn!(self.machine_st, self.machine_st.registers[2], outcome);
+ }
- let position = self.store(self.deref(self[temp_v!(2)]));
+ #[inline(always)]
+ pub(crate) fn term_variables(&mut self) {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
- let position = match Number::try_from((position, &self.heap)) {
- Ok(Number::Fixnum(n)) => n as u64,
- Ok(Number::Integer(n)) => {
- if let Some(n) = n.to_u64() {
- n
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- _ => {
- unreachable!()
- }
- };
+ let stored_v = self.machine_st.store(self.machine_st.deref(a1));
- stream.set_position(position);
- }
- &SystemClauseType::StreamProperty => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "stream_property",
- 2,
- )?;
-
- let property = match self.store(self.deref(self[temp_v!(2)])) {
- Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] {
- HeapCellValue::Atom(ref name, _) => match name.as_str() {
- "file_name" => {
- if let Some(file_name) = stream.file_name() {
- HeapCellValue::Atom(file_name, None)
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- "mode" => HeapCellValue::Atom(clause_name!(stream.mode()), None),
- "direction" => HeapCellValue::Atom(
- if stream.is_input_stream() && stream.is_output_stream() {
- clause_name!("input_output")
- } else if stream.is_input_stream() {
- clause_name!("input")
- } else {
- clause_name!("output")
- },
- None,
- ),
- "alias" => {
- if let Some(alias) = &stream.options().alias {
- HeapCellValue::Atom(alias.clone(), None)
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- "position" => {
- if let Some((position, lines_read)) = stream.position() {
- let h = self.heap.h();
+ if stored_v.is_constant() {
+ self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(a2)));
+ return;
+ }
- let position_term = functor!(
- "position_and_lines_read",
- [integer(position), integer(lines_read)]
- );
+ let mut seen_set = IndexSet::new();
- self.heap.extend(position_term.into_iter());
+ {
+ let mut iter = stackless_preorder_iter(&mut self.machine_st.heap, stored_v);
- HeapCellValue::Addr(Addr::HeapCell(h))
- } else {
- self.fail = true;
- return Ok(());
- }
- }
- "end_of_stream" => {
- let end_of_stream_pos = stream.position_relative_to_end();
- HeapCellValue::Atom(clause_name!(end_of_stream_pos.as_str()), None)
- }
- "eof_action" => HeapCellValue::Atom(
- clause_name!(stream.options().eof_action.as_str()),
- None,
- ),
- "reposition" => HeapCellValue::Atom(
- clause_name!(if stream.options().reposition {
- "true"
- } else {
- "false"
- }),
- None,
- ),
- "type" => HeapCellValue::Atom(
- clause_name!(stream.options().stream_type.as_property_str()),
- None,
- ),
- _ => {
- unreachable!()
- }
- },
- _ => {
- unreachable!()
- }
- },
- _ => {
- unreachable!()
- }
- };
+ while let Some(addr) = iter.next() {
+ let addr = unmark_cell_bits!(addr);
- let property = self.heap.to_unifiable(property);
- (self.unify_fn)(self, self[temp_v!(3)], property);
+ if addr.is_var() {
+ seen_set.insert(addr);
+ }
}
- &SystemClauseType::StoreGlobalVar => {
- let key = match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
- atom.clone()
- } else {
- unreachable!()
- }
- }
- _ => {
- unreachable!()
- }
- };
+ }
+
+ let outcome = heap_loc_as_cell!(
+ filtered_iter_to_heap_list(
+ &mut self.machine_st.heap,
+ seen_set.into_iter().rev(),
+ |heap, value| {
+ heap_bound_store(
+ heap,
+ heap_bound_deref(heap, value),
+ ).is_var()
+ },
+ )
+ );
+
+ unify_fn!(self.machine_st, a2, outcome);
+ }
- let value = self[temp_v!(2)];
- let mut ball = Ball::new();
+ #[inline(always)]
+ pub(crate) fn term_variables_under_max_depth(&mut self) {
+ // Term, MaxDepth, VarList
+ let max_depth = cell_as_fixnum!(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+ ).get_num() as usize;
+
+ self.machine_st.term_variables_under_max_depth(
+ self.machine_st.registers[1],
+ max_depth,
+ self.machine_st.registers[3],
+ );
+ }
- ball.boundary = self.heap.h();
+ #[inline(always)]
+ pub(crate) fn truncate_lifted_heap_to(&mut self) {
+ let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let lh_offset = cell_as_fixnum!(a1).get_num() as usize;
- copy_term(
- CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub),
- value,
- AttrVarPolicy::DeepCopy,
- );
+ self.machine_st.lifted_heap.truncate(lh_offset);
+ }
- indices.global_variables.insert(key, (ball, None));
- }
- &SystemClauseType::StoreBacktrackableGlobalVar => {
- let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
- (h, atom.clone())
- } else {
- unreachable!()
- }
- }
- _ => {
- unreachable!()
- }
- };
+ #[inline(always)]
+ pub(crate) fn unify_with_occurs_check(&mut self) {
+ let a1 = self.machine_st.registers[1];
+ let a2 = self.machine_st.registers[2];
- let new_value = self.store(self.deref(self[temp_v!(2)]));
+ unify_with_occurs_check!(&mut self.machine_st, a1, a2);
+ }
- match indices.global_variables.get_mut(&key) {
- Some((_, ref mut loc)) => match loc {
- Some(ref mut value) => {
- let old_value_loc = self.heap.push(HeapCellValue::Addr(*value));
- self.trail(TrailRef::BlackboardOffset(key_h, old_value_loc));
- *value = new_value;
- }
- loc @ None => {
- self.trail(TrailRef::BlackboardEntry(key_h));
- *loc = Some(new_value);
- }
- },
- None => {
- self.trail(TrailRef::BlackboardEntry(key_h));
- indices
- .global_variables
- .insert(key, (Ball::new(), Some(new_value)));
- }
- }
+ #[inline(always)]
+ pub(crate) fn unwind_environments(&mut self) -> bool {
+ let mut e = self.machine_st.e;
+ let mut cp = self.machine_st.cp;
+
+ while e > 0 {
+ if self.is_reset_cont_marker(cp) {
+ self.machine_st.e = e;
+ self.machine_st.p = cp + 1; // skip the reset marker.
+
+ return true;
}
- &SystemClauseType::Succeed => {}
- &SystemClauseType::TermAttributedVariables => {
- let seen_vars = self.attr_vars_of_term(self[temp_v!(1)]);
- let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter()));
- (self.unify_fn)(self, self[temp_v!(2)], outcome);
+ let and_frame = self.machine_st.stack.index_and_frame(e);
+
+ cp = and_frame.prelude.cp;
+ e = and_frame.prelude.e;
+ }
+
+ false
+ }
+
+ #[inline(always)]
+ pub(crate) fn wam_instructions(&mut self) -> CallResult {
+ let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1])
+ ));
+
+ let name = self.machine_st.registers[2];
+ let arity = self.machine_st.registers[3];
+
+ let name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(name)));
+ let arity = self.machine_st.store(self.machine_st.deref(arity));
+
+ let arity = match Number::try_from(arity) {
+ Ok(Number::Fixnum(n)) => n.get_num() as usize,
+ Ok(Number::Integer(n)) => n.to_usize().unwrap(),
+ _ => {
+ unreachable!()
}
- &SystemClauseType::TermVariables => {
- let a1 = self[temp_v!(1)];
- let mut seen_set = IndexSet::new();
- let mut seen_vars = vec![];
+ };
- for addr in self.acyclic_pre_order_iter(a1) {
- if addr.is_ref() && !seen_set.contains(&addr) {
- seen_vars.push(addr);
- seen_set.insert(addr);
- }
+ let key = (name, arity);
+
+ let first_idx = match module_name {
+ atom!("user") => self.indices.code_dir.get(&key),
+ _ => match self.indices.modules.get(&module_name) {
+ Some(module) => module.code_dir.get(&key),
+ None => {
+ let stub = functor_stub(key.0, key.1);
+ let err = self.machine_st.session_error(
+ SessionError::from(CompilationError::InvalidModuleResolution(
+ module_name,
+ )),
+ );
+
+ return Err(self.machine_st.error_form(err, stub));
}
+ },
+ };
- let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter()));
- (self.unify_fn)(self, self[temp_v!(2)], outcome);
- }
- &SystemClauseType::TruncateLiftedHeapTo => {
- match self.store(self.deref(self[temp_v!(1)])) {
- Addr::Usize(lh_offset) => self.lifted_heap.truncate(lh_offset),
- _ => self.fail = true,
+ let first_idx = match first_idx {
+ Some(ref idx) if idx.local().is_some() => {
+ if let Some(idx) = idx.local() {
+ idx
+ } else {
+ unreachable!()
}
}
- &SystemClauseType::UnifyWithOccursCheck => {
- let a1 = self[temp_v!(1)];
- let a2 = self[temp_v!(2)];
+ _ => {
+ let stub = functor_stub(name, arity);
+ let err = self.machine_st.existence_error(
+ ExistenceError::Procedure(name, arity),
+ );
- self.unify_with_occurs_check(a1, a2);
+ return Err(self.machine_st.error_form(err, stub));
}
- &SystemClauseType::UnwindEnvironments => {
- let mut e = self.e;
- let mut cp = self.cp;
+ };
- while e > 0 {
- if cp.is_reset_cont_marker(code_repo, self.last_call) {
- self.e = e;
- self.p = CodePtr::Local(cp + 1); // skip the reset marker.
+ let mut h = self.machine_st.heap.len();
- return Ok(());
- }
+ let mut functors = vec![];
+ let mut functor_list = vec![];
- cp = self.stack.index_and_frame(e).prelude.cp;
- e = self.stack.index_and_frame(e).prelude.e;
- }
- }
- &SystemClauseType::UnwindStack => {
- self.unwind_stack();
- }
- &SystemClauseType::Variant => {
- self.fail = self.structural_eq_test();
- }
- &SystemClauseType::WAMInstructions => {
- let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)])));
+ walk_code(&self.code, first_idx, |instr| {
+ let old_len = functors.len();
+ instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors);
+ let new_len = functors.len();
- let name = self[temp_v!(2)];
- let arity = self[temp_v!(3)];
+ for index in old_len..new_len {
+ let functor_len = functors[index].len();
- let name = match self.store(self.deref(name)) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
- atom.clone()
- } else {
- unreachable!()
- }
+ match functor_len {
+ 0 => {}
+ 1 => {
+ functor_list.push(heap_loc_as_cell!(h));
+ h += functor_len;
}
_ => {
- unreachable!()
+ functor_list.push(str_loc_as_cell!(h));
+ h += functor_len;
}
- };
+ }
+ }
+ });
- let arity = self.store(self.deref(arity));
+ for functor in functors {
+ self.machine_st.heap.extend(functor.into_iter());
+ }
- let arity = match Number::try_from((arity, &self.heap)) {
- Ok(Number::Fixnum(n)) => Integer::from(n),
- Ok(Number::Integer(n)) => Integer::from(n.as_ref()),
- _ => {
- unreachable!()
- }
- };
+ let listing = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, functor_list.into_iter())
+ );
- let key = (name.clone(), arity.to_usize().unwrap());
+ let listing_var = self.machine_st.registers[4];
- let first_idx = match module_name.as_str() {
- "user" => indices.code_dir.get(&key),
- _ => match indices.modules.get(&module_name) {
- Some(module) => module.code_dir.get(&key),
- None => {
- let stub = MachineError::functor_stub(key.0, key.1);
- let h = self.heap.h();
+ unify!(self.machine_st, listing, listing_var);
+ Ok(())
+ }
- let err = MachineError::session_error(
- h,
- SessionError::from(CompilationError::InvalidModuleResolution(
- module_name,
- )),
- );
+ #[inline(always)]
+ pub(crate) fn write_term(&mut self) -> CallResult {
+ let mut stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("write_term"),
+ 3,
+ )?;
+
+ self.machine_st.check_stream_properties(
+ stream,
+ StreamType::Text,
+ None, // input
+ atom!("write_term"),
+ 3,
+ )?;
+
+ let opt_err = if !stream.is_output_stream() {
+ Some(atom!("stream")) // 8.14.2.3 g)
+ } else if stream.options().stream_type() == StreamType::Binary {
+ Some(atom!("binary_stream")) // 8.14.2.3 h)
+ } else {
+ None
+ };
- let err = self.error_form(err, stub);
+ if let Some(err_atom) = opt_err {
+ return Err(self.machine_st.stream_permission_error(
+ Permission::OutputStream,
+ err_atom,
+ stream,
+ atom!("write_term"),
+ 3,
+ ));
+ }
- self.throw_exception(err);
- return Ok(());
- }
- },
- };
+ let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
+ Some(printer) => printer,
+ None => {
+ // this next line is executed by
+ // MachineState::write_term in this case. it's
+ // commented here because rustc can't prove
+ // that it's no longer borrowed.
- let first_idx = match first_idx {
- Some(ref idx) if idx.local().is_some() => {
- if let Some(idx) = idx.local() {
- idx
- } else {
- unreachable!()
- }
- }
- _ => {
- let arity = arity.to_usize().unwrap();
- let stub = MachineError::functor_stub(name.clone(), arity);
- let h = self.heap.h();
+ // self.machine_st.fail = true;
+ return Ok(());
+ }
+ };
+
+ let output = printer.print();
- let err = MachineError::existence_error(
- h,
- ExistenceError::Procedure(name, arity),
- );
+ match write!(&mut stream, "{}", output.result()) {
+ Ok(_) => {}
+ Err(_) => {
+ let stub = functor_stub(atom!("open"), 4);
+ let err = self.machine_st.existence_error(
+ ExistenceError::Stream(self.machine_st.registers[1]),
+ );
- let err = self.error_form(err, stub);
+ return Err(self.machine_st.error_form(err, stub));
+ }
+ }
- self.throw_exception(err);
- return Ok(());
- }
- };
+ stream.flush().unwrap();
+ Ok(())
+ }
- let mut h = self.heap.h();
- let mut functors = vec![];
- let mut functor_list = vec![];
+ #[inline(always)]
+ pub(crate) fn write_term_to_chars(&mut self) -> CallResult {
+ let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
+ None => {
+ // this next line is executed by
+ // MachineState::write_term in this case. it's
+ // commented here because rustc can't prove
+ // that it's no longer borrowed.
- walk_code(&code_repo.code, first_idx, |instr| {
- let old_len = functors.len();
- instr.enqueue_functors(h, &mut functors);
- let new_len = functors.len();
+ // self.machine_st.fail = true;
+ return Ok(());
+ }
+ Some(printer) => printer,
+ };
- for index in old_len..new_len {
- functor_list.push(Addr::HeapCell(h));
- h += functors[index].len();
- }
- });
+ let result = printer.print().result();
+ let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl);
- for functor in functors {
- self.heap.extend(functor.into_iter());
- }
+ let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
- let listing = Addr::HeapCell(self.heap.to_list(functor_list.into_iter()));
- let listing_var = self[temp_v!(4)];
+ if let Some(var) = result_addr.as_var() {
+ self.machine_st.bind(var, chars);
+ } else {
+ unreachable!()
+ }
- (self.unify_fn)(self, listing, listing_var);
- }
- &SystemClauseType::WriteTerm => {
- let mut stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "write_term",
- 3,
- )?;
+ Ok(())
+ }
- self.check_stream_properties(
- &mut stream,
- StreamType::Text,
- None, // input
- clause_name!("write_term"),
- 3,
- )?;
+ #[inline(always)]
+ pub(crate) fn scryer_prolog_version(&mut self) {
+ use git_version::git_version;
- let opt_err = if !stream.is_output_stream() {
- Some("stream") // 8.14.2.3 g)
- } else if stream.options().stream_type == StreamType::Binary {
- Some("binary_stream") // 8.14.2.3 h)
- } else {
- None
- };
+ let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
+ let buffer_atom = self.machine_st.atom_tbl.build_with(buffer);
- if let Some(err_string) = opt_err {
- return Err(self.stream_permission_error(
- Permission::OutputStream,
- err_string,
- stream,
- clause_name!("write_term"),
- 3,
- ));
- }
+ self.machine_st.unify_complete_string(
+ buffer_atom,
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
+ );
+ }
- let addr = self[temp_v!(2)];
+ #[inline(always)]
+ pub(crate) fn crypto_random_byte(&mut self) {
+ let arg = self.machine_st.registers[1];
+ let mut bytes: [u8; 1] = [0];
- let printer = match self.write_term(&indices.op_dir)? {
- None => {
- self.fail = true;
- return Ok(());
- }
- Some(printer) => printer,
- };
+ match rng().fill(&mut bytes) {
+ Ok(()) => {}
+ Err(_) => {
+ // the error payload here is of type 'Unspecified',
+ // which contains no information whatsoever. So, for now,
+ // just fail.
+ self.machine_st.fail = true;
+ return;
+ }
+ }
+
+ let byte = Fixnum::build_with(bytes[0] as i64);
+ self.machine_st.unify_fixnum(byte, arg);
+ }
- let output = printer.print(addr);
+ #[inline(always)]
+ pub(crate) fn crypto_data_hash(&mut self) {
+ let encoding = cell_as_atom!(self.machine_st.registers[2]);
+ let bytes = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
- match write!(&mut stream, "{}", output.result()) {
- Ok(_) => {}
- Err(_) => {
- let stub = MachineError::functor_stub(clause_name!("open"), 4);
- let err = MachineError::existence_error(
- self.heap.h(),
- ExistenceError::Stream(self[temp_v!(1)]),
- );
+ let algorithm = cell_as_atom!(self.machine_st.registers[4]);
- return Err(self.error_form(err, stub));
- }
- }
+ let ints_list = match algorithm {
+ atom!("sha3_224") => {
+ let mut context = Sha3_224::new();
+ context.input(&bytes);
+
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ context
+ .result()
+ .as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ }
+ atom!("sha3_256") => {
+ let mut context = Sha3_256::new();
+ context.input(&bytes);
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ context
+ .result()
+ .as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ }
+ atom!("sha3_384") => {
+ let mut context = Sha3_384::new();
+ context.input(&bytes);
+
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ context
+ .result()
+ .as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ }
+ atom!("sha3_512") => {
+ let mut context = Sha3_512::new();
+ context.input(&bytes);
+
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ context
+ .result()
+ .as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ }
+ atom!("blake2s256") => {
+ let mut context = Blake2s::new();
+ context.input(&bytes);
+
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ context
+ .result()
+ .as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ }
+ atom!("blake2b512") => {
+ let mut context = Blake2b::new();
+ context.input(&bytes);
+
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ context
+ .result()
+ .as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ }
+ atom!("ripemd160") => {
+ let mut context = Ripemd160::new();
+ context.input(&bytes);
+
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ context
+ .result()
+ .as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ }
+ _ => {
+ let ints = digest::digest(
+ match algorithm {
+ atom!("sha256") => &digest::SHA256,
+ atom!("sha384") => &digest::SHA384,
+ atom!("sha512") => &digest::SHA512,
+ atom!("sha512_256") => &digest::SHA512_256,
+ _ => {
+ unreachable!()
+ }
+ },
+ &bytes,
+ );
- stream.flush().unwrap();
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ ints.as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
}
- &SystemClauseType::WriteTermToChars => {
- let addr = self[temp_v!(2)];
+ };
- let printer = match self.write_term(&indices.op_dir)? {
- None => {
- self.fail = true;
- return Ok(());
- }
- Some(printer) => printer,
- };
+ unify!(self.machine_st, self.machine_st.registers[3], ints_list);
+ }
- let result = printer.print(addr).result();
- let chars = self.heap.put_complete_string(&result);
+ #[inline(always)]
+ pub(crate) fn crypto_data_hkdf(&mut self) {
+ let encoding = cell_as_atom!(self.machine_st.registers[2]);
+ let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
- let result_addr = self.store(self.deref(self[temp_v!(1)]));
+ let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
+ let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
- if let Some(var) = result_addr.as_var() {
- self.bind(var, chars);
- } else {
- unreachable!()
+ let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
+ let info = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
+
+ let algorithm = cell_as_atom!(self.machine_st.registers[5]);
+
+ let length = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[6]));
+
+ let length = match Number::try_from(length) {
+ Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
+ Ok(Number::Integer(n)) => match n.to_usize() {
+ Some(u) => u,
+ _ => {
+ self.machine_st.fail = true;
+ return;
}
+ },
+ _ => {
+ unreachable!()
}
- &SystemClauseType::ScryerPrologVersion => {
- use git_version::git_version;
- let version = self[temp_v!(1)];
- let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
- let chars = buffer.chars().map(|c| Addr::Char(c));
- let result = Addr::HeapCell(self.heap.to_list(chars));
- (self.unify_fn)(self, version, result);
- }
- &SystemClauseType::CryptoRandomByte => {
- let arg = self[temp_v!(1)];
- let mut bytes: [u8; 1] = [0];
+ };
- match rng().fill(&mut bytes) {
- Ok(()) => {}
- Err(_) => {
- // the error payload here is of type 'Unspecified',
- // which contains no information whatsoever. So, for now,
- // just fail.
- self.fail = true;
- return Ok(());
- }
+ let ints_list = {
+ let digest_alg = match algorithm {
+ atom!("sha256") => hkdf::HKDF_SHA256,
+ atom!("sha384") => hkdf::HKDF_SHA384,
+ atom!("sha512") => hkdf::HKDF_SHA512,
+ _ => {
+ self.machine_st.fail = true;
+ return;
}
+ };
- let byte = self
- .heap
- .to_unifiable(HeapCellValue::Integer(Rc::new(Integer::from(bytes[0]))));
+ let salt = hkdf::Salt::new(digest_alg, &salt);
+ let mut bytes: Vec<u8> = Vec::new();
- (self.unify_fn)(self, arg, byte);
+ bytes.resize(length, 0);
+
+ match salt.extract(&data).expand(&[&info[..]], MyKey(length)) {
+ Ok(r) => {
+ r.fill(&mut bytes).unwrap();
+ }
+ _ => {
+ self.machine_st.fail = true;
+ return;
+ }
}
- &SystemClauseType::CryptoDataHash => {
- let encoding = self.atom_argument_to_string(2);
- let bytes = self.string_encoding_bytes(1, &encoding);
- let algorithm = self.atom_argument_to_string(4);
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ bytes
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ };
- let ints_list = match algorithm.as_str() {
- "sha3_224" => {
- let mut context = Sha3_224::new();
- context.input(&bytes);
- Addr::HeapCell(
- self.heap.to_list(
- context
- .result()
- .as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- "sha3_256" => {
- let mut context = Sha3_256::new();
- context.input(&bytes);
- Addr::HeapCell(
- self.heap.to_list(
- context
- .result()
- .as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- "sha3_384" => {
- let mut context = Sha3_384::new();
- context.input(&bytes);
- Addr::HeapCell(
- self.heap.to_list(
- context
- .result()
- .as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- "sha3_512" => {
- let mut context = Sha3_512::new();
- context.input(&bytes);
- Addr::HeapCell(
- self.heap.to_list(
- context
- .result()
- .as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- "blake2s256" => {
- let mut context = Blake2s::new();
- context.input(&bytes);
- Addr::HeapCell(
- self.heap.to_list(
- context
- .result()
- .as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- "blake2b512" => {
- let mut context = Blake2b::new();
- context.input(&bytes);
- Addr::HeapCell(
- self.heap.to_list(
- context
- .result()
- .as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- "ripemd160" => {
- let mut context = Ripemd160::new();
- context.input(&bytes);
- Addr::HeapCell(
- self.heap.to_list(
- context
- .result()
- .as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- _ => {
- let ints = digest::digest(
- match algorithm.as_str() {
- "sha256" => &digest::SHA256,
- "sha384" => &digest::SHA384,
- "sha512" => &digest::SHA512,
- "sha512_256" => &digest::SHA512_256,
- _ => {
- unreachable!()
- }
- },
- &bytes,
- );
- Addr::HeapCell(
- self.heap.to_list(
- ints.as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- }
- };
+ unify!(self.machine_st, self.machine_st.registers[7], ints_list);
+ }
+
+ #[inline(always)]
+ pub(crate) fn crypto_password_hash(&mut self) {
+ let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3);
+ let data = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
+ let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3);
+ let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
+
+ let iterations = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
- (self.unify_fn)(self, self[temp_v!(3)], ints_list);
+ let iterations = match Number::try_from(iterations) {
+ Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(),
+ Ok(Number::Integer(n)) => match n.to_u64() {
+ Some(i) => i,
+ None => {
+ self.machine_st.fail = true;
+ return;
+ }
+ },
+ _ => {
+ unreachable!()
}
- &SystemClauseType::CryptoDataHKDF => {
- let encoding = self.atom_argument_to_string(2);
- let data = self.string_encoding_bytes(1, &encoding);
- let stub1 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4);
- let salt = self.integers_to_bytevec(temp_v!(3), stub1);
- let stub2 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4);
- let info = self.integers_to_bytevec(temp_v!(4), stub2);
+ };
- let algorithm = self.atom_argument_to_string(5);
+ let ints_list = {
+ let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN];
+
+ pbkdf2::derive(
+ pbkdf2::PBKDF2_HMAC_SHA512,
+ NonZeroU32::new(iterations as u32).unwrap(),
+ &salt,
+ &data,
+ &mut bytes,
+ );
+
+ heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ bytes
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ )
+ };
- let length = self.store(self.deref(self[temp_v!(6)]));
+ unify!(self.machine_st, self.machine_st.registers[4], ints_list);
+ }
- let length = match Number::try_from((length, &self.heap)) {
- Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(),
- Ok(Number::Integer(n)) => match n.to_usize() {
- Some(u) => u,
- _ => {
- self.fail = true;
- return Ok(());
- }
- },
- _ => {
- unreachable!()
- }
- };
+ #[inline(always)]
+ pub(crate) fn crypto_data_encrypt(&mut self) {
+ let encoding = cell_as_atom!(self.machine_st.registers[3]);
- let ints_list = {
- let digest_alg = match algorithm.as_str() {
- "sha256" => hkdf::HKDF_SHA256,
- "sha384" => hkdf::HKDF_SHA384,
- "sha512" => hkdf::HKDF_SHA512,
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
- let salt = hkdf::Salt::new(digest_alg, &salt);
- let mut bytes: Vec<u8> = Vec::new();
- bytes.resize(length, 0);
- match salt.extract(&data).expand(&[&info[..]], MyKey(length)) {
- Ok(r) => {
- r.fill(&mut bytes).unwrap();
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
- }
+ let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
+ let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
- Addr::HeapCell(
- self.heap.to_list(
- bytes
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- };
+ let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
+ let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
+
+ let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
+ let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[5], stub3_gen);
+
+ let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
+ let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
+ let key = aead::LessSafeKey::new(unbound_key);
- (self.unify_fn)(self, self[temp_v!(7)], ints_list);
+ let mut in_out = data;
+
+ let tag = match key.seal_in_place_separate_tag(
+ nonce,
+ aead::Aad::from(aad),
+ &mut in_out,
+ ) {
+ Ok(d) => d,
+ _ => {
+ self.machine_st.fail = true;
+ return;
}
- &SystemClauseType::CryptoPasswordHash => {
- let stub1 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3);
- let data = self.integers_to_bytevec(temp_v!(1), stub1);
- let stub2 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3);
- let salt = self.integers_to_bytevec(temp_v!(2), stub2);
+ };
- let iterations = self.store(self.deref(self[temp_v!(3)]));
+ let tag_list = heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ tag.as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ );
- let iterations = match Number::try_from((iterations, &self.heap)) {
- Ok(Number::Fixnum(n)) => u64::try_from(n).unwrap(),
- Ok(Number::Integer(n)) => match n.to_u64() {
- Some(i) => i,
- None => {
- self.fail = true;
- return Ok(());
- }
- },
- _ => {
- unreachable!()
- }
- };
+ let complete_string = {
+ let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
- let ints_list = {
- let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN];
- pbkdf2::derive(
- pbkdf2::PBKDF2_HMAC_SHA512,
- NonZeroU32::new(iterations as u32).unwrap(),
- &salt,
- &data,
- &mut bytes,
- );
+ if buffer.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer))
+ }
+ };
- Addr::HeapCell(
- self.heap.to_list(
- bytes
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- )
- };
+ unify!(self.machine_st, self.machine_st.registers[6], tag_list);
+ unify!(self.machine_st, self.machine_st.registers[7], complete_string);
+ }
+
+ #[inline(always)]
+ pub(crate) fn crypto_data_decrypt(&mut self) {
+ let data = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+ let encoding = cell_as_atom!(self.machine_st.registers[5]);
+
+ let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
+ let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
+
+ let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
+ let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
+ let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
+
+ let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
+ let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
+ let key = aead::LessSafeKey::new(unbound_key);
- (self.unify_fn)(self, self[temp_v!(4)], ints_list);
- }
- &SystemClauseType::CryptoDataEncrypt => {
- let encoding = self.atom_argument_to_string(3);
- let data = self.string_encoding_bytes(1, &encoding);
- let aad = self.string_encoding_bytes(2, &encoding);
- let stub2 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7);
- let key = self.integers_to_bytevec(temp_v!(4), stub2);
- let stub3 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7);
- let iv = self.integers_to_bytevec(temp_v!(5), stub3);
-
- let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
- let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
- let key = aead::LessSafeKey::new(unbound_key);
-
- let mut in_out = data.clone();
- let tag = match key.seal_in_place_separate_tag(
- nonce,
- aead::Aad::from(aad),
- &mut in_out,
- ) {
+ let mut in_out = data;
+
+ let complete_string = {
+ let decrypted_data =
+ match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) {
Ok(d) => d,
_ => {
- self.fail = true;
- return Ok(());
+ self.machine_st.fail = true;
+ return;
}
};
- let tag_list = Addr::HeapCell(
- self.heap.to_list(
- tag.as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- );
+ let buffer = match encoding {
+ atom!("octet") => String::from_iter(decrypted_data.iter().map(|b| *b as char)),
+ atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) {
+ Ok(str) => str,
+ _ => {
+ self.machine_st.fail = true;
+ return;
+ }
+ },
+ _ => {
+ unreachable!()
+ }
+ };
- let complete_string = {
- let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
- self.heap.put_complete_string(&buffer)
- };
+ if buffer.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer))
+ }
+ };
+
+ unify!(self.machine_st, self.machine_st.registers[6], complete_string);
+ }
- (self.unify_fn)(self, self[temp_v!(6)], tag_list);
- (self.unify_fn)(self, self[temp_v!(7)], complete_string);
+ #[inline(always)]
+ pub(crate) fn crypto_curve_scalar_mult(&mut self) {
+ let curve = cell_as_atom!(self.machine_st.registers[1]);
+
+ let curve_id = match curve {
+ atom!("secp112r1") => Nid::SECP112R1,
+ atom!("secp256k1") => Nid::SECP256K1,
+ _ => {
+ unreachable!()
}
- &SystemClauseType::CryptoDataDecrypt => {
- let data = self.string_encoding_bytes(1, "octet");
- let encoding = self.atom_argument_to_string(5);
- let aad = self.string_encoding_bytes(2, &encoding);
- let stub1 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7);
- let key = self.integers_to_bytevec(temp_v!(3), stub1);
- let stub2 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7);
- let iv = self.integers_to_bytevec(temp_v!(4), stub2);
+ };
- let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
- let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
- let key = aead::LessSafeKey::new(unbound_key);
+ let scalar = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
- let mut in_out = data.clone();
+ let scalar = match Number::try_from(scalar) {
+ Ok(Number::Fixnum(n)) => Integer::from(n.get_num()),
+ Ok(Number::Integer(n)) => Integer::from(&*n),
+ _ => {
+ unreachable!()
+ }
+ };
- let complete_string = {
- let decrypted_data =
- match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) {
- Ok(d) => d,
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
+ let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5);
+ let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen);
- let buffer = match encoding.as_str() {
- "octet" => String::from_iter(decrypted_data.iter().map(|b| *b as char)),
- "utf8" => match String::from_utf8(decrypted_data.to_vec()) {
- Ok(str) => str,
- _ => {
- self.fail = true;
- return Ok(());
- }
- },
- _ => {
- unreachable!()
- }
- };
+ let mut bnctx = BigNumContext::new().unwrap();
+ let group = EcGroup::from_curve_name(curve_id).unwrap();
+ let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap();
+ let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap();
+ let mut result = EcPoint::new(&group).unwrap();
- self.heap.put_complete_string(&buffer)
- };
+ result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok();
- (self.unify_fn)(self, self[temp_v!(6)], complete_string);
- }
- &SystemClauseType::CryptoCurveScalarMult => {
- let curve = self.atom_argument_to_string(1);
- let curve_id = match curve.as_str() {
- "secp112r1" => Nid::SECP112R1,
- "secp256k1" => Nid::SECP256K1,
- _ => {
- unreachable!()
- }
- };
+ let mut rx = BigNum::new().unwrap();
+ let mut ry = BigNum::new().unwrap();
- let scalar = self.store(self.deref(self[temp_v!(2)]));
+ result
+ .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx)
+ .ok();
- let scalar = match Number::try_from((scalar, &self.heap)) {
- Ok(Number::Fixnum(n)) => Integer::from(n),
- Ok(Number::Integer(n)) => Integer::from(&*n.clone()),
- _ => {
- unreachable!()
- }
- };
+ let sx = rx.to_dec_str().unwrap();
+ let sx = if sx.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&sx))
+ };
+
+ let sy = ry.to_dec_str().unwrap();
+ let sy = if sy.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&sy))
+ };
- let stub = MachineError::functor_stub(clause_name!("crypto_curve_scalar_mult"), 5);
- let qbytes = self.integers_to_bytevec(temp_v!(3), stub);
+ unify!(self.machine_st, self.machine_st.registers[4], sx);
+ unify!(self.machine_st, self.machine_st.registers[5], sy);
+ }
- let mut bnctx = BigNumContext::new().unwrap();
- let group = EcGroup::from_curve_name(curve_id).unwrap();
- let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap();
- let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap();
- let mut result = EcPoint::new(&group).unwrap();
- result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok();
+ #[inline(always)]
+ pub(crate) fn ed25519_new_key_pair(&mut self) {
+ let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
+ let complete_string = {
+ let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char));
- let mut rx = BigNum::new().unwrap();
- let mut ry = BigNum::new().unwrap();
- result
- .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx)
- .ok();
- let sx = self
- .heap
- .put_complete_string(&rx.to_dec_str().unwrap().to_string());
- let sy = self
- .heap
- .put_complete_string(&ry.to_dec_str().unwrap().to_string());
-
- (self.unify_fn)(self, self[temp_v!(4)], sx);
- (self.unify_fn)(self, self[temp_v!(5)], sy);
- }
- &SystemClauseType::Ed25519NewKeyPair => {
- let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
- let complete_string = {
- let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char));
- self.heap.put_complete_string(&buffer)
- };
+ if buffer.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer))
+ }
+ };
+
+ unify!(self.machine_st, self.machine_st.registers[1], complete_string)
+ }
- (self.unify_fn)(self, self[temp_v!(1)], complete_string);
+ #[inline(always)]
+ pub(crate) fn ed25519_key_pair_public_key(&mut self) {
+ let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+
+ let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
+ Ok(kp) => kp,
+ _ => {
+ self.machine_st.fail = true;
+ return;
}
- &SystemClauseType::Ed25519KeyPairPublicKey => {
- let bytes = self.string_encoding_bytes(1, "octet");
+ };
- let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
- Ok(kp) => kp,
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
+ let complete_string = {
+ let buffer = String::from_iter(
+ key_pair.public_key().as_ref().iter().map(|b| *b as char),
+ );
- let complete_string = {
- let buffer = String::from_iter(
- key_pair.public_key().as_ref().iter().map(|b| *b as char),
- );
- self.heap.put_complete_string(&buffer)
- };
+ if buffer.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer))
+ }
+ };
+
+ unify!(self.machine_st, self.machine_st.registers[2], complete_string);
+ }
- (self.unify_fn)(self, self[temp_v!(2)], complete_string);
+ #[inline(always)]
+ pub(crate) fn ed25519_sign(&mut self) {
+ let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+ let encoding = cell_as_atom!(self.machine_st.registers[3]);
+ let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
+
+ let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
+ Ok(kp) => kp,
+ _ => {
+ self.machine_st.fail = true;
+ return;
}
- &SystemClauseType::Ed25519Sign => {
- let key = self.string_encoding_bytes(1, "octet");
- let encoding = self.atom_argument_to_string(3);
- let data = self.string_encoding_bytes(2, &encoding);
+ };
- let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
- Ok(kp) => kp,
- _ => {
- self.fail = true;
- return Ok(());
- }
- };
+ let sig = key_pair.sign(&data);
- let sig = key_pair.sign(&data);
+ let sig_list = heap_loc_as_cell!(
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ sig.as_ref()
+ .iter()
+ .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+ )
+ );
- let sig_list = Addr::HeapCell(
- self.heap.to_list(
- sig.as_ref()
- .iter()
- .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))),
- ),
- );
+ unify!(self.machine_st, self.machine_st.registers[4], sig_list);
+ }
+
+ #[inline(always)]
+ pub(crate) fn ed25519_verify(&mut self) {
+ let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+ let encoding = cell_as_atom!(self.machine_st.registers[3]);
+ let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
+ let stub_gen = || functor_stub(atom!("ed25519_verify"), 5);
+ let signature = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
+
+ let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
- (self.unify_fn)(self, self[temp_v!(4)], sig_list);
+ match peer_public_key.verify(&data, &signature) {
+ Ok(_) => {}
+ _ => {
+ self.machine_st.fail = true;
}
- &SystemClauseType::Ed25519Verify => {
- let key = self.string_encoding_bytes(1, "octet");
- let encoding = self.atom_argument_to_string(3);
- let data = self.string_encoding_bytes(2, &encoding);
- let stub = MachineError::functor_stub(clause_name!("ed25519_verify"), 5);
- let signature = self.integers_to_bytevec(temp_v!(4), stub);
+ }
+ }
- let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
- match peer_public_key.verify(&data, &signature) {
- Ok(_) => {}
- _ => {
- self.fail = true;
- return Ok(());
- }
+ #[inline(always)]
+ pub(crate) fn curve25519_scalar_mult(&mut self) {
+ let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
+ let scalar_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
+ let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap());
+
+ let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
+ let point_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
+ let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap());
+
+ let result = scalarmult(&scalar, &point).unwrap();
+
+ let string = String::from_iter(result[..].iter().map(|b| *b as char));
+ let cstr = if string.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&string))
+ };
+
+ unify!(self.machine_st, self.machine_st.registers[3], cstr);
+ }
+
+ #[inline(always)]
+ pub(crate) fn first_non_octet(&mut self) {
+ let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+ if let Some(string) = self.machine_st.value_to_str_like(addr) {
+ for c in string.as_str().chars() {
+ if c as u32 > 255 {
+ let non_octet = self.machine_st.atom_tbl.build_with(&c.to_string());
+ self.machine_st.unify_atom(non_octet, self.machine_st.registers[2]);
+ return;
}
}
- &SystemClauseType::Curve25519ScalarMult => {
- let stub1 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3);
- let scalar_bytes = self.integers_to_bytevec(temp_v!(1), stub1);
- let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap());
+ }
- let stub2 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3);
- let point_bytes = self.integers_to_bytevec(temp_v!(2), stub2);
- let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap());
+ self.machine_st.fail = true;
+ }
+
+ #[inline(always)]
+ pub(crate) fn load_html(&mut self) {
+ if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ let doc = select::document::Document::from_read(string.as_str().as_bytes()).unwrap();
+ let result = self.html_node_to_term(doc.nth(0).unwrap());
- let result = scalarmult(&scalar, &point).unwrap();
+ unify!(self.machine_st, self.machine_st.registers[2], result);
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
- let string = String::from_iter(result[..].iter().map(|b| *b as char));
- let cstr = self.heap.put_complete_string(&string);
- (self.unify_fn)(self, self[temp_v!(3)], cstr);
+ #[inline(always)]
+ pub(crate) fn load_xml(&mut self) {
+ if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ match roxmltree::Document::parse(string.as_str()) {
+ Ok(doc) => {
+ let result = self.xml_node_to_term(doc.root_element());
+ unify!(self.machine_st, self.machine_st.registers[2], result);
+ }
+ _ => {
+ self.machine_st.fail = true;
+ }
}
- &SystemClauseType::FirstNonOctet => {
- for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() {
- if c as u32 > 255 {
- let chars = clause_name!(String::from(c.to_string()), self.atom_tbl);
- let non_octet = self.heap.to_unifiable(HeapCellValue::Atom(chars, None));
- (self.unify_fn)(self, self[temp_v!(2)], non_octet);
- return return_from_clause!(self.last_call, self);
- }
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_env(&mut self) {
+ if let Some(key) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+ match env::var(key.as_str()) {
+ Ok(value) => {
+ let cstr = put_complete_string(
+ &mut self.machine_st.heap,
+ &value,
+ &mut self.machine_st.atom_tbl,
+ );
+
+ unify!(self.machine_st, self.machine_st.registers[2], cstr);
+ }
+ _ => {
+ self.machine_st.fail = true;
}
- self.fail = true;
- return Ok(());
}
- &SystemClauseType::LoadHTML => {
- let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- let doc = select::document::Document::from_read(string.as_bytes()).unwrap();
- let result = self.html_node_to_term(indices, doc.nth(0).unwrap());
+ } else {
+ self.machine_st.fail = true;
+ }
+ }
- (self.unify_fn)(self, self[temp_v!(2)], result);
+ #[inline(always)]
+ pub(crate) fn set_env(&mut self) {
+ let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
+ let value = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
+
+ env::set_var(key.as_str(), value.as_str());
+ }
+
+ #[inline(always)]
+ pub(crate) fn unset_env(&mut self) {
+ let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
+ env::remove_var(key.as_str());
+ }
+
+ #[inline(always)]
+ pub(crate) fn pid(&mut self) {
+ let pid = process::id();
+
+ match fixnum!(Number, pid as i64, &mut self.machine_st.arena) {
+ Number::Fixnum(pid) => {
+ self.machine_st.unify_fixnum(pid, self.machine_st.registers[1]);
}
- &SystemClauseType::LoadXML => {
- let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- match roxmltree::Document::parse(&string) {
- Ok(doc) => {
- let result = self.xml_node_to_term(indices, doc.root_element());
- (self.unify_fn)(self, self[temp_v!(2)], result);
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
- }
+ Number::Integer(pid) => {
+ self.machine_st.unify_big_int(pid, self.machine_st.registers[1]);
}
- &SystemClauseType::GetEnv => {
- let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- match env::var(key) {
- Ok(value) => {
- let cstr = self.heap.put_complete_string(&value);
- (self.unify_fn)(self, self[temp_v!(2)], cstr);
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
- }
+ _ => {
+ unreachable!();
}
- &SystemClauseType::SetEnv => {
- let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- let value = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
- env::set_var(key, value);
- }
- &SystemClauseType::UnsetEnv => {
- let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- env::remove_var(key);
- }
- &SystemClauseType::Shell => {
- // shell executes a command in a system shell
- // the code looks for a SHELL env var to do it in a UNIX-style
- // if not found, the code looks for COMSPEC env var to do it in a DOS-style
- // the output is printed directly to stdout
- // the output status code is returned after finishing
- fn command_result(machine: &mut MachineState, command: std::io::Result<process::ExitStatus>) {
- match command {
- Ok(status) => {
- match status.code() {
- Some(code) => {
- let addr = machine.heap.put_constant(Constant::Integer(Rc::new(Integer::from(code))));
- (machine.unify_fn)(machine, machine[temp_v!(2)], addr);
- }
- _ => {
- machine.fail = true;
- }
- }
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn shell(&mut self) {
+ // shell executes a command in a system shell
+ // the code looks for a SHELL env var to do it in a UNIX-style
+ // if not found, the code looks for COMSPEC env var to do it in a DOS-style
+ // the output is printed directly to stdout
+ // the output status code is returned after finishing
+ fn command_result(machine: &mut MachineState, command: std::io::Result<process::ExitStatus>) {
+ match command {
+ Ok(status) => {
+ match status.code() {
+ Some(code) => {
+ let code = integer_as_cell!(Number::arena_from(code, &mut machine.arena));
+ unify!(machine, code, machine.registers[2]);
}
_ => {
machine.fail = true;
}
}
}
+ _ => {
+ machine.fail = true;
+ }
+ }
+ }
+
+ let command = self.machine_st.value_to_str_like(
+ self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+ ).unwrap();
- let command = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
- match env::var("SHELL") {
+ match env::var("SHELL") {
+ Ok(value) => {
+ let command = process::Command::new(&value)
+ .arg("-c")
+ .arg(command.as_str())
+ .status();
+ command_result(&mut self.machine_st, command);
+ }
+ _ => {
+ match env::var("COMSPEC") {
Ok(value) => {
let command = process::Command::new(&value)
- .arg("-c")
- .arg(command)
+ .arg("/C")
+ .arg(command.as_str())
.status();
- command_result(self, command);
+ command_result(&mut self.machine_st, command);
}
_ => {
- match env::var("COMSPEC") {
- Ok(value) => {
- let command = process::Command::new(&value)
- .arg("/C")
- .arg(command)
- .status();
- command_result(self, command);
- }
- _ => {
- self.fail = true;
- }
- }
+ self.machine_st.fail = true;
}
- };
+ }
+ }
+ };
+ }
+
+ #[inline(always)]
+ pub(crate) fn chars_base64(&mut self) -> CallResult {
+ let padding = cell_as_atom!(self.machine_st.registers[3]);
+ let charset = cell_as_atom!(self.machine_st.registers[4]);
+
+ let config = if padding == atom!("true") {
+ if charset == atom!("standard") {
+ base64::STANDARD
+ } else {
+ base64::URL_SAFE
}
- &SystemClauseType::PID => {
- let a1 = self[temp_v!(1)];
- let pid = process::id();
- let addr = self.heap.put_constant(Constant::Integer(Rc::new(Integer::from(pid))));
- (self.unify_fn)(self, a1, addr);
+ } else {
+ if charset == atom!("standard") {
+ base64::STANDARD_NO_PAD
+ } else {
+ base64::URL_SAFE_NO_PAD
}
- &SystemClauseType::CharsBase64 => {
- let padding = self.atom_argument_to_string(3);
- let charset = self.atom_argument_to_string(4);
+ };
- let config = if padding == "true" {
- if charset == "standard" {
- base64::STANDARD
- } else {
- base64::URL_SAFE
- }
- } else {
- if charset == "standard" {
- base64::STANDARD_NO_PAD
- } else {
- base64::URL_SAFE_NO_PAD
- }
- };
+ if self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])).is_var() {
+ let b64 = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
+ let bytes = base64::decode_config(b64.as_str(), config);
- if self.store(self.deref(self[temp_v!(1)])).is_ref() {
- let b64 = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
- let bytes = base64::decode_config(b64, config);
+ match bytes {
+ Ok(bs) => {
+ let string = String::from_iter(bs.iter().map(|b| *b as char));
+ let cstr = if string.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&string))
+ };
- match bytes {
- Ok(bs) => {
- let string = String::from_iter(bs.iter().map(|b| *b as char));
- let cstr = self.heap.put_complete_string(&string);
- (self.unify_fn)(self, self[temp_v!(1)], cstr);
- }
- _ => {
- self.fail = true;
- return Ok(());
- }
- }
- } else {
- let mut bytes = vec![];
- for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() {
- bytes.push(c as u8);
- }
- let b64 = base64::encode_config(bytes, config);
+ unify!(self.machine_st, self.machine_st.registers[1], cstr);
+ }
+ _ => {
+ self.machine_st.fail = true;
+ return Ok(());
+ }
+ }
+ } else {
+ let mut bytes = vec![];
+ for c in self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap().as_str().chars() {
+ if c as u32 > 255 {
+ let stub = functor_stub(atom!("chars_base64"), 3);
+
+ let err = self.machine_st.type_error(
+ ValidType::Byte,
+ char_as_cell!(c),
+ );
- let cstr = self.heap.put_complete_string(&b64);
- (self.unify_fn)(self, self[temp_v!(2)], cstr);
+ return Err(self.machine_st.error_form(err, stub));
}
+
+ bytes.push(c as u8);
}
- &SystemClauseType::LoadLibraryAsStream => {
- let library_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)])));
- use crate::LIBRARIES;
+ let b64 = base64::encode_config(bytes, config);
+ let cstr = if b64.len() == 0 {
+ empty_list_as_cell!()
+ } else {
+ atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&b64))
+ };
+
+ unify!(self.machine_st, self.machine_st.registers[2], cstr);
+ }
- match LIBRARIES.borrow().get(library_name.as_str()) {
- Some(library) => {
- let var_ref = Ref::HeapCell(
- self.heap
- .push(HeapCellValue::Stream(Stream::from(*library))),
- );
+ Ok(())
+ }
- self.bind(var_ref, self[temp_v!(2)]);
+ #[inline(always)]
+ pub(crate) fn load_library_as_stream(&mut self) -> CallResult {
+ let library_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[1]
+ )));
- let mut path_buf = machine::current_dir();
+ use crate::machine::LIBRARIES;
- path_buf.push("/lib");
- path_buf.push(library_name.as_str());
+ match LIBRARIES.borrow().get(library_name.as_str()) {
+ Some(library) => {
+ let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena);
+ unify!(self.machine_st, stream_as_cell!(lib_stream), self.machine_st.registers[2]);
- let library_path_str = path_buf.to_str().unwrap();
- let library_path =
- clause_name!(library_path_str.to_string(), self.atom_tbl);
+ let mut path_buf = machine::current_dir();
- let library_path_ref =
- Ref::HeapCell(self.heap.push(HeapCellValue::Atom(library_path, None)));
+ path_buf.push("/lib");
+ path_buf.push(library_name.as_str());
- self.bind(library_path_ref, self[temp_v!(3)]);
- }
- None => {
- return Err(self.error_form(
- MachineError::existence_error(
- self.heap.h(),
- ExistenceError::ModuleSource(ModuleSource::Library(library_name)),
- ),
- MachineError::functor_stub(clause_name!("load"), 1),
- ));
- }
- }
+ let library_path_str = path_buf.to_str().unwrap();
+ let library_path = self.machine_st.atom_tbl.build_with(library_path_str);
+
+ self.machine_st.unify_atom(library_path, self.machine_st.registers[3]);
}
- &SystemClauseType::DevourWhitespace => {
- let stream = self.get_stream_or_alias(
- self[temp_v!(1)],
- &indices.stream_aliases,
- "$devour_whitespace",
- 1,
- )?;
+ None => {
+ let stub = functor_stub(atom!("load"), 1);
+ let err = self.machine_st.existence_error(
+ ExistenceError::ModuleSource(ModuleSource::Library(library_name))
+ );
- match self.devour_whitespace(stream, self.atom_tbl.clone()) {
- Ok(false) => {} // not at EOF.
- _ => {
- self.fail = true;
- return Ok(());
- }
- }
+ return Err(self.machine_st.error_form(err, stub));
}
- &SystemClauseType::IsSTOEnabled => {
- if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
- let value = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("true"), None));
+ }
- (self.unify_fn)(self, self[temp_v!(1)], value);
- } else if self.unify_fn as usize
- == MachineState::unify_with_occurs_check_with_error as usize
- {
- let value = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("error"), None));
+ Ok(())
+ }
- (self.unify_fn)(self, self[temp_v!(1)], value);
- } else {
- let value = self
- .heap
- .to_unifiable(HeapCellValue::Atom(clause_name!("false"), None));
+ #[inline(always)]
+ pub(crate) fn devour_whitespace(&mut self) -> CallResult {
+ let stream = self.machine_st.get_stream_or_alias(
+ self.machine_st.registers[1],
+ &self.indices.stream_aliases,
+ atom!("$devour_whitespace"),
+ 1,
+ )?;
- (self.unify_fn)(self, self[temp_v!(1)], value);
- }
+ match self.machine_st.devour_whitespace(stream) {
+ Ok(false) => { // not at EOF.
}
- &SystemClauseType::SetSTOAsUnify => {
- self.unify_fn = MachineState::unify_with_occurs_check;
- self.bind_fn = MachineState::bind_with_occurs_check_wrapper;
+ _ => {
+ self.machine_st.fail = true;
}
- &SystemClauseType::SetNSTOAsUnify => {
- self.unify_fn = MachineState::unify;
- self.bind_fn = MachineState::bind;
+ }
+
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn is_sto_enabled(&mut self) {
+ if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
+ self.machine_st.unify_atom(atom!("true"), self.machine_st.registers[1]);
+ } else if self.machine_st.unify_fn as usize
+ == MachineState::unify_with_occurs_check_with_error as usize
+ {
+ self.machine_st.unify_atom(atom!("error"), self.machine_st.registers[1]);
+ } else {
+ self.machine_st.unify_atom(atom!("false"), self.machine_st.registers[1]);
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_sto_as_unify(&mut self) {
+ self.machine_st.unify_fn = MachineState::unify_with_occurs_check;
+ self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper;
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_nsto_as_unify(&mut self) {
+ self.machine_st.unify_fn = MachineState::unify;
+ self.machine_st.bind_fn = MachineState::bind;
+ }
+
+ #[inline(always)]
+ pub(crate) fn set_sto_with_error_as_unify(&mut self) {
+ self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error;
+ self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper;
+ }
+
+ #[inline(always)]
+ pub(crate) fn home_directory(&mut self) {
+ let path = match dirs_next::home_dir() {
+ Some(path) => path,
+ None => {
+ self.machine_st.fail = true;
+ return;
}
- &SystemClauseType::SetSTOWithErrorAsUnify => {
- self.unify_fn = MachineState::unify_with_occurs_check_with_error;
- self.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper;
+ };
+
+ if path.is_dir() {
+ if let Some(path) = path.to_str() {
+ let path_string = put_complete_string(
+ &mut self.machine_st.heap,
+ path,
+ &mut self.machine_st.atom_tbl,
+ );
+
+ unify!(self.machine_st, self.machine_st.registers[1], path_string);
+ return;
}
- &SystemClauseType::HomeDirectory => {
- let path = match dirs_next::home_dir() {
- Some(path) => path,
- None => {
- self.fail = true;
- return Ok(());
- }
- };
+ }
- if path.is_dir() {
- if let Some(path) = path.to_str() {
- let path_string = self.heap.put_complete_string(path);
+ self.machine_st.fail = true;
+ }
- self.unify(self[temp_v!(1)], path_string);
- return return_from_clause!(self.last_call, self);
- }
- }
+ pub(crate) fn debug_hook(&mut self) {
+ }
- self.fail = true;
+ #[inline(always)]
+ pub(crate) fn pop_count(&mut self) {
+ let number = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ let pop_count = integer_as_cell!(match Number::try_from(number) {
+ Ok(Number::Fixnum(n)) => {
+ Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64))
}
- &SystemClauseType::DebugHook => {
- self.fail = false;
+ Ok(Number::Integer(n)) => {
+ Number::arena_from(n.count_ones().unwrap(), &mut self.machine_st.arena)
}
- &SystemClauseType::PopCount => {
- let number = self.store(self.deref(self[temp_v!(1)]));
- let count = match Number::try_from((number, &self.heap)) {
- Ok(Number::Fixnum(n)) => Integer::from(n.count_ones()),
- Ok(Number::Integer(n)) => Integer::from((&*n).count_ones().unwrap()),
- _ => {
- unreachable!()
- }
- };
-
- let pop_count = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(count)));
- (self.unify_fn)(self, self[temp_v!(2)], pop_count);
+ _ => {
+ unreachable!()
}
- };
+ });
- return_from_clause!(self.last_call, self)
+ unify!(self.machine_st, self.machine_st.registers[2], pop_count);
}
- pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Addr {
+ pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom {
let datetime: DateTime<Local> = system_time.into();
let mut fstr = "[".to_string();
- let specifiers = vec![
- "Y", "m", "d", "H", "M", "S", "y", "b", "B", "a", "A", "w", "u", "U", "W", "j", "D",
- "x", "v",
+ const SPECIFIERS: [char; 19] = [
+ 'Y', 'm', 'd', 'H', 'M', 'S', 'y', 'b', 'B', 'a', 'A', 'w', 'u', 'U', 'W', 'j', 'D',
+ 'x', 'v',
];
- for spec in specifiers {
+
+ for spec in SPECIFIERS {
fstr.push_str(&format!("'{}'=\"%{}\", ", spec, spec).to_string());
}
+
fstr.push_str("finis].");
let s = datetime.format(&fstr).to_string();
- self.heap.put_complete_string(&s)
- }
- pub(super) fn atom_argument_to_string(&mut self, atom_arg: usize) -> String {
- match self.store(self.deref(self[temp_v!(atom_arg)])) {
- Addr::Con(h) if self.heap.atom_at(h) => {
- if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
- atom.as_str().to_string()
- } else {
- unreachable!()
- }
- }
- _ => {
- unreachable!()
- }
- }
+ self.machine_st.atom_tbl.build_with(&s)
}
- pub(super) fn string_encoding_bytes(&mut self, data_arg: usize, encoding: &str) -> Vec<u8> {
- let data = self.heap_pstr_iter(self[temp_v!(data_arg)]).to_string();
+ pub(super) fn string_encoding_bytes(&mut self, data_arg: HeapCellValue, encoding: Atom) -> Vec<u8> {
+ let data = self.machine_st.value_to_str_like(data_arg).unwrap();
match encoding {
- "utf8" => data.into_bytes(),
- "octet" => {
- let mut buf = vec![];
- for c in data.chars() {
- buf.push(c as u8);
- }
- buf
- }
+ atom!("utf8") => data.as_str().bytes().collect(),
+ atom!("octet") => data.as_str().chars().map(|c| c as u8).collect(),
_ => {
unreachable!()
}
}
}
- pub(super) fn xml_node_to_term(
- &mut self,
- indices: &mut IndexStore,
- node: roxmltree::Node,
- ) -> Addr {
+ pub(super) fn xml_node_to_term(&mut self, node: roxmltree::Node) -> HeapCellValue {
if node.is_text() {
- let string = String::from(node.text().unwrap());
- self.heap.put_complete_string(&string)
+ put_complete_string(
+ &mut self.machine_st.heap,
+ node.text().unwrap(),
+ &mut self.machine_st.atom_tbl,
+ )
} else {
let mut avec = Vec::new();
- for attr in node.attributes() {
- let chars = clause_name!(String::from(attr.name()), self.atom_tbl);
- let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None));
- let value = self.heap.put_complete_string(&attr.value());
+ for attr in node.attributes() {
+ let name = self.machine_st.atom_tbl.build_with(attr.name());
+ let value = put_complete_string(
+ &mut self.machine_st.heap,
+ &attr.value(),
+ &mut self.machine_st.atom_tbl,
+ );
- avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h())));
+ avec.push(str_loc_as_cell!(self.machine_st.heap.len()));
- self.heap
- .push(HeapCellValue::NamedStr(2, clause_name!("="), None));
- self.heap.push(HeapCellValue::Addr(name));
- self.heap.push(HeapCellValue::Addr(value));
+ self.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
+ self.machine_st.heap.push(atom_as_cell!(name));
+ self.machine_st.heap.push(value);
}
- let attrs = Addr::HeapCell(self.heap.to_list(avec.into_iter()));
+
+ let attrs = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, avec.into_iter())
+ );
let mut cvec = Vec::new();
+
for child in node.children() {
- cvec.push(self.xml_node_to_term(indices, child));
+ cvec.push(self.xml_node_to_term(child));
}
- let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter()));
- let chars = clause_name!(String::from(node.tag_name().name()), self.atom_tbl);
- let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None));
+ let children = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, cvec.into_iter())
+ );
+
+ let tag = self.machine_st.atom_tbl.build_with(node.tag_name().name());
- let result = Addr::HeapCell(self.heap.h());
+ let result = str_loc_as_cell!(self.machine_st.heap.len());
- self.heap
- .push(HeapCellValue::NamedStr(3, clause_name!("element"), None));
- self.heap.push(HeapCellValue::Addr(tag));
- self.heap.push(HeapCellValue::Addr(attrs));
- self.heap.push(HeapCellValue::Addr(children));
+ self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3));
+ self.machine_st.heap.push(atom_as_cell!(tag));
+ self.machine_st.heap.push(attrs);
+ self.machine_st.heap.push(children);
result
}
}
- pub(super) fn html_node_to_term(
- &mut self,
- indices: &mut IndexStore,
- node: select::node::Node,
- ) -> Addr {
+ pub(super) fn html_node_to_term(&mut self, node: select::node::Node) -> HeapCellValue {
match node.name() {
None => {
- let string = String::from(node.text());
- self.heap.put_complete_string(&string)
+ put_complete_string(
+ &mut self.machine_st.heap,
+ &node.text(),
+ &mut self.machine_st.atom_tbl,
+ )
}
Some(name) => {
let mut avec = Vec::new();
- for attr in node.attrs() {
- let chars = clause_name!(String::from(attr.0), self.atom_tbl);
- let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None));
- let value = self.heap.put_complete_string(&String::from(attr.1));
+ for attr in node.attrs() {
+ let name = self.machine_st.atom_tbl.build_with(attr.0);
+ let value = put_complete_string(
+ &mut self.machine_st.heap,
+ &attr.1,
+ &mut self.machine_st.atom_tbl,
+ );
- avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h())));
+ avec.push(str_loc_as_cell!(self.machine_st.heap.len()));
- self.heap
- .push(HeapCellValue::NamedStr(2, clause_name!("="), None));
- self.heap.push(HeapCellValue::Addr(name));
- self.heap.push(HeapCellValue::Addr(value));
+ self.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
+ self.machine_st.heap.push(atom_as_cell!(name));
+ self.machine_st.heap.push(value);
}
- let attrs = Addr::HeapCell(self.heap.to_list(avec.into_iter()));
+
+ let attrs = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, avec.into_iter())
+ );
let mut cvec = Vec::new();
+
for child in node.children() {
- cvec.push(self.html_node_to_term(indices, child));
+ cvec.push(self.html_node_to_term(child));
}
- let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter()));
- let chars = clause_name!(String::from(name), self.atom_tbl);
- let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None));
+ let children = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.machine_st.heap, cvec.into_iter())
+ );
- let result = Addr::HeapCell(self.heap.h());
+ let tag = self.machine_st.atom_tbl.build_with(name);
+ let result = str_loc_as_cell!(self.machine_st.heap.len());
- self.heap
- .push(HeapCellValue::NamedStr(3, clause_name!("element"), None));
- self.heap.push(HeapCellValue::Addr(tag));
- self.heap.push(HeapCellValue::Addr(attrs));
- self.heap.push(HeapCellValue::Addr(children));
+ self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3));
+ self.machine_st.heap.push(atom_as_cell!(tag));
+ self.machine_st.heap.push(attrs);
+ self.machine_st.heap.push(children);
result
}
@@ -5808,3 +6087,4 @@ impl hkdf::KeyType for MyKey<usize> {
self.0
}
}
+
diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs
index e55a5499..a1d38271 100644
--- a/src/machine/term_stream.rs
+++ b/src/machine/term_stream.rs
@@ -1,48 +1,53 @@
-use prolog_parser::ast::*;
-use prolog_parser::parser::*;
-
-use crate::machine::machine_errors::CompilationError;
+use crate::forms::*;
use crate::machine::*;
+use crate::machine::load_state::*;
+use crate::machine::loader::*;
+use crate::machine::machine_errors::*;
+use crate::parser::ast::*;
+use crate::parser::parser::*;
+
+use crate::predicate_queue;
use indexmap::IndexSet;
use std::collections::VecDeque;
use std::fmt;
-pub(crate) trait TermStream: Sized {
- type Evacuable;
+pub struct LoadStatePayload<TS> {
+ pub term_stream: TS,
+ pub(super) compilation_target: CompilationTarget,
+ pub(super) retraction_info: RetractionInfo,
+ pub(super) module_op_exports: ModuleOpExports,
+ pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
+ pub(super) predicates: PredicateQueue,
+ pub(super) clause_clauses: Vec<(Term, Term)>,
+}
+pub trait TermStream: Sized {
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
- fn evacuate<'a>(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
}
#[derive(Debug)]
-pub(super) struct BootstrappingTermStream<'a> {
+pub struct BootstrappingTermStream<'a> {
listing_src: ListingSource,
- parser: Parser<'a, Stream>,
+ pub(super) parser: Parser<'a, Stream>,
}
impl<'a> BootstrappingTermStream<'a> {
#[inline]
- pub(super) fn from_prolog_stream(
- stream: &'a mut PrologStream,
- atom_tbl: TabledData<Atom>,
- flags: MachineFlags,
+ pub(super) fn from_char_reader(
+ stream: Stream,
+ machine_st: &'a mut MachineState,
listing_src: ListingSource,
) -> Self {
- let parser = Parser::new(stream, atom_tbl, flags);
- Self {
- parser,
- listing_src,
- }
+ let parser = Parser::new(stream, machine_st);
+ Self { parser, listing_src }
}
}
impl<'a> TermStream for BootstrappingTermStream<'a> {
- type Evacuable = CompilationTarget;
-
#[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
self.parser.reset();
@@ -61,24 +66,9 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
-
- fn evacuate(mut loader: Loader<Self>) -> Result<Self::Evacuable, SessionError> {
- if !loader.predicates.is_empty() {
- loader.compile_and_submit()?;
- }
-
- loader
- .load_state
- .retraction_info
- .reset(loader.load_state.wam.code_repo.code.len());
-
- loader.load_state.remove_module_op_exports();
-
- Ok(loader.load_state.compilation_target.take())
- }
}
-pub(crate) struct LiveTermStream {
+pub struct LiveTermStream {
pub(super) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource,
}
@@ -93,28 +83,18 @@ impl LiveTermStream {
}
}
-pub(crate) struct LoadStatePayload {
- pub(super) term_stream: LiveTermStream,
- pub(super) compilation_target: CompilationTarget,
- pub(super) retraction_info: RetractionInfo,
- pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>,
- pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
- pub(super) predicates: PredicateQueue,
- pub(super) clause_clauses: Vec<(Term, Term)>,
-}
-
-impl fmt::Debug for LoadStatePayload {
+impl<TS> fmt::Debug for LoadStatePayload<TS> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LoadStatePayload")
}
}
-impl LoadStatePayload {
- pub(super) fn new(wam: &Machine) -> Self {
+impl<TS> LoadStatePayload<TS> {
+ pub(super) fn new(code_repo_len: usize, term_stream: TS) -> Self {
Self {
- term_stream: LiveTermStream::new(ListingSource::User),
+ term_stream,
compilation_target: CompilationTarget::default(),
- retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
+ retraction_info: RetractionInfo::new(code_repo_len),
module_op_exports: vec![],
non_counted_bt_preds: IndexSet::new(),
predicates: predicate_queue![],
@@ -124,8 +104,6 @@ impl LoadStatePayload {
}
impl TermStream for LiveTermStream {
- type Evacuable = LoadStatePayload;
-
#[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
@@ -140,9 +118,4 @@ impl TermStream for LiveTermStream {
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
-
- #[inline]
- fn evacuate(loader: Loader<Self>) -> Result<LoadStatePayload, SessionError> {
- Ok(loader.to_load_state_payload())
- }
}
diff --git a/src/macros.rs b/src/macros.rs
index b8b6d802..0b83bbb7 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -1,9 +1,3 @@
-macro_rules! interm {
- ($n: expr) => {
- ArithmeticTerm::Interm($n)
- };
-}
-
/* A simple macro to count the arguments in a variadic list
* of token trees.
*/
@@ -13,53 +7,420 @@ macro_rules! count_tt {
($($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()),*];
+macro_rules! char_as_cell {
+ ($c: expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64)
+ };
+}
- let mut result =
- vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
- $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
+macro_rules! fixnum_as_cell {
+ ($n: expr) => {
+ HeapCellValue::from_bytes($n.into_bytes()) //HeapCellValueTag::Fixnum, $n.get_num() as u64)
+ };
+}
- $(
- result.extend($aux.into_iter());
- )*
+macro_rules! cell_as_fixnum {
+ ($cell:expr) => {
+ Fixnum::from_bytes($cell.into_bytes())
+ };
+}
- result.extend(addendum.into_iter());
- result
+macro_rules! integer_as_cell {
+ ($n: expr) => {{
+ match $n {
+ Number::Float(_) => unreachable!(),
+ Number::Fixnum(n) => fixnum_as_cell!(n),
+ Number::Rational(r) => typed_arena_ptr_as_cell!(r),
+ Number::Integer(n) => typed_arena_ptr_as_cell!(n),
}
+ }};
+}
+
+macro_rules! empty_list_as_cell {
+ () => {
+ // the empty list atom has the fixed index of 8 (8 >> 3 == 1 in the condensed atom representation).
+ atom_as_cell!(atom!("[]"))
+ };
+}
+
+macro_rules! atom_as_cell {
+ ($atom:expr) => {
+ HeapCellValue::from_bytes(
+ AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(),
+ )
+ };
+ ($atom:expr, $arity:expr) => {
+ HeapCellValue::from_bytes(
+ AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom)
+ .into_bytes(),
+ )
+ };
+}
+
+macro_rules! cell_as_ossified_op_dir {
+ ($cell:expr) => {{
+ let ptr_u64 = cell_as_untyped_arena_ptr!($cell);
+ TypedArenaPtr::new(ptr_u64.payload_offset() as *mut OssifiedOpDir)
+ }};
+}
+
+macro_rules! cell_as_string {
+ ($cell:expr) => {
+ PartialString::from(cell_as_atom!($cell))
+ };
+}
+
+macro_rules! cell_as_atom {
+ ($cell:expr) => {{
+ let cell = AtomCell::from_bytes($cell.into_bytes());
+ let name = cell.get_index() << 3;
+
+ Atom::from(name as usize)
+ }};
+}
+
+macro_rules! cell_as_atom_cell {
+ ($cell:expr) => {
+ AtomCell::from_bytes($cell.into_bytes())
+ };
+}
+
+macro_rules! cell_as_f64_ptr {
+ ($cell:expr) => {{
+ let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes());
+ F64Ptr(TypedArenaPtr::new(
+ ptr_u64.as_ptr() as *mut OrderedFloat<f64>
+ ))
+ }};
+}
+
+macro_rules! cell_as_untyped_arena_ptr {
+ ($cell:expr) => {
+ UntypedArenaPtr::from(u64::from($cell) as *const ArenaHeader)
+ };
+}
+
+macro_rules! pstr_as_cell {
+ ($atom:expr) => {
+ HeapCellValue::from_bytes(
+ AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::PStr).into_bytes(),
+ )
+ };
+}
+
+macro_rules! pstr_loc_as_cell {
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64)
+ };
+}
+
+macro_rules! pstr_offset_as_cell {
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::PStrOffset, $h as u64)
+ };
+}
+
+macro_rules! list_loc_as_cell {
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64)
+ };
+}
+
+macro_rules! str_loc_as_cell {
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::Str, $h as u64)
+ };
+}
+
+macro_rules! stack_loc {
+ (OrFrame, $b:expr, $idx:expr) => ({
+ $b + prelude_size::<OrFrame>() + $idx * std::mem::size_of::<HeapCellValue>()
});
- ($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({
- {
- #[allow(unused_variables, unused_mut)]
- let mut addendum = Heap::new();
- let arity = count_tt!($($dt) +);
+ (AndFrame, $e:expr, $idx:expr) => ({
+ $e + prelude_size::<AndFrame>() + ($idx - 1) * std::mem::size_of::<HeapCellValue>()
+ });
+}
- let mut result =
- vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
- $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
+macro_rules! stack_loc_as_cell {
+ (OrFrame, $b:expr, $idx:expr) => {
+ stack_loc_as_cell!(stack_loc!(OrFrame, $b, $idx))
+ };
+ (AndFrame, $b:expr, $idx:expr) => {
+ stack_loc_as_cell!(stack_loc!(AndFrame, $b, $idx))
+ };
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::StackVar, $h as u64)
+ };
+}
- result.extend(addendum.into_iter());
- result
+#[macro_export]
+macro_rules! heap_loc_as_cell {
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::Var, $h as u64)
+ };
+}
+
+macro_rules! attr_var_as_cell {
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64)
+ };
+}
+
+#[allow(unused)]
+macro_rules! attr_var_loc_as_cell {
+ ($h:expr) => {
+ HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64)
+ };
+}
+
+macro_rules! typed_arena_ptr_as_cell {
+ ($ptr:expr) => {
+ untyped_arena_ptr_as_cell!($ptr.header_ptr())
+ };
+}
+
+macro_rules! untyped_arena_ptr_as_cell {
+ ($ptr:expr) => {
+ HeapCellValue::from_bytes(unsafe { std::mem::transmute($ptr) })
+ };
+}
+
+macro_rules! atom_as_cstr_cell {
+ ($atom:expr) => {{
+ let offset = $atom.flat_index();
+
+ HeapCellValue::from_bytes(
+ AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
+ )
+ }};
+}
+
+macro_rules! string_as_cstr_cell {
+ ($ptr:expr) => {{
+ let atom: Atom = $ptr.into();
+ let offset = atom.flat_index();
+
+ HeapCellValue::from_bytes(
+ AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
+ )
+ }};
+}
+
+macro_rules! string_as_pstr_cell {
+ ($ptr:expr) => {{
+ let atom: Atom = $ptr.into();
+ let offset = atom.flat_index();
+
+ HeapCellValue::from_bytes(
+ AtomCell::build_with(offset as u64, 0, HeapCellValueTag::PStr).into_bytes(),
+ )
+ }};
+}
+
+macro_rules! stream_as_cell {
+ ($ptr:expr) => {
+ untyped_arena_ptr_as_cell!($ptr.as_ptr())
+ };
+}
+
+macro_rules! cell_as_stream {
+ ($cell:expr) => {{
+ let ptr = cell_as_untyped_arena_ptr!($cell);
+ Stream::from_tag(ptr.get_tag(), ptr.payload_offset())
+ }};
+}
+
+macro_rules! cell_as_load_state_payload {
+ ($cell:expr) => { unsafe {
+ let ptr = cell_as_untyped_arena_ptr!($cell);
+ let ptr = std::mem::transmute::<_, *mut LiveLoadState>(ptr.payload_offset());
+
+ TypedArenaPtr::new(ptr)
+ }};
+}
+
+macro_rules! match_untyped_arena_ptr_pat_body {
+ ($ptr:ident, Integer, $n:ident, $code:expr) => {{
+ let payload_ptr = unsafe { std::mem::transmute::<_, *mut Integer>($ptr.payload_offset()) };
+ let $n = TypedArenaPtr::new(payload_ptr);
+ #[allow(unused_braces)]
+ $code
+ }};
+ ($ptr:ident, F64, $n:ident, $code:expr) => {{
+ let payload_ptr =
+ unsafe { std::mem::transmute::<_, *mut OrderedFloat<f64>>($ptr.payload_offset()) };
+ let $n = TypedArenaPtr::new(payload_ptr);
+ #[allow(unused_braces)]
+ $code
+ }};
+ ($ptr:ident, Rational, $n:ident, $code:expr) => {{
+ let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) };
+ let $n = TypedArenaPtr::new(payload_ptr);
+ #[allow(unused_braces)]
+ $code
+ }};
+ ($cell:ident, OssifiedOpDir, $n:ident, $code:expr) => {{
+ let $n = cell_as_ossified_op_dir!($cell);
+ #[allow(unused_braces)]
+ $code
+ }};
+ ($cell:ident, LiveLoadState, $n:ident, $code:expr) => {{
+ let $n = cell_as_load_state_payload!($cell);
+ #[allow(unused_braces)]
+ $code
+ }};
+ ($ptr:ident, Stream, $s:ident, $code:expr) => {{
+ let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
+ #[allow(unused_braces)]
+ $code
+ }};
+ ($ptr:ident, TcpListener, $listener:ident, $code:expr) => {{
+ let payload_ptr = unsafe { std::mem::transmute::<_, *mut TcpListener>($ptr.payload_offset()) };
+ #[allow(unused_mut)]
+ let mut $listener = TypedArenaPtr::new(payload_ptr);
+ #[allow(unused_braces)]
+ $code
+ }};
+ ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
+ let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
+ #[allow(unused_braces)]
+ $code
+ }};
+}
+
+macro_rules! match_untyped_arena_ptr_pat {
+ (Stream) => {
+ ArenaHeaderTag::InputFileStream
+ | ArenaHeaderTag::OutputFileStream
+ | ArenaHeaderTag::NamedTcpStream
+ | ArenaHeaderTag::NamedTlsStream
+ | ArenaHeaderTag::ReadlineStream
+ | ArenaHeaderTag::StaticStringStream
+ | ArenaHeaderTag::ByteStream
+ | ArenaHeaderTag::StandardOutputStream
+ | ArenaHeaderTag::StandardErrorStream
+ };
+ ($tag:ident) => {
+ ArenaHeaderTag::$tag
+ };
+}
+
+macro_rules! match_untyped_arena_ptr {
+ ($ptr:expr, $( ($(ArenaHeaderTag::$tag:tt)|+, $n:ident) => $code:block $(,)?)+ $(_ => $misc_code:expr $(,)?)?) => ({
+ let ptr_id = $ptr;
+
+ match ptr_id.get_tag() {
+ $($(match_untyped_arena_ptr_pat!($tag) => {
+ match_untyped_arena_ptr_pat_body!(ptr_id, $tag, $n, $code)
+ })+)+
+ $(_ => $misc_code)?
}
});
+}
+
+macro_rules! read_heap_cell_pat_body {
+ ($cell:ident, Cons, $n:ident, $code:expr) => ({
+ let $n = cell_as_untyped_arena_ptr!($cell);
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, F64, $n:ident, $code:expr) => ({
+ let $n = cell_as_f64_ptr!($cell);
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => ({
+ let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity();
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, PStr, $atom:ident, $code:expr) => ({
+ let $atom = cell_as_atom!($cell);
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, CStr, $atom:ident, $code:expr) => ({
+ let $atom = cell_as_atom!($cell);
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, CStr | PStr, $atom:ident, $code:expr) => ({
+ let $atom = cell_as_atom!($cell);
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, PStr | CStr, $atom:ident, $code:expr) => ({
+ let $atom = cell_as_atom!($cell);
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, Fixnum, $value:ident, $code:expr) => ({
+ let $value = Fixnum::from_bytes($cell.into_bytes());
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, Char, $value:ident, $code:expr) => ({
+ let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) };
+ #[allow(unused_braces)]
+ $code
+ });
+ ($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => ({
+ let $value = $cell.get_value() as usize;
+ #[allow(unused_braces)]
+ $code
+ });
+}
+
+macro_rules! read_heap_cell_pat {
+ (($(HeapCellValueTag::$tag:tt)|+, $n:tt)) => {
+ $(HeapCellValueTag::$tag)|+
+ };
+ (($(HeapCellValueTag::$tag:tt)|+)) => {
+ $(HeapCellValueTag::$tag)|+
+ };
+ (_) => { _ };
+}
+
+macro_rules! read_heap_cell_pat_expander {
+ ($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+, $n:tt), $code:block) => ({
+ read_heap_cell_pat_body!($cell_id, $($tag)|+, $n, $code)
+ });
+ ($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+), $code:block) => ({
+ $code
+ });
+ ($cell_id:ident, _, $code:block) => ({
+ $code
+ });
+}
+
+macro_rules! read_heap_cell {
+ ($cell:expr, $($pat:tt $(if $guard_expr:expr)? => $code:block $(,)?)+) => ({
+ let cell_id = $cell;
+
+ match cell_id.get_tag() {
+ $(read_heap_cell_pat!($pat) $(if $guard_expr)? => {
+ read_heap_cell_pat_expander!(cell_id, $pat, $code)
+ })+
+ }
+ });
+}
+
+macro_rules! functor {
($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 arity: usize = count_tt!($($dt) +);
+
+ #[allow(unused_variables)]
+ let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*];
let mut result =
- vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
+ vec![ atom_as_cell!($name, arity as u16),
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
$(
- result.extend($aux.into_iter());
+ result.extend($aux.iter());
)*
result.extend(addendum.into_iter());
@@ -68,383 +429,183 @@ macro_rules! functor {
});
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{
- use crate::machine::heap::*;
+ let arity: usize = count_tt!($($dt) +);
- let arity = count_tt!($($dt) +);
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let mut result =
- vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
+ vec![ atom_as_cell!($name, arity as u16),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter());
result
}
});
- ($name:expr, $fixity:expr) => (
- vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ]
- );
- (clause_name($name:expr)) => (
- vec![ HeapCellValue::Atom($name, None) ]
- );
- ($name:expr) => (
- vec![ HeapCellValue::Atom(clause_name!($name), None) ]
- );
+ ($name:expr) => ({
+ vec![ atom_as_cell!($name) ]
+ });
}
macro_rules! functor_term {
- (aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
- HeapCellValue::Addr(Addr::HeapCell($arity + 1))
+ (str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
+ str_loc_as_cell!($arity + 1)
});
- (aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
+ (str($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))
+ str_loc_as_cell!($arity + 1 + len)
});
- (aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
- HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1))
+ (str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
+ str_loc_as_cell!($arity + $h + 1)
});
- (aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
+ (str($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))
+ str_loc_as_cell!($arity + $h + 1 + len)
});
- (addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
- HeapCellValue::Addr($e)
+ (literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
+ HeapCellValue::from($e)
);
- (constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
- from_constant!($e, $h, $arity, $aux_lens, $addendum)
+ (integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
+ HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena)
);
- (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)))
+ (fixnum($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
+ fixnum_as_cell!(Fixnum::build_with($e as i64))
);
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let stub =
match $e {
- IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]),
- IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
- IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
- IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
+ IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]),
+ IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
+ IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
+ IndexingCodePtr::Fail => {
+ vec![atom_as_cell!(atom!("fail"))]
+ },
};
let len: usize = $aux_lens.iter().sum();
- let h = len + $arity + 1 + $addendum.h() + $h;
+ let h = len + $arity + 1 + $addendum.len() + $h;
$addendum.extend(stub.into_iter());
- HeapCellValue::Addr(Addr::HeapCell(h))
+ str_loc_as_cell!(h)
});
- (clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
- HeapCellValue::Atom($e, None)
+ (number($arena:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
+ HeapCellValue::from(($e, $arena))
);
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
- HeapCellValue::Atom(clause_name!($e), None)
- );
- (value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
- $e
+ atom_as_cell!($e)
);
(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;
+ let h = len + $arity + 1 + $addendum.len() + $h;
+
+ let cell = string_as_pstr_cell!($e);
- $addendum.put_complete_string(&$e);
+ $addendum.push(cell);
+ $addendum.push(empty_list_as_cell!());
- HeapCellValue::Addr(Addr::PStrLocation(h, 0))
+ heap_loc_as_cell!(h)
});
(boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
if $e {
- functor_term!(atom("true"), $arity, $aux_lens, $addendum)
+ functor_term!(atom(atom!("true")), $arity, $aux_lens, $addendum)
} else {
- functor_term!(atom("false"), $arity, $aux_lens, $addendum)
+ functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum)
}
});
- ($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => (
+ (cell($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::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 {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0)
- };
-}
-
-macro_rules! is_atomic {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtomic($r)), 1, 0)
- };
-}
-
-macro_rules! is_integer {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsInteger($r)), 1, 0)
- };
-}
-
-macro_rules! is_compound {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsCompound($r)), 1, 0)
- };
-}
-
-macro_rules! is_float {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsFloat($r)), 1, 0)
- };
-}
-
-macro_rules! is_rational {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsRational($r)), 1, 0)
- };
-}
-
-macro_rules! is_number {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsNumber($r)), 1, 0)
- };
-}
-
-macro_rules! is_nonvar {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsNonVar($r)), 1, 0)
- };
-}
-
-macro_rules! is_var {
- ($r:expr) => {
- call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
- };
+macro_rules! compare_number_instr {
+ ($cmp: expr, $at_1: expr, $at_2: expr) => {{
+ $cmp.set_terms($at_1, $at_2);
+ call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0)
+ }};
}
macro_rules! call_clause {
- ($ct:expr, $arity:expr, $pvs:expr) => {
- Line::Control(ControlInstruction::CallClause(
- $ct, $arity, $pvs, false, false,
- ))
- };
- ($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
- Line::Control(ControlInstruction::CallClause(
- $ct, $arity, $pvs, $lco, false,
- ))
- };
+ ($clause_type:expr, $pvs:expr) => {{
+ let mut instr = $clause_type.to_instr();
+ instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
+ instr
+ }};
}
macro_rules! call_clause_by_default {
- ($ct:expr, $arity:expr, $pvs:expr) => {
- Line::Control(ControlInstruction::CallClause(
- $ct, $arity, $pvs, false, true,
- ))
- };
- ($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
- Line::Control(ControlInstruction::CallClause(
- $ct, $arity, $pvs, $lco, true,
- ))
- };
-}
-
-macro_rules! proceed {
- () => {
- Line::Control(ControlInstruction::Proceed)
- };
-}
-
-macro_rules! is_call {
- ($r:expr, $at:expr) => {
- call_clause!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
- };
-}
-
-macro_rules! is_call_by_default {
- ($r:expr, $at:expr) => {
- call_clause_by_default!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
- };
-}
-
-macro_rules! set_cp {
- ($r:expr) => {
- call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
- };
-}
-
-macro_rules! succeed {
- () => {
- call_clause!(ClauseType::System(SystemClauseType::Succeed), 0, 0)
- };
+ ($clause_type:expr, $pvs:expr) => {{
+ let mut instr = $clause_type.to_instr().to_default();
+ instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
+ instr
+ }};
}
-macro_rules! fail {
- () => {
- call_clause!(ClauseType::System(SystemClauseType::Fail), 0, 0)
+macro_rules! interm {
+ ($n: expr) => {
+ ArithmeticTerm::Interm($n)
};
}
-macro_rules! compare_number_instr {
- ($cmp: expr, $at_1: expr, $at_2: expr) => {{
- let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2));
- call_clause!(ct, 2, 0)
- }};
-}
-
-macro_rules! jmp_call {
- ($arity:expr, $offset:expr, $pvs:expr) => {
- Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, false))
+macro_rules! ar_reg {
+ ($r: expr) => {
+ ArithmeticTerm::Reg($r)
};
}
-macro_rules! return_from_clause {
- ($lco:expr, $machine_st:expr) => {{
- if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
- return Ok(());
- }
+macro_rules! unmark_cell_bits {
+ ($e:expr) => {{
+ let mut result = $e;
- if $lco {
- $machine_st.p = CodePtr::Local($machine_st.cp);
- } else {
- $machine_st.p += 1;
- }
+ result.set_mark_bit(false);
+ result.set_forwarding_bit(false);
- Ok(())
+ result
}};
}
-macro_rules! dir_entry {
- ($idx:expr) => {
- LocalCodePtr::DirEntry($idx)
- };
-}
-
macro_rules! index_store {
($code_dir:expr, $op_dir:expr, $modules:expr) => {
IndexStore {
code_dir: $code_dir,
- extensible_predicates: ExtensiblePredicates::new(),
- local_extensible_predicates: LocalExtensiblePredicates::new(),
- global_variables: GlobalVarDir::new(),
- meta_predicates: MetaPredicateDir::new(),
+ extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+ local_extensible_predicates: LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+ global_variables: GlobalVarDir::with_hasher(FxBuildHasher::default()),
+ meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
modules: $modules,
op_dir: $op_dir,
streams: StreamDir::new(),
- stream_aliases: StreamAliasDir::new(),
+ stream_aliases: StreamAliasDir::with_hasher(FxBuildHasher::default()),
}
};
}
-macro_rules! put_constant {
- ($lvl:expr, $cons:expr, $r:expr) => {
- QueryInstruction::PutConstant($lvl, $cons, $r)
- };
+macro_rules! unify {
+ ($machine_st:expr, $($value:expr),*) => {{
+ $($machine_st.pdl.push($value);)*
+ $machine_st.unify()
+ }};
}
-macro_rules! get_level_and_unify {
- ($r: expr) => {
- Line::Cut(CutInstruction::GetLevelAndUnify($r))
- };
+macro_rules! unify_fn {
+ ($machine_st:expr, $($value:expr),*) => {{
+ $($machine_st.pdl.push($value);)*
+ ($machine_st.unify_fn)(&mut $machine_st)
+ }};
}
-/*
-macro_rules! unwind_protect {
- ($e: expr, $protected: expr) => {
- match $e {
- Err(e) => {
- $protected;
- return Err(e);
- }
- _ => {}
- }
- };
-}
-*/
-/*
-macro_rules! discard_result {
- ($f: expr) => {
- match $f {
- _ => (),
- }
- };
-}
-*/
-macro_rules! ar_reg {
- ($r: expr) => {
- ArithmeticTerm::Reg($r)
- };
+macro_rules! unify_with_occurs_check {
+ ($machine_st:expr, $($value:expr),*) => {{
+ $($machine_st.pdl.push($value);)*
+ $machine_st.unify_with_occurs_check()
+ }};
}
-macro_rules! atom_from {
- ($self:expr, $e:expr) => {
- match $e {
- Addr::Con(h) if $self.heap.atom_at(h) => {
- match &$self.heap[h] {
- HeapCellValue::Atom(ref atom, _) => {
- atom.clone()
- }
- _ => {
- unreachable!()
- }
- }
- }
- Addr::Char(c) => {
- clause_name!(c.to_string(), $self.atom_tbl)
- }
- _ => {
- unreachable!()
- }
- }
- }
-}
+macro_rules! compare_term_test {
+ ($machine_st:expr, $e1:expr, $e2:expr) => {{
+ $machine_st.pdl.push($e2);
+ $machine_st.pdl.push($e1);
-macro_rules! try_or_fail {
- ($s:expr, $e:expr) => {{
- match $e {
- Ok(val) => val,
- Err(msg) => {
- $s.throw_exception(msg);
- return;
- }
- }
+ $machine_st.compare_term_test()
}};
}
diff --git a/src/parser/ast.rs b/src/parser/ast.rs
new file mode 100644
index 00000000..3db3ca0e
--- /dev/null
+++ b/src/parser/ast.rs
@@ -0,0 +1,632 @@
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::parser::char_reader::*;
+use crate::types::HeapCellValueTag;
+
+use std::cell::Cell;
+use std::fmt;
+use std::hash::Hash;
+use std::io::{Error as IOError};
+use std::ops::Neg;
+use std::rc::Rc;
+use std::vec::Vec;
+
+use rug::{Integer, Rational};
+
+use fxhash::FxBuildHasher;
+use indexmap::IndexMap;
+use modular_bitfield::error::OutOfBounds;
+use modular_bitfield::prelude::*;
+
+pub type Specifier = u32;
+
+pub const MAX_ARITY: usize = 1023;
+
+pub const XFX: u32 = 0x0001;
+pub const XFY: u32 = 0x0002;
+pub const YFX: u32 = 0x0004;
+pub const XF: u32 = 0x0010;
+pub const YF: u32 = 0x0020;
+pub const FX: u32 = 0x0040;
+pub const FY: u32 = 0x0080;
+pub const DELIMITER: u32 = 0x0100;
+pub const TERM: u32 = 0x1000;
+pub const LTERM: u32 = 0x3000;
+
+pub const NEGATIVE_SIGN: u32 = 0x0200;
+
+#[macro_export]
+macro_rules! fixnum {
+ ($wrapper:tt, $n:expr, $arena:expr) => {
+ Fixnum::build_with_checked($n)
+ .map(<$wrapper>::Fixnum)
+ .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena)))
+ };
+}
+
+macro_rules! is_term {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::TERM) != 0
+ };
+}
+
+macro_rules! is_lterm {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::LTERM) != 0
+ };
+}
+
+macro_rules! is_op {
+ ($x:expr) => {
+ $x as u32
+ & ($crate::parser::ast::XF
+ | $crate::parser::ast::YF
+ | $crate::parser::ast::FX
+ | $crate::parser::ast::FY
+ | $crate::parser::ast::XFX
+ | $crate::parser::ast::XFY
+ | $crate::parser::ast::YFX)
+ != 0
+ };
+}
+
+macro_rules! is_negate {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::NEGATIVE_SIGN) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_prefix {
+ ($x:expr) => {
+ $x as u32 & ($crate::parser::ast::FX | $crate::parser::ast::FY) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_postfix {
+ ($x:expr) => {
+ $x as u32 & ($crate::parser::ast::XF | $crate::parser::ast::YF) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_infix {
+ ($x:expr) => {
+ ($x as u32
+ & ($crate::parser::ast::XFX | $crate::parser::ast::XFY | $crate::parser::ast::YFX))
+ != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_xfx {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::XFX) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_xfy {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::XFY) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_yfx {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::YFX) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_yf {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::YF) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_xf {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::XF) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_fx {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::FX) != 0
+ };
+}
+
+#[macro_export]
+macro_rules! is_fy {
+ ($x:expr) => {
+ ($x as u32 & $crate::parser::ast::FY) != 0
+ };
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum RegType {
+ Perm(usize),
+ Temp(usize),
+}
+
+impl Default for RegType {
+ fn default() -> Self {
+ RegType::Temp(0)
+ }
+}
+
+impl RegType {
+ pub fn reg_num(self) -> usize {
+ match self {
+ RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num,
+ }
+ }
+
+ pub fn is_perm(self) -> bool {
+ matches!(self, RegType::Perm(_))
+ }
+}
+
+impl fmt::Display for RegType {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ RegType::Perm(val) => write!(f, "Y{}", val),
+ RegType::Temp(val) => write!(f, "X{}", val),
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum VarReg {
+ ArgAndNorm(RegType, usize),
+ Norm(RegType),
+}
+
+impl VarReg {
+ pub fn norm(self) -> RegType {
+ match self {
+ VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg,
+ }
+ }
+}
+
+impl fmt::Display for VarReg {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
+ VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
+ VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
+ VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
+ }
+ }
+}
+
+impl Default for VarReg {
+ fn default() -> Self {
+ VarReg::Norm(RegType::default())
+ }
+}
+
+#[macro_export]
+macro_rules! temp_v {
+ ($x:expr) => {
+ $crate::parser::ast::RegType::Temp($x)
+ };
+}
+
+#[macro_export]
+macro_rules! perm_v {
+ ($x:expr) => {
+ $crate::parser::ast::RegType::Perm($x)
+ };
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum GenContext {
+ Head,
+ Mid(usize),
+ Last(usize), // Mid & Last: chunk_num
+}
+
+impl GenContext {
+ pub fn chunk_num(self) -> usize {
+ match self {
+ GenContext::Head => 0,
+ GenContext::Mid(cn) | GenContext::Last(cn) => cn,
+ }
+ }
+}
+
+#[bitfield]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
+pub struct OpDesc {
+ prec: B11,
+ spec: B8,
+ #[allow(unused)] padding: B13,
+}
+
+impl OpDesc {
+ #[inline]
+ pub fn build_with(prec: u16, spec: u8) -> Self {
+ OpDesc::new().with_spec(spec).with_prec(prec)
+ }
+
+ #[inline]
+ pub fn get(self) -> (u16, u8) {
+ (self.prec(), self.spec())
+ }
+
+ pub fn set(&mut self, prec: u16, spec: u8) {
+ self.set_prec(prec);
+ self.set_spec(spec);
+ }
+
+ #[inline]
+ pub fn get_prec(self) -> u16 {
+ self.prec()
+ }
+
+ #[inline]
+ pub fn get_spec(self) -> u8 {
+ self.spec()
+ }
+
+ #[inline]
+ pub fn arity(self) -> usize {
+ if self.spec() as u32 & (XFX | XFY | YFX) == 0 {
+ 1
+ } else {
+ 2
+ }
+ }
+}
+
+// name and fixity -> operator type and precedence.
+pub type OpDir = IndexMap<(Atom, Fixity), OpDesc, FxBuildHasher>;
+
+#[derive(Debug, Clone, Copy)]
+pub struct MachineFlags {
+ pub double_quotes: DoubleQuotes,
+}
+
+impl Default for MachineFlags {
+ fn default() -> Self {
+ MachineFlags {
+ double_quotes: DoubleQuotes::default(),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum DoubleQuotes {
+ Atom,
+ Chars,
+ Codes,
+}
+
+impl DoubleQuotes {
+ pub fn is_chars(self) -> bool {
+ matches!(self, DoubleQuotes::Chars)
+ }
+
+ pub fn is_atom(self) -> bool {
+ matches!(self, DoubleQuotes::Atom)
+ }
+
+ pub fn is_codes(self) -> bool {
+ matches!(self, DoubleQuotes::Codes)
+ }
+}
+
+impl Default for DoubleQuotes {
+ fn default() -> Self {
+ DoubleQuotes::Chars
+ }
+}
+
+pub fn default_op_dir() -> OpDir {
+ let mut op_dir = OpDir::with_hasher(FxBuildHasher::default());
+
+ op_dir.insert(
+ (atom!(":-"), Fixity::In),
+ OpDesc::build_with(1200, XFX as u8),
+ );
+ op_dir.insert(
+ (atom!(":-"), Fixity::Pre),
+ OpDesc::build_with(1200, FX as u8),
+ );
+ op_dir.insert(
+ (atom!("?-"), Fixity::Pre),
+ OpDesc::build_with(1200, FX as u8),
+ );
+ op_dir.insert(
+ (atom!(","), Fixity::In),
+ OpDesc::build_with(1000, XFY as u8),
+ );
+
+ op_dir
+}
+
+#[derive(Debug, Clone)]
+pub enum ArithmeticError {
+ NonEvaluableFunctor(Literal, usize),
+ UninstantiatedVar,
+}
+
+#[derive(Debug)]
+pub enum ParserError {
+ BackQuotedString(usize, usize),
+ UnexpectedChar(char, usize, usize),
+ UnexpectedEOF,
+ IO(IOError),
+ IncompleteReduction(usize, usize),
+ InvalidSingleQuotedCharacter(char),
+ MissingQuote(usize, usize),
+ NonPrologChar(usize, usize),
+ ParseBigInt(usize, usize),
+ LexicalError(lexical::Error),
+ Utf8Error(usize, usize),
+}
+
+impl ParserError {
+ pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
+ match self {
+ &ParserError::BackQuotedString(line_num, col_num)
+ | &ParserError::UnexpectedChar(_, line_num, col_num)
+ | &ParserError::IncompleteReduction(line_num, col_num)
+ | &ParserError::MissingQuote(line_num, col_num)
+ | &ParserError::NonPrologChar(line_num, col_num)
+ | &ParserError::ParseBigInt(line_num, col_num)
+ | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
+ _ => None,
+ }
+ }
+
+ pub fn as_atom(&self) -> Atom {
+ match self {
+ ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
+ ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
+ ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
+ ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
+ ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
+ ParserError::IO(_) => atom!("input_output_error"),
+ ParserError::LexicalError(_) => atom!("lexical_error"), // TODO: ?
+ ParserError::MissingQuote(..) => atom!("missing_quote"),
+ ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
+ ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
+ ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
+ }
+ }
+}
+
+impl From<lexical::Error> for ParserError {
+ fn from(e: lexical::Error) -> ParserError {
+ ParserError::LexicalError(e)
+ }
+}
+
+impl From<IOError> for ParserError {
+ fn from(e: IOError) -> ParserError {
+ ParserError::IO(e)
+ }
+}
+
+impl From<&IOError> for ParserError {
+ fn from(error: &IOError) -> ParserError {
+ if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
+ ParserError::Utf8Error(0, 0)
+ } else {
+ ParserError::IO(error.kind().into())
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct CompositeOpDir<'a, 'b> {
+ pub primary_op_dir: Option<&'b OpDir>,
+ pub secondary_op_dir: &'a OpDir,
+}
+
+impl<'a, 'b> CompositeOpDir<'a, 'b> {
+ #[inline]
+ pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self {
+ CompositeOpDir {
+ primary_op_dir,
+ secondary_op_dir,
+ }
+ }
+
+ #[inline]
+ pub(crate) fn get(&self, name: Atom, fixity: Fixity) -> Option<OpDesc> {
+ let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir {
+ primary_op_dir.get(&(name, fixity))
+ } else {
+ None
+ };
+
+ entry
+ .or_else(move || self.secondary_op_dir.get(&(name, fixity)))
+ .cloned()
+ }
+}
+
+#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
+pub enum Fixity {
+ In,
+ Post,
+ Pre,
+}
+
+#[bitfield]
+#[repr(u64)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Fixnum {
+ num: B57,
+ #[allow(unused)] m: bool,
+ #[allow(unused)] tag: B6,
+}
+
+impl Fixnum {
+ #[inline]
+ pub fn build_with(num: i64) -> Self {
+ Fixnum::new()
+ .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))
+ .with_tag(HeapCellValueTag::Fixnum as u8)
+ .with_m(false)
+ //num as u64).with__m(false)
+ }
+
+ #[inline]
+ pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
+ const UPPER_BOUND: i64 = (1 << 56) - 1;
+ const LOWER_BOUND: i64 = -(1 << 56);
+
+ if LOWER_BOUND <= num && num <= UPPER_BOUND {
+ Ok(Fixnum::new()
+ .with_m(false)
+ .with_tag(HeapCellValueTag::Fixnum as u8)
+ .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1)))
+ } else {
+ Err(OutOfBounds {})
+ }
+ }
+
+ #[inline]
+ pub fn get_num(self) -> i64 {
+ let n = self.num() as i64;
+ let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum.
+ debug_assert_eq!(overflowed, false);
+ n
+ }
+}
+
+impl Neg for Fixnum {
+ type Output = Self;
+
+ #[inline]
+ fn neg(self) -> Self::Output {
+ Fixnum::build_with(-self.get_num())
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum Literal {
+ Atom(Atom),
+ Char(char),
+ Fixnum(Fixnum),
+ Integer(TypedArenaPtr<Integer>),
+ Rational(TypedArenaPtr<Rational>),
+ Float(F64Ptr),
+ String(Atom),
+}
+
+impl fmt::Display for Literal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Literal::Atom(ref atom) => {
+ // if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
+ // write!(f, "'{}'", atom)
+ // } else {
+ write!(f, "{}", atom.flat_index())
+ // }
+ }
+ Literal::Char(c) => write!(f, "'{}'", *c as u32),
+ Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
+ Literal::Integer(ref n) => write!(f, "{}", n),
+ Literal::Rational(ref n) => write!(f, "{}", n),
+ Literal::Float(ref n) => write!(f, "{}", *n),
+ Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
+ // Literal::Usize(integer) => write!(f, "u{}", integer),
+ }
+ }
+}
+
+impl Literal {
+ pub fn to_atom(&self, atom_tbl: &mut AtomTable) -> Option<Atom> {
+ match self {
+ Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)),
+ _ => None,
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+pub enum Term {
+ AnonVar,
+ Clause(Cell<RegType>, Atom, Vec<Term>),
+ Cons(Cell<RegType>, Box<Term>, Box<Term>),
+ Literal(Cell<RegType>, Literal),
+ PartialString(Cell<RegType>, Atom, Option<Box<Term>>),
+ Var(Cell<VarReg>, Rc<String>),
+}
+
+impl Term {
+ pub fn into_literal(self) -> Option<Literal> {
+ match self {
+ Term::Literal(_, c) => Some(c),
+ _ => None,
+ }
+ }
+
+ pub fn first_arg(&self) -> Option<&Term> {
+ match self {
+ Term::Clause(_, _, ref terms) => terms.first(),
+ _ => None,
+ }
+ }
+
+ pub fn set_name(&mut self, new_name: Atom) {
+ match self {
+ Term::Literal(_, Literal::Atom(ref mut atom)) | Term::Clause(_, ref mut atom, ..) => {
+ *atom = new_name;
+ }
+ _ => {}
+ }
+ }
+
+ pub fn name(&self) -> Option<Atom> {
+ match self {
+ &Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => {
+ Some(*atom)
+ }
+ _ => None,
+ }
+ }
+
+ pub fn arity(&self) -> usize {
+ match self {
+ Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
+ _ => 0,
+ }
+ }
+}
+
+fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
+ if let Term::Clause(_, ref name, ref mut subterms) = term {
+ if name == &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: Atom) -> 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
+}
diff --git a/src/parser/char_reader.rs b/src/parser/char_reader.rs
new file mode 100644
index 00000000..9c23371e
--- /dev/null
+++ b/src/parser/char_reader.rs
@@ -0,0 +1,747 @@
+/*
+ * CharReader is a not entirely redundant flattening/chimera of std's
+ * BufReader and unicode_reader's CodePoints, introduced to allow
+ * peekable buffered UTF-8 codepoints and access to the underlying
+ * reader.
+ *
+ * Unlike CodePoints, it doesn't make the reader inaccessible by
+ * wrapping it a Bytes struct.
+ *
+ * Unlike BufReader, its buffer is peekable as a char.
+ */
+
+use smallvec::*;
+
+use std::error::Error;
+use std::fmt;
+use std::io;
+use std::io::{ErrorKind, IoSliceMut, Read};
+use std::str;
+
+pub struct CharReader<R> {
+ inner: R,
+ buf: SmallVec<[u8;4]>,
+ pos: usize,
+}
+
+/// An error raised when parsing a UTF-8 byte stream fails.
+#[derive(Debug)]
+pub struct BadUtf8Error {
+ /// The bytes that could not be parsed as a code point.
+ pub bytes: Vec<u8>,
+}
+
+impl Error for BadUtf8Error {
+ fn description(&self) -> &str {
+ "BadUtf8Error"
+ }
+}
+
+impl fmt::Display for BadUtf8Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Bad UTF-8: {:?}", self.bytes)
+ }
+}
+
+impl<R> CharReader<R> {
+ pub fn new(inner: R) -> CharReader<R> {
+ Self {
+ inner,
+ buf: SmallVec::new(),
+ pos: 0,
+ }
+ }
+
+ #[inline]
+ pub fn inner(&self) -> &R {
+ &self.inner
+ }
+
+ #[inline]
+ pub fn inner_mut(&mut self) -> &mut R {
+ &mut self.inner
+ }
+}
+
+pub trait CharRead {
+ fn read_char(&mut self) -> Option<io::Result<char>> {
+ match self.peek_char() {
+ Some(Ok(c)) => {
+ self.consume(c.len_utf8());
+ Some(Ok(c))
+ }
+ result => result
+ }
+ }
+
+ fn peek_char(&mut self) -> Option<io::Result<char>>;
+ fn put_back_char(&mut self, c: char);
+ fn consume(&mut self, nread: usize);
+}
+
+impl<R> CharReader<R> {
+ pub fn get_ref(&self) -> &R {
+ &self.inner
+ }
+
+ pub fn get_mut(&mut self) -> &mut R {
+ &mut self.inner
+ }
+
+ pub fn buffer(&self) -> &[u8] {
+ &self.buf[self.pos..]
+ }
+
+ pub fn into_inner(self) -> R {
+ self.inner
+ }
+
+ fn reset_buffer(&mut self) {
+ self.buf.clear();
+ self.pos = 0;
+ }
+}
+
+impl<R: Read> CharReader<R> {
+ fn refresh_buffer(&mut self) -> io::Result<&[u8]> {
+ // If we've reached the end of our internal buffer then we need to fetch
+ // some more data from the underlying reader.
+ // Branch using `>=` instead of the more correct `==`
+ // to tell the compiler that the pos..cap slice is always valid.
+ if self.pos >= self.buf.len() {
+ debug_assert!(self.pos == self.buf.len());
+
+ self.buf.clear();
+
+ let mut word = [0u8;4];
+ let nread = self.inner.read(&mut word)?;
+
+ self.buf.extend_from_slice(&word[..nread]);
+ self.pos = 0;
+ }
+
+ Ok(&self.buf[self.pos..])
+ }
+}
+
+impl<R: Read> CharRead for CharReader<R> {
+ fn peek_char(&mut self) -> Option<io::Result<char>> {
+ match self.refresh_buffer() {
+ Ok(_buf) => {}
+ Err(e) => return Some(Err(e)),
+ }
+
+ loop {
+ let buf = &self.buf[self.pos..];
+
+ if !buf.is_empty() {
+ let e = match str::from_utf8(buf) {
+ Ok(s) => {
+ let mut chars = s.chars();
+ let c = chars.next().unwrap();
+
+ return Some(Ok(c));
+ }
+ Err(e) => {
+ e
+ }
+ };
+
+ if buf.len() - e.valid_up_to() >= 4 {
+ // If we have 4 bytes that still don't make up
+ // a valid code point, then we have garbage.
+
+ // We have bad data in the buffer. Remove
+ // leading bytes until either the buffer is
+ // empty, or we have a valid code point.
+
+ let mut split_point = 1;
+ let mut badbytes = vec![];
+
+ loop {
+ let (bad, rest) = buf.split_at(split_point);
+
+ if rest.is_empty() || str::from_utf8(rest).is_ok() {
+ badbytes.extend_from_slice(bad);
+ break;
+ }
+
+ split_point += 1;
+ }
+
+ // Raise the error. If we still have data in
+ // the buffer, it will be returned on the next
+ // loop.
+
+ return Some(Err(io::Error::new(io::ErrorKind::InvalidData,
+ BadUtf8Error { bytes: badbytes })));
+ } else {
+ if self.pos >= self.buf.len() {
+ return None;
+ } else if self.buf.len() - self.pos >= 4 {
+ return match str::from_utf8(&self.buf[..e.valid_up_to()]) {
+ Ok(s) => {
+ let mut chars = s.chars();
+ let c = chars.next().unwrap();
+
+ Some(Ok(c))
+ }
+ Err(e) => {
+ let badbytes = self.buf[..e.valid_up_to()].to_vec();
+
+ Some(Err(io::Error::new(io::ErrorKind::InvalidData,
+ BadUtf8Error { bytes: badbytes })))
+ }
+ };
+ } else {
+ let buf_len = self.buf.len();
+
+ for (c, idx) in (self.pos..buf_len).enumerate() {
+ self.buf[c] = self.buf[idx];
+ }
+
+ self.buf.truncate(buf_len - self.pos);
+
+ let buf_len = self.buf.len();
+
+ let mut word = [0u8;4];
+ let word_slice = &mut word[buf_len..4];
+
+ match self.inner.read(word_slice) {
+ Err(e) => return Some(Err(e)),
+ Ok(nread) => {
+ self.buf.extend_from_slice(&word_slice[0..nread]);
+ }
+ }
+
+ self.pos = 0;
+ }
+ }
+ } else {
+ return None;
+ }
+ }
+ }
+
+ #[inline(always)]
+ fn put_back_char(&mut self, c: char) {
+ let src_len = self.buf.len() - self.pos;
+ debug_assert!(src_len <= 4);
+
+ let c_len = c.len_utf8();
+ let mut shifted_slice = [0u8; 4];
+
+ shifted_slice[0..src_len].copy_from_slice(&self.buf[self.pos .. self.buf.len()]);
+
+ self.buf.resize(c_len, 0);
+ self.buf.extend_from_slice(&shifted_slice[0..src_len]);
+ self.pos = 0;
+
+ c.encode_utf8(&mut self.buf[0..c_len]);
+ }
+
+ #[inline(always)]
+ fn consume(&mut self, nread: usize) {
+ self.pos += nread;
+ }
+}
+
+/*
+impl<R: Seek> BufReader<R> {
+ /// Seeks relative to the current position. If the new position lies within the buffer,
+ /// the buffer will not be flushed, allowing for more efficient seeks.
+ /// This method does not return the location of the underlying reader, so the caller
+ /// must track this information themselves if it is required.
+ #[stable(feature = "bufreader_seek_relative", since = "1.53.0")]
+ pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+ let pos = self.pos as u64;
+ if offset < 0 {
+ if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+ self.pos = new_pos as usize;
+ return Ok(());
+ }
+ } else {
+ if let Some(new_pos) = pos.checked_add(offset as u64) {
+ if new_pos <= self.cap as u64 {
+ self.pos = new_pos as usize;
+ return Ok(());
+ }
+ }
+ }
+ self.seek(SeekFrom::Current(offset)).map(drop)
+ }
+}
+*/
+
+impl<R: Read> Read for CharReader<R> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ // // If we don't have any buffered data and we're doing a massive read
+ // // (larger than our internal buffer), bypass our internal buffer
+ // // entirely.
+ // if self.pos == self.cap && buf.len() >= self.buf.len() {
+ // self.discard_buffer();
+ // return self.inner.read(buf);
+ // }
+
+ let mut inner_buf = self.refresh_buffer()?;
+ let nread = inner_buf.read(buf)?;
+
+ // let nread = {
+ // let mut rem = self.fill_buf()?;
+ // rem.read(buf)?
+ // };
+
+ self.consume(nread);
+ Ok(nread)
+ }
+
+ // Small read_exacts from a BufReader are extremely common when used with a deserializer.
+ // The default implementation calls read in a loop, which results in surprisingly poor code
+ // generation for the common path where the buffer has enough bytes to fill the passed-in
+ // buffer.
+ fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
+ if self.buffer().len() >= buf.len() {
+ buf.copy_from_slice(&self.buffer()[..buf.len()]);
+ self.consume(buf.len());
+ return Ok(());
+ }
+
+ while !buf.is_empty() {
+ match self.read(buf) {
+ Ok(0) => break,
+ Ok(n) => {
+ let tmp = buf;
+ buf = &mut tmp[n..];
+ }
+ Err(e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ if !buf.is_empty() {
+ Err(io::Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
+ } else {
+ Ok(())
+ }
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
+
+ if self.pos == self.buf.len() && total_len >= self.buf.len() {
+ self.reset_buffer(); // self.discard_buffer();
+ return self.inner.read_vectored(bufs);
+ }
+
+ let nread = {
+ self.refresh_buffer()?;
+ (&self.buf[self.pos..]).read_vectored(bufs)?
+ };
+
+ self.consume(nread);
+ Ok(nread)
+ }
+}
+
+/*
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> BufRead for BufReader<R> {
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ // If we've reached the end of our internal buffer then we need to fetch
+ // some more data from the underlying reader.
+ // Branch using `>=` instead of the more correct `==`
+ // to tell the compiler that the pos..cap slice is always valid.
+ if self.pos >= self.cap {
+ debug_assert!(self.pos == self.cap);
+ self.cap = self.inner.read(&mut self.buf)?;
+ self.pos = 0;
+ }
+ Ok(&self.buf[self.pos..self.cap])
+ }
+
+ fn consume(&mut self, amt: usize) {
+ self.pos = cmp::min(self.pos + amt, self.cap);
+ }
+}
+*/
+
+impl<R> fmt::Debug for CharReader<R>
+where
+ R: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("CharReader")
+ .field("reader", &self.inner)
+ .field("buf", &format_args!("{}/{}", self.buf.capacity() - self.pos, self.buf.len()))
+ .finish()
+ }
+}
+
+/*
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Seek> Seek for BufReader<R> {
+ /// Seek to an offset, in bytes, in the underlying reader.
+ ///
+ /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
+ /// position the underlying reader would be at if the `BufReader<R>` had no
+ /// internal buffer.
+ ///
+ /// Seeking always discards the internal buffer, even if the seek position
+ /// would otherwise fall within it. This guarantees that calling
+ /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
+ /// at the same position.
+ ///
+ /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
+ ///
+ /// See [`std::io::Seek`] for more details.
+ ///
+ /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
+ /// where `n` minus the internal buffer length overflows an `i64`, two
+ /// seeks will be performed instead of one. If the second seek returns
+ /// [`Err`], the underlying reader will be left at the same position it would
+ /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
+ ///
+ /// [`std::io::Seek`]: Seek
+ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+ let result: u64;
+ if let SeekFrom::Current(n) = pos {
+ let remainder = (self.cap - self.pos) as i64;
+ // it should be safe to assume that remainder fits within an i64 as the alternative
+ // means we managed to allocate 8 exbibytes and that's absurd.
+ // But it's not out of the realm of possibility for some weird underlying reader to
+ // support seeking by i64::MIN so we need to handle underflow when subtracting
+ // remainder.
+ if let Some(offset) = n.checked_sub(remainder) {
+ result = self.inner.seek(SeekFrom::Current(offset))?;
+ } else {
+ // seek backwards by our remainder, and then by the offset
+ self.inner.seek(SeekFrom::Current(-remainder))?;
+ self.discard_buffer();
+ result = self.inner.seek(SeekFrom::Current(n))?;
+ }
+ } else {
+ // Seeking with Start/End doesn't care about our buffer length.
+ result = self.inner.seek(pos)?;
+ }
+ self.discard_buffer();
+ Ok(result)
+ }
+
+ /// Returns the current seek position from the start of the stream.
+ ///
+ /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
+ /// but does not flush the internal buffer. Due to this optimization the
+ /// function does not guarantee that calling `.into_inner()` immediately
+ /// afterwards will yield the underlying reader at the same position. Use
+ /// [`BufReader::seek`] instead if you require that guarantee.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the position of the inner reader is smaller
+ /// than the amount of buffered data. That can happen if the inner reader
+ /// has an incorrect implementation of [`Seek::stream_position`], or if the
+ /// position has gone out of sync due to calling [`Seek::seek`] directly on
+ /// the underlying reader.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use std::{
+ /// io::{self, BufRead, BufReader, Seek},
+ /// fs::File,
+ /// };
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = BufReader::new(File::open("foo.txt")?);
+ ///
+ /// let before = f.stream_position()?;
+ /// f.read_line(&mut String::new())?;
+ /// let after = f.stream_position()?;
+ ///
+ /// println!("The first line was {} bytes long", after - before);
+ /// Ok(())
+ /// }
+ /// ```
+ fn stream_position(&mut self) -> io::Result<u64> {
+ let remainder = (self.cap - self.pos) as u64;
+ self.inner.stream_position().map(|pos| {
+ pos.checked_sub(remainder).expect(
+ "overflow when subtracting remaining buffer size from inner stream position",
+ )
+ })
+ }
+}
+*/
+/*
+impl<T> SizeHint for CharReader<T> {
+ fn lower_bound(&self) -> usize {
+ self.buffer().len()
+ }
+}
+*/
+
+#[cfg(test)]
+mod tests {
+ use crate::parser::char_reader::*;
+ use std::io::Cursor;
+
+ #[test]
+ fn plain_string() {
+ let mut read_string = CharReader::new(Cursor::new("a string"));
+
+ for c in "a string".chars() {
+ assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
+ assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
+ }
+
+ assert!(read_string.read_char().is_none());
+ }
+
+ #[test]
+ fn greek_string() {
+ let mut read_string = CharReader::new(Cursor::new("λέξη"));
+
+ for c in "λέξη".chars() {
+ assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
+ assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
+ }
+
+ assert!(read_string.read_char().is_none());
+ }
+
+ #[test]
+ fn russian_string() {
+ let mut read_string = CharReader::new(Cursor::new("слово"));
+
+ for c in "слово".chars() {
+ assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
+ assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
+ }
+
+ assert!(read_string.read_char().is_none());
+ }
+
+ #[test]
+ fn greek_lorem_ipsum() {
+ let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ
+ εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ
+ σιγνιφερθμqθε, σεδ ετ μθτατ jθστο, ει cθμ ελιγενδι σcριπτορεμ
+ ρεπρεηενδθντ. Εοσ ατ αμετ μαλισ ελειφενδ. Ιν cθμ εριπθιτ
+ νομινατι. Θσθ ιν cετεροσ μαιορθμ, μθνερε ατομορθμ ινcιδεριντ θτ
+ ηασ. Αν ηασ λιβρισ πραεσεντ πατριοqθε, ηινc θτιναμ πριμισ νε
+ cθμ. Cθ μοδο ερρεμ σcριβεντθρ cθμ. Ει vισ δεcορε μαλορθμ
+ σεντεντιαε, σεδ νο λιβερ εvερτι μεντιτθμ. Προ φαcερ vολθτπατ
+ σαπιεντεμ ιν. Cθ εροσ περσεqθερισ πρι, εα ποσσιτ cετεροσ δθο. Πρι
+ εα μαλισ μθνερε.
+
+ Qθισ jθστο μαλορθμ cθ qθο. Νεc ατ οδιο σολετ μαιεστατισ, νε
+ φορενσιβθσ σαδιπσcινγ ιθσ, αν qθι ειθσ βρθτε σαπιεντεμ. Cομμθνε
+ περcιπιτθρ ιθσ αδ, μθνερε δολορθμ ιμπεδιτ ηισ νε. Νεc ετιαμ
+ προπριαε vιτθπερατα ιν. Σονετ νεμορε ιθσ cθ, ιν αφφερτ ινερμισ
+ cοτιδιεqθε vισ.
+
+ Ηασ ιδ νονθμυ δοcτθσ cοτιδιεqθε. Σινγθλισ πηιλοσοπηια εξ δθο. Εστ
+ νο ιραcθνδια cονσεqθθντθρ. Τε διcτασ επιcθρει εφφιcιαντθρ δθο, εοσ
+ νε νθλλα νομιναvι. Εθμ cθ ελιτρ λιβεραvισσε, σιτ περσεqθερισ
+ cομπλεcτιτθρ εξ, πονδερθμ σιμιλιqθε ηασ νο.
+
+ Σολθμ ποσσιμ λαβιτθρ εξ ηισ, ει δομινγ εξπετενδισ vελ, διαμ μινιμ
+ σcριπσεριτ ει περ. Αθδιαμ οcθρρερετ προ εξ, δομινγ vολθπταρια ετ
+ qθο. Cονσθλ σανcτθσ αccθμσαν νο ιθσ, αδ εαμ αλβθcιθσ
+ ηονεστατισ. Ετ vιξ φαcιλισ qθαλισqθε ερροριβθσ, ηισ εθ πθρτο
+ ασσεντιορ. Ιθσ βονορθμ ηονεστατισ σcριπσεριτ ατ, ιν ναμ εσσε μοvετ
+ γραεcο. Αθγθε cονσεcτετθερ εστ ατ.
+
+ Αδ ταλε σθασ μθνερε σεδ, vισ φεθγαιτ αντιοπαμ ιδ. Προ εθ ινερμισ
+ σαλθτατθσ, σαεπε qθαεστιο θρβανιτασ cθ περ. Ιν μαλορθμ σαλθτατθσ
+ δετερρθισσετ περ, νε παρτεμ vολθτπατ ινστρθcτιορ vιξ. Νο vισ
+ δεμοcριτθμ εφφιcιαντθρ, επιcθρει αδολεσcενσ εστ cθ, ιδ vιξ
+ λθcιλιθσ αδιπισcινγ. Σεα τε cλιτα ιραcθνδια. Σεα αν σιμθλ
+ εσσεντ. Vοcιβθσ ελειφενδ cονσεqθθντθρ περ αδ, αν ναμ πονδερθμ
+ vολθπταρια.
+
+ Λιβερ ερθδιτι αccθσαμθσ θτ ναμ. Σιτ αντιοπαμ γθβεργρεν νε. Αμετ
+ ανcιλλαε ετ qθι, μεα σολθμ λαθδεμ εα. Εθ μελ παρτεμ οβλιqθε
+ πηαεδρθμ. Εξ μελ jθστο αccομμοδαρε, νε νολθισσε σινγθλισ σενσιβθσ
+ cθμ, vισ εθ τιμεαμ αδιπισcινγ.
+
+ Τε νολθισσε vολθπτατθμ εστ. Ασσθμ νομιναvι πρι νε, ει νοστρθμ
+ επιcθρει μεα. Σεδ cθ ελιτ δεσερθντ, γραεcε ερροριβθσ προ θτ, περ
+ νε εθισμοδ vολθπταρια. Νο εθμ διcατ ποσσιμ, νεc πρινcιπεσ
+ cονcεπταμ νε. Εθ αππαρεατ ιντελλεγατ σεα. Μελ θτ ελιτ λαθδεμ, θσθ
+ δολορεμ cομπλεcτιτθρ ετ, νε μεα δολορεσ μολεστιαε.
+
+ Θσθ λεγενδοσ vολθπτατιβθσ cθ. Qθο νε αδηθc ρεφερρεντθρ, αλια
+ μεδιοcρεμ δθο νε, σεδ ερρεμ δολορθμ αccομμοδαρε νε. Ετιαμ εqθιδεμ
+ δετερρθισσετ cθ μει, ετ εροσ cετεροσ σεα, εξ vιξ ενιμ cασε
+ δετραξιτ. Σεδ σολθτα λιβρισ ειρμοδ τε, νοvθμ ποπθλο νε εθμ. Σθμμο
+ αδμοδθμ δεσερθντ εστ εξ, εστ διcαμ εqθιδεμ cθ.
+
+ Ιλλθμ cορπορα ινvιδθντ εαμ ετ. Σεδ μαλισ ταcιματεσ εvερτιτθρ εα,
+ μαζιμ νθλλαμ vοcιβθσ μεα ει. Μεα ορνατθσ λθπτατθμ αδιπισcινγ
+ αδ. Μεα αφφερτ νοστερ ατ, ναμ αν σολεατ ερροριβθσ. Εξ σεα αεqθε
+ μθνερε cετερο, εοσ ηινc ελειφενδ δεμοcριτθμ.";
+
+ let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
+
+ for c in lorem_ipsum.chars() {
+ assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
+ assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
+ }
+
+ assert!(lorem_ipsum_reader.read_char().is_none());
+ }
+
+ #[test]
+ fn armenian_lorem_ipsum() {
+ let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո
+ սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում
+ եսթ, մեա թե ծոմմոդո ծոռպոռա. եթ ծոնսուլ ադիպիսծինգ ռեֆոռմիդանս
+ պեռ, ինեռմիս ֆեուգաիթ նո քուո, թալե սալե պռո եա. եթ նիբհ
+ աուգուե վոլումուս դուո, նե ծում եխեռծի սալութաթուս գլոռիաթուռ,
+ ծու թաթիոն պռաեսենթ մեդիոծռեմ վիս.
+
+ վիխ եռոս ռեֆեռռենթուռ եու. պեռսիուս վիթուպեռաթոռիբուս ութ սեա,
+ վիդե ինվիդունթ պռոբաթուս նո քուո. մեի եռոս մելիուս նոմինավի
+ իդ, ութ պռո քուաս քուաեսթիո. եթ նաթում պեթենթիում սուավիթաթե
+ հիս. քուի ծոնսթիթութո մեդիոծռիթաթեմ թե. ծեթեռո դեթռածթո
+ ծոնծեպթամ սեա եթ. դիսսենթիեթ ելոքուենթիամ թհեոպհռասթուս նեծ
+ աթ, աթ ֆածեթե եռիպուիթ վիխ.
+
+ ասսուեվեռիթ սծռիպսեռիթ եսթ եթ, վիդիթ դեբեթ եվեռթի եխ
+ եսթ. աութեմ լաուդեմ պոսիդոնիում մեի եի. ռեբում դիծամ ծեթեռոս
+ եում ծու. նիհիլ եխպեթենդա ասսուեվեռիթ ուսու ան. ւիսի թաթիոն
+ դելենիթ նո իուս, սեդ եխ իդքուե սիգնիֆեռումքուե, բռութե զռիլ
+ ալբուծիուս ան պռի.
+
+ մովեթ իռիուռե սալութանդի պեռ նո, եի ոմնիս աֆֆեռթ պեռսեքուեռիս
+ իուս, եթ պռաեսենթ մալուիսսեթ եսթ. եսթ պռոբո գուբեռգռեն եթ, հաս
+ ին դիամ նումքուամ. ֆեուգաիթ ինվենիռե ռեպուդիանդաե աթ սեդ,
+ իուվառեթ ծոնսուլաթու եֆֆիծիանթուռ ուսու եի. ութ մեա ածծումսան
+ նոմինավի թինծիդունթ, մեի դիծթա ածծումսան ութ. վիմ ոմնիում
+ ելիգենդի սծռիպթոռեմ եու.
+
+ իդ վիս եռռոռ ալիքուիպ ելոքուենթիամ, ադ դելենիթի պեռծիպիթ
+ դեֆինիթիոնես իուս. վիմ իուդիծո դեմոծռիթում ծոմպռեհենսամ թե,
+ ութ նիհիլ լոբոռթիս վոլուպթաթիբուս վել, դիծունթ մենթիթում
+ ֆածիլիսիս եի եում. եսսե սալե մինիմ եոս նե. ագամ ոմնեսքուե ծում
+ ին.
+
+ իուվառեթ իուդիծաբիթ ծում աթ, ուսու նիբհ աթքուի դոմինգ եխ. եի
+ քուի սանծթուս սենսիբուս, նամ ուբիքուե ապպեթեռե պռոդեսսեթ
+ եու. ուսու եթ աուգուե ծոնվենիռե սծռիբենթուռ. ան ոմնիում վեռեառ
+ ութռոքուե դուո, եսթ եի լիբեռ մեդիոծռեմ եխպլիծառի, ոմնիս
+ աուդիռե թե պռի. վիմ մունեռե սոլեաթ ծու, եռոս ինվենիռե
+ դիսպութաթիոնի եի քուո, ան ալթեռա պութենթ լաբոռես պռո. անթիոպամ
+ դեմոծռիթում պեռ ին.
+
+ նե քուի ծիբո ելիթռ. նեծ նե լիբեռ վոլուպթուա. նիսլ ծոմմունե
+ եխպեթենդիս նամ եխ, իուդիծո պլածեռաթ պեռծիպիթուռ մել նո, եթ
+ պառթեմ պութանթ քուի. վիմ թինծիդունթ ածծոմմոդառե աթ, նե նամ
+ վիդիթ իռիուռե, պռո եա ելիգենդի պոսթուլանթ ծոնսթիթութո.
+
+ մել ութ ոդիո նուլլամ եխպլիծառի. պռոպռիաե թինծիդունթ
+ դելիծաթիսսիմի եամ ան, մոդո քուոդսի ապեռիռի եու եսթ, պեռ աթ
+ լաբոռես սենսեռիթ. վիմ ծոնգուե ռեպուդիանդաե եի, նեծ ագամ
+ դիծունթ դելիծաթիսսիմի աթ. պոսսիթ լիբեռավիսսե եոս եու.
+
+ աթ ալիա դեբեթ ելաբոռառեթ քուո, ին ալիի ածծումսան ծոնսթիթուամ
+ հաս, մել թոթա ոմիթթանթուռ ինսթռուծթիոռ նո. պեռ նե ծաուսաե
+ սապիենթեմ, պաուլո ոմնեսքուե եի քուո, եխ ոռաթիո պհիլոսոպհիա
+ սիթ. իգնոթա ծաուսաե աթ ուսու, եխ քուո դիծթաս քուոդսի
+ ռեպուդիառե. ծոռպոռա պռոդեսսեթ ռեֆեռռենթուռ եոս եխ.
+
+ եու եթիամ ելեիֆենդ մել, սալե սծռիպսեռիթ հիս եու. պոռռո
+ ադոլեսծենս մեի եա. ին մեա զռիլ պռոբաթուս սալութաթուս. եոս ադ
+ մինիմ թեմպոռիբուս. սեա նե եթիամ.";
+
+ let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
+
+ for c in lorem_ipsum.chars() {
+ assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
+ assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
+ }
+
+ assert!(lorem_ipsum_reader.read_char().is_none());
+ }
+
+ #[test]
+ fn russian_lorem_ipsum() {
+ let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи
+ сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи
+ саперет аппеллантур. Ех иус диам дицта волуптариа, еу пер
+ бруте омиттам аццусата. Хис сапиентем губергрен те, яуидам
+ луптатум персеяуерис ад ест.
+
+ Ан алияуип перицулис нам, нец апериам цотидиеяуе волуптатибус
+ но. Солум тритани пер ех, меи не одио тритани рецусабо, цу при
+ веро мелиоре импердиет. Ин граеци индоцтум салутатус нец, диам
+ сцаевола пертинациа про те. Ут сеа дебитис лаборамус
+ диссентиас, еи цум яуот лобортис.
+
+ Децоре сингулис вим не. Еос не риденс оффициис, еу нонумы
+ лабитур еррорибус хас, вел омнис цонституто посидониум но. Вел
+ персиус фастидии репрехендунт ид. Натум иллум ипсум сит ад, еа
+ еам новум латине. Еос нолуиссе патриояуе елояуентиам те.
+
+ Стет малис яуаерендум хас ад, прима цотидиеяуе мел ан,
+ трацтатос десеруиссе нам ех. Ин малорум сусципиантур вим, ех
+ меа граецо тритани адолесценс. Промпта цонцлусионемяуе нам еи,
+ дуо ин лаборе алтерум цотидиеяуе. Но елитр промпта сплендиде
+ еум, аеяуе ассуеверит цонституам яуи ид. Ад тале еррор
+ интеллегебат хас, ерудити граецис хас не, пер ут лабитур
+ еуисмод. Те при суммо путант. Про утинам цоммуне урбанитас еа.
+
+ Идяуе репрехендунт еи нам, алии толлит легере нам не, хис еа
+ виси адверсариум цонцлусионемяуе. Хас ассум омиттам луцилиус
+ ет, вих цонсул малорум фастидии не, сенсибус ассуеверит дуо
+ ут. Дуо алиа видит цетеро ат, еа аппареат пертинах вел. Пер
+ цонституто инцидеринт ин, убияуе риденс сенсерит цум цу. Про
+ ет цетерос темпорибус, те вел пурто суммо, дуо мунере вертерем
+ урбанитас ад. Сит оптион елецтрам форенсибус но. Еи татион
+ сапиентем ест, лаборе сцрипта сингулис но вим, усу еу елигенди
+ персецути.
+
+ Иус ан елецтрам цонтентионес. Меи атяуи нонумес ут, вел амет
+ репрехендунт ан, вис еу яуаестио патриояуе. Про синт легере
+ детрацто ад. Постеа долорем евертитур при ет, вим номинави
+ принципес ирацундиа ех. Доцтус интеллегебат но нам. Фацете
+ оффициис нецесситатибус цу меа.
+
+ Промпта симилияуе вис ин. Пер бонорум перицулис аргументум
+ ад. Еу дицат фацилис губергрен нам, еффициенди цомпрехенсам
+ хас еу. Инани нонумы усу но, ад цонцептам репудиандае
+ про. Тота нуллам делицата еа яуо, усу дуис дебет путент еи.
+
+ Вис апериам доценди елояуентиам еа. Ех яуот детрацто
+ елояуентиам цум, ерос малис дицерет вис ин. Еа цум модус
+ еяуидем, дебет нуллам ан меи. Алтерум омиттам про ет.
+
+ Яуи ех латине алияуам, ан меи одио нуллам. Ид хас омнис ребум
+ либрис. Ет убияуе путант дебитис про, ех хис медиоцрем
+ партиендо, но елит елецтрам дуо. Еу меа сонет номинави
+ цотидиеяуе. Нам фалли новум минимум еу, перфецто ратионибус
+ цонституто ад меа.
+
+ Нобис детрацто еам ид, при еу ассум пертинах, те етиам
+ проприае салутанди яуо. Легимус сусципиантур ет хас, сед
+ поссит дефинитионес еа. Ест не патриояуе омиттантур
+ интеллегебат, еу яуо дебет цонцлудатуряуе. Еум ад мнесарчум
+ дефинитионем, елитр лаборамус перципитур про не, хас феугаит
+ фастидии луцилиус ид. Фастидии интеллегат ех.";
+
+ let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
+
+ for c in lorem_ipsum.chars() {
+ assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
+ assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
+
+ lorem_ipsum_reader.put_back_char(c);
+
+ assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
+ assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
+ }
+
+ assert!(lorem_ipsum_reader.read_char().is_none());
+ }
+}
diff --git a/crates/prolog_parser/src/lexer.rs b/src/parser/lexer.rs
index 8be50d36..4696b226 100644
--- a/crates/prolog_parser/src/lexer.rs
+++ b/src/parser/lexer.rs
@@ -1,20 +1,24 @@
-use crate::rug::Integer;
use lexical::parse_lossy;
use ordered_float::*;
-use crate::ast::*;
-use crate::tabled_rc::*;
+use crate::atom_table::*;
+pub use crate::machine::machine_state::*;
+use crate::parser::ast::*;
+use crate::parser::char_reader::*;
+use crate::parser::rug::Integer;
use std::convert::TryFrom;
use std::fmt;
-use std::io::Read;
-use std::rc::Rc;
macro_rules! is_not_eof {
- ($c:expr) => {
+ ($parser:expr, $c:expr) => {
match $c {
+ Ok('\u{0}') => {
+ $parser.consume('\u{0}'.len_utf8());
+ return Ok(true);
+ }
Ok(c) => c,
- Err($crate::ast::ParserError::UnexpectedEOF) => return Ok(true),
+ Err($crate::parser::ast::ParserError::UnexpectedEOF) => return Ok(true),
Err(e) => return Err(e),
}
};
@@ -26,17 +30,17 @@ macro_rules! consume_chars_with {
match $e {
Ok(Some(c)) => $token.push(c),
Ok(None) => continue,
- Err($crate::ast::ParserError::UnexpectedChar(..)) => break,
+ Err($crate::parser::ast::ParserError::UnexpectedChar(..)) => break,
Err(e) => return Err(e),
}
}
};
}
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, PartialEq)]
pub enum Token {
- Constant(Constant),
- Var(Rc<Atom>),
+ Literal(Literal),
+ Var(String),
Open, // '('
OpenCT, // '('
Close, // ')'
@@ -60,94 +64,85 @@ impl Token {
}
}
-pub struct Lexer<'a, R: Read> {
- pub(crate) atom_tbl: TabledData<Atom>,
- pub(crate) reader: &'a mut ParsingStream<R>,
- pub(crate) flags: MachineFlags,
+pub struct Lexer<'a, R> {
+ pub(crate) reader: R,
+ pub(crate) machine_st: &'a mut MachineState,
pub(crate) line_num: usize,
pub(crate) col_num: usize,
}
-impl<'a, R: Read + fmt::Debug> fmt::Debug for Lexer<'a, R> {
+impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Lexer")
- .field("atom_tbl", &self.atom_tbl)
- .field("reader", &"&'a mut ParsingStream<R>") // Hacky solution.
+ .field("reader", &"&'a mut R") // Hacky solution.
.field("line_num", &self.line_num)
.field("col_num", &self.col_num)
.finish()
}
}
-impl<'a, R: Read> Lexer<'a, R> {
- pub fn new(
- atom_tbl: TabledData<Atom>,
- flags: MachineFlags,
- src: &'a mut ParsingStream<R>,
- ) -> Self {
+impl<'a, R: CharRead> Lexer<'a, R> {
+ pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
Lexer {
- atom_tbl,
- flags,
reader: src,
+ machine_st,
line_num: 0,
col_num: 0,
}
}
- fn return_char(&mut self, c: char) {
- if new_line_char!(c) {
- self.line_num -= 1;
- self.col_num = 0;
+ pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
+ match self.reader.peek_char() {
+ Some(Ok(c)) => Ok(c),
+ _ => Err(ParserError::UnexpectedEOF)
}
+ }
- self.reader.put_back(Ok(c));
+ pub fn read_char(&mut self) -> Result<char, ParserError> {
+ match self.reader.read_char() {
+ Some(Ok(c)) => Ok(c),
+ _ => Err(ParserError::UnexpectedEOF)
+ }
}
- fn skip_char(&mut self) -> Result<char, ParserError> {
- if let Some(Ok(c)) = self.reader.next() {
- self.col_num += 1;
+ #[inline(always)]
+ fn return_char(&mut self, c: char) {
+ self.reader.put_back_char(c);
+ }
- if new_line_char!(c) {
- self.line_num += 1;
- self.col_num = 0;
- }
+ fn skip_char(&mut self, c: char) {
+ self.reader.consume(c.len_utf8());
- Ok(c)
+ if new_line_char!(c) {
+ self.line_num += 1;
+ self.col_num = 0;
} else {
- Err(ParserError::UnexpectedEOF)
+ self.col_num += 1;
}
}
pub fn eof(&mut self) -> Result<bool, ParserError> {
- if self.reader.peek().is_none() {
- return Ok(true);
- }
-
- let mut c = is_not_eof!(self.lookahead_char());
+ let mut c = is_not_eof!(self.reader, self.lookahead_char());
while layout_char!(c) {
- self.skip_char()?;
-
- if self.reader.peek().is_none() {
- return Ok(true);
- }
+ self.skip_char(c);
- c = is_not_eof!(self.lookahead_char());
+ c = is_not_eof!(self.reader, self.lookahead_char());
}
Ok(false)
}
- pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
- match self.reader.peek() {
- Some(&Ok(c)) => Ok(c),
- _ => Err(ParserError::UnexpectedEOF),
- }
- }
-
fn single_line_comment(&mut self) -> Result<(), ParserError> {
loop {
- if self.reader.peek().is_none() || new_line_char!(self.skip_char()?) {
+ if self.reader.peek_char().is_none() {
+ break;
+ }
+
+ let c = self.lookahead_char()?;
+ self.skip_char(c);
+
+ if new_line_char!(c) {
break;
}
}
@@ -156,65 +151,80 @@ impl<'a, R: Read> Lexer<'a, R> {
}
fn bracketed_comment(&mut self) -> Result<bool, ParserError> {
- // we have already checked that the current lookahead_char is comment_1_char, just skip it
- let c = self.skip_char()?;
+ // we have already checked that the current lookahead_char is
+ // comment_1_char, just skip it
+ self.skip_char('/');
- if comment_2_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ let c = self.lookahead_char()?;
+
+ if comment_2_char!(c) {
+ self.skip_char(c);
// Keep reading until we find characters '*' and '/'
- // Deliberately skip checks for prolog_char to allow comments to contain any characters,
- // including so-called "extended characters", without having to explicitly add them to a character class.
+ // Deliberately skip checks for prolog_char to allow
+ // comments to contain any characters, including so-called
+ // "extended characters", without having to explicitly add
+ // them to a character class.
+
let mut c = self.lookahead_char()?;
+
loop {
while !comment_2_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
c = self.lookahead_char()?;
}
- self.skip_char()?;
-
+ self.skip_char(c);
c = self.lookahead_char()?;
+
if comment_1_char!(c) {
break;
}
}
if prolog_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
Ok(true)
} else {
Err(ParserError::NonPrologChar(self.line_num, self.col_num))
}
} else {
- self.return_char(c);
+ self.return_char('/');
Ok(false)
}
}
fn get_back_quoted_char(&mut self) -> Result<char, ParserError> {
- if back_quote_char!(self.lookahead_char()?) {
- let c = self.skip_char()?;
+ let c = self.lookahead_char()?;
+
+ if back_quote_char!(c) {
+ self.skip_char(c);
+ let c2 = self.lookahead_char()?;
- if !back_quote_char!(self.lookahead_char()?) {
+ if !back_quote_char!(c2) {
self.return_char(c);
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else {
- self.skip_char()
+ self.skip_char(c2);
+ Ok(c2)
}
- } else if single_quote_char!(self.lookahead_char()?) {
- self.skip_char()
+ } else if single_quote_char!(c) {
+ self.skip_char(c);
+ self.read_char()
} else {
self.get_non_quote_char()
}
}
fn get_back_quoted_item(&mut self) -> Result<Option<char>, ParserError> {
- if backslash_char!(self.lookahead_char()?) {
- let c = self.skip_char()?;
+ let c = self.lookahead_char()?;
+
+ if backslash_char!(c) {
+ self.skip_char(c);
+ let c2 = self.lookahead_char()?;
- if new_line_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ if new_line_char!(c2) {
+ self.skip_char(c2);
Ok(None)
} else {
self.return_char(c);
@@ -229,13 +239,15 @@ impl<'a, R: Read> Lexer<'a, R> {
let c = self.lookahead_char()?;
if back_quote_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
- let mut token = String::new();
+ let mut token = String::with_capacity(16);
consume_chars_with!(token, self.get_back_quoted_item());
- if back_quote_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ let c = self.lookahead_char()?;
+
+ if back_quote_char!(c) {
+ self.skip_char(c);
Ok(token)
} else {
Err(ParserError::MissingQuote(self.line_num, self.col_num))
@@ -246,11 +258,14 @@ impl<'a, R: Read> Lexer<'a, R> {
}
fn get_single_quoted_item(&mut self) -> Result<Option<char>, ParserError> {
- if backslash_char!(self.lookahead_char()?) {
- let c = self.skip_char()?;
+ let c = self.lookahead_char()?;
- if new_line_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ if backslash_char!(c) {
+ self.skip_char(c);
+ let c2 = self.lookahead_char()?;
+
+ if new_line_char!(c2) {
+ self.skip_char(c2);
return Ok(None);
} else {
self.return_char(c);
@@ -264,27 +279,34 @@ impl<'a, R: Read> Lexer<'a, R> {
let c = self.lookahead_char()?;
if single_quote_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
+ let c2 = self.lookahead_char()?;
- if !single_quote_char!(self.lookahead_char()?) {
+ if !single_quote_char!(c2) {
self.return_char(c);
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else {
- self.skip_char()
+ self.skip_char(c2);
+ Ok(c2)
}
} else if double_quote_char!(c) || back_quote_char!(c) {
- self.skip_char()
+ self.skip_char(c);
+ Ok(c)
} else {
self.get_non_quote_char()
}
}
fn get_double_quoted_item(&mut self) -> Result<Option<char>, ParserError> {
- if backslash_char!(self.lookahead_char()?) {
- let c = self.skip_char()?;
+ let c = self.lookahead_char()?;
- if new_line_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ if backslash_char!(c) {
+ self.skip_char(c);
+
+ let c2 = self.lookahead_char()?;
+
+ if new_line_char!(c2) {
+ self.skip_char(c2);
return Ok(None);
} else {
self.return_char(c);
@@ -295,26 +317,31 @@ impl<'a, R: Read> Lexer<'a, R> {
}
fn get_double_quoted_char(&mut self) -> Result<char, ParserError> {
- if double_quote_char!(self.lookahead_char()?) {
- let c = self.skip_char()?;
+ let c = self.lookahead_char()?;
- if !double_quote_char!(self.lookahead_char()?) {
+ if double_quote_char!(c) {
+ self.skip_char(c);
+ let c2 = self.lookahead_char()?;
+
+ if !double_quote_char!(c2) {
self.return_char(c);
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else {
- self.skip_char()
+ self.skip_char(c2);
+ Ok(c2)
}
- } else if single_quote_char!(self.lookahead_char()?) {
- self.skip_char()
- } else if back_quote_char!(self.lookahead_char()?) {
- self.skip_char()
+ } else if single_quote_char!(c) || back_quote_char!(c) {
+ self.skip_char(c);
+ Ok(c)
} else {
self.get_non_quote_char()
}
}
fn get_control_escape_sequence(&mut self) -> Result<char, ParserError> {
- let escaped = match self.lookahead_char()? {
+ let c = self.lookahead_char()?;
+
+ let escaped = match c {
'a' => '\u{07}', // UTF-8 alert
'b' => '\u{08}', // UTF-8 backspace
'v' => '\u{0b}', // UTF-8 vertical tab
@@ -325,16 +352,16 @@ impl<'a, R: Read> Lexer<'a, R> {
c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)),
};
- self.skip_char()?;
- return Ok(escaped);
+ self.skip_char(c);
+ Ok(escaped)
}
fn get_octal_escape_sequence(&mut self) -> Result<char, ParserError> {
self.escape_sequence_to_char(|c| octal_digit_char!(c), 8)
}
- fn get_hexadecimal_escape_sequence(&mut self) -> Result<char, ParserError> {
- self.skip_char()?;
+ fn get_hexadecimal_escape_sequence(&mut self, start: char) -> Result<char, ParserError> {
+ self.skip_char(start);
let c = self.lookahead_char()?;
if hexadecimal_digit_char!(c) {
@@ -350,12 +377,12 @@ impl<'a, R: Read> Lexer<'a, R> {
radix: u32,
) -> Result<char, ParserError> {
let mut c = self.lookahead_char()?;
- let mut token = String::new();
+ let mut token = String::with_capacity(16);
loop {
token.push(c);
- self.skip_char()?;
+ self.skip_char(c);
c = self.lookahead_char()?;
if !accept_char(c) {
@@ -364,7 +391,7 @@ impl<'a, R: Read> Lexer<'a, R> {
}
if backslash_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
u32::from_str_radix(&token, radix).map_or_else(
|_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
|n| {
@@ -374,8 +401,8 @@ impl<'a, R: Read> Lexer<'a, R> {
)
} else {
// on failure, restore the token characters and backslash.
- self.reader.put_back_all(token.chars().map(Ok));
- self.reader.put_back(Ok('\\'));
+ // self.reader.put_back_all(token.chars().map(Ok));
+ // self.reader.put_back(Ok('\\'));
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
}
@@ -385,158 +412,212 @@ impl<'a, R: Read> Lexer<'a, R> {
let c = self.lookahead_char()?;
if graphic_char!(c) || alpha_numeric_char!(c) || solo_char!(c) || space_char!(c) {
- self.skip_char()
+ self.skip_char(c);
+ Ok(c)
} else {
if !backslash_char!(c) {
return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num));
}
- self.skip_char()?;
-
+ self.skip_char(c);
let c = self.lookahead_char()?;
if meta_char!(c) {
- self.skip_char()
+ self.skip_char(c);
+ Ok(c)
} else if octal_digit_char!(c) {
self.get_octal_escape_sequence()
} else if symbolic_hexadecimal_char!(c) {
- self.get_hexadecimal_escape_sequence()
+ self.get_hexadecimal_escape_sequence(c)
} else {
self.get_control_escape_sequence()
}
}
}
- fn char_code_list_token(&mut self) -> Result<String, ParserError> {
- let mut token = String::new();
+ fn char_code_list_token(&mut self, start: char) -> Result<String, ParserError> {
+ let mut token = String::with_capacity(16);
- self.skip_char()?;
+ self.skip_char(start);
consume_chars_with!(token, self.get_double_quoted_item());
- if double_quote_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ let c = self.lookahead_char()?;
+
+ if double_quote_char!(c) {
+ self.skip_char(c);
Ok(token)
} else {
Err(ParserError::MissingQuote(self.line_num, self.col_num))
}
}
- fn hexadecimal_constant(&mut self) -> Result<Token, ParserError> {
- self.skip_char()?;
+ fn hexadecimal_constant(&mut self, start: char) -> Result<Token, ParserError> {
+ self.skip_char(start);
+ let mut c = self.lookahead_char()?;
- if hexadecimal_digit_char!(self.lookahead_char()?) {
- let mut token = String::new();
+ if hexadecimal_digit_char!(c) {
+ let mut token = String::with_capacity(16);
- while hexadecimal_digit_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ loop {
+ if hexadecimal_digit_char!(c) {
+ self.skip_char(c);
+ token.push(c);
+ c = self.lookahead_char()?;
+ } else {
+ break;
+ }
}
- isize::from_str_radix(&token, 16)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 16)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
Integer::from_str_radix(&token, 16)
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| Token::Literal(Literal::Integer(
+ arena_alloc!(n, &mut self.machine_st.arena)
+ )))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
- self.return_char('x');
+ self.return_char(start);
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
}
}
- fn octal_constant(&mut self) -> Result<Token, ParserError> {
- self.skip_char()?;
+ fn octal_constant(&mut self, start: char) -> Result<Token, ParserError> {
+ self.skip_char(start);
+ let mut c = self.lookahead_char()?;
- if octal_digit_char!(self.lookahead_char()?) {
- let mut token = String::new();
+ if octal_digit_char!(c) {
+ let mut token = String::with_capacity(16);
- while octal_digit_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ loop {
+ if octal_digit_char!(c) {
+ self.skip_char(c);
+ token.push(c);
+ c = self.lookahead_char()?;
+ } else {
+ break;
+ }
}
- isize::from_str_radix(&token, 8)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 8)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
Integer::from_str_radix(&token, 8)
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| Token::Literal(Literal::Integer(
+ arena_alloc!(n, &mut self.machine_st.arena)
+ )))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
- self.return_char('o');
+ self.return_char(start);
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
}
}
- fn binary_constant(&mut self) -> Result<Token, ParserError> {
- self.skip_char()?;
+ fn binary_constant(&mut self, start: char) -> Result<Token, ParserError> {
+ self.skip_char(start);
+ let mut c = self.lookahead_char()?;
- if binary_digit_char!(self.lookahead_char()?) {
- let mut token = String::new();
+ if binary_digit_char!(c) {
+ let mut token = String::with_capacity(16);
- while binary_digit_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ loop {
+ if binary_digit_char!(c) {
+ self.skip_char(c);
+ token.push(c);
+ c = self.lookahead_char()?;
+ } else {
+ break;
+ }
}
- isize::from_str_radix(&token, 2)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 2)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
Integer::from_str_radix(&token, 2)
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| Token::Literal(Literal::Integer(
+ arena_alloc!(n, &mut self.machine_st.arena)
+ )))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
- self.return_char('b');
+ self.return_char(start);
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
}
}
fn variable_token(&mut self) -> Result<Token, ParserError> {
- let mut s = String::new();
- s.push(self.skip_char()?);
+ let mut s = String::with_capacity(16);
+ s.push(self.read_char()?);
+
+ loop {
+ let c = self.lookahead_char()?;
- while alpha_numeric_char!(self.lookahead_char()?) {
- s.push(self.skip_char()?);
+ if alpha_numeric_char!(c) {
+ self.skip_char(c);
+ s.push(c);
+ } else {
+ break;
+ }
}
- Ok(Token::Var(rc_atom!(s)))
+ Ok(Token::Var(s))
}
fn name_token(&mut self, c: char) -> Result<Token, ParserError> {
- let mut token = String::new();
+ let mut token = String::with_capacity(16);
if small_letter_char!(c) {
- token.push(self.skip_char()?);
+ self.skip_char(c);
+ token.push(c);
+
+ loop {
+ let c = self.lookahead_char()?;
- while alpha_numeric_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ if alpha_numeric_char!(c) {
+ self.skip_char(c);
+ token.push(c);
+ } else {
+ break;
+ }
}
} else if graphic_token_char!(c) {
- token.push(self.skip_char()?);
+ self.skip_char(c);
+ token.push(c);
+
+ loop {
+ let c = self.lookahead_char()?;
- while graphic_token_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ if graphic_token_char!(c) {
+ self.skip_char(c);
+ token.push(c);
+ } else {
+ break;
+ }
}
} else if cut_char!(c) {
- token.push(self.skip_char()?);
+ self.skip_char(c);
+ token.push(c);
} else if semicolon_char!(c) {
- token.push(self.skip_char()?);
+ self.skip_char(c);
+ token.push(c);
} else if single_quote_char!(c) {
- self.skip_char()?;
-
+ self.skip_char(c);
consume_chars_with!(token, self.get_single_quoted_item());
- if single_quote_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ let c = self.lookahead_char()?;
+
+ if single_quote_char!(c) {
+ self.skip_char(c);
if !token.is_empty() && token.chars().nth(1).is_none() {
if let Some(c) = token.chars().next() {
- return Ok(Token::Constant(Constant::Char(c)));
+ return Ok(Token::Literal(Literal::Char(c)));
}
}
} else {
- return Err(ParserError::InvalidSingleQuotedCharacter(
- self.lookahead_char()?,
- ));
+ return Err(ParserError::InvalidSingleQuotedCharacter(c));
}
} else {
match self.get_back_quoted_string() {
@@ -546,24 +627,29 @@ impl<'a, R: Read> Lexer<'a, R> {
}
if token.as_str() == "[]" {
- Ok(Token::Constant(Constant::EmptyList))
+ Ok(Token::Literal(Literal::Atom(atom!("[]"))))
} else {
- Ok(Token::Constant(atom!(token, self.atom_tbl)))
+ Ok(Token::Literal(Literal::Atom(
+ self.machine_st.atom_tbl.build_with(&token),
+ )))
}
}
- fn vacate_with_float(&mut self, mut token: String) -> Token {
+ fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
self.return_char(token.pop().unwrap());
- let result = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes()).unwrap());
- Token::Constant(Constant::Float(result))
+ let result = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
+ Ok(Token::Literal(Literal::Float(arena_alloc!(
+ result,
+ &mut self.machine_st.arena
+ ))))
}
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
let mut c = self.lookahead_char()?;
if c == '_' {
- self.skip_char()?;
+ self.skip_char(c);
self.scan_for_layout()?;
c = self.lookahead_char()?;
@@ -577,112 +663,140 @@ impl<'a, R: Read> Lexer<'a, R> {
}
}
- pub fn number_token(&mut self) -> Result<Token, ParserError> {
- let mut token = String::new();
+ pub fn number_token(&mut self, leading_c: char) -> Result<Token, ParserError> {
+ let mut token = String::with_capacity(16);
- token.push(self.skip_char()?);
+ self.skip_char(leading_c);
+ token.push(leading_c);
let mut c = self.skip_underscore_in_number()?;
while decimal_digit_char!(c) {
token.push(c);
- self.skip_char()?;
+ self.skip_char(c);
c = self.skip_underscore_in_number()?;
}
if decimal_point_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
- if self.reader.peek().is_none() {
+ if self.reader.peek_char().is_none() {
self.return_char('.');
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena)))
+ })
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else if decimal_digit_char!(self.lookahead_char()?) {
token.push('.');
- token.push(self.skip_char()?);
+ token.push(self.read_char()?);
let mut c = self.lookahead_char()?;
while decimal_digit_char!(c) {
token.push(c);
- self.skip_char()?;
+ self.skip_char(c);
c = self.lookahead_char()?;
}
- if exponent_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ if exponent_char!(c) {
+ self.skip_char(c);
+ token.push(c);
let c = match self.lookahead_char() {
- Err(_) => return Ok(self.vacate_with_float(token)),
+ Err(_) => return Ok(self.vacate_with_float(token)?),
Ok(c) => c,
};
if !sign_char!(c) && !decimal_digit_char!(c) {
- return Ok(self.vacate_with_float(token));
+ return Ok(self.vacate_with_float(token)?);
}
if sign_char!(c) {
- token.push(self.skip_char()?);
+ self.skip_char(c);
+ token.push(c);
let c = match self.lookahead_char() {
Err(_) => {
self.return_char(token.pop().unwrap());
- return Ok(self.vacate_with_float(token));
+ return Ok(self.vacate_with_float(token)?);
}
Ok(c) => c,
};
if !decimal_digit_char!(c) {
self.return_char(token.pop().unwrap());
- return Ok(self.vacate_with_float(token));
+ return Ok(self.vacate_with_float(token)?);
}
}
- if decimal_digit_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ let mut c = self.lookahead_char()?;
+
+ if decimal_digit_char!(c) {
+ self.skip_char(c);
+ token.push(c);
- while decimal_digit_char!(self.lookahead_char()?) {
- token.push(self.skip_char()?);
+ loop {
+ c = self.lookahead_char()?;
+
+ if decimal_digit_char!(c) {
+ self.skip_char(c);
+ token.push(c);
+ } else {
+ break;
+ }
}
- let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes()).unwrap());
- Ok(Token::Constant(Constant::Float(n)))
+ let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
+ Ok(Token::Literal(Literal::Float(arena_alloc!(
+ n,
+ &mut self.machine_st.arena
+ ))))
} else {
- return Ok(self.vacate_with_float(token));
+ return Ok(self.vacate_with_float(token)?);
}
} else {
- let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes()).unwrap());
- Ok(Token::Constant(Constant::Float(n)))
+ let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
+ Ok(Token::Literal(Literal::Float(arena_alloc!(
+ n,
+ &mut self.machine_st.arena
+ ))))
}
} else {
self.return_char('.');
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena)))
+ })
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
} else {
if token.starts_with('0') && token.len() == 1 {
if c == 'x' {
- self.hexadecimal_constant().or_else(|e| {
+ self.hexadecimal_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(
+ n,
+ &mut self.machine_st.arena
+ )))
+ })
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
@@ -692,14 +806,19 @@ impl<'a, R: Read> Lexer<'a, R> {
}
})
} else if c == 'o' {
- self.octal_constant().or_else(|e| {
+ self.octal_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(
+ n,
+ &mut self.machine_st.arena
+ )))
+ })
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
@@ -709,14 +828,19 @@ impl<'a, R: Read> Lexer<'a, R> {
}
})
} else if c == 'b' {
- self.binary_constant().or_else(|e| {
+ self.binary_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(
+ n,
+ &mut self.machine_st.arena
+ )))
+ })
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
@@ -726,54 +850,68 @@ impl<'a, R: Read> Lexer<'a, R> {
}
})
} else if single_quote_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
+ let c = self.lookahead_char()?;
- if backslash_char!(self.lookahead_char()?) {
- self.skip_char()?;
+ if backslash_char!(c) {
+ self.skip_char(c);
+ let c = self.lookahead_char()?;
- if new_line_char!(self.lookahead_char()?) {
- self.return_char('\\');
+ if new_line_char!(c) {
+ self.skip_char(c);
self.return_char('\'');
- return Ok(Token::Constant(Constant::Fixnum(0)));
+ return Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(0))));
} else {
self.return_char('\\');
}
}
self.get_single_quoted_char()
- .map(|c| Token::Constant(Constant::Fixnum(c as isize)))
+ .map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64))))
.or_else(|_| {
self.return_char(c);
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(
+ n,
+ &mut self.machine_st.arena
+ )))
+ })
.map_err(|_| {
ParserError::ParseBigInt(self.line_num, self.col_num)
})
})
})
} else {
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(
+ n,
+ &mut self.machine_st.arena
+ )))
+ })
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
} else {
- isize::from_str_radix(&token, 10)
- .map(|n| Token::Constant(Constant::Fixnum(n)))
+ i64::from_str_radix(&token, 10)
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
- .map(|n| Token::Constant(Constant::Integer(Rc::new(n))))
+ .map(|n| {
+ Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena)))
+ })
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
@@ -789,7 +927,7 @@ impl<'a, R: Read> Lexer<'a, R> {
match cr {
Ok(c) if layout_char!(c) => {
- self.skip_char()?;
+ self.skip_char(c);
layout_inserted = true;
}
Ok(c) if end_line_comment_char!(c) => {
@@ -825,17 +963,17 @@ impl<'a, R: Read> Lexer<'a, R> {
}
if c == ',' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(Token::Comma);
}
if c == ')' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(Token::Close);
}
if c == '(' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(if layout_inserted {
Token::Open
} else {
@@ -844,12 +982,12 @@ impl<'a, R: Read> Lexer<'a, R> {
}
if c == '.' {
- self.skip_char()?;
+ self.skip_char(c);
match self.lookahead_char() {
Ok(c) if layout_char!(c) || c == '%' => {
if new_line_char!(c) {
- self.skip_char()?;
+ self.skip_char(c);
}
return Ok(Token::End);
@@ -861,47 +999,52 @@ impl<'a, R: Read> Lexer<'a, R> {
self.return_char('.');
}
};
+
+ return self.name_token(c);
}
if decimal_digit_char!(c) {
- return self.number_token();
+ return self.number_token(c);
}
if c == ']' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(Token::CloseList);
}
if c == '[' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(Token::OpenList);
}
if c == '|' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(Token::HeadTailSeparator);
}
if c == '{' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(Token::OpenCurly);
}
if c == '}' {
- self.skip_char()?;
+ self.skip_char(c);
return Ok(Token::CloseCurly);
}
if c == '"' {
- let s = self.char_code_list_token()?;
+ let s = self.char_code_list_token(c)?;
+ let atom = self.machine_st.atom_tbl.build_with(&s);
- if let DoubleQuotes::Atom = self.flags.double_quotes {
- let s = clause_name!(s, self.atom_tbl);
- return Ok(Token::Constant(Constant::Atom(s, None)));
+ return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
+ Ok(Token::Literal(Literal::Atom(atom)))
} else {
- let s = Rc::new(s);
- return Ok(Token::Constant(Constant::String(s)));
- }
+ Ok(Token::Literal(Literal::String(atom)))
+ };
+ }
+
+ if c == '\u{0}' {
+ return Err(ParserError::UnexpectedEOF);
}
self.name_token(c)
diff --git a/crates/prolog_parser/src/macros.rs b/src/parser/macros.rs
index f8ec9072..6e37f320 100644
--- a/crates/prolog_parser/src/macros.rs
+++ b/src/parser/macros.rs
@@ -54,9 +54,9 @@ macro_rules! back_quote_char {
}
#[macro_export]
-macro_rules! binary_digit_char {
+macro_rules! octet_char {
($c: expr) => {
- $c >= '0' && $c <= '1'
+ ('\u{0000}'..='\u{00FF}').contains(&$c)
};
}
@@ -172,9 +172,9 @@ macro_rules! octal_digit_char {
}
#[macro_export]
-macro_rules! octet_char {
+macro_rules! binary_digit_char {
($c: expr) => {
- ('\u{0000}'..='\u{00FF}').contains(&$c)
+ $c >= '0' && $c <= '1'
};
}
diff --git a/crates/prolog_parser/src/lib.rs b/src/parser/mod.rs
index 2c37cea6..8835c9ef 100644
--- a/crates/prolog_parser/src/lib.rs
+++ b/src/parser/mod.rs
@@ -1,15 +1,17 @@
#[cfg(feature = "num-rug-adapter")]
use num_rug_adapter as rug;
#[cfg(feature = "rug")]
-use rug;
+pub use rug;
-#[macro_use]
-pub mod tabled_rc;
+// #[macro_use]
+// extern crate lazy_static;
+// #[macro_use]
+// extern crate static_assertions;
+
+pub mod char_reader;
#[macro_use]
pub mod ast;
#[macro_use]
pub mod macros;
-pub mod parser;
-pub mod put_back_n;
-
pub mod lexer;
+pub mod parser;
diff --git a/crates/prolog_parser/src/parser.rs b/src/parser/parser.rs
index 43ee244c..2d6334c0 100644
--- a/crates/prolog_parser/src/parser.rs
+++ b/src/parser/parser.rs
@@ -1,14 +1,15 @@
-use crate::ast::*;
-use crate::lexer::*;
-use crate::tabled_rc::*;
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::parser::ast::*;
+use crate::parser::char_reader::*;
+use crate::parser::lexer::*;
use ordered_float::OrderedFloat;
-use crate::rug::ops::NegAssign;
+use rug::ops::NegAssign;
use std::cell::Cell;
-use std::io::Read;
-use std::mem::swap;
+use std::mem;
use std::rc::Rc;
#[derive(Debug, Clone, Copy, PartialEq)]
@@ -50,69 +51,114 @@ struct TokenDesc {
spec: u32,
}
-pub fn get_clause_spec(
- name: ClauseName,
- arity: usize,
- op_dir: &CompositeOpDir,
-) -> Option<SharedOpDesc> {
- match arity {
- 1 => {
- /* This is a clause with an operator principal functor. Prefix operators
- are supposed over post.
- */
- if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) {
- return Some(cell.clone());
+fn is_partial_string(
+ head: Term,
+ mut tail: Term,
+ atom_tbl: &mut AtomTable,
+) -> Result<(Atom, Option<Box<Term>>), Term> {
+ let mut string = match &head {
+ Term::Literal(_, Literal::Atom(atom)) => {
+ if let Some(c) = atom.as_char() {
+ c.to_string()
+ } else {
+ return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
}
+ }
+ Term::Literal(_, Literal::Char(c)) => c.to_string(),
+ _ => {
+ return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
+ }
+ };
+
+ let mut orig_tail = Box::new(tail);
+ let mut tail_ref = &mut orig_tail;
+
+ loop {
+ match &mut **tail_ref {
+ Term::Cons(_, prev, succ) => {
+ match prev.as_ref() {
+ Term::Literal(_, Literal::Atom(atom)) => {
+ if let Some(c) = atom.as_char() {
+ string.push(c);
+ } else {
+ return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
+ }
+ }
+ Term::Literal(_, Literal::Char(c)) => {
+ string.push(*c);
+ }
+ _ => {
+ return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
+ }
+ }
- if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) {
- return Some(cell.clone());
+ tail_ref = succ;
}
- }
- 2 => {
- if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) {
- return Some(cell.clone());
+ tail_ref => {
+ tail = mem::replace(tail_ref, Term::AnonVar);
+ break;
}
}
- _ => {}
- };
+ }
- None
+ match &tail {
+ Term::AnonVar | Term::Var(..) => {
+ let pstr_atom = atom_tbl.build_with(&string);
+ Ok((pstr_atom, Some(Box::new(tail))))
+ }
+ Term::Literal(_, Literal::Atom(atom!("[]"))) => {
+ let pstr_atom = atom_tbl.build_with(&string);
+ Ok((pstr_atom, None))
+ }
+ Term::Literal(_, Literal::String(tail)) => {
+ string += tail.as_str();
+ let pstr_atom = atom_tbl.build_with(&string);
+ Ok((pstr_atom, None))
+ }
+ _ => {
+ let pstr_atom = atom_tbl.build_with(&string);
+ Ok((pstr_atom, Some(Box::new(tail))))
+ }
+ }
}
-pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option<OpDesc> {
- let mut op_desc = OpDesc {
+pub fn get_op_desc(
+ name: Atom,
+ op_dir: &CompositeOpDir,
+) -> Option<CompositeOpDesc> {
+ let mut op_desc = CompositeOpDesc {
pre: 0,
inf: 0,
post: 0,
spec: 0,
};
- if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) {
+ if let Some(cell) = op_dir.get(name, Fixity::Pre) {
let (pri, spec) = cell.get();
if pri > 0 {
- op_desc.pre = pri;
- op_desc.spec |= spec;
- } else if name.as_str() == "-" {
+ op_desc.pre = pri as usize;
+ op_desc.spec |= spec as u32;
+ } else if name == atom!("-") {
op_desc.spec |= NEGATIVE_SIGN;
}
}
- if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Post) {
+ if let Some(cell) = op_dir.get(name, Fixity::Post) {
let (pri, spec) = cell.get();
if pri > 0 {
- op_desc.post = pri;
- op_desc.spec |= spec;
+ op_desc.post = pri as usize;
+ op_desc.spec |= spec as u32;
}
}
- if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::In) {
+ if let Some(cell) = op_dir.get(name, Fixity::In) {
let (pri, spec) = cell.get();
if pri > 0 {
- op_desc.inf = pri;
- op_desc.spec |= spec;
+ op_desc.inf = pri as usize;
+ op_desc.spec |= spec as u32;
}
}
@@ -123,6 +169,31 @@ pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option<OpDesc>
}
}
+pub fn get_clause_spec(name: Atom, arity: usize, op_dir: &CompositeOpDir) -> Option<OpDesc> {
+ match arity {
+ 1 => {
+ /* This is a clause with an operator principal functor. Prefix operators
+ are supposed over post.
+ */
+ if let Some(cell) = op_dir.get(name, Fixity::Pre) {
+ return Some(cell);
+ }
+
+ if let Some(cell) = op_dir.get(name, Fixity::Post) {
+ return Some(cell);
+ }
+ }
+ 2 => {
+ if let Some(cell) = op_dir.get(name, Fixity::In) {
+ return Some(cell);
+ }
+ }
+ _ => {}
+ };
+
+ None
+}
+
fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool {
d2.priority <= priority
&& is_term!(d3.spec)
@@ -164,23 +235,8 @@ fn affirm_fx(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool {
d2.priority <= priority && is_term!(d1.spec) && d1.priority < d2.priority
}
-fn sep_to_atom(tt: TokenType) -> Option<ClauseName> {
- match tt {
- TokenType::Open | TokenType::OpenCT => Some(clause_name!("(")),
- TokenType::Close => Some(clause_name!(")")),
- TokenType::OpenList => Some(clause_name!("[")),
- TokenType::CloseList => Some(clause_name!("]")),
- TokenType::OpenCurly => Some(clause_name!("{")),
- TokenType::CloseCurly => Some(clause_name!("}")),
- TokenType::HeadTailSeparator => Some(clause_name!("|")),
- TokenType::Comma => Some(clause_name!(",")),
- TokenType::End => Some(clause_name!(".")),
- _ => None,
- }
-}
-
#[derive(Debug, Clone, Copy)]
-pub struct OpDesc {
+pub struct CompositeOpDesc {
pub pre: usize,
pub inf: usize,
pub post: usize,
@@ -188,14 +244,14 @@ pub struct OpDesc {
}
#[derive(Debug)]
-pub struct Parser<'a, R: Read> {
- lexer: Lexer<'a, R>,
+pub struct Parser<'a, R> {
+ pub lexer: Lexer<'a, R>,
tokens: Vec<Token>,
stack: Vec<TokenDesc>,
terms: Vec<Term>,
}
-fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
+fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
let mut tokens = vec![];
loop {
@@ -209,7 +265,10 @@ fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError>
}
}
Err(ParserError::UnexpectedEOF) if !tokens.is_empty() => {
- return Err(ParserError::IncompleteReduction(lexer.line_num, lexer.col_num));
+ return Err(ParserError::IncompleteReduction(
+ lexer.line_num,
+ lexer.col_num,
+ ));
}
Err(e) => {
return Err(e);
@@ -222,20 +281,46 @@ fn read_tokens<R: Read>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError>
Ok(tokens)
}
-impl<'a, R: Read> Parser<'a, R> {
- pub fn new(
- stream: &'a mut ParsingStream<R>,
- atom_tbl: TabledData<Atom>,
- flags: MachineFlags,
- ) -> Self {
+fn atomize_term(atom_tbl: &mut AtomTable, term: &Term) -> Option<Atom> {
+ match term {
+ Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
+ _ => None,
+ }
+}
+
+fn atomize_constant(atom_tbl: &mut AtomTable, c: Literal) -> Option<Atom> {
+ match c {
+ Literal::Atom(ref name) => Some(*name),
+ Literal::Char(c) => Some(atom_tbl.build_with(&c.to_string())),
+ _ => None,
+ }
+}
+
+impl<'a, R: CharRead> Parser<'a, R> {
+ pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self {
Parser {
- lexer: Lexer::new(atom_tbl, flags, stream),
+ lexer: Lexer::new(stream, machine_st),
tokens: vec![],
stack: Vec::new(),
terms: Vec::new(),
}
}
+ fn sep_to_atom(&mut self, tt: TokenType) -> Option<Atom> {
+ match tt {
+ TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
+ TokenType::Close => Some(atom!(")")),
+ TokenType::OpenList => Some(atom!("[")),
+ TokenType::CloseList => Some(atom!("]")),
+ TokenType::OpenCurly => Some(atom!("{")),
+ TokenType::CloseCurly => Some(atom!("}")),
+ TokenType::HeadTailSeparator => Some(atom!("|")),
+ TokenType::Comma => Some(atom!(",")),
+ TokenType::End => Some(atom!(".")),
+ _ => None,
+ }
+ }
+
#[inline]
pub fn line_num(&self) -> usize {
self.lexer.line_num
@@ -246,25 +331,12 @@ impl<'a, R: Read> Parser<'a, R> {
self.lexer.col_num
}
- #[inline]
- pub fn get_atom_tbl(&self) -> TabledData<Atom> {
- self.lexer.atom_tbl.clone()
- }
-
- #[inline]
- pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
- self.lexer.atom_tbl = atom_tbl;
- }
-
- fn get_term_name(&mut self, td: TokenDesc) -> Option<(ClauseName, Option<SharedOpDesc>)> {
+ fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
match td.tt {
- TokenType::HeadTailSeparator => Some((
- clause_name!("|"),
- Some(SharedOpDesc::new(td.priority, td.spec)),
- )),
- TokenType::Comma => Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))),
+ TokenType::HeadTailSeparator => Some(atom!("|")),
+ TokenType::Comma => Some(atom!(",")),
TokenType::Term => match self.terms.pop() {
- Some(Term::Constant(_, Constant::Atom(atom, spec))) => Some((atom, spec)),
+ Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom),
Some(term) => {
self.terms.push(term);
None
@@ -277,14 +349,9 @@ impl<'a, R: Read> Parser<'a, R> {
fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) {
if let Some(arg2) = self.terms.pop() {
- if let Some((name, shared_op_desc)) = self.get_term_name(td) {
+ if let Some(name) = self.get_term_name(td) {
if let Some(arg1) = self.terms.pop() {
- let term = Term::Clause(
- Cell::default(),
- name,
- vec![Box::new(arg1), Box::new(arg2)],
- shared_op_desc,
- );
+ let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]);
self.terms.push(term);
self.stack.push(TokenDesc {
@@ -301,12 +368,11 @@ impl<'a, R: Read> Parser<'a, R> {
if let Some(mut arg1) = self.terms.pop() {
if let Some(mut name) = self.terms.pop() {
if is_postfix!(assoc) {
- swap(&mut arg1, &mut name);
+ mem::swap(&mut arg1, &mut name);
}
- if let Term::Constant(_, Constant::Atom(name, shared_op_desc)) = name {
- let term =
- Term::Clause(Cell::default(), name, vec![Box::new(arg1)], shared_op_desc);
+ if let Term::Literal(_, Literal::Atom(name)) = name {
+ let term = Term::Clause(Cell::default(), name, vec![arg1]);
self.terms.push(term);
self.stack.push(TokenDesc {
@@ -319,17 +385,8 @@ impl<'a, R: Read> Parser<'a, R> {
}
}
- fn promote_atom_op(
- &mut self,
- atom: ClauseName,
- priority: usize,
- assoc: u32,
- op_dir_val: Option<&OpDirValue>,
- ) {
- let spec = op_dir_val.map(|op_dir_val| op_dir_val.shared_op_desc());
-
- self.terms
- .push(Term::Constant(Cell::default(), Constant::Atom(atom, spec)));
+ fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
+ self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
self.stack.push(TokenDesc {
tt: TokenType::Term,
priority,
@@ -339,15 +396,15 @@ impl<'a, R: Read> Parser<'a, R> {
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
let tt = match token {
- Token::Constant(Constant::String(s)) if self.lexer.flags.double_quotes.is_codes() => {
- let mut list = Term::Constant(Cell::default(), Constant::EmptyList);
+ Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_codes() => {
+ let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
- for c in s.chars().rev() {
+ for c in s.as_str().chars().rev() {
list = Term::Cons(
Cell::default(),
- Box::new(Term::Constant(
+ Box::new(Term::Literal(
Cell::default(),
- Constant::Fixnum(c as isize),
+ Literal::Fixnum(Fixnum::build_with(c as i64)),
)),
Box::new(list),
);
@@ -356,15 +413,19 @@ impl<'a, R: Read> Parser<'a, R> {
self.terms.push(list);
TokenType::Term
}
- Token::Constant(c) => {
- self.terms.push(Term::Constant(Cell::default(), c));
+ Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => {
+ self.terms.push(Term::PartialString(Cell::default(), s, None));
+ TokenType::Term
+ }
+ Token::Literal(c) => {
+ self.terms.push(Term::Literal(Cell::default(), c));
TokenType::Term
}
Token::Var(v) => {
if v.trim() == "_" {
self.terms.push(Term::AnonVar);
} else {
- self.terms.push(Term::Var(Cell::default(), v));
+ self.terms.push(Term::Var(Cell::default(), Rc::new(v)));
}
TokenType::Term
@@ -457,7 +518,7 @@ impl<'a, R: Read> Parser<'a, R> {
None
}
- fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool {
+ fn reduce_term(&mut self) -> bool {
if self.stack.is_empty() {
return false;
}
@@ -489,22 +550,40 @@ impl<'a, R: Read> Parser<'a, R> {
let idx = self.terms.len() - arity;
if TokenType::Term == self.stack[stack_len].tt {
- if self.atomize_term(&self.terms[idx - 1]).is_some() {
+ if atomize_term(&mut self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some() {
self.stack.truncate(stack_len + 1);
- let mut subterms: Vec<_> = self.terms.drain(idx..).map(Box::new).collect();
+ let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
- if let Some(name) = self.terms.pop().and_then(|t| self.atomize_term(&t)) {
+ if let Some(name) = self
+ .terms
+ .pop()
+ .and_then(|t| atomize_term(&mut self.lexer.machine_st.atom_tbl, &t))
+ {
// reduce the '.' functor to a cons cell if it applies.
- if name.as_str() == "." && subterms.len() == 2 {
+ if name == atom!(".") && subterms.len() == 2 {
let tail = subterms.pop().unwrap();
let head = subterms.pop().unwrap();
- self.terms.push(Term::Cons(Cell::default(), head, tail));
+ self.terms.push(
+ match is_partial_string(head, tail, &mut self.lexer.machine_st.atom_tbl) {
+ Ok((string_buf, tail_opt)) => {
+ Term::PartialString(Cell::default(), string_buf, tail_opt)
+ }
+ Err(term) => term,
+ },
+ );
+
+ /*
+ self.terms.push(Term::Cons(
+ Cell::default(),
+ Box::new(head),
+ Box::new(tail),
+ ));
+ */
} else {
- let spec = get_clause_spec(name.clone(), subterms.len(), op_dir);
self.terms
- .push(Term::Clause(Cell::default(), name, subterms, spec));
+ .push(Term::Clause(Cell::default(), name, subterms));
}
if let Some(&mut TokenDesc {
@@ -544,8 +623,8 @@ impl<'a, R: Read> Parser<'a, R> {
* an operator, so expand the
* terms it compacted out again. */
match (term.name(), term.arity()) {
- (Some(name), 2) if name.as_str() == "," => {
- let terms = unfold_by_str(term, ",");
+ (Some(name), 2) if name == atom!(",") => {
+ let terms = unfold_by_str(term, name); // notice: name == "," here.
let arity = terms.len() - 1;
self.terms.extend(terms.into_iter());
@@ -603,8 +682,7 @@ impl<'a, R: Read> Parser<'a, R> {
td.tt = TokenType::Term;
td.priority = 0;
- self.terms
- .push(Term::Constant(Cell::default(), Constant::EmptyList));
+ self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))));
return Ok(true);
}
}
@@ -621,7 +699,7 @@ impl<'a, R: Read> Parser<'a, R> {
let list_len = self.stack.len() - 2 * arity;
let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
- Term::Constant(Cell::default(), Constant::EmptyList)
+ Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))
} else {
let term = match self.terms.pop() {
Some(term) => term,
@@ -662,7 +740,18 @@ impl<'a, R: Read> Parser<'a, R> {
priority: 0,
spec: TERM,
});
- self.terms.push(list);
+
+ self.terms.push(match list {
+ Term::Cons(_, head, tail) => {
+ match is_partial_string(*head, *tail, &mut self.lexer.machine_st.atom_tbl) {
+ Ok((string_buf, tail_opt)) => {
+ Term::PartialString(Cell::default(), string_buf, tail_opt)
+ }
+ Err(term) => term,
+ }
+ }
+ term => term,
+ });
Ok(true)
}
@@ -678,7 +767,11 @@ impl<'a, R: Read> Parser<'a, R> {
td.priority = 0;
td.spec = TERM;
- let term = Term::Constant(Cell::default(), atom!("{}", self.lexer.atom_tbl));
+ let term = Term::Literal(
+ Cell::default(),
+ Literal::Atom(atom!("{}")),
+ );
+
self.terms.push(term);
return Ok(true);
}
@@ -710,9 +803,8 @@ impl<'a, R: Read> Parser<'a, R> {
self.terms.push(Term::Clause(
Cell::default(),
- clause_name!("{}"),
- vec![Box::new(term)],
- None,
+ atom!("{}"),
+ vec![term],
));
return Ok(true);
@@ -744,27 +836,28 @@ impl<'a, R: Read> Parser<'a, R> {
return false;
}
- if let Some(atom) = sep_to_atom(self.stack[idx].tt) {
+ if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) {
self.terms
- .push(Term::Constant(Cell::default(), Constant::Atom(atom, None)));
+ .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
}
self.stack[idx].spec = TERM;
self.stack[idx].tt = TokenType::Term;
self.stack[idx].priority = 0;
+
true
}
_ => false,
}
}
- fn shift_op(&mut self, name: ClauseName, op_dir: &CompositeOpDir) -> Result<bool, ParserError> {
- if let Some(OpDesc {
+ fn shift_op(&mut self, name: Atom, op_dir: &CompositeOpDir) -> Result<bool, ParserError> {
+ if let Some(CompositeOpDesc {
pre,
inf,
post,
spec,
- }) = get_op_desc(name.clone(), op_dir)
+ }) = get_op_desc(name, op_dir)
{
if (pre > 0 && inf + post > 0) || is_negate!(spec) {
match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? {
@@ -775,15 +868,9 @@ impl<'a, R: Read> Parser<'a, R> {
// or post == 0.
self.reduce_op(inf + post);
- let fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
- let op_dir_val = op_dir.get(name.clone(), fixity);
+ // let fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
- self.promote_atom_op(
- name,
- inf + post,
- spec & (XFX | XFY | YFX | YF | XF),
- op_dir_val,
- );
+ self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF));
}
_ => {
self.reduce_op(inf + post);
@@ -791,49 +878,22 @@ impl<'a, R: Read> Parser<'a, R> {
if let Some(TokenDesc { spec: pspec, .. }) = self.stack.last().cloned() {
// rterm.c: 412
if is_term!(pspec) {
- let fixity = if inf > 0 { Fixity::In } else { Fixity::Post };
- let op_dir_val = op_dir.get(name.clone(), fixity);
-
self.promote_atom_op(
name,
inf + post,
spec & (XFX | XFY | YFX | XF | YF),
- op_dir_val,
);
} else {
- let op_dir_val = op_dir.get(name.clone(), Fixity::Pre);
- self.promote_atom_op(
- name,
- pre,
- spec & (FX | FY | NEGATIVE_SIGN),
- op_dir_val,
- );
+ self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN));
}
} else {
- let op_dir_val = op_dir.get(name.clone(), Fixity::Pre);
- self.promote_atom_op(
- name,
- pre,
- spec & (FX | FY | NEGATIVE_SIGN),
- op_dir_val,
- );
+ self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN));
}
}
}
} else {
- let op_dir_val = op_dir.get(
- name.clone(),
- if pre + inf == 0 {
- Fixity::Post
- } else if post + pre == 0 {
- Fixity::In
- } else {
- Fixity::Pre
- },
- );
-
self.reduce_op(pre + inf + post); // only one non-zero priority among these.
- self.promote_atom_op(name, pre + inf + post, spec, op_dir_val);
+ self.promote_atom_op(name, pre + inf + post, spec);
}
Ok(true)
@@ -843,38 +903,23 @@ impl<'a, R: Read> Parser<'a, R> {
}
}
- fn atomize_term(&self, term: &Term) -> Option<ClauseName> {
- match term {
- Term::Constant(_, ref c) => self.atomize_constant(c),
- _ => None,
- }
- }
-
- fn atomize_constant(&self, c: &Constant) -> Option<ClauseName> {
- match c {
- Constant::Atom(ref name, _) => Some(name.clone()),
- Constant::Char(c) => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)),
- Constant::EmptyList => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)),
- _ => None,
- }
- }
-
- fn negate_number<N, Negator, ToConstant>(&mut self, n: N, negator: Negator, constr: ToConstant)
+ fn negate_number<N, Negator, ToLiteral>(&mut self, n: N, negator: Negator, constr: ToLiteral)
where
Negator: Fn(N) -> N,
- ToConstant: Fn(N) -> Constant,
+ ToLiteral: Fn(N, &mut Arena) -> Literal,
{
if let Some(desc) = self.stack.last().cloned() {
if let Some(term) = self.terms.last().cloned() {
match term {
- Term::Constant(_, Constant::Atom(ref name, _))
- if name.as_str() == "-"
- && (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
+ Term::Literal(_, Literal::Atom(name))
+ if name == atom!("-") && (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
{
self.stack.pop();
self.terms.pop();
- self.shift(Token::Constant(constr(negator(n))), 0, TERM);
+ let literal = constr(negator(n), &mut self.lexer.machine_st.arena);
+ self.shift(Token::Literal(literal), 0, TERM);
+
return;
}
_ => {}
@@ -882,43 +927,45 @@ impl<'a, R: Read> Parser<'a, R> {
}
}
- self.shift(Token::Constant(constr(n)), 0, TERM);
+ let literal = constr(n, &mut self.lexer.machine_st.arena);
+ self.shift(Token::Literal(literal), 0, TERM);
}
fn shift_token(&mut self, token: Token, op_dir: &CompositeOpDir) -> Result<(), ParserError> {
- fn negate_rc<T: NegAssign>(mut t: Rc<T>) -> Rc<T> {
- if let Some(t) = Rc::get_mut(&mut t) {
- t.neg_assign();
- };
-
+ fn negate_rc<T: NegAssign>(mut t: TypedArenaPtr<T>) -> TypedArenaPtr<T> {
+ (&mut t).neg_assign();
t
}
match token {
- Token::Constant(Constant::Fixnum(n)) => self.negate_number(n, |n| -n, Constant::Fixnum),
- Token::Constant(Constant::Integer(n)) => {
- self.negate_number(n, negate_rc, Constant::Integer)
+ Token::Literal(Literal::Fixnum(n)) => {
+ self.negate_number(n, |n| -n, |n, _| Literal::Fixnum(n))
}
- Token::Constant(Constant::Rational(n)) => {
- self.negate_number(n, negate_rc, Constant::Rational)
+ Token::Literal(Literal::Integer(n)) => {
+ self.negate_number(n, negate_rc, |n, _| Literal::Integer(n))
}
- Token::Constant(Constant::Float(n)) => {
- self.negate_number(n, |n| OrderedFloat(-n.into_inner()), Constant::Float)
+ Token::Literal(Literal::Rational(n)) => {
+ self.negate_number(n, negate_rc, |r, _| Literal::Rational(r))
}
- Token::Constant(c) => {
- if let Some(name) = self.atomize_constant(&c) {
+ Token::Literal(Literal::Float(n)) => self.negate_number(
+ **n,
+ |n| OrderedFloat(-n.into_inner()),
+ |n, arena| Literal::Float(arena_alloc!(n, arena)),
+ ),
+ Token::Literal(c) => {
+ if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, c) {
if !self.shift_op(name, op_dir)? {
- self.shift(Token::Constant(c), 0, TERM);
+ self.shift(Token::Literal(c), 0, TERM);
}
} else {
- self.shift(Token::Constant(c), 0, TERM);
+ self.shift(Token::Literal(c), 0, TERM);
}
}
Token::Var(v) => self.shift(Token::Var(v), 0, TERM),
Token::Open => self.shift(Token::Open, 1300, DELIMITER),
Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
Token::Close => {
- if !self.reduce_term(op_dir) {
+ if !self.reduce_term() {
if !self.reduce_brackets() {
return Err(ParserError::IncompleteReduction(
self.lexer.line_num,
@@ -949,8 +996,10 @@ impl<'a, R: Read> Parser<'a, R> {
/* '|' as an operator must have priority > 1000 and can only be infix.
* See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78
*/
- let (priority, spec) = get_op_desc(clause_name!("|"), op_dir)
- .map(|OpDesc { inf, spec, .. }| (inf, spec))
+ let bar_atom = atom!("|");
+
+ let (priority, spec) = get_op_desc(bar_atom, op_dir)
+ .map(|CompositeOpDesc { inf, spec, .. }| (inf, spec))
.unwrap_or((1000, DELIMITER));
self.reduce_op(priority);
@@ -990,7 +1039,7 @@ impl<'a, R: Read> Parser<'a, R> {
}
#[inline]
- pub fn num_lines_read(&self) -> usize {
+ pub fn lines_read(&self) -> usize {
self.lexer.line_num
}
diff --git a/src/raw_block.rs b/src/raw_block.rs
new file mode 100644
index 00000000..d39c65ca
--- /dev/null
+++ b/src/raw_block.rs
@@ -0,0 +1,105 @@
+use core::marker::PhantomData;
+
+use std::alloc;
+use std::ptr;
+
+pub trait RawBlockTraits {
+ fn init_size() -> usize;
+ fn align() -> usize;
+}
+
+#[derive(Debug)]
+pub struct RawBlock<T: RawBlockTraits> {
+ pub base: *const u8,
+ pub top: *const u8,
+ pub ptr: *mut u8,
+ _marker: PhantomData<T>,
+}
+
+impl<T: RawBlockTraits> RawBlock<T> {
+ #[inline]
+ fn empty_block() -> Self {
+ RawBlock {
+ base: ptr::null(),
+ top: ptr::null(),
+ ptr: ptr::null_mut(),
+ _marker: PhantomData,
+ }
+ }
+
+ pub fn new() -> Self {
+ let mut block = Self::empty_block();
+
+ unsafe {
+ block.grow();
+ }
+
+ block
+ }
+
+ unsafe fn init_at_size(&mut self, cap: usize) {
+ let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
+
+ self.base = alloc::alloc(layout) as *const _;
+ self.top = (self.base as usize + cap) as *const _;
+ self.ptr = self.base as *mut _;
+ }
+
+ pub unsafe fn grow(&mut self) {
+ if self.base.is_null() {
+ self.init_at_size(T::init_size());
+ } else {
+ let size = self.size();
+ let layout = alloc::Layout::from_size_align_unchecked(size, T::align());
+
+ self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _;
+ self.top = (self.base as usize + size * 2) as *const _;
+ self.ptr = (self.base as usize + size) as *mut _;
+ }
+ }
+
+ /*
+ #[inline]
+ pub fn take(&mut self) -> Self {
+ mem::replace(self, Self::empty_block())
+ }
+ */
+
+ #[inline]
+ pub fn size(&self) -> usize {
+ self.top as usize - self.base as usize
+ }
+
+ #[inline(always)]
+ fn free_space(&self) -> usize {
+ debug_assert!(
+ self.ptr as *const _ >= self.base,
+ "self.ptr = {:?} < {:?} = self.base",
+ self.ptr,
+ self.base
+ );
+
+ self.top as usize - self.ptr as usize
+ }
+
+ pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 {
+ if self.free_space() >= size {
+ let ptr = self.ptr;
+ self.ptr = (self.ptr as usize + size) as *mut _;
+ ptr
+ } else {
+ ptr::null_mut()
+ }
+ }
+
+ pub fn deallocate(&mut self) {
+ unsafe {
+ let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
+ alloc::dealloc(self.base as *mut _, layout);
+
+ self.top = ptr::null();
+ self.base = ptr::null();
+ self.ptr = ptr::null_mut();
+ }
+ }
+}
diff --git a/src/read.rs b/src/read.rs
index 366962cb..72dc9900 100644
--- a/src/read.rs
+++ b/src/read.rs
@@ -1,263 +1,278 @@
-use prolog_parser::ast::*;
-use prolog_parser::parser::*;
-use prolog_parser::tabled_rc::TabledData;
+use crate::parser::ast::*;
+use crate::parser::parser::*;
+use crate::arena::*;
+use crate::atom_table::*;
use crate::forms::*;
use crate::iterators::*;
+use crate::machine::heap::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::MachineState;
-use crate::machine::streams::Stream;
+use crate::machine::streams::*;
+use crate::parser::char_reader::*;
+use crate::types::*;
+
+use fxhash::FxBuildHasher;
+
+use rustyline::error::ReadlineError;
+use rustyline::{Cmd, Config, Editor, KeyEvent};
use std::collections::VecDeque;
+use std::io::{Cursor, Error, ErrorKind, Read};
type SubtermDeque = VecDeque<(usize, usize)>;
-pub(crate) type PrologStream = ParsingStream<Stream>;
+// pub(crate) type PrologStream = ParsingStream<Stream>;
+
+impl MachineState {
+ pub(crate) fn devour_whitespace(
+ &mut self,
+ mut inner: Stream,
+ ) -> Result<bool, ParserError> {
+ let mut parser = Parser::new(inner, self);
+
+ parser.devour_whitespace()?;
+ inner.add_lines_read(parser.lines_read());
+
+ parser.eof()
+ }
+
+ pub(crate) fn read(
+ &mut self,
+ mut inner: Stream,
+ op_dir: &OpDir,
+ ) -> Result<TermWriteResult, ParserError> {
+ let (term, num_lines_read) = {
+ let prior_num_lines_read = inner.lines_read();
+ let mut parser = Parser::new(inner, self);
+
+ parser.add_lines_read(prior_num_lines_read);
-pub mod readline {
- use crate::machine::streams::Stream;
- use rustyline::error::ReadlineError;
- use rustyline::{Cmd, Config, Editor, KeyEvent};
- use std::io::{Cursor, Error, ErrorKind, Read};
+ let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
+ (term, parser.lines_read() - prior_num_lines_read)
+ };
- static mut PROMPT: bool = false;
+ inner.add_lines_read(num_lines_read);
+ Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl))
+ }
+}
+
+static mut PROMPT: bool = false;
- const HISTORY_FILE: &'static str = ".scryer_history";
+const HISTORY_FILE: &'static str = ".scryer_history";
+
+pub(crate) fn set_prompt(value: bool) {
+ unsafe {
+ PROMPT = value;
+ }
+}
- pub(crate) fn set_prompt(value: bool) {
- unsafe {
- PROMPT = value;
+#[inline]
+fn get_prompt() -> &'static str {
+ unsafe {
+ if PROMPT {
+ "?- "
+ } else {
+ ""
}
}
+}
+#[inline]
+pub fn input_stream(arena: &mut Arena) -> Stream {
+ let input_stream = ReadlineStream::new("");
+ Stream::from_readline_stream(input_stream, arena)
+}
+
+#[derive(Debug)]
+pub struct ReadlineStream {
+ rl: Editor<()>,
+ pending_input: Cursor<String>,
+}
+
+impl ReadlineStream {
#[inline]
- fn get_prompt() -> &'static str {
- unsafe {
- if PROMPT {
- "?- "
- } else {
- ""
+ pub fn new(pending_input: &str) -> Self {
+ let config = Config::builder().check_cursor_position(true).build();
+ let mut rl = Editor::<()>::with_config(config);
+
+ if let Some(mut path) = dirs_next::home_dir() {
+ path.push(HISTORY_FILE);
+ if path.exists() && rl.load_history(&path).is_err() {
+ println!("Warning: loading history failed");
}
}
+
+ rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
+
+ ReadlineStream {
+ rl,
+ pending_input: Cursor::new(pending_input.to_owned()),
+ }
}
- #[derive(Debug)]
- pub struct ReadlineStream {
- rl: Editor<()>,
- pending_input: Cursor<String>,
+ #[inline]
+ pub fn reset(&mut self) {
+ self.pending_input.get_mut().clear();
+ self.pending_input.set_position(0);
}
- impl ReadlineStream {
- #[inline]
- pub(crate) fn new(pending_input: String) -> Self {
- let config = Config::builder().check_cursor_position(true).build();
-
- let mut rl = Editor::<()>::with_config(config); //Editor::<()>::new();
- if let Some(mut path) = dirs_next::home_dir() {
- path.push(HISTORY_FILE);
- if path.exists() {
- if rl.load_history(&path).is_err() {
- println!("Warning: loading history failed");
+ fn call_readline(&mut self) -> std::io::Result<usize> {
+ match self.rl.readline(get_prompt()) {
+ Ok(text) => {
+ *self.pending_input.get_mut() = text;
+ self.pending_input.set_position(0);
+
+ unsafe {
+ if PROMPT {
+ self.rl.history_mut().add(self.pending_input.get_ref());
+ self.save_history();
+ PROMPT = false;
}
}
- }
- rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
- ReadlineStream {
- rl,
- pending_input: Cursor::new(pending_input),
- }
- }
+ if self.pending_input.get_ref().chars().last() != Some('\n') {
+ *self.pending_input.get_mut() += "\n";
+ }
- #[inline]
- pub(crate) fn input_stream(pending_input: String) -> Stream {
- Stream::from(Self::new(pending_input))
+ Ok(self.pending_input.get_ref().len())
+ }
+ Err(ReadlineError::Eof) => Ok(0),
+ Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
}
+ }
- fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- match self.rl.readline(get_prompt()) {
- Ok(text) => {
- *self.pending_input.get_mut() = text;
- self.pending_input.set_position(0);
-
- unsafe {
- if PROMPT {
- self.rl.history_mut().add(self.pending_input.get_ref());
- self.save_history();
- PROMPT = false;
- }
- }
-
- if self.pending_input.get_ref().chars().last() != Some('\n') {
- *self.pending_input.get_mut() += "\n";
- }
-
- self.pending_input.read(buf)
+ fn save_history(&mut self) {
+ if let Some(mut path) = dirs_next::home_dir() {
+ path.push(HISTORY_FILE);
+ if path.exists() {
+ if self.rl.append_history(&path).is_err() {
+ println!("Warning: couldn't append history (existing file)");
}
- Err(ReadlineError::Eof) => Ok(0),
- Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
+ } else if self.rl.save_history(&path).is_err() {
+ println!("Warning: couldn't save history (new file)");
}
}
+ }
- fn save_history(&mut self) {
- if let Some(mut path) = dirs_next::home_dir() {
- path.push(HISTORY_FILE);
- if path.exists() {
- if self.rl.append_history(&path).is_err() {
- println!("Warning: couldn't append history (existing file)");
+ pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
+ loop {
+ match self.pending_input.get_ref().bytes().next() {
+ Some(0) => {
+ return Ok(0);
+ }
+ Some(b) => {
+ return Ok(b);
+ }
+ None => match self.call_readline() {
+ Err(e) => {
+ return Err(e);
}
- } else {
- if self.rl.save_history(&path).is_err() {
- println!("Warning: couldn't save history (new file)");
+ Ok(0) => {
+ self.pending_input.get_mut().push('\u{0}');
+ return Ok(0);
}
- }
+ _ => {
+ set_prompt(false);
+ }
+ },
}
}
+ }
+}
- pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
- set_prompt(false);
-
- loop {
- match self.pending_input.get_ref().bytes().next() {
- Some(b) => {
- return Ok(b);
- }
- None => match self.call_readline(&mut []) {
- Err(e) => {
- return Err(e);
- }
- Ok(0) => {
- return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
- }
- _ => {}
- },
- }
+impl Read for ReadlineStream {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ match self.pending_input.read(buf) {
+ Ok(0) => {
+ self.call_readline()?;
+ self.pending_input.read(buf)
}
+ result => result
}
+ }
+}
- pub(crate) fn peek_char(&mut self) -> std::io::Result<char> {
- set_prompt(false);
+impl CharRead for ReadlineStream {
+ fn peek_char(&mut self) -> Option<std::io::Result<char>> {
+ loop {
+ let pos = self.pending_input.position() as usize;
- loop {
- match self.pending_input.get_ref().chars().next() {
- Some(c) => {
- return Ok(c);
- }
- None => match self.call_readline(&mut []) {
+ match self.pending_input.get_ref()[pos ..].chars().next() {
+ Some('\u{0}') => {
+ return Some(Ok('\u{0}'));
+ }
+ Some(c) => {
+ return Some(Ok(c));
+ }
+ None => {
+ match self.call_readline() {
Err(e) => {
- return Err(e);
+ return Some(Err(e));
}
Ok(0) => {
- return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
+ self.pending_input.get_mut().push('\u{0}');
+ return Some(Ok('\u{0}'));
}
- _ => {}
- },
+ _ => {
+ set_prompt(false);
+ }
+ }
}
}
}
}
- impl Read for ReadlineStream {
- fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- match self.pending_input.read(buf) {
- Ok(0) => self.call_readline(buf),
- result => result,
- }
- }
- }
-
- #[inline]
- pub fn input_stream() -> Stream {
- let input_stream = ReadlineStream::input_stream(String::from(""));
- Stream::from(input_stream)
+ fn consume(&mut self, nread: usize) {
+ let offset = self.pending_input.position() as usize;
+ self.pending_input.set_position((offset + nread) as u64);
}
-}
-
-impl MachineState {
- pub(crate) fn devour_whitespace(
- &mut self,
- mut inner: Stream,
- atom_tbl: TabledData<Atom>,
- ) -> Result<bool, ParserError> {
- let mut stream = parsing_stream(inner.clone())?;
- let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
-
- parser.devour_whitespace()?;
-
- inner.add_lines_read(parser.num_lines_read());
-
- let result = parser.eof();
- let buf = stream.take_buf();
-
- inner.pause_stream(buf)?;
-
- result
- }
-
- pub(crate) fn read(
- &mut self,
- mut inner: Stream,
- atom_tbl: TabledData<Atom>,
- op_dir: &OpDir,
- ) -> Result<TermWriteResult, ParserError> {
- let mut stream = parsing_stream(inner.clone())?;
-
- let (term, num_lines_read) = {
- let prior_num_lines_read = inner.lines_read();
- let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
-
- parser.add_lines_read(prior_num_lines_read);
-
- let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
- (term, parser.num_lines_read() - prior_num_lines_read)
- };
- inner.add_lines_read(num_lines_read);
-
- // 'pausing' the stream saves the pending top buffer
- // created by the parsing stream, which was created in this
- // scope and is about to be destroyed in it.
-
- let buf = stream.take_buf();
- inner.pause_stream(buf)?;
-
- Ok(write_term_to_heap(&term, self))
+ fn put_back_char(&mut self, c: char) {
+ let offset = self.pending_input.position() as usize;
+ self.pending_input.set_position((offset - c.len_utf8()) as u64);
}
}
#[inline]
-pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
- let term_writer = TermWriter::new(machine_st);
+pub(crate) fn write_term_to_heap(
+ term: &Term,
+ heap: &mut Heap,
+ atom_tbl: &mut AtomTable,
+) -> TermWriteResult {
+ let term_writer = TermWriter::new(heap, atom_tbl);
term_writer.write_term_to_heap(term)
}
#[derive(Debug)]
-struct TermWriter<'a> {
- machine_st: &'a mut MachineState,
+struct TermWriter<'a, 'b> {
+ heap: &'a mut Heap,
+ atom_tbl: &'b mut AtomTable,
queue: SubtermDeque,
var_dict: HeapVarDict,
}
#[derive(Debug)]
-pub(crate) struct TermWriteResult {
- pub(crate) heap_loc: usize,
- pub(crate) var_dict: HeapVarDict,
+pub struct TermWriteResult {
+ pub heap_loc: usize,
+ pub var_dict: HeapVarDict,
}
-impl<'a> TermWriter<'a> {
+impl<'a, 'b> TermWriter<'a, 'b> {
#[inline]
- fn new(machine_st: &'a mut MachineState) -> Self {
+ fn new(heap: &'a mut Heap, atom_tbl: &'b mut AtomTable) -> Self {
TermWriter {
- machine_st,
+ heap,
+ atom_tbl,
queue: SubtermDeque::new(),
- var_dict: HeapVarDict::new(),
+ var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
}
}
#[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));
+ self.heap[site_h] = self.term_as_addr(term, h);
if arity > 1 {
self.queue.push_front((arity - 1, site_h + 1));
@@ -267,64 +282,87 @@ impl<'a> TermWriter<'a> {
#[inline]
fn push_stub_addr(&mut self) {
- let h = self.machine_st.heap.h();
- self.machine_st
- .heap
- .push(HeapCellValue::Addr(Addr::HeapCell(h)));
+ let h = self.heap.len();
+ self.heap.push(heap_loc_as_cell!(h));
}
- fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
+ fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> HeapCellValue {
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),
+ &TermRef::Cons(..) => list_loc_as_cell!(h),
+ &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
+ &TermRef::PartialString(_, _, ref src, None) =>
+ if src.as_str().is_empty() {
+ empty_list_as_cell!()
+ } else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
+ heap_loc_as_cell!(h)
+ } else {
+ pstr_loc_as_cell!(h)
+ },
+ &TermRef::PartialString(..) => pstr_loc_as_cell!(h),
+ &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
+ &TermRef::Clause(_,_,_,subterms) if subterms.len() == 0 => heap_loc_as_cell!(h),
+ &TermRef::Clause(..) => str_loc_as_cell!(h),
}
}
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
- let heap_loc = self.machine_st.heap.h();
+ let heap_loc = self.heap.len();
for term in breadth_first_iter(term, true) {
- let h = self.machine_st.heap.h();
+ let h = self.heap.len();
match &term {
- &TermRef::Cons(lvl, ..) => {
+ &TermRef::Cons(Level::Root, ..) => {
self.queue.push_back((2, h + 1));
- self.machine_st
- .heap
- .push(HeapCellValue::Addr(Addr::Lis(h + 1)));
+ self.heap.push(list_loc_as_cell!(h + 1));
self.push_stub_addr();
self.push_stub_addr();
- if let Level::Root = lvl {
- continue;
- }
+ continue;
}
- &TermRef::Clause(lvl, _, ref ct, subterms) => {
- self.queue.push_back((subterms.len(), h + 1));
- let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
+ &TermRef::Cons(..) => {
+ self.queue.push_back((2, h));
- self.machine_st.heap.push(named);
+ self.push_stub_addr();
+ self.push_stub_addr();
+ }
+ &TermRef::Clause(Level::Root, _, ref ct, subterms) => {
+ self.heap.push(if subterms.len() == 0 {
+ heap_loc_as_cell!(heap_loc + 1)
+ } else {
+ str_loc_as_cell!(heap_loc + 1)
+ });
+
+ self.queue.push_back((subterms.len(), h + 2));
+ let named = atom_as_cell!(ct.name(), subterms.len());
+
+ self.heap.push(named);
for _ in 0..subterms.len() {
self.push_stub_addr();
}
- if let Level::Root = lvl {
- continue;
+ continue;
+ }
+ &TermRef::Clause(_, _, ref ct, subterms) => {
+ self.queue.push_back((subterms.len(), h + 1));
+ let named = atom_as_cell!(ct.name(), subterms.len());
+
+ self.heap.push(named);
+
+ for _ in 0..subterms.len() {
+ self.push_stub_addr();
}
}
- &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => {
+ &TermRef::AnonVar(Level::Root) | &TermRef::Literal(Level::Root, ..) => {
let addr = self.term_as_addr(&term, h);
- self.machine_st.heap.push(HeapCellValue::Addr(addr));
+ self.heap.push(addr);
}
&TermRef::Var(Level::Root, _, ref var) => {
let addr = self.term_as_addr(&term, h);
- self.var_dict.insert(var.clone(), Addr::HeapCell(h));
- self.machine_st.heap.push(HeapCellValue::Addr(addr));
+ self.var_dict.insert(var.clone(), heap_loc_as_cell!(h));
+ self.heap.push(addr);
}
&TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = self.queue.pop_front() {
@@ -335,25 +373,28 @@ impl<'a> TermWriter<'a> {
continue;
}
- &TermRef::PartialString(lvl, _, ref pstr, tail) => {
+ &TermRef::PartialString(lvl, _, ref src, tail) => {
if tail.is_some() {
- self.machine_st.heap.allocate_pstr(&pstr);
+ allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
} else {
- self.machine_st.heap.put_complete_string(&pstr);
+ put_complete_string(self.heap, src.as_str(), self.atom_tbl);
}
- if let Level::Root = lvl {
- } else if tail.is_some() {
- let h = self.machine_st.heap.h();
+ if tail.is_some() {
+ let h = self.heap.len();
self.queue.push_back((1, h - 1));
+
+ if let Level::Root = lvl {
+ continue;
+ }
}
}
&TermRef::Var(_, _, ref var) => {
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);
+ self.heap[site_h] = addr;
} else {
- self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
+ self.var_dict.insert(var.clone(), heap_loc_as_cell!(site_h));
}
if arity > 1 {
diff --git a/src/targets.rs b/src/targets.rs
index 78e988e5..cbb469f9 100644
--- a/src/targets.rs
+++ b/src/targets.rs
@@ -1,37 +1,41 @@
-use prolog_parser::ast::*;
+use crate::parser::ast::*;
-use crate::clause_types::*;
+use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
+use crate::types::*;
+
+pub(crate) struct FactInstruction;
+pub(crate) struct QueryInstruction;
pub(crate) trait CompilationTarget<'a> {
type Iterator: Iterator<Item = TermRef<'a>>;
- fn iter(_: &'a Term) -> Self::Iterator;
+ fn iter(term: &'a Term) -> Self::Iterator;
- fn to_constant(_: Level, _: Constant, _: RegType) -> Self;
- fn to_list(_: Level, _: RegType) -> Self;
- fn to_structure(_: ClauseType, _: usize, _: RegType) -> Self;
+ fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
+ fn to_list(lvl: Level, r: RegType) -> Instruction;
+ fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction;
- fn to_void(_: usize) -> Self;
- fn is_void_instr(&self) -> bool;
+ fn to_void(num_subterms: usize) -> Instruction;
+ fn is_void_instr(instr: &Instruction) -> bool;
- fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self;
+ fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction;
- fn incr_void_instr(&mut self);
+ fn incr_void_instr(instr: &mut Instruction);
- fn constant_subterm(_: Constant) -> Self;
+ fn constant_subterm(literal: Literal) -> Instruction;
- fn argument_to_variable(_: RegType, _: usize) -> Self;
- fn argument_to_value(_: RegType, _: usize) -> Self;
+ fn argument_to_variable(r: RegType, r: usize) -> Instruction;
+ fn argument_to_value(r: RegType, val: usize) -> Instruction;
- fn move_to_register(_: RegType, _: usize) -> Self;
+ fn move_to_register(r: RegType, val: usize) -> Instruction;
- fn subterm_to_variable(_: RegType) -> Self;
- fn subterm_to_value(_: RegType) -> Self;
+ fn subterm_to_variable(r: RegType) -> Instruction;
+ fn subterm_to_value(r: RegType) -> Instruction;
- fn clause_arg_to_instr(_: RegType) -> Self;
+ fn clause_arg_to_instr(r: RegType) -> Instruction;
}
impl<'a> CompilationTarget<'a> for FactInstruction {
@@ -41,66 +45,66 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
breadth_first_iter(term, false) // do not iterate over the root clause if one exists.
}
- fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
- FactInstruction::GetConstant(lvl, constant, reg)
+ fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+ Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
}
- fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self {
- FactInstruction::GetStructure(ct, arity, reg)
+ fn to_structure(name: Atom, arity: usize, reg: RegType) -> Instruction {
+ Instruction::GetStructure(name, arity, reg)
}
- fn to_list(lvl: Level, reg: RegType) -> Self {
- FactInstruction::GetList(lvl, reg)
+ fn to_list(lvl: Level, reg: RegType) -> Instruction {
+ Instruction::GetList(lvl, reg)
}
- fn to_void(subterms: usize) -> Self {
- FactInstruction::UnifyVoid(subterms)
+ fn to_void(num_subterms: usize) -> Instruction {
+ Instruction::UnifyVoid(num_subterms)
}
- fn is_void_instr(&self) -> bool {
- match self {
- &FactInstruction::UnifyVoid(_) => true,
+ fn is_void_instr(instr: &Instruction) -> bool {
+ match instr {
+ &Instruction::UnifyVoid(_) => true,
_ => false,
}
}
- fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
- FactInstruction::GetPartialString(lvl, string, r, has_tail)
+ fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
+ Instruction::GetPartialString(lvl, string, r, has_tail)
}
- fn incr_void_instr(&mut self) {
- match self {
- &mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
+ fn incr_void_instr(instr: &mut Instruction) {
+ match instr {
+ &mut Instruction::UnifyVoid(ref mut incr) => *incr += 1,
_ => {}
}
}
- fn constant_subterm(constant: Constant) -> Self {
- FactInstruction::UnifyConstant(constant)
+ fn constant_subterm(constant: Literal) -> Instruction {
+ Instruction::UnifyConstant(HeapCellValue::from(constant))
}
- fn argument_to_variable(arg: RegType, val: usize) -> Self {
- FactInstruction::GetVariable(arg, val)
+ fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
+ Instruction::GetVariable(arg, val)
}
- fn move_to_register(arg: RegType, val: usize) -> Self {
- FactInstruction::GetVariable(arg, val)
+ fn move_to_register(arg: RegType, val: usize) -> Instruction {
+ Instruction::GetVariable(arg, val)
}
- fn argument_to_value(arg: RegType, val: usize) -> Self {
- FactInstruction::GetValue(arg, val)
+ fn argument_to_value(arg: RegType, val: usize) -> Instruction {
+ Instruction::GetValue(arg, val)
}
- fn subterm_to_variable(val: RegType) -> Self {
- FactInstruction::UnifyVariable(val)
+ fn subterm_to_variable(val: RegType) -> Instruction {
+ Instruction::UnifyVariable(val)
}
- fn subterm_to_value(val: RegType) -> Self {
- FactInstruction::UnifyValue(val)
+ fn subterm_to_value(val: RegType) -> Instruction {
+ Instruction::UnifyValue(val)
}
- fn clause_arg_to_instr(val: RegType) -> Self {
- FactInstruction::UnifyVariable(val)
+ fn clause_arg_to_instr(val: RegType) -> Instruction {
+ Instruction::UnifyVariable(val)
}
}
@@ -111,65 +115,65 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
post_order_iter(term)
}
- fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self {
- QueryInstruction::PutStructure(ct, arity, r)
+ fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction {
+ Instruction::PutStructure(name, arity, r)
}
- fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
- QueryInstruction::PutConstant(lvl, constant, reg)
+ fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+ Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
}
- fn to_list(lvl: Level, reg: RegType) -> Self {
- QueryInstruction::PutList(lvl, reg)
+ fn to_list(lvl: Level, reg: RegType) -> Instruction {
+ Instruction::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_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
+ Instruction::PutPartialString(lvl, string, r, has_tail)
}
- fn to_void(subterms: usize) -> Self {
- QueryInstruction::SetVoid(subterms)
+ fn to_void(subterms: usize) -> Instruction {
+ Instruction::SetVoid(subterms)
}
- fn is_void_instr(&self) -> bool {
- match self {
- &QueryInstruction::SetVoid(_) => true,
+ fn is_void_instr(instr: &Instruction) -> bool {
+ match instr {
+ &Instruction::SetVoid(_) => true,
_ => false,
}
}
- fn incr_void_instr(&mut self) {
- match self {
- &mut QueryInstruction::SetVoid(ref mut incr) => *incr += 1,
+ fn incr_void_instr(instr: &mut Instruction) {
+ match instr {
+ &mut Instruction::SetVoid(ref mut incr) => *incr += 1,
_ => {}
}
}
- fn constant_subterm(constant: Constant) -> Self {
- QueryInstruction::SetConstant(constant)
+ fn constant_subterm(constant: Literal) -> Instruction {
+ Instruction::SetConstant(HeapCellValue::from(constant))
}
- fn argument_to_variable(arg: RegType, val: usize) -> Self {
- QueryInstruction::PutVariable(arg, val)
+ fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
+ Instruction::PutVariable(arg, val)
}
- fn move_to_register(arg: RegType, val: usize) -> Self {
- QueryInstruction::GetVariable(arg, val)
+ fn move_to_register(arg: RegType, val: usize) -> Instruction {
+ Instruction::GetVariable(arg, val)
}
- fn argument_to_value(arg: RegType, val: usize) -> Self {
- QueryInstruction::PutValue(arg, val)
+ fn argument_to_value(arg: RegType, val: usize) -> Instruction {
+ Instruction::PutValue(arg, val)
}
- fn subterm_to_variable(val: RegType) -> Self {
- QueryInstruction::SetVariable(val)
+ fn subterm_to_variable(val: RegType) -> Instruction {
+ Instruction::SetVariable(val)
}
- fn subterm_to_value(val: RegType) -> Self {
- QueryInstruction::SetValue(val)
+ fn subterm_to_value(val: RegType) -> Instruction {
+ Instruction::SetValue(val)
}
- fn clause_arg_to_instr(val: RegType) -> Self {
- QueryInstruction::SetValue(val)
+ fn clause_arg_to_instr(val: RegType) -> Instruction {
+ Instruction::SetValue(val)
}
}
diff --git a/crates/prolog_parser/tests/bom.rs b/src/tests/bom.rs
index 8a92c127..9a394d63 100644
--- a/crates/prolog_parser/tests/bom.rs
+++ b/src/tests/bom.rs
@@ -1,8 +1,6 @@
-use prolog_parser::ast::*;
-use prolog_parser::lexer::{Lexer, Token};
-use prolog_parser::tabled_rc::TabledData;
-
-use std::rc::Rc;
+use crate::atom_table::*;
+use crate::parser::ast::*;
+use crate::parser::lexer::{Lexer, Token};
#[test]
fn valid_token() {
@@ -18,13 +16,12 @@ fn empty_stream() {
#[test]
fn skip_utf8_bom() {
- let atom_tbl = TabledData::new(Rc::new("my_module".to_string()));
- let flags = MachineFlags::default();
+ let mut machine_st = MachineState::new();
let bytes: &[u8] = &[0xEF, 0xBB, 0xBF, '4' as u8, '\n' as u8];
- let mut stream = parsing_stream(bytes).expect("valid stream");
- let mut lexer = Lexer::new(atom_tbl, flags, &mut stream);
+ let stream = parsing_stream(bytes).expect("valid stream");
+ let mut lexer = Lexer::new(stream, &mut machine_st);
match lexer.next_token() {
- Ok(Token::Constant(Constant::Fixnum(4))) => (),
+ Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))) => (),
_ => assert!(false),
}
}
diff --git a/src/tests/builtins.pl b/src/tests/builtins.pl
index 96b5e4c0..a87fc22a 100644
--- a/src/tests/builtins.pl
+++ b/src/tests/builtins.pl
@@ -115,14 +115,6 @@ test_queries_on_builtins :-
1.1 @< 1,
1.0 @=< 1,
\+ 1 @=< 1.0,
- \+ \+ (variant(X, Y)),
- \+ (variant(f(X), f(x))),
- \+ \+ (variant(X, X)),
- \+ \+ (variant(f(x), f(x))),
- \+ (variant([X,Y,Z], [V,W,V])),
- \+ \+ (variant([X,Y,Z], [V,W,Z])),
- \+ \+ (variant([X,Y,X], [V,W,V])),
- \+ \+ (g(B) = B, g(A) = A, variant(A, B)),
keysort([1-1,1-1],[1-1,1-1]),
\+ \+ findall(Sorted, keysort([2-99,1-a,3-f(_),1-z,1-a,2-44],Sorted), [[1-a,1-z,1-a,2-99,2-44,3-f(_)]]),
\+ \+ findall(X, keysort([X-1,1-1],[2-1,1-1]), [2]).
diff --git a/src/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl
index a1cf2a4e..18fda2dd 100644
--- a/src/tests/call_with_inference_limit.pl
+++ b/src/tests/call_with_inference_limit.pl
@@ -16,39 +16,40 @@ test_queries_on_call_with_inference_limit :-
\+ call_with_inference_limit(g(X), 5, R),
maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]),
findall([R,X],
- call_with_inference_limit(g(X), 10, R),
+ call_with_inference_limit(g(X), 11, R),
[[true, 1],
[true, 2],
[true, 3],
[true, 4],
[!, 5]]),
findall([R,X],
- (call_with_inference_limit(g(X), 10, R), call(true)),
+ (call_with_inference_limit(g(X), 11, R), call(true)),
[[true, 1],
[true, 2],
[true, 3],
[true, 4],
[!, 5]]),
findall([R,X],
- (call_with_inference_limit(g(X), 4, R), call(true)),
+ (call_with_inference_limit(g(X), 5, R), call(true)),
[[true, 1],
[true, 2],
[inference_limit_exceeded, _]]),
findall([X,R1,R2],
- (call_with_inference_limit(g(X), 4, R1),
- call_with_inference_limit(g(X), 5, R2)),
+ (call_with_inference_limit(g(X), 5, R1),
+ call_with_inference_limit(g(X), 6, R2)),
[[1,true,!],
[2,true,!],
[3,true,!],
[4,true,!],
[5,!,!]]),
- \+ \+ assertz((f(X) :- call_with_inference_limit(g(X), 8, _))),
+ \+ \+ assertz((f(X) :- call_with_inference_limit(tests_on_call_with_inference_limit:g(X), 11, _))),
findall([R,X],
- call_with_inference_limit(f(X), 12, R),
- [[true,1],
- [true,2],
- [true,3],
- [true,4],
- [!,5]]).
+ call_with_inference_limit(f(X), 14, R),
+ Solutions),
+ Solutions == [[true,1],
+ [true,2],
+ [true,3],
+ [true,4],
+ [!,5]].
:- initialization(test_queries_on_call_with_inference_limit).
diff --git a/crates/prolog_parser/tests/parse_tokens.rs b/src/tests/parse_tokens.rs
index 69b63286..a4763b4d 100644
--- a/crates/prolog_parser/tests/parse_tokens.rs
+++ b/src/tests/parse_tokens.rs
@@ -1,14 +1,11 @@
-use prolog_parser::ast::*;
-use prolog_parser::lexer::{Lexer, Token};
-use prolog_parser::tabled_rc::TabledData;
-
-use std::rc::Rc;
+use crate::atom_table::*;
+use crate::parser::ast::*;
+use crate::parser::lexer::{Lexer, Token};
fn read_all_tokens(text: &str) -> Result<Vec<Token>, ParserError> {
- let atom_tbl = TabledData::new(Rc::new("my_module".to_string()));
- let flags = MachineFlags::default();
- let mut stream = parsing_stream(text.as_bytes())?;
- let mut lexer = Lexer::new(atom_tbl, flags, &mut stream);
+ let mut machine_st = MachineState::new();
+ let stream = parsing_stream(text.as_bytes())?;
+ let mut lexer = Lexer::new(stream, &mut machine_st);
let mut tokens = Vec::new();
while !lexer.eof()? {
@@ -21,21 +18,21 @@ fn read_all_tokens(text: &str) -> Result<Vec<Token>, ParserError> {
#[test]
fn empty_multiline_comment() -> Result<(), ParserError> {
let tokens = read_all_tokens("/**/ 4\n")?;
- assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]);
+ assert_eq!(tokens, [Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))]);
Ok(())
}
#[test]
fn any_char_multiline_comment() -> Result<(), ParserError> {
let tokens = read_all_tokens("/* █╗╚═══╝ © */ 4\n")?;
- assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]);
+ assert_eq!(tokens, [Token::Literal(Literal::Fixnum(4))]);
Ok(())
}
#[test]
fn simple_char() -> Result<(), ParserError> {
let tokens = read_all_tokens("'a'\n")?;
- assert_eq!(tokens, [Token::Constant(Constant::Char('a'))]);
+ assert_eq!(tokens, [Token::Literal(Literal::Char('a'))]);
Ok(())
}
@@ -45,10 +42,10 @@ fn char_with_meta_seq() -> Result<(), ParserError> {
assert_eq!(
tokens,
[
- Token::Constant(Constant::Char('\\')),
- Token::Constant(Constant::Char('\'')),
- Token::Constant(Constant::Char('"')),
- Token::Constant(Constant::Char('`'))
+ Token::Literal(Literal::Char('\\')),
+ Token::Literal(Literal::Char('\'')),
+ Token::Literal(Literal::Char('"')),
+ Token::Literal(Literal::Char('`'))
]
);
Ok(())
@@ -60,13 +57,13 @@ fn char_with_control_seq() -> Result<(), ParserError> {
assert_eq!(
tokens,
[
- Token::Constant(Constant::Char('\u{07}')),
- Token::Constant(Constant::Char('\u{08}')),
- Token::Constant(Constant::Char('\r')),
- Token::Constant(Constant::Char('\u{0c}')),
- Token::Constant(Constant::Char('\t')),
- Token::Constant(Constant::Char('\n')),
- Token::Constant(Constant::Char('\u{0b}')),
+ Token::Literal(Literal::Char('\u{07}')),
+ Token::Literal(Literal::Char('\u{08}')),
+ Token::Literal(Literal::Char('\r')),
+ Token::Literal(Literal::Char('\u{0c}')),
+ Token::Literal(Literal::Char('\t')),
+ Token::Literal(Literal::Char('\n')),
+ Token::Literal(Literal::Char('\u{0b}')),
]
);
Ok(())
@@ -75,21 +72,21 @@ fn char_with_control_seq() -> Result<(), ParserError> {
#[test]
fn char_with_octseq() -> Result<(), ParserError> {
let tokens = read_all_tokens(r"'\60433\' ")?;
- assert_eq!(tokens, [Token::Constant(Constant::Char('愛'))]); // Japanese character
+ assert_eq!(tokens, [Token::Literal(Literal::Char('愛'))]); // Japanese character
Ok(())
}
#[test]
fn char_with_octseq_0() -> Result<(), ParserError> {
let tokens = read_all_tokens(r"'\0\' ")?;
- assert_eq!(tokens, [Token::Constant(Constant::Char('\u{0000}'))]);
+ assert_eq!(tokens, [Token::Literal(Literal::Char('\u{0000}'))]);
Ok(())
}
#[test]
fn char_with_hexseq() -> Result<(), ParserError> {
let tokens = read_all_tokens(r"'\x2124\' ")?;
- assert_eq!(tokens, [Token::Constant(Constant::Char('ℤ'))]); // Z math symbol
+ assert_eq!(tokens, [Token::Literal(Literal::Char('ℤ'))]); // Z math symbol
Ok(())
}
diff --git a/src/toplevel.pl b/src/toplevel.pl
index fdc5c18f..90e0a3a8 100644
--- a/src/toplevel.pl
+++ b/src/toplevel.pl
@@ -2,8 +2,10 @@
copy_term/3]).
:- use_module(library(charsio)).
+:- use_module(library(error)).
:- use_module(library(files)).
:- use_module(library(iso_ext)).
+:- use_module(library(lambda)).
:- use_module(library(lists)).
:- use_module(library(si)).
@@ -17,7 +19,7 @@ load_scryerrc :-
append(HomeDir, "/.scryerrc", ScryerrcFile),
( file_exists(ScryerrcFile) ->
atom_chars(ScryerrcFileAtom, ScryerrcFile),
- catch(consult(ScryerrcFileAtom), E, print_exception(E))
+ catch(use_module(ScryerrcFileAtom), E, print_exception(E))
; true
)
; true
@@ -111,7 +113,7 @@ run_goals([g(Gs0)|Goals]) :-
( ends_with_dot(Gs0) -> Gs1 = Gs0
; append(Gs0, ".", Gs1)
),
- read_term_from_chars(Gs1, Goal),
+ read_from_chars(Gs1, Goal),
( catch(
user:Goal,
Exception,
@@ -152,26 +154,27 @@ instruction_match(Term, VarList) :-
( var(Term) ->
throw(error(instantiation_error, repl/0))
; Term = [Item] ->
- !,
( atom(Item) ->
- ( Item == user ->
- catch(load(user_input), E, print_exception_with_check(E))
- ;
+ ( Item == user ->
+ catch(load(user_input), E, print_exception_with_check(E))
+ ;
submit_query_and_print_results(consult(Item), [])
- )
+ )
; catch(type_error(atom, Item, repl/0),
- E,
- print_exception_with_check(E))
+ E,
+ print_exception_with_check(E))
)
; Term = end_of_file ->
halt
;
- submit_query_and_print_results(Term, VarList)
+ submit_query_and_print_results(Term, VarList)
).
submit_query_and_print_results_(Term, VarList) :-
'$get_b_value'(B),
+ bb_put('$report_all', false),
+ bb_put('$report_n_more', 0),
'$call'(Term),
write_eqs_and_read_input(B, VarList),
!.
@@ -184,7 +187,7 @@ submit_query_and_print_results(Term0, VarList) :-
( functor(Term0, call, _) ->
Term = Term0 % prevent pre-mature expansion of incomplete goal
% in the first argument, which is done by call/N
- ; expand_goal(call(Term0), user, call(Term))
+ ; expand_goal(Term0, user, Term)
),
setup_call_cleanup(bb_put('$first_answer', true),
submit_query_and_print_results_(Term, VarList),
@@ -193,10 +196,10 @@ submit_query_and_print_results(Term0, VarList) :-
needs_bracketing(Value, Op) :-
catch((functor(Value, F, _),
- current_op(EqPrec, EqSpec, Op),
- current_op(FPrec, _, F)),
- _,
- false),
+ current_op(EqPrec, EqSpec, Op),
+ current_op(FPrec, _, F)),
+ _,
+ false),
( EqPrec < FPrec ->
true
; FPrec > 0, F == Value, graphic_token_char(F) ->
@@ -210,15 +213,15 @@ needs_bracketing(Value, Op) :-
write_goal(G, VarList, MaxDepth) :-
( G = (Var = Value) ->
( var(Value) ->
- select((Var = _), VarList, NewVarList)
+ select((Var = _), VarList, NewVarList)
; VarList = NewVarList
),
write(Var),
write(' = '),
( needs_bracketing(Value, (=)) ->
- write('('),
- write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
- write(')')
+ write('('),
+ write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
+ write(')')
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)])
)
; G == [] ->
@@ -229,20 +232,20 @@ write_goal(G, VarList, MaxDepth) :-
write_last_goal(G, VarList, MaxDepth) :-
( G = (Var = Value) ->
( var(Value) ->
- select((Var = _), VarList, NewVarList)
+ select((Var = _), VarList, NewVarList)
; VarList = NewVarList
),
write(Var),
write(' = '),
( needs_bracketing(Value, (=)) ->
- write('('),
- write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
- write(')')
+ write('('),
+ write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
+ write(')')
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
- ( trailing_period_is_ambiguous(Value) ->
- write(' ')
- ; true
- )
+ ( trailing_period_is_ambiguous(Value) ->
+ write(' ')
+ ; true
+ )
)
; G == [] ->
write('true')
@@ -272,8 +275,13 @@ trailing_period_is_ambiguous(Value) :-
ValueChars \== ['.'],
graphic_token_char(Char).
+term_variables_under_max_depth(Term, MaxDepth, Vars) :-
+ '$term_variables_under_max_depth'(Term, MaxDepth, Vars).
+
write_eqs_and_read_input(B, VarList) :-
- term_variables(VarList, Vars0),
+ gather_query_vars(VarList, OrigVars),
+ % one layer of depth added for (=/2) functor
+ '$term_variables_under_max_depth'(OrigVars, 22, Vars0),
'$term_attributed_variables'(VarList, AttrVars),
'$project_atts':project_attributes(Vars0, AttrVars),
copy_term(AttrVars, AttrVars, AttrGoals),
@@ -281,12 +289,13 @@ write_eqs_and_read_input(B, VarList) :-
append([Vars0, AttrGoalVars, AttrVars], Vars),
charsio:extend_var_list(Vars, VarList, NewVarList, fabricated),
'$get_b_value'(B0),
- gather_query_vars(VarList, OrigVars),
gather_equations(NewVarList, OrigVars, Equations),
append(Equations, AttrGoals, Goals),
- term_variables(Equations, EquationVars),
- append([AttrGoalVars, EquationVars], Vars1),
- charsio:extend_var_list(Vars1, VarList, NewVarList0, fabricated),
+ % one layer of depth added for (=/2) functor
+ maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
+ append([AttrGoalVars | EquationVars], Vars1),
+ term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
+ charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
( bb_get('$first_answer', true) ->
write(' '),
bb_put('$first_answer', false)
@@ -294,11 +303,11 @@ write_eqs_and_read_input(B, VarList) :-
),
( B0 == B ->
( Goals == [] ->
- write('true.'), nl
+ write('true.'), nl
; loader:thread_goals(Goals, ThreadedGoals, (',')),
- write_eq(ThreadedGoals, NewVarList0, 20),
- write('.'),
- nl
+ write_eq(ThreadedGoals, NewVarList0, 20),
+ write('.'),
+ nl
)
; loader:thread_goals(Goals, ThreadedGoals, (',')),
write_eq(ThreadedGoals, NewVarList0, 20),
@@ -306,7 +315,14 @@ write_eqs_and_read_input(B, VarList) :-
).
read_input(ThreadedGoals, NewVarList) :-
- get_single_char(C),
+ ( bb_get('$report_all', true) ->
+ C = n
+ ; bb_get('$report_n_more', N), N > 1 ->
+ N1 is N - 1,
+ bb_put('$report_n_more', N1),
+ C = n
+ ; get_single_char(C)
+ ),
( C = w ->
nl,
write(' '),
@@ -323,7 +339,13 @@ read_input(ThreadedGoals, NewVarList) :-
help_message,
read_input(ThreadedGoals, NewVarList)
; member(C, ['\n', .]) ->
- nl, write('; ...'), nl
+ nl, write('; ... .'), nl
+ ; C = a ->
+ bb_put('$report_all', true),
+ nl, write('; '), false
+ ; C = f ->
+ bb_put('$report_n_more', 5),
+ nl, write('; '), false
; read_input(ThreadedGoals, NewVarList)
).
@@ -331,6 +353,8 @@ help_message :-
nl, nl,
write('SPACE, "n" or ";": next solution, if any\n'),
write('RETURN or ".": stop enumeration\n'),
+ write('"a": enumerate all solutions\n'),
+ write('"f": enumerate the next 5 solutions\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').
@@ -340,7 +364,7 @@ gather_query_vars([_ = Var | Vars], QueryVars) :-
QueryVars = [Var | QueryVars0],
gather_query_vars(Vars, QueryVars0)
;
- gather_query_vars(Vars, QueryVars)
+ gather_query_vars(Vars, QueryVars)
).
gather_query_vars([], []).
@@ -358,8 +382,8 @@ select_all([OtherVar = OtherValue | Pairs], Var, Value, Vars, NewPairs) :-
Vars = [OtherVar = OtherValue | Vars0],
select_all(Pairs, Var, Value, Vars0, NewPairs)
;
- NewPairs = [OtherVar = OtherValue | NewPairs0],
- select_all(Pairs, Var, Value, Vars, NewPairs0)
+ NewPairs = [OtherVar = OtherValue | NewPairs0],
+ select_all(Pairs, Var, Value, Vars, NewPairs0)
).
gather_equations([], _, []).
@@ -370,11 +394,11 @@ gather_equations([Var = Value | Pairs], OrigVarList, Goals) :-
append([Var = Value | VarEqs], Goals0, Goals),
gather_equations(NewPairs, OrigVarList, Goals0)
;
- gather_equations(Pairs, OrigVarList, Goals)
+ gather_equations(Pairs, OrigVarList, Goals)
)
;
- Goals = [Var = Value | Goals0],
- gather_equations(Pairs, OrigVarList, Goals0)
+ Goals = [Var = Value | Goals0],
+ gather_equations(Pairs, OrigVarList, Goals0)
).
print_exception(E) :-
diff --git a/src/types.rs b/src/types.rs
new file mode 100644
index 00000000..b151ee23
--- /dev/null
+++ b/src/types.rs
@@ -0,0 +1,810 @@
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::forms::*;
+use crate::machine::machine_indices::*;
+use crate::machine::partial_string::PartialString;
+use crate::machine::streams::*;
+use crate::parser::ast::Fixnum;
+use crate::parser::rug::{Integer, Rational};
+
+use ordered_float::OrderedFloat;
+
+use std::cmp::Ordering;
+use std::convert::TryFrom;
+use std::fmt;
+use std::mem;
+use std::ops::{Add, Sub, SubAssign};
+
+#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[bits = 6]
+pub enum HeapCellValueTag {
+ // non-constants / tags with adjoining forwarding bits.
+ Cons = 0b00,
+ F64 = 0b01,
+ Str = 0b000010,
+ Lis = 0b000011,
+ Var = 0b000110,
+ StackVar = 0b000111,
+ AttrVar = 0b010011,
+ PStrLoc = 0b111111,
+ PStrOffset = 0b001110,
+ // constants.
+ Fixnum = 0b010010,
+ Char = 0b011011,
+ Atom = 0b001010,
+ PStr = 0b001011,
+ CStr = 0b010110, // a complete string.
+}
+
+#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[bits = 6]
+pub enum HeapCellValueView {
+ // non-constants / tags with adjoining forwarding bits.
+ Cons = 0b00,
+ F64 = 0b01,
+ Str = 0b000010,
+ Lis = 0b000011,
+ Var = 0b000110,
+ StackVar = 0b000111,
+ AttrVar = 0b010011,
+ PStrLoc = 0b111111,
+ PStrOffset = 0b001110,
+ // constants.
+ Fixnum = 0b010010,
+ Char = 0b011011,
+ Atom = 0b001010,
+ PStr = 0b001011,
+ CStr = 0b010110,
+ // trail elements.
+ TrailedHeapVar = 0b011110,
+ TrailedStackVar = 0b011111,
+ TrailedAttrVarHeapLink = 0b101110,
+ TrailedAttrVarListLink = 0b100010,
+ TrailedAttachedValue = 0b101010,
+ TrailedBlackboardEntry = 0b100110,
+ TrailedBlackboardOffset = 0b100111,
+}
+
+#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[bits = 2]
+pub enum ConsPtrMaskTag {
+ Cons = 0b00,
+ F64 = 0b01,
+}
+
+#[bitfield]
+#[repr(u64)]
+#[derive(Copy, Clone, Debug)]
+pub struct ConsPtr {
+ ptr: B61,
+ m: bool,
+ tag: ConsPtrMaskTag,
+}
+
+impl ConsPtr {
+ #[inline(always)]
+ pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
+ ConsPtr::new()
+ .with_ptr(ptr as *const u8 as u64)
+ .with_m(false)
+ .with_tag(tag)
+ }
+
+ #[inline]
+ pub fn as_ptr(self) -> *mut u8 {
+ self.ptr() as *mut _
+ }
+}
+
+#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
+#[bits = 6]
+pub(crate) enum RefTag {
+ HeapCell = 0b0110,
+ StackCell = 0b111,
+ AttrVar = 0b10011,
+}
+
+#[bitfield]
+#[repr(u64)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Ref {
+ val: B56,
+ #[allow(unused)] m: bool,
+ #[allow(unused)] f: bool,
+ tag: RefTag,
+}
+
+impl Ord for Ref {
+ fn cmp(&self, rhs: &Ref) -> Ordering {
+ match self.get_tag() {
+ RefTag::HeapCell | RefTag::AttrVar => {
+ match rhs.get_tag() {
+ RefTag::StackCell => Ordering::Less,
+ _ => self.get_value().cmp(&rhs.get_value()),
+ }
+ }
+ RefTag::StackCell => {
+ match rhs.get_tag() {
+ RefTag::StackCell =>
+ self.get_value().cmp(&rhs.get_value()),
+ _ =>
+ Ordering::Greater,
+ }
+ }
+ }
+ }
+}
+
+impl PartialOrd for Ref {
+ fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
+ Some(self.cmp(rhs))
+ }
+}
+
+impl Ref {
+ #[inline(always)]
+ pub(crate) fn build_with(tag: RefTag, value: u64) -> Self {
+ Ref::new().with_tag(tag).with_val(value)
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_tag(self) -> RefTag {
+ self.tag()
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_value(self) -> u64 {
+ self.val()
+ }
+
+ #[inline(always)]
+ pub(crate) fn as_heap_cell_value(self) -> HeapCellValue {
+ HeapCellValue::from_bytes(self.into_bytes())
+ }
+
+ #[inline(always)]
+ pub(crate) fn heap_cell(h: usize) -> Self {
+ Ref::build_with(RefTag::HeapCell, h as u64)
+ }
+
+ #[inline(always)]
+ pub(crate) fn stack_cell(h: usize) -> Self {
+ Ref::build_with(RefTag::StackCell, h as u64)
+ }
+
+ #[inline(always)]
+ pub(crate) fn attr_var(h: usize) -> Self {
+ Ref::build_with(RefTag::AttrVar, h as u64)
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum TrailRef {
+ Ref(Ref),
+ AttrVarHeapLink(usize),
+ AttrVarListLink(usize, usize),
+ BlackboardEntry(Atom),
+ BlackboardOffset(Atom, HeapCellValue), // key atom, key value
+}
+
+#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[bits = 6]
+pub(crate) enum TrailEntryTag {
+ TrailedHeapVar = 0b011110,
+ TrailedStackVar = 0b011111,
+ TrailedAttrVar = 0b101110,
+ TrailedAttrVarHeapLink = 0b100010,
+ TrailedAttrVarListLink = 0b100011,
+ TrailedAttachedValue = 0b101010,
+ TrailedBlackboardEntry = 0b100110,
+ TrailedBlackboardOffset = 0b100111,
+}
+
+#[bitfield]
+#[derive(Copy, Clone, Debug)]
+#[repr(u64)]
+pub(crate) struct TrailEntry {
+ val: B56,
+ #[allow(unused)] f: bool,
+ #[allow(unused)] m: bool,
+ #[allow(unused)] tag: TrailEntryTag,
+}
+
+impl TrailEntry {
+ #[inline(always)]
+ pub(crate) fn build_with(tag: TrailEntryTag, value: u64) -> Self {
+ TrailEntry::new()
+ .with_tag(tag)
+ .with_m(false)
+ .with_f(false)
+ .with_val(value)
+ }
+
+ #[inline(always)]
+ pub(crate) fn get_tag(self) -> TrailEntryTag {
+ match self.tag_or_err() {
+ Ok(tag) => tag,
+ Err(_) => TrailEntryTag::TrailedAttachedValue,
+ }
+ }
+
+ #[inline]
+ pub(crate) fn get_value(self) -> u64 {
+ self.val()
+ }
+}
+
+#[repr(u64)]
+#[bitfield]
+#[derive(Copy, Clone, Hash, PartialEq, Eq)]
+pub struct HeapCellValue {
+ val: B56,
+ f: bool,
+ m: bool,
+ tag: HeapCellValueTag,
+}
+
+impl fmt::Display for HeapCellValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ read_heap_cell!(*self,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ write!(f, "{}", name.as_str())
+ } else {
+ write!(
+ f,
+ "{}/{}",
+ name.as_str(),
+ arity
+ )
+ }
+ }
+ (HeapCellValueTag::PStr, pstr_atom) => {
+ let pstr = PartialString::from(pstr_atom);
+
+ write!(
+ f,
+ "pstr ( \"{}\", )",
+ pstr.as_str_from(0)
+ )
+ }
+ (HeapCellValueTag::Cons, c) => {
+ match_untyped_arena_ptr!(c,
+ (ArenaHeaderTag::Integer, n) => {
+ write!(f, "{}", n)
+ }
+ (ArenaHeaderTag::Rational, r) => {
+ write!(f, "{}", r)
+ }
+ (ArenaHeaderTag::F64, fl) => {
+ write!(f, "{}", fl)
+ }
+ (ArenaHeaderTag::Stream, stream) => {
+ write!(f, "$stream({})", stream.as_ptr() as usize)
+ }
+ _ => {
+ write!(f, "")
+ }
+ )
+ }
+ _ => {
+ unreachable!()
+ }
+ )
+ }
+}
+
+impl fmt::Debug for HeapCellValue {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
+ match self.get_tag() {
+ tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => {
+ let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
+
+ f.debug_struct("HeapCellValue")
+ .field("tag", &tag)
+ .field("ptr", &cons_ptr.ptr())
+ .field("m", &cons_ptr.m())
+ .finish()
+ }
+ HeapCellValueTag::Atom => {
+ let (name, arity) = cell_as_atom_cell!(self)
+ .get_name_and_arity();
+
+ f.debug_struct("HeapCellValue")
+ .field("tag", &HeapCellValueTag::Atom)
+ .field("name", &name.as_str())
+ .field("arity", &arity)
+ .field("m", &self.m())
+ .field("f", &self.f())
+ .finish()
+ }
+ HeapCellValueTag::PStr => {
+ let (name, _) = cell_as_atom_cell!(self)
+ .get_name_and_arity();
+
+ f.debug_struct("HeapCellValue")
+ .field("tag", &HeapCellValueTag::PStr)
+ .field("contents", &name.as_str())
+ .field("m", &self.m())
+ .field("f", &self.f())
+ .finish()
+ }
+ tag => {
+ f.debug_struct("HeapCellValue")
+ .field("tag", &tag)
+ .field("value", &self.get_value())
+ .field("m", &self.get_mark_bit())
+ .field("f", &self.get_forwarding_bit())
+ .finish()
+ }
+ }
+ }
+}
+
+impl<T> From<TypedArenaPtr<T>> for HeapCellValue {
+ #[inline]
+ fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
+ HeapCellValue::from(arena_ptr.header_ptr() as u64)
+ }
+}
+
+impl From<F64Ptr> for HeapCellValue {
+ #[inline]
+ fn from(f64_ptr: F64Ptr) -> HeapCellValue {
+ HeapCellValue::from_bytes(
+ ConsPtr::from(f64_ptr.as_ptr() as u64)
+ .with_tag(ConsPtrMaskTag::F64)
+ .with_m(false)
+ .into_bytes(),
+ )
+ }
+}
+
+impl From<ConsPtr> for HeapCellValue {
+ #[inline(always)]
+ fn from(cons_ptr: ConsPtr) -> HeapCellValue {
+ HeapCellValue::from_bytes(
+ ConsPtr::from(cons_ptr.as_ptr() as u64)
+ .with_tag(ConsPtrMaskTag::Cons)
+ .with_m(false)
+ .into_bytes(),
+ )
+ }
+}
+
+impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
+ #[inline(always)]
+ fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
+ match n {
+ Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)),
+ Number::Integer(n) => HeapCellValue::from(n),
+ Number::Rational(n) => HeapCellValue::from(n),
+ Number::Fixnum(n) => fixnum_as_cell!(n),
+ }
+ }
+}
+
+impl HeapCellValue {
+ #[inline(always)]
+ pub fn build_with(tag: HeapCellValueTag, value: u64) -> Self {
+ HeapCellValue::new()
+ .with_tag(tag)
+ .with_val(value)
+ .with_m(false)
+ .with_f(false)
+ }
+
+ #[inline]
+ pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool {
+ use crate::machine::heap::*;
+
+ loop {
+ return read_heap_cell!(self,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ name == atom!("[]") && arity == 0
+ }
+ (HeapCellValueTag::CStr) => {
+ true
+ }
+ (HeapCellValueTag::PStrLoc, h) => {
+ self = heap[h];
+ continue;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[h]));
+
+ if cell.is_var() {
+ return false;
+ }
+
+ self = cell;
+ continue;
+ }
+ (HeapCellValueTag::PStrOffset, pstr_offset) => {
+ heap[pstr_offset].get_tag() == HeapCellValueTag::CStr
+ }
+ _ => {
+ false
+ }
+ );
+ }
+ }
+
+ #[inline(always)]
+ pub fn is_forwarded(self) -> bool {
+ self.get_forwarding_bit().unwrap_or(false)
+ }
+
+ #[inline]
+ pub fn is_ref(self) -> bool {
+ match self.get_tag() {
+ HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::Var |
+ HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc |
+ HeapCellValueTag::PStrOffset => true,
+ _ => false,
+ }
+ }
+
+ #[inline]
+ pub fn as_char(self) -> Option<char> {
+ read_heap_cell!(self,
+ (HeapCellValueTag::Char, c) => {
+ Some(c)
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity > 0 {
+ return None;
+ }
+
+ name.as_char()
+ }
+ _ => {
+ None
+ }
+ )
+ }
+
+ #[inline]
+ pub fn is_constant(self) -> bool {
+ match self.get_tag() {
+ HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum |
+ HeapCellValueTag::Char | HeapCellValueTag::CStr => {
+ true
+ }
+ HeapCellValueTag::Atom => {
+ cell_as_atom_cell!(self).get_arity() == 0
+ }
+ _ => {
+ false
+ }
+ }
+ }
+
+ #[inline(always)]
+ pub fn is_stack_var(self) -> bool {
+ self.get_tag() == HeapCellValueTag::StackVar
+ }
+
+ #[inline]
+ pub fn is_compound(self) -> bool {
+ match self.get_tag() {
+ HeapCellValueTag::Str
+ | HeapCellValueTag::Lis
+ | HeapCellValueTag::CStr
+ | HeapCellValueTag::PStr
+ | HeapCellValueTag::PStrLoc
+ | HeapCellValueTag::PStrOffset => {
+ true
+ }
+ HeapCellValueTag::Atom => {
+ cell_as_atom_cell!(self).get_arity() > 0
+ }
+ _ => { false }
+ }
+ }
+
+ #[inline]
+ pub fn is_var(self) -> bool {
+ read_heap_cell!(self,
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+ true
+ }
+ _ => {
+ false
+ }
+ )
+ }
+
+ #[inline]
+ pub(crate) fn as_var(self) -> Option<Ref> {
+ read_heap_cell!(self,
+ (HeapCellValueTag::Var, h) => {
+ Some(Ref::heap_cell(h))
+ }
+ (HeapCellValueTag::AttrVar, h) => {
+ Some(Ref::attr_var(h))
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ Some(Ref::stack_cell(s))
+ }
+ _ => {
+ None
+ }
+ )
+ }
+
+ #[inline]
+ pub fn get_value(self) -> usize {
+ self.val() as usize
+ }
+
+ #[inline]
+ pub fn set_value(&mut self, val: usize) {
+ self.set_val(val as u64);
+ }
+
+ #[inline]
+ pub fn get_tag(self) -> HeapCellValueTag {
+ match self.tag_or_err() {
+ Ok(tag) => tag,
+ Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
+ ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
+ ConsPtrMaskTag::F64 => HeapCellValueTag::F64,
+ },
+ }
+ }
+
+ #[inline]
+ pub fn to_atom(self) -> Option<Atom> {
+ match self.tag() {
+ HeapCellValueTag::Atom => Some(Atom::from((self.val() << 3) as usize)),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_pstr(self) -> Option<PartialString> {
+ match self.tag() {
+ HeapCellValueTag::PStr => {
+ Some(PartialString::from(Atom::from((self.val() as usize) << 3)))
+ }
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_fixnum(self) -> Option<Fixnum> {
+ match self.get_tag() {
+ HeapCellValueTag::Fixnum => Some(Fixnum::from_bytes(self.into_bytes())),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_untyped_arena_ptr(self) -> Option<UntypedArenaPtr> {
+ match self.tag() {
+ HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(self.into_bytes())),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn get_forwarding_bit(self) -> Option<bool> {
+ match self.get_tag() {
+ HeapCellValueTag::Cons // the list of non-forwardable cell tags.
+ | HeapCellValueTag::F64
+ // | HeapCellValueTag::Atom
+ // | HeapCellValueTag::PStr
+ | HeapCellValueTag::Fixnum
+ | HeapCellValueTag::Char => None,
+ _ => Some(self.f()),
+ }
+ }
+
+ #[inline]
+ pub fn set_forwarding_bit(&mut self, f: bool) {
+ match self.get_tag() {
+ HeapCellValueTag::Cons // the list of non-forwardable cell tags.
+ | HeapCellValueTag::F64
+ // | HeapCellValueTag::Atom
+ // | HeapCellValueTag::PStr
+ | HeapCellValueTag::Fixnum
+ | HeapCellValueTag::Char => {}
+ _ => self.set_f(f),
+ }
+ }
+
+ #[inline]
+ pub fn get_mark_bit(self) -> bool {
+ match self.get_tag() {
+ HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
+ ConsPtr::from_bytes(self.into_bytes()).m()
+ }
+ _ => self.m(),
+ }
+ }
+
+ #[inline]
+ pub fn set_mark_bit(&mut self, m: bool) {
+ match self.get_tag() {
+ HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
+ let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m);
+ *self = HeapCellValue::from_bytes(value.into_bytes());
+ }
+ _ => self.set_m(m),
+ }
+ }
+
+ pub fn order_category(self) -> Option<TermOrderCategory> {
+ match Number::try_from(self).ok() {
+ Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
+ Some(TermOrderCategory::Integer)
+ }
+ Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
+ None => match self.get_tag() {
+ HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => {
+ Some(TermOrderCategory::Variable)
+ }
+ HeapCellValueTag::Char => Some(TermOrderCategory::Atom),
+ HeapCellValueTag::Atom => {
+ Some(if cell_as_atom_cell!(self).get_arity() > 0 {
+ TermOrderCategory::Compound
+ } else {
+ TermOrderCategory::Atom
+ })
+ }
+ HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
+ HeapCellValueTag::CStr | HeapCellValueTag::Str => {
+ Some(TermOrderCategory::Compound)
+ }
+ _ => {
+ None
+ }
+ },
+ }
+ }
+
+ #[inline(always)]
+ pub fn is_protected(self, e: usize) -> bool {
+ read_heap_cell!(self,
+ (HeapCellValueTag::StackVar, s) => {
+ s < e
+ }
+ _ => {
+ true
+ }
+ )
+ }
+}
+
+const_assert!(mem::size_of::<HeapCellValue>() == 8);
+
+#[bitfield]
+#[repr(u64)]
+#[derive(Copy, Clone, Debug)]
+pub struct UntypedArenaPtr {
+ ptr: B61,
+ m: bool,
+ #[allow(unused)] padding: B2,
+}
+
+const_assert!(mem::size_of::<UntypedArenaPtr>() == 8);
+
+impl From<*const ArenaHeader> for UntypedArenaPtr {
+ #[inline]
+ fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr {
+ unsafe { mem::transmute(ptr) }
+ }
+}
+
+impl From<UntypedArenaPtr> for *const ArenaHeader {
+ #[inline]
+ fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
+ unsafe { mem::transmute(ptr) }
+ }
+}
+
+impl UntypedArenaPtr {
+ #[inline]
+ pub fn set_mark_bit(&mut self, m: bool) {
+ self.set_m(m);
+ }
+
+ #[inline]
+ pub fn get_ptr(self) -> *const u8 {
+ self.ptr() as *const u8
+ }
+
+ #[inline]
+ pub fn get_tag(self) -> ArenaHeaderTag {
+ unsafe {
+ let header = *(self.ptr() as *const ArenaHeader);
+ header.get_tag()
+ }
+ }
+
+ #[inline]
+ pub fn payload_offset(self) -> *const u8 {
+ unsafe {
+ self.get_ptr()
+ .offset(mem::size_of::<ArenaHeader>() as isize)
+ }
+ }
+
+ #[inline]
+ pub fn get_mark_bit(self) -> bool {
+ self.m()
+ }
+}
+
+impl Add<usize> for HeapCellValue {
+ type Output = HeapCellValue;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ match self.get_tag() {
+ tag @ HeapCellValueTag::Str |
+ tag @ HeapCellValueTag::Lis |
+ tag @ HeapCellValueTag::PStrOffset |
+ tag @ HeapCellValueTag::PStrLoc |
+ tag @ HeapCellValueTag::Var |
+ tag @ HeapCellValueTag::AttrVar => {
+ HeapCellValue::build_with(tag, (self.get_value() + rhs) as u64)
+ }
+ _ => {
+ self
+ }
+ }
+ }
+}
+
+impl Sub<usize> for HeapCellValue {
+ type Output = HeapCellValue;
+
+ fn sub(self, rhs: usize) -> Self::Output {
+ match self.get_tag() {
+ tag @ HeapCellValueTag::Str |
+ tag @ HeapCellValueTag::Lis |
+ tag @ HeapCellValueTag::PStrOffset |
+ tag @ HeapCellValueTag::PStrLoc |
+ tag @ HeapCellValueTag::Var |
+ tag @ HeapCellValueTag::AttrVar => {
+ HeapCellValue::build_with(tag, (self.get_value() - rhs) as u64)
+ }
+ _ => {
+ self
+ }
+ }
+ }
+}
+
+impl SubAssign<usize> for HeapCellValue {
+ #[inline(always)]
+ fn sub_assign(&mut self, rhs: usize) {
+ *self = *self - rhs;
+ }
+}
+
+impl Sub<i64> for HeapCellValue {
+ type Output = HeapCellValue;
+
+ fn sub(self, rhs: i64) -> Self::Output {
+ if rhs < 0 {
+ match self.get_tag() {
+ tag @ HeapCellValueTag::Str |
+ tag @ HeapCellValueTag::Lis |
+ tag @ HeapCellValueTag::PStrOffset |
+ tag @ HeapCellValueTag::PStrLoc |
+ tag @ HeapCellValueTag::Var |
+ tag @ HeapCellValueTag::AttrVar => {
+ HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64)
+ }
+ _ => {
+ self
+ }
+ }
+ } else {
+ self.sub(rhs as usize)
+ }
+ }
+}
+
diff --git a/src/write.rs b/src/write.rs
deleted file mode 100644
index 1c1fc3dc..00000000
--- a/src/write.rs
+++ /dev/null
@@ -1,674 +0,0 @@
-use crate::clause_types::*;
-use crate::forms::*;
-use crate::indexing::IndexingCodePtr;
-use crate::instructions::*;
-use crate::machine::loader::CompilationTarget;
-use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::*;
-
-use std::fmt;
-
-impl fmt::Display for LocalCodePtr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
- LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
- LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
- }
- }
-}
-
-impl fmt::Display for REPLCodePtr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- REPLCodePtr::AddDiscontiguousPredicate =>
- write!(f, "REPLCodePtr::AddDiscontiguousPredicate"),
- REPLCodePtr::AddDynamicPredicate =>
- write!(f, "REPLCodePtr::AddDynamicPredicate"),
- REPLCodePtr::AddMultifilePredicate =>
- write!(f, "REPLCodePtr::AddMultifilePredicate"),
- REPLCodePtr::AddGoalExpansionClause =>
- write!(f, "REPLCodePtr::AddGoalExpansionClause"),
- REPLCodePtr::AddTermExpansionClause =>
- write!(f, "REPLCodePtr::AddTermExpansionClause"),
- REPLCodePtr::AddInSituFilenameModule =>
- write!(f, "REPLCodePtr::AddInSituFilenameModule"),
- REPLCodePtr::AbolishClause =>
- write!(f, "REPLCodePtr::AbolishClause"),
- REPLCodePtr::Assertz =>
- write!(f, "REPLCodePtr::Assertz"),
- REPLCodePtr::Asserta =>
- write!(f, "REPLCodePtr::Asserta"),
- REPLCodePtr::Retract =>
- write!(f, "REPLCodePtr::Retract"),
- REPLCodePtr::ClauseToEvacuable =>
- write!(f, "REPLCodePtr::ClauseToEvacuable"),
- REPLCodePtr::ScopedClauseToEvacuable =>
- write!(f, "REPLCodePtr::ScopedClauseToEvacuable"),
- REPLCodePtr::ConcludeLoad =>
- write!(f, "REPLCodePtr::ConcludeLoad"),
- REPLCodePtr::DeclareModule =>
- write!(f, "REPLCodePtr::DeclareModule"),
- REPLCodePtr::LoadCompiledLibrary =>
- write!(f, "REPLCodePtr::LoadCompiledLibrary"),
- REPLCodePtr::LoadContextSource =>
- write!(f, "REPLCodePtr::LoadContextSource"),
- REPLCodePtr::LoadContextFile =>
- write!(f, "REPLCodePtr::LoadContextFile"),
- REPLCodePtr::LoadContextDirectory =>
- write!(f, "REPLCodePtr::LoadContextDirectory"),
- REPLCodePtr::LoadContextModule =>
- write!(f, "REPLCodePtr::LoadContextModule"),
- REPLCodePtr::LoadContextStream =>
- write!(f, "REPLCodePtr::LoadContextStream"),
- REPLCodePtr::PopLoadContext =>
- write!(f, "REPLCodePtr::PopLoadContext"),
- REPLCodePtr::PopLoadStatePayload =>
- write!(f, "REPLCodePtr::PopLoadStatePayload"),
- REPLCodePtr::PushLoadContext =>
- write!(f, "REPLCodePtr::PushLoadContext"),
- REPLCodePtr::PushLoadStatePayload =>
- write!(f, "REPLCodePtr::PushLoadStatePayload"),
- REPLCodePtr::UseModule =>
- write!(f, "REPLCodePtr::UseModule"),
- REPLCodePtr::MetaPredicateProperty =>
- write!(f, "REPLCodePtr::MetaPredicateProperty"),
- REPLCodePtr::BuiltInProperty =>
- write!(f, "REPLCodePtr::BuiltInProperty"),
- REPLCodePtr::DynamicProperty =>
- write!(f, "REPLCodePtr::DynamicProperty"),
- REPLCodePtr::MultifileProperty =>
- write!(f, "REPLCodePtr::MultifileProperty"),
- REPLCodePtr::DiscontiguousProperty =>
- write!(f, "REPLCodePtr::DiscontiguousProperty"),
- REPLCodePtr::IsConsistentWithTermQueue =>
- write!(f, "REPLCodePtr::IsConsistentWithTermQueue"),
- REPLCodePtr::FlushTermQueue =>
- write!(f, "REPLCodePtr::FlushTermQueue"),
- REPLCodePtr::RemoveModuleExports =>
- write!(f, "REPLCodePtr::RemoveModuleExports"),
- REPLCodePtr::AddNonCountedBacktracking =>
- write!(f, "REPLCodePtr::AddNonCountedBacktracking"),
- }
- }
-}
-
-impl fmt::Display for IndexPtr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &IndexPtr::DynamicUndefined => write!(f, "undefined"),
- &IndexPtr::Undefined => write!(f, "undefined"),
- &IndexPtr::DynamicIndex(i) | &IndexPtr::Index(i) => write!(f, "{}", i),
- }
- }
-}
-
-impl fmt::Display for CompilationTarget {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- CompilationTarget::User => write!(f, "user"),
- CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name),
- }
- }
-}
-
-impl fmt::Display for FactInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &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::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)
- }
- &FactInstruction::GetValue(ref x, ref a) => {
- write!(f, "get_value {}, A{}", x, a)
- }
- &FactInstruction::GetVariable(ref x, ref a) => {
- write!(f, "fact:get_variable {}, A{}", x, a)
- }
- &FactInstruction::UnifyConstant(ref constant) => {
- write!(f, "unify_constant {}", constant)
- }
- &FactInstruction::UnifyVariable(ref r) => {
- write!(f, "unify_variable {}", r)
- }
- &FactInstruction::UnifyLocalValue(ref r) => {
- write!(f, "unify_local_value {}", r)
- }
- &FactInstruction::UnifyValue(ref r) => {
- write!(f, "unify_value {}", r)
- }
- &FactInstruction::UnifyVoid(n) => {
- write!(f, "unify_void {}", n)
- }
- }
- }
-}
-
-impl fmt::Display for QueryInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &QueryInstruction::GetVariable(ref x, ref a) => {
- write!(f, "query:get_variable {}, A{}", x, a)
- }
- &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::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)
- }
- &QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a),
- &QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a),
- &QueryInstruction::PutVariable(ref x, ref a) => write!(f, "put_variable {}, A{}", x, a),
- &QueryInstruction::SetConstant(ref constant) => write!(f, "set_constant {}", constant),
- &QueryInstruction::SetLocalValue(ref r) => write!(f, "set_local_value {}", r),
- &QueryInstruction::SetVariable(ref r) => write!(f, "set_variable {}", r),
- &QueryInstruction::SetValue(ref r) => write!(f, "set_value {}", r),
- &QueryInstruction::SetVoid(n) => write!(f, "set_void {}", n),
- }
- }
-}
-
-impl fmt::Display for CompareNumberQT {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &CompareNumberQT::GreaterThan => write!(f, ">"),
- &CompareNumberQT::GreaterThanOrEqual => write!(f, ">="),
- &CompareNumberQT::LessThan => write!(f, "<"),
- &CompareNumberQT::LessThanOrEqual => write!(f, "<="),
- &CompareNumberQT::NotEqual => write!(f, "=\\="),
- &CompareNumberQT::Equal => write!(f, "=:="),
- }
- }
-}
-
-impl fmt::Display for CompareTermQT {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &CompareTermQT::GreaterThan => write!(f, "@>"),
- &CompareTermQT::GreaterThanOrEqual => write!(f, "@>="),
- &CompareTermQT::LessThan => write!(f, "@<"),
- &CompareTermQT::LessThanOrEqual => write!(f, "@<="),
- }
- }
-}
-
-impl fmt::Display for ClauseType {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &ClauseType::System(SystemClauseType::SetCutPoint(r)) => {
- write!(f, "$set_cp({})", r)
- }
- &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
- let idx = idx.0.get();
- write!(f, "{}/{}", name, idx)
- }
- ref ct => {
- write!(f, "{}", ct.name())
- }
- }
- }
-}
-
-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::LoadStatePayload(_) => write!(f, "LoadStatePayload"),
- &HeapCellValue::Rational(ref n) => write!(f, "{}", n),
- &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
- f,
- "{}/{} (op, priority: {}, spec: {})",
- name.as_str(),
- arity,
- cell.prec(),
- cell.assoc()
- ),
- &HeapCellValue::NamedStr(arity, ref name, None) => {
- write!(f, "{}/{}", name.as_str(), arity)
- }
- &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)
- }
- &HeapCellValue::TcpListener(ref tcp_listener) => {
- write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap())
- }
- }
- }
-}
-
-impl fmt::Display for DBRef {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &DBRef::NamedPred(ref name, arity, _) => write!(f, "db_ref:named:{}/{}", name, arity),
- &DBRef::Op(priority, spec, ref name, ..) => {
- write!(f, "db_ref:op({}, {}, {})", priority, spec, name)
- }
- }
- }
-}
-
-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::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::Lis(l) => write!(f, "Addr::Lis({})", l),
- &Addr::LoadStatePayload(s) => write!(f, "Addr::LoadStatePayload({})", s),
- &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::Stream(stream) => write!(f, "Addr::Stream({})", stream),
- &Addr::TcpListener(tcp_listener) => write!(f, "Addr::TcpListener({})", tcp_listener),
- &Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp),
- }
- }
-}
-
-impl fmt::Display for ControlInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &ControlInstruction::Allocate(num_cells) => write!(f, "allocate {}", num_cells),
- &ControlInstruction::CallClause(ref ct, arity, pvs, true, true) => {
- write!(f, "call_with_default_policy {}/{}, {}", ct, arity, pvs)
- }
- &ControlInstruction::CallClause(ref ct, arity, pvs, false, true) => {
- write!(f, "execute_with_default_policy {}/{}, {}", ct, arity, pvs)
- }
- &ControlInstruction::CallClause(ref ct, arity, pvs, true, false) => {
- write!(f, "execute {}/{}, {}", ct, arity, pvs)
- }
- &ControlInstruction::CallClause(ref ct, arity, pvs, false, false) => {
- write!(f, "call {}/{}, {}", ct, arity, pvs)
- }
- &ControlInstruction::Deallocate => write!(f, "deallocate"),
- &ControlInstruction::JmpBy(arity, offset, pvs, false) => {
- write!(f, "jmp_by_call {}/{}, {}", offset, arity, pvs)
- }
- &ControlInstruction::JmpBy(arity, offset, pvs, true) => {
- write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs)
- }
- &ControlInstruction::RevJmpBy(offset) => {
- write!(f, "rev_jmp_by {}", offset)
- }
- &ControlInstruction::Proceed => write!(f, "proceed"),
- }
- }
-}
-
-impl fmt::Display for IndexedChoiceInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &IndexedChoiceInstruction::Try(offset) => write!(f, "try {}", offset),
- &IndexedChoiceInstruction::Retry(offset) => write!(f, "retry {}", offset),
- &IndexedChoiceInstruction::Trust(offset) => write!(f, "trust {}", offset),
- }
- }
-}
-
-impl fmt::Display for ChoiceInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
- write!(f, "dynamic_else {}, {}, {}", offset, "inf", i)
- }
- &ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
- write!(f, "dynamic_else {}, {}, fail({})", offset, "inf", i)
- }
- &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
- write!(f, "dynamic_else {}, {}, {}", offset, d, i)
- }
- &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
- write!(f, "dynamic_else {}, {}, fail({})", offset, d, i)
- }
- &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
- write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i)
- }
- &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
- write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i)
- }
- &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
- write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i)
- }
- &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
- write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i)
- }
- &ChoiceInstruction::TryMeElse(offset) =>
- write!(f, "try_me_else {}", offset),
- &ChoiceInstruction::DefaultRetryMeElse(offset) => {
- write!(f, "retry_me_else_by_default {}", offset)
- }
- &ChoiceInstruction::RetryMeElse(offset) =>
- write!(f, "retry_me_else {}", offset),
- &ChoiceInstruction::DefaultTrustMe(_) =>
- write!(f, "trust_me_by_default"),
- &ChoiceInstruction::TrustMe(_) =>
- write!(f, "trust_me"),
- }
- }
-}
-
-impl fmt::Display for IndexingCodePtr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &IndexingCodePtr::DynamicExternal(o) => {
- write!(f, "IndexingCodePtr::DynamicExternal({})", o)
- }
- &IndexingCodePtr::External(o) => {
- write!(f, "IndexingCodePtr::External({})", o)
- }
- &IndexingCodePtr::Fail => {
- write!(f, "IndexingCodePtr::Fail")
- }
- &IndexingCodePtr::Internal(o) => {
- write!(f, "IndexingCodePtr::Internal({})", o)
- }
- }
- }
-}
-
-impl fmt::Display for IndexingInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => {
- write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s)
- }
- &IndexingInstruction::SwitchOnConstant(ref constants) => {
- write!(f, "switch_on_constant {}", constants.len())
- }
- &IndexingInstruction::SwitchOnStructure(ref structures) => {
- write!(f, "switch_on_structure {}", structures.len())
- }
- }
- }
-}
-
-impl fmt::Display for SessionError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &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::ModuleDoesNotContainExport(ref module, ref key) => {
- write!(
- f,
- "module {} does not contain claimed export {}/{}",
- module,
- key.0,
- key.1,
- )
- }
- &SessionError::OpIsInfixAndPostFix(_) => {
- write!(f, "cannot define an op to be both postfix and infix.")
- }
- &SessionError::NamelessEntry => {
- write!(f, "the predicate head is not an atom or clause.")
- }
- &SessionError::CompilationError(ref e) => {
- write!(f, "syntax_error({:?})", e)
- }
- &SessionError::QueryCannotBeDefinedAsFact => {
- write!(f, "queries cannot be defined as facts.")
- }
- &SessionError::ModuleCannotImportSelf(ref module_name) => {
- write!(f, "modules ({}, in this case) cannot import themselves.",
- module_name)
- }
- &SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => {
- write!(f, "module {} does not define {}/{} as multifile or discontiguous.",
- compilation_target.module_name(), key.0, key.1)
- }
- }
- }
-}
-
-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::ModuleSource(ref module_source) => {
- write!(f, "the source/sink {} does not exist", module_source)
- }
- &ExistenceError::Procedure(ref name, arity) => {
- write!(f, "the procedure {}/{} does not exist", name, arity)
- }
- &ExistenceError::SourceSink(ref addr) => {
- write!(f, "the source/sink {} does not exist", addr)
- }
- &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)
- }
- }
- }
-}
-
-impl fmt::Display for IndexingLine {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &IndexingLine::Indexing(ref indexing_instr) => {
- write!(f, "{}", indexing_instr)
- }
- &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
- for indexed_choice_instr in indexed_choice_instrs {
- write!(f, "{}", indexed_choice_instr)?;
- }
-
- Ok(())
- }
- &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
- for indexed_choice_instr in indexed_choice_instrs {
- write!(f, "dynamic({})", indexed_choice_instr)?;
- }
-
- Ok(())
- }
- }
- }
-}
-
-impl fmt::Display for Line {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &Line::Arithmetic(ref arith_instr) => write!(f, "{}", arith_instr),
- &Line::Choice(ref choice_instr) => write!(f, "{}", choice_instr),
- &Line::Control(ref control_instr) => write!(f, "{}", control_instr),
- &Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr),
- &Line::Fact(ref fact_instr) => write!(f, "{}", fact_instr),
- &Line::IndexingCode(ref indexing_instrs) => {
- for indexing_instr in indexing_instrs {
- write!(f, "{}", indexing_instr)?;
- }
-
- Ok(())
- }
- &Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
- &Line::DynamicIndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
- &Line::Query(ref query_instr) => write!(f, "{}", query_instr),
- }
- }
-}
-
-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),
- }
- }
-}
-
-impl fmt::Display for ArithmeticTerm {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &ArithmeticTerm::Reg(r) => write!(f, "{}", r),
- &ArithmeticTerm::Interm(i) => write!(f, "@{}", i),
- &ArithmeticTerm::Number(ref n) => write!(f, "{}", n),
- }
- }
-}
-
-impl fmt::Display for ArithmeticInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &ArithmeticInstruction::Abs(ref a1, ref t) => write!(f, "abs {}, @{}", a1, t),
- &ArithmeticInstruction::Add(ref a1, ref a2, ref t) => {
- write!(f, "add {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Sub(ref a1, ref a2, ref t) => {
- write!(f, "sub {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Mul(ref a1, ref a2, ref t) => {
- write!(f, "mul {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Pow(ref a1, ref a2, ref t) => {
- write!(f, "** {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::IntPow(ref a1, ref a2, ref t) => {
- write!(f, "^ {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Div(ref a1, ref a2, ref t) => {
- write!(f, "div {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) => {
- write!(f, "idiv {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Max(ref a1, ref a2, ref t) => {
- write!(f, "max {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Min(ref a1, ref a2, ref t) => {
- write!(f, "min {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, ref t) => {
- write!(f, "int_floor_div {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => {
- write!(f, "rdiv {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Gcd(ref a1, ref a2, ref t) => {
- write!(f, "gcd {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => {
- write!(f, "shl {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Shr(ref a1, ref a2, ref t) => {
- write!(f, "shr {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Xor(ref a1, ref a2, ref t) => {
- write!(f, "xor {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::And(ref a1, ref a2, ref t) => {
- write!(f, "and {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Or(ref a1, ref a2, ref t) => {
- write!(f, "or {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Mod(ref a1, ref a2, ref t) => {
- write!(f, "mod {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Rem(ref a1, ref a2, ref t) => {
- write!(f, "rem {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::ATan2(ref a1, ref a2, ref t) => {
- write!(f, "atan2 {}, {}, @{}", a1, a2, t)
- }
- &ArithmeticInstruction::Plus(ref a, ref t) => write!(f, "plus {}, @{}", a, t),
- &ArithmeticInstruction::Sign(ref a, ref t) => write!(f, "sign {}, @{}", a, t),
- &ArithmeticInstruction::Neg(ref a, ref t) => write!(f, "neg {}, @{}", a, t),
- &ArithmeticInstruction::Cos(ref a, ref t) => write!(f, "cos {}, @{}", a, t),
- &ArithmeticInstruction::Sin(ref a, ref t) => write!(f, "sin {}, @{}", a, t),
- &ArithmeticInstruction::Tan(ref a, ref t) => write!(f, "tan {}, @{}", a, t),
- &ArithmeticInstruction::ATan(ref a, ref t) => write!(f, "atan {}, @{}", a, t),
- &ArithmeticInstruction::ASin(ref a, ref t) => write!(f, "asin {}, @{}", a, t),
- &ArithmeticInstruction::ACos(ref a, ref t) => write!(f, "acos {}, @{}", a, t),
- &ArithmeticInstruction::Log(ref a, ref t) => write!(f, "log {}, @{}", a, t),
- &ArithmeticInstruction::Exp(ref a, ref t) => write!(f, "exp {}, @{}", a, t),
- &ArithmeticInstruction::Sqrt(ref a, ref t) => write!(f, "sqrt {}, @{}", a, t),
- &ArithmeticInstruction::BitwiseComplement(ref a, ref t) => {
- write!(f, "bitwise_complement {}, @{}", a, t)
- }
- &ArithmeticInstruction::Truncate(ref a, ref t) => write!(f, "truncate {}, @{}", a, t),
- &ArithmeticInstruction::Round(ref a, ref t) => write!(f, "round {}, @{}", a, t),
- &ArithmeticInstruction::Ceiling(ref a, ref t) => write!(f, "ceiling {}, @{}", a, t),
- &ArithmeticInstruction::Floor(ref a, ref t) => write!(f, "floor {}, @{}", a, t),
- &ArithmeticInstruction::Float(ref a, ref t) => write!(f, "float {}, @{}", a, t),
- }
- }
-}
-
-impl fmt::Display for CutInstruction {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &CutInstruction::Cut(r) => write!(f, "cut {}", r),
- &CutInstruction::NeckCut => write!(f, "neck_cut"),
- &CutInstruction::GetLevel(r) => write!(f, "get_level {}", r),
- &CutInstruction::GetLevelAndUnify(r) => write!(f, "get_level_and_unify {}", r),
- }
- }
-}
-
-impl fmt::Display for Level {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &Level::Root | &Level::Shallow => write!(f, "A"),
- &Level::Deep => write!(f, "X"),
- }
- }
-}
diff --git a/tests-pl/issue839-op3.pl b/tests-pl/issue839-op3.pl
index 3f362cf6..52d36f95 100644
--- a/tests-pl/issue839-op3.pl
+++ b/tests-pl/issue839-op3.pl
@@ -1 +1 @@
-:- op(900, fy, [$,@]). \ No newline at end of file
+:- op(900, fy, [$,@]).
diff --git a/tests/scryer/helper.rs b/tests/scryer/helper.rs
index baa057d0..9cb2f0a3 100644
--- a/tests/scryer/helper.rs
+++ b/tests/scryer/helper.rs
@@ -29,23 +29,10 @@ impl Expectable for &[u8] {
/// Tests whether the file can be successfully loaded
/// and produces the expected output during it
pub(crate) fn load_module_test<T: Expectable>(file: &str, expected: T) {
- use scryer_prolog::*;
+ use scryer_prolog::machine::mock_wam::*;
- let input = machine::Stream::from("");
- let output = machine::Stream::from(String::new());
- let error = machine::Stream::from(String::new());
-
- let mut wam = machine::Machine::new(input, output.clone(), error);
-
- wam.load_file(
- file.into(),
- machine::Stream::from(
- std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
- ),
- );
-
- let output = output.bytes().unwrap();
- expected.assert_eq(output.as_slice());
+ let mut wam = Machine::with_test_streams();
+ expected.assert_eq(wam.test_load_file(file).as_slice());
}
pub const SCRYER_PROLOG: &str = "scryer-prolog";
diff --git a/tests/scryer/issues.rs b/tests/scryer/issues.rs
index 54deae58..3c207471 100644
--- a/tests/scryer/issues.rs
+++ b/tests/scryer/issues.rs
@@ -1,4 +1,5 @@
use crate::helper::{load_module_test, run_top_level_test_no_args, run_top_level_test_with_args};
+use serial_test::serial;
// issue #857
#[test]
@@ -8,7 +9,8 @@ fn display_constraints() {
X = 1.\n\
use_module(library(dif)).\n\
X = 1.\n\
- dif(X,1).\n",
+ dif(X,1).\n
+ halt.\n",
" \
X = 1.\n \
true.\n \
@@ -23,9 +25,10 @@ fn display_constraints() {
fn do_not_duplicate_path_components() {
run_top_level_test_no_args(
"\
- ['tests-pl/issue852-throw_e.pl'].\n\
- ['tests-pl/issue852-throw_e.pl'].\n\
- ",
+ ['tests-pl/issue852-throw_e.pl'].\n\
+ ['tests-pl/issue852-throw_e.pl'].\n\
+ halt.\n\
+ ",
"\
caught: e\n\
false.\n\
@@ -50,6 +53,7 @@ fn handle_residual_goal() {
set_prolog_flag(occurs_check, true).\n\
-X\\=X.\n\
dif(-X,X).\n\
+ halt.\n\
",
" \
true.\n \
@@ -72,8 +76,9 @@ fn occurs_check_flag() {
run_top_level_test_with_args(
&["tests-pl/issue841-occurs-check.pl"],
"\
- f(X, X).\n\
- ",
+ f(X, X).\n\
+ halt.\n\
+ ",
"false.\n",
)
}
@@ -86,7 +91,8 @@ fn occurs_check_flag2() {
X = -X.\n\
asserta(f(X,g(X))).\n\
f(X,X).\n\
- X-X = X-g(X).
+ X-X = X-g(X).\n\
+ halt.\n\
",
" \
true.\n\
@@ -101,7 +107,7 @@ fn occurs_check_flag2() {
// issue #839
#[test]
fn op3() {
- run_top_level_test_with_args(&["tests-pl/issue839-op3.pl"], "", "")
+ run_top_level_test_with_args(&["tests-pl/issue839-op3.pl", "-g", "halt"], "", "")
}
// issue #820
@@ -127,31 +133,39 @@ fn compound_goal() {
// issue #815
#[test]
fn no_stutter() {
- run_top_level_test_no_args("write(a), write(b), false.\n", "abfalse.\n")
+ run_top_level_test_no_args("write(a), write(b), false.\n\
+ halt.\n\
+ ",
+ "abfalse.\n")
}
+/*
// issue #812
#[test] // FIXME: the line number is of by one (should be 4), empty line not accounted for or starting to count at line 0?
fn singleton_warning() {
run_top_level_test_no_args(
- "['tests-pl/issue812-singleton-warning.pl'].",
+ "['tests-pl/issue812-singleton-warning.pl'].\n\
+ halt.\n",
"\
Warning: singleton variables X at line 3 of issue812-singleton-warning.pl\n \
true.\n\
",
);
}
+*/
// issue #807
#[test]
fn ignored_constraint() {
run_top_level_test_no_args(
- "use_module(library(freeze)), freeze(X,false), X \\=a.",
- " freeze:freeze(X,user:false).\n",
+ "use_module(library(freeze)), freeze(X,false), X \\=a.\n\
+ halt.",
+ " freeze:freeze(X,false).\n",
);
}
// issue #831
+#[serial]
#[test]
fn call_0() {
load_module_test(
diff --git a/tests/scryer/main.rs b/tests/scryer/main.rs
index 1b3ada5f..7865c0b3 100644
--- a/tests/scryer/main.rs
+++ b/tests/scryer/main.rs
@@ -1,4 +1,3 @@
mod helper;
-
mod issues;
mod src_tests;
diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs
index 51caf4a8..b0b9efb5 100644
--- a/tests/scryer/src_tests.rs
+++ b/tests/scryer/src_tests.rs
@@ -1,25 +1,31 @@
use crate::helper::{load_module_test, run_top_level_test_with_args};
+use serial_test::serial;
+#[serial]
#[test]
fn builtins() {
load_module_test("src/tests/builtins.pl", "");
}
+#[serial]
#[test]
fn call_with_inference_limit() {
load_module_test("src/tests/call_with_inference_limit.pl", "");
}
+#[serial]
#[test]
fn facts() {
load_module_test("src/tests/facts.pl", "");
}
+#[serial]
#[test]
fn hello_world() {
load_module_test("src/tests/hello_world.pl", "Hello World!\n");
}
+#[serial]
#[test]
fn syntax_error() {
load_module_test(
@@ -28,36 +34,37 @@ fn syntax_error() {
);
}
+#[serial]
#[test]
-#[ignore] // fails to halt
fn predicates() {
load_module_test("src/tests/predicates.pl", "");
}
+#[serial]
#[test]
fn rules() {
load_module_test("src/tests/rules.pl", "");
}
+#[serial]
#[test]
-#[ignore]
fn setup_call_cleanup_load() {
load_module_test(
"src/tests/setup_call_cleanup.pl",
- "1+21+31+2>_13165+_131661+_121811+2>41+2>_131661+2>31+2>31+2>4ba",
+ "1+21+31+2>_17737+_177381+_158071+2>41+2>_177381+2>31+2>31+2>4ba"
);
}
#[test]
-#[ignore]
fn setup_call_cleanup_process() {
run_top_level_test_with_args(
- &["src/tests/setup_call_cleanup.pl"],
+ &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"],
"",
- "1+21+31+2>_14108+_141091+_131241+2>41+2>_141091+2>31+2>31+2>4ba",
+ "1+21+31+2>_19590+_195911+_176601+2>41+2>_195911+2>31+2>31+2>4ba"
);
}
+#[serial]
#[test]
fn clpz_load() {
load_module_test("src/tests/clpz/test_clpz.pl", "");