]> Repositorios git - scryer-prolog.git/commitdiff
move to a predicate-based module system, move to loader.[rs|pl]-based compilation...
authorMark Thom <[email protected]>
Sat, 30 Jan 2021 21:32:47 +0000 (14:32 -0700)
committerMark Thom <[email protected]>
Sun, 31 Jan 2021 04:07:51 +0000 (21:07 -0700)
55 files changed:
Cargo.lock
Cargo.toml
build.rs
src/clause_types.rs
src/codegen.rs
src/forms.rs
src/heap_iter.rs
src/heap_print.rs
src/indexing.rs
src/instructions.rs
src/iterators.rs
src/lib/atts.pl
src/lib/builtins.pl
src/lib/clpb.pl
src/lib/dcgs.pl
src/lib/diag.pl
src/lib/dif.pl
src/lib/error.pl
src/lib/iso_ext.pl
src/lib/lists.pl
src/lib/ops_and_meta_predicates.pl [new file with mode: 0644]
src/lib/pairs.pl
src/lib/tabling/wrapper.pl
src/lib/time.pl
src/loader.pl [new file with mode: 0644]
src/machine/attributed_variables.pl
src/machine/attributed_variables.rs
src/machine/code_repo.rs
src/machine/code_walker.rs
src/machine/compile.rs
src/machine/dynamic_database.rs [deleted file]
src/machine/heap.rs
src/machine/load_state.rs [new file with mode: 0644]
src/machine/loader.rs [new file with mode: 0644]
src/machine/machine_errors.rs
src/machine/machine_indices.rs
src/machine/machine_state.rs
src/machine/machine_state_impl.rs
src/machine/mod.rs
src/machine/modules.rs [deleted file]
src/machine/partial_string.rs
src/machine/preprocessor.rs [new file with mode: 0644]
src/machine/project_attributes.pl
src/machine/stack.rs
src/machine/streams.rs
src/machine/system_calls.rs
src/machine/term_expansion.rs [deleted file]
src/machine/term_stream.rs [new file with mode: 0644]
src/machine/toplevel.rs [deleted file]
src/macros.rs
src/main.rs
src/read.rs
src/term_and_goal_expansion.pl [new file with mode: 0644]
src/toplevel.pl
src/write.rs

index 0b2ca779edd253f425538af9a36b9262007e7d48..b9f316baeb2b7beb2f7b09ca26924d1ca778b68a 100644 (file)
@@ -1,17 +1,5 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-[[package]]
-name = "arc-swap"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b585a98a234c46fc563103e9278c9391fde1f4e6850334da895d27edb9580f62"
-
-[[package]]
-name = "arrayref"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
-
 [[package]]
 name = "arrayvec"
 version = "0.4.12"
@@ -21,12 +9,6 @@ dependencies = [
  "nodrop",
 ]
 
-[[package]]
-name = "arrayvec"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
-
 [[package]]
 name = "autocfg"
 version = "0.1.7"
@@ -35,21 +17,15 @@ checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
 
 [[package]]
 name = "autocfg"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "az"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41a6b78289a33e09b00818ca8c90ab17c5dabb6e74f4b29a6de679c0e0886ade"
-
-[[package]]
-name = "base64"
-version = "0.11.0"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
+checksum = "e9bcd47d94aa4eb8c076b50fc61a75020789394ffb9bd74a180b3379130f6569"
 
 [[package]]
 name = "base64"
@@ -68,9 +44,9 @@ dependencies = [
 
 [[package]]
 name = "bit-vec"
-version = "0.6.2"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
 
 [[package]]
 name = "bitflags"
@@ -90,17 +66,6 @@ dependencies = [
  "opaque-debug",
 ]
 
-[[package]]
-name = "blake2b_simd"
-version = "0.5.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
-dependencies = [
- "arrayref",
- "arrayvec 0.5.1",
- "constant_time_eq",
-]
-
 [[package]]
 name = "block-buffer"
 version = "0.7.3"
@@ -124,9 +89,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.2.1"
+version = "3.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
+checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9"
 
 [[package]]
 name = "byte-tools"
@@ -136,15 +101,15 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
 
 [[package]]
 name = "byteorder"
-version = "1.3.4"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
 
 [[package]]
 name = "cc"
-version = "1.0.52"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
+checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
 
 [[package]]
 name = "cfg-if"
@@ -160,13 +125,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.11"
+version = "0.4.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
 dependencies = [
+ "libc",
  "num-integer",
- "num-traits 0.2.11",
+ "num-traits 0.2.14",
  "time",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -178,17 +145,11 @@ dependencies = [
  "bitflags",
 ]
 
-[[package]]
-name = "constant_time_eq"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
-
 [[package]]
 name = "core-foundation"
-version = "0.7.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
+checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -196,9 +157,9 @@ dependencies = [
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.7.0"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
+checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
 
 [[package]]
 name = "cpu-time"
@@ -207,18 +168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded"
 dependencies = [
  "libc",
- "winapi 0.3.8",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
-dependencies = [
- "autocfg 1.0.0",
- "cfg-if 0.1.10",
- "lazy_static",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -234,16 +184,16 @@ dependencies = [
  "mio",
  "parking_lot",
  "signal-hook",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
 name = "crossterm_winapi"
-version = "0.6.1"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057b7146d02fb50175fd7dbe5158f6097f33d02831f43b4ee8ae4ddf67b68f5c"
+checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db"
 dependencies = [
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -265,15 +215,6 @@ dependencies = [
  "generic-array",
 ]
 
-[[package]]
-name = "dirs"
-version = "3.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
-dependencies = [
- "dirs-sys",
-]
-
 [[package]]
 name = "dirs-next"
 version = "2.0.0"
@@ -284,26 +225,15 @@ dependencies = [
  "dirs-sys-next",
 ]
 
-[[package]]
-name = "dirs-sys"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
-dependencies = [
- "libc",
- "redox_users",
- "winapi 0.3.8",
-]
-
 [[package]]
 name = "dirs-sys-next"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d"
+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
 dependencies = [
  "libc",
  "redox_users",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -340,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
 dependencies = [
  "libc",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -386,11 +316,11 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.1.14"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "libc",
  "wasi",
 ]
@@ -412,21 +342,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657"
 dependencies = [
  "proc-macro-hack",
- "proc-macro2 1.0.10",
- "quote 1.0.3",
- "syn 1.0.18",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "syn 1.0.60",
 ]
 
 [[package]]
 name = "gmp-mpfr-sys"
-version = "1.2.2"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63d7f805cf9df081683d463f62864bda8b8e3ce7162a8e11cd0c49f27b8ce89b"
+checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e"
 dependencies = [
  "libc",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+
 [[package]]
 name = "hostname"
 version = "0.3.1"
@@ -435,7 +371,7 @@ checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
 dependencies = [
  "libc",
  "match_cfg",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -454,11 +390,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.3.2"
+version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
+checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
 dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
+ "hashbrown",
 ]
 
 [[package]]
@@ -472,15 +409,15 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
 
 [[package]]
 name = "js-sys"
-version = "0.3.39"
+version = "0.3.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa5a448de267e7358beaf4a5d849518fe9a0c13fce7afd44b06e68550e5562a7"
+checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -524,7 +461,7 @@ version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
 dependencies = [
- "arrayvec 0.4.12",
+ "arrayvec",
  "cfg-if 0.1.10",
  "rustc_version",
  "ryu",
@@ -533,9 +470,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.81"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
+checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
 
 [[package]]
 name = "libsodium-sys"
@@ -559,11 +496,11 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.8"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
 ]
 
 [[package]]
@@ -572,6 +509,15 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
 
+[[package]]
+name = "mach"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "markup5ever"
 version = "0.8.1"
@@ -595,23 +541,17 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
 
-[[package]]
-name = "maybe-uninit"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
-
 [[package]]
 name = "memchr"
-version = "2.3.3"
+version = "2.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
 
 [[package]]
 name = "mio"
-version = "0.6.21"
+version = "0.6.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
+checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
 dependencies = [
  "cfg-if 0.1.10",
  "fuchsia-zircon",
@@ -628,9 +568,9 @@ dependencies = [
 
 [[package]]
 name = "miow"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
 dependencies = [
  "kernel32-sys",
  "net2",
@@ -640,9 +580,9 @@ dependencies = [
 
 [[package]]
 name = "native-tls"
-version = "0.2.4"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d"
+checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4"
 dependencies = [
  "lazy_static",
  "libc",
@@ -658,13 +598,13 @@ dependencies = [
 
 [[package]]
 name = "net2"
-version = "0.2.33"
+version = "0.2.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
+checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
 dependencies = [
  "cfg-if 0.1.10",
  "libc",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -710,19 +650,19 @@ version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
 dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
  "num-integer",
- "num-traits 0.2.11",
+ "num-traits 0.2.14",
 ]
 
 [[package]]
 name = "num-integer"
-version = "0.1.42"
+version = "0.1.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
 dependencies = [
- "autocfg 1.0.0",
- "num-traits 0.2.11",
+ "autocfg 1.0.1",
+ "num-traits 0.2.14",
 ]
 
 [[package]]
@@ -731,10 +671,10 @@ version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
 dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
  "num-bigint",
  "num-integer",
- "num-traits 0.2.11",
+ "num-traits 0.2.14",
 ]
 
 [[package]]
@@ -747,7 +687,7 @@ dependencies = [
  "num-bigint",
  "num-integer",
  "num-rational",
- "num-traits 0.2.11",
+ "num-traits 0.2.14",
 ]
 
 [[package]]
@@ -756,23 +696,23 @@ version = "0.1.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
 dependencies = [
- "num-traits 0.2.11",
+ "num-traits 0.2.14",
 ]
 
 [[package]]
 name = "num-traits"
-version = "0.2.11"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
 dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.3.1"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
+checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
 
 [[package]]
 name = "opaque-debug"
@@ -782,12 +722,12 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
 
 [[package]]
 name = "openssl"
-version = "0.10.29"
+version = "0.10.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd"
+checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70"
 dependencies = [
  "bitflags",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "foreign-types",
  "lazy_static",
  "libc",
@@ -802,20 +742,20 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
 
 [[package]]
 name = "openssl-src"
-version = "111.9.0+1.1.1g"
+version = "111.13.0+1.1.1i"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2dbe10ddd1eb335aba3780eb2eaa13e1b7b441d2562fd962398740927f39ec4"
+checksum = "045e4dc48af57aad93d665885789b43222ae26f4886494da12d1ed58d309dcb6"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.58"
+version = "0.9.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
+checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6"
 dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
  "cc",
  "libc",
  "openssl-src",
@@ -852,9 +792,9 @@ dependencies = [
  "cfg-if 0.1.10",
  "cloudabi",
  "libc",
- "redox_syscall",
- "smallvec 1.4.0",
- "winapi 0.3.8",
+ "redox_syscall 0.1.57",
+ "smallvec",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -897,15 +837,15 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.17"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
+checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.8"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
 
 [[package]]
 name = "precomputed-hash"
@@ -915,9 +855,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "proc-macro-hack"
-version = "0.5.15"
+version = "0.5.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
 
 [[package]]
 name = "proc-macro2"
@@ -930,18 +870,16 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.10"
+version = "1.0.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
 dependencies = [
- "unicode-xid 0.2.0",
+ "unicode-xid 0.2.1",
 ]
 
 [[package]]
 name = "prolog_parser"
 version = "0.8.68"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520bf98dcd386ef320ef11239415c9a11856d3b28fab0d8dc0b61b0d7e65ffe5"
 dependencies = [
  "lexical",
  "num-rug-adapter",
@@ -961,11 +899,11 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.3"
+version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
+checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
 dependencies = [
- "proc-macro2 1.0.10",
+ "proc-macro2 1.0.24",
 ]
 
 [[package]]
@@ -984,20 +922,19 @@ dependencies = [
  "rand_os",
  "rand_pcg",
  "rand_xorshift",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
 name = "rand"
-version = "0.7.3"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
 dependencies = [
- "getrandom",
  "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc 0.2.0",
+ "rand_chacha 0.3.0",
+ "rand_core 0.6.1",
+ "rand_hc 0.3.0",
 ]
 
 [[package]]
@@ -1012,12 +949,12 @@ dependencies = [
 
 [[package]]
 name = "rand_chacha"
-version = "0.2.2"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.5.1",
+ "rand_core 0.6.1",
 ]
 
 [[package]]
@@ -1037,9 +974,9 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5"
 dependencies = [
  "getrandom",
 ]
@@ -1055,11 +992,11 @@ dependencies = [
 
 [[package]]
 name = "rand_hc"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
 dependencies = [
- "rand_core 0.5.1",
+ "rand_core 0.6.1",
 ]
 
 [[package]]
@@ -1079,7 +1016,7 @@ checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
 dependencies = [
  "libc",
  "rand_core 0.4.2",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -1093,7 +1030,7 @@ dependencies = [
  "libc",
  "rand_core 0.4.2",
  "rdrand",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -1126,19 +1063,27 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.1.56"
+version = "0.1.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570"
+dependencies = [
+ "bitflags",
+]
 
 [[package]]
 name = "redox_users"
-version = "0.3.4"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
 dependencies = [
  "getrandom",
- "redox_syscall",
- "rust-argon2",
+ "redox_syscall 0.2.4",
 ]
 
 [[package]]
@@ -1149,18 +1094,18 @@ checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
 
 [[package]]
 name = "remove_dir_all"
-version = "0.5.2"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
 dependencies = [
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
 name = "ring"
-version = "0.16.13"
+version = "0.16.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "703516ae74571f24b465b4a1431e81e2ad51336cb0ded733a55a1aa3eccac196"
+checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226"
 dependencies = [
  "cc",
  "libc",
@@ -1168,7 +1113,7 @@ dependencies = [
  "spin",
  "untrusted",
  "web-sys",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -1193,27 +1138,15 @@ dependencies = [
 
 [[package]]
 name = "rug"
-version = "1.8.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72315b6d9cb7d886fb99724330c47ceb29e923df657c31da3849fe88c0ded710"
+checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45"
 dependencies = [
  "az",
  "gmp-mpfr-sys",
  "libc",
 ]
 
-[[package]]
-name = "rust-argon2"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
-dependencies = [
- "base64 0.11.0",
- "blake2b_simd",
- "constant_time_eq",
- "crossbeam-utils",
-]
-
 [[package]]
 name = "rustc_version"
 version = "0.2.3"
@@ -1225,13 +1158,13 @@ dependencies = [
 
 [[package]]
 name = "rustyline"
-version = "7.0.0"
+version = "7.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a5f54deba50e65ee4cf786dbc37e8b3c63bdccccbcf9d3a8a9fd0c1bb7e1984"
+checksum = "8227301bfc717136f0ecbd3d064ba8199e44497a0bdd46bb01ede4387cfd2cec"
 dependencies = [
  "bitflags",
  "cfg-if 1.0.0",
- "dirs",
+ "dirs-next",
  "fs2",
  "libc",
  "log",
@@ -1241,14 +1174,14 @@ dependencies = [
  "unicode-segmentation",
  "unicode-width",
  "utf8parse",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
 
 [[package]]
 name = "schannel"
@@ -1257,7 +1190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
 dependencies = [
  "lazy_static",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -1270,7 +1203,7 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 name = "scryer-prolog"
 version = "0.8.127"
 dependencies = [
- "base64 0.12.3",
+ "base64",
  "blake2",
  "chrono",
  "cpu-time",
@@ -1297,15 +1230,16 @@ dependencies = [
  "rustyline",
  "select",
  "sha3",
+ "slice-deque",
  "sodiumoxide",
  "unicode_reader",
 ]
 
 [[package]]
 name = "security-framework"
-version = "0.4.4"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535"
+checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69"
 dependencies = [
  "bitflags",
  "core-foundation",
@@ -1316,9 +1250,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "0.4.3"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405"
+checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -1351,26 +1285,26 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
 name = "serde"
-version = "1.0.114"
+version = "1.0.123"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
+checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
 
 [[package]]
 name = "serde_derive"
-version = "1.0.113"
+version = "1.0.123"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93c5eaa17d0954cb481cdcfffe9d84fcfa7a1a9f2349271e678677be4c26ae31"
+checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
 dependencies = [
- "proc-macro2 1.0.10",
- "quote 1.0.3",
- "syn 1.0.18",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "syn 1.0.60",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.55"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
+checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
 dependencies = [
  "itoa",
  "ryu",
@@ -1392,9 +1326,9 @@ dependencies = [
 
 [[package]]
 name = "signal-hook"
-version = "0.1.13"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10b9f3a1686a29f53cfd91ee5e3db3c12313ec02d33765f02c1a9645a1811e2c"
+checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
 dependencies = [
  "libc",
  "mio",
@@ -1403,11 +1337,10 @@ dependencies = [
 
 [[package]]
 name = "signal-hook-registry"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
+checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
 dependencies = [
- "arc-swap",
  "libc",
 ]
 
@@ -1424,19 +1357,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
 
 [[package]]
-name = "smallvec"
-version = "0.6.13"
+name = "slice-deque"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
+checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25"
 dependencies = [
- "maybe-uninit",
+ "libc",
+ "mach",
+ "winapi 0.3.9",
 ]
 
 [[package]]
 name = "smallvec"
-version = "1.4.0"
+version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
+checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
 
 [[package]]
 name = "sodiumoxide"
@@ -1484,8 +1419,8 @@ checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6"
 dependencies = [
  "phf_generator",
  "phf_shared",
- "proc-macro2 1.0.10",
- "quote 1.0.3",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
  "string_cache_shared",
 ]
 
@@ -1514,34 +1449,34 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.18"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
+checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
 dependencies = [
- "proc-macro2 1.0.10",
- "quote 1.0.3",
- "unicode-xid 0.2.0",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "unicode-xid 0.2.1",
 ]
 
 [[package]]
 name = "tempfile"
-version = "3.1.0"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "libc",
- "rand 0.7.3",
- "redox_syscall",
+ "rand 0.8.3",
+ "redox_syscall 0.2.4",
  "remove_dir_all",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
 name = "tendril"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b"
+checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33"
 dependencies = [
  "futf",
  "mac",
@@ -1555,7 +1490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
 dependencies = [
  "libc",
- "winapi 0.3.8",
+ "winapi 0.3.9",
 ]
 
 [[package]]
@@ -1566,15 +1501,15 @@ checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.6.0"
+version = "1.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
 
 [[package]]
 name = "unicode-xid"
@@ -1584,17 +1519,17 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 
 [[package]]
 name = "unicode_reader"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f886d405a2be65db804cb1088f969dbd99528a9eec9bcf941584b17de4cd3034"
+checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a"
 dependencies = [
- "smallvec 0.6.13",
+ "smallvec",
  "unicode-segmentation",
 ]
 
@@ -1627,9 +1562,9 @@ checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
 
 [[package]]
 name = "vcpkg"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c"
+checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
 
 [[package]]
 name = "void"
@@ -1639,69 +1574,69 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 
 [[package]]
 name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
+version = "0.10.2+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.62"
+version = "0.2.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551"
+checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.62"
+version = "0.2.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94"
+checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
 dependencies = [
  "bumpalo",
  "lazy_static",
  "log",
- "proc-macro2 1.0.10",
- "quote 1.0.3",
- "syn 1.0.18",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "syn 1.0.60",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.62"
+version = "0.2.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776"
+checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
 dependencies = [
- "quote 1.0.3",
+ "quote 1.0.8",
  "wasm-bindgen-macro-support",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.62"
+version = "0.2.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a"
+checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
 dependencies = [
- "proc-macro2 1.0.10",
- "quote 1.0.3",
- "syn 1.0.18",
+ "proc-macro2 1.0.24",
+ "quote 1.0.8",
+ "syn 1.0.60",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.62"
+version = "0.2.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad"
+checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
 
 [[package]]
 name = "web-sys"
-version = "0.3.39"
+version = "0.3.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bc359e5dd3b46cb9687a051d50a2fdd228e4ba7cf6fcf861a5365c3d671a642"
+checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -1715,9 +1650,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 
 [[package]]
 name = "winapi"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 dependencies = [
  "winapi-i686-pc-windows-gnu",
  "winapi-x86_64-pc-windows-gnu",
@@ -1753,6 +1688,6 @@ dependencies = [
 
 [[package]]
 name = "xmlparser"
-version = "0.13.2"
+version = "0.13.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52613e655f6f11f63c0fe7d1c3b5ef69e44d96df9b65dab296b441ed0e1125f5"
+checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
index 6d10a3ae3be5767b08cc50c3e4aa7d22ae60b1d2..cf1d85e36b6f2e271e755ab5fe0b9ee5888cfa77 100644 (file)
@@ -32,7 +32,7 @@ libc = "0.2.62"
 nix = "0.15.0"
 num-rug-adapter = { optional = true, version = "0.1.4" }
 ordered-float = "0.5.0"
-prolog_parser = { version = "0.8.68", default-features = false }
+prolog_parser = { version = "0.8.63", path = "../prolog_parser", default-features = false }
 ref_thread_local = "0.0.0"
 rug = { version = "1.4.0", optional = true }
 rustyline = "7.0.0"
@@ -48,3 +48,4 @@ select = "0.4.3"
 roxmltree = "0.11.0"
 base64 = "0.12.3"
 sodiumoxide = "0.2.6"
+slice-deque = "0.3.0"
\ No newline at end of file
index a9ec444e45f0e0ab54109bd8462f9f6b2c44b6ac..aaa876abf9f725d57ebbaa8099dc0764db2f8ca8 100644 (file)
--- a/build.rs
+++ b/build.rs
@@ -11,6 +11,7 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
         Ok(entries) => entries,
         Err(_) => return,
     };
+
     for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
         if entry.is_dir() {
             if let Some(file_name) = entry.file_name() {
@@ -24,6 +25,7 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
                 let contain =
                     String::from_utf8(fs::read(&entry).unwrap()).unwrap();
                 let name = entry.file_stem().unwrap().to_str().unwrap();
+
                 let line = format!(
                     "        m.insert(\"{}\",\n{:?});\n",
                     prefix.to_owned() + name,
index dbaefb6962ded0ce751790caa5f9d37c4c7fa636..a0318d8dc39fcb565321192bd9f9c9f5d247b6b3 100644 (file)
@@ -150,11 +150,11 @@ impl InlinedClauseType {
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 pub enum SystemClauseType {
-    AbolishClause,
-    AbolishModuleClause,
-    AssertDynamicPredicateToBack,
-    AssertDynamicPredicateToFront,
-    AtEndOfExpansion,
+    // AbolishClause,
+    // AbolishModuleClause,
+    // AssertDynamicPredicateToBack,
+    // AssertDynamicPredicateToFront,
+    // AtEndOfExpansion,
     AtomChars,
     AtomCodes,
     AtomLength,
@@ -189,8 +189,8 @@ pub enum SystemClauseType {
     DynamicModuleResolution(usize),
     EnqueueAttributeGoal,
     EnqueueAttributedVar,
-    ExpandGoal,
-    ExpandTerm,
+//  ExpandGoal,
+//  ExpandTerm,
     FetchGlobalVar,
     FetchGlobalVarWithOffset,
     FirstStream,
@@ -207,16 +207,16 @@ pub enum SystemClauseType {
     GetAttrVarQueueDelimiter,
     GetAttrVarQueueBeyond,
     GetBValue,
-    GetClause,
+//  GetClause,
     GetContinuationChunk,
-    GetModuleClause,
+//  GetModuleClause,
     GetNextDBRef,
     GetNextOpDBRef,
     IsPartialString,
     LookupDBRef,
     LookupOpDBRef,
     Halt,
-    ModuleHeadIsDynamic,
+//  ModuleHeadIsDynamic,
     GetLiftedHeapFromOffset,
     GetLiftedHeapFromOffsetDiff,
     GetSCCCleaner,
@@ -224,11 +224,11 @@ pub enum SystemClauseType {
     InstallSCCCleaner,
     InstallInferenceCounter,
     LiftedHeapLength,
-    ModuleAssertDynamicPredicateToFront,
-    ModuleAssertDynamicPredicateToBack,
+    LoadLibraryAsStream,
+    // ModuleAssertDynamicPredicateToFront,
+    // ModuleAssertDynamicPredicateToBack,
     ModuleExists,
-    ModuleOf,
-    ModuleRetractClause,
+    // ModuleRetractClause,
     NextEP,
     NoSuchPredicate,
     NumberToChars,
@@ -254,7 +254,7 @@ pub enum SystemClauseType {
     ResetContinuationMarker,
     ResetGlobalVarAtKey,
     ResetGlobalVarAtOffset,
-    RetractClause,
+    // RetractClause,
     RestoreCutPolicy,
     SetCutPoint(RegType),
     SetInput,
@@ -324,11 +324,11 @@ pub enum SystemClauseType {
 impl SystemClauseType {
     pub fn name(&self) -> ClauseName {
         match self {
-            &SystemClauseType::AbolishClause => clause_name!("$abolish_clause"),
-            &SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
-            &SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
-            &SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
-            &SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"),
+            // &SystemClauseType::AbolishClause => clause_name!("$abolish_clause"),
+            // &SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
+            // &SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
+            // &SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
+            // &SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"),
             &SystemClauseType::AtomChars => clause_name!("$atom_chars"),
             &SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
             &SystemClauseType::AtomLength => clause_name!("$atom_length"),
@@ -356,17 +356,50 @@ impl SystemClauseType {
             &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
             &SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
             &SystemClauseType::FileTime => clause_name!("$file_time"),
-            &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
-            &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
-            &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
-                    clause_name!("$use_qualified_module")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => {
-                    clause_name!("$use_module_from_file")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
-                    clause_name!("$use_qualified_module_from_file")
-            }
+            &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) =>
+                clause_name!("$add_dynamic_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::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::UserAsserta) =>
+                clause_name!("$asserta"),
+            &SystemClauseType::REPL(REPLCodePtr::UserAssertz) =>
+                clause_name!("$assertz"),
+            &SystemClauseType::REPL(REPLCodePtr::UserRetract) =>
+                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::CompilePendingPredicates) =>
+                clause_name!("$compile_pending_predicates"),
             &SystemClauseType::Close => clause_name!("$close"),
             &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
             &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
@@ -374,12 +407,9 @@ impl SystemClauseType {
             &SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"),
             &SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"),
             &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
-            &SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
-            &SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
             &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
-            &SystemClauseType::FetchGlobalVarWithOffset => {
-                clause_name!("$fetch_global_var_with_offset")
-            }
+            &SystemClauseType::FetchGlobalVarWithOffset =>
+                clause_name!("$fetch_global_var_with_offset"),
             &SystemClauseType::FirstStream => clause_name!("$first_stream"),
             &SystemClauseType::FlushOutput => clause_name!("$flush_output"),
             &SystemClauseType::GetByte => clause_name!("$get_byte"),
@@ -405,13 +435,13 @@ impl SystemClauseType {
                 clause_name!("$get_lh_from_offset_diff")
             }
             &SystemClauseType::GetBValue => clause_name!("$get_b_value"),
-            &SystemClauseType::GetClause => clause_name!("$get_clause"),
+//          &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::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"),
@@ -430,15 +460,14 @@ impl SystemClauseType {
             &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::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::ModuleOf => clause_name!("$module_of"),
             &SystemClauseType::NextStream => clause_name!("$next_stream"),
             &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
             &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
@@ -483,14 +512,13 @@ impl SystemClauseType {
             &SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
             &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
             &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
-            &SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
+            // &SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
             &SystemClauseType::NextEP => clause_name!("$nextEP"),
             &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
             &SystemClauseType::ReadTerm => clause_name!("$read_term"),
             &SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
             &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
             &SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
-            &SystemClauseType::RetractClause => clause_name!("$retract_clause"),
             &SystemClauseType::ResetBlock => clause_name!("$reset_block"),
             &SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
             &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
@@ -533,22 +561,27 @@ impl SystemClauseType {
             &SystemClauseType::SetEnv => clause_name!("$setenv"),
             &SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
             &SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
+            &SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"),
         }
     }
 
     pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
         match (name, arity) {
-            ("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause),
-            ("$at_end_of_expansion", 0) => Some(SystemClauseType::AtEndOfExpansion),
+            // ("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause),
+            ("$add_dynamic_predicate", 3) =>
+                Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate)),
+            ("$add_goal_expansion_clause", 4) =>
+                Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause)),
+            ("$add_term_expansion_clause", 3) =>
+                Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause)),
+            // ("$at_end_of_expansion", 0) => Some(SystemClauseType::AtEndOfExpansion),
             ("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
             ("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
             ("$atom_length", 2) => Some(SystemClauseType::AtomLength),
-            ("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
+            // ("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
             ("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
-            ("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
-            ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
-            ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
-            ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
+            // ("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
+            // ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
             ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
             ("$char_code", 2) => Some(SystemClauseType::CharCode),
             ("$char_type", 2) => Some(SystemClauseType::CharType),
@@ -559,7 +592,6 @@ impl SystemClauseType {
             ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
             ("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
             ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
-            ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
             ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
             ("$close", 2) => Some(SystemClauseType::Close),
             ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
@@ -582,8 +614,8 @@ impl SystemClauseType {
             ("$peek_char", 2) => Some(SystemClauseType::PeekChar),
             ("$peek_code", 2) => Some(SystemClauseType::PeekCode),
             ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
-            ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
-            ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
+//          ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
+//          ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
             ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
             ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
             ("$get_byte", 2) => Some(SystemClauseType::GetByte),
@@ -615,14 +647,14 @@ impl SystemClauseType {
             }
             ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
             ("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
-            ("$get_clause", 2) => Some(SystemClauseType::GetClause),
-            ("$get_module_clause", 3) => Some(SystemClauseType::GetModuleClause),
+//          ("$get_clause", 2) => Some(SystemClauseType::GetClause),
+//          ("$get_module_clause", 3) => Some(SystemClauseType::GetModuleClause),
             ("$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", 1) => Some(SystemClauseType::HeadIsDynamic),
+            ("$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),
@@ -630,10 +662,9 @@ impl SystemClauseType {
             ("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
             ("$current_time", 1) => Some(SystemClauseType::CurrentTime),
             ("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
-            ("$module_of", 2) => Some(SystemClauseType::ModuleOf),
-            ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
-            ("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
-            ("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate),
+            // ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
+            // ("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
+            ("$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),
@@ -667,7 +698,7 @@ impl SystemClauseType {
             ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
             ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
             ("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
-            ("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
+            // ("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
             ("$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))),
@@ -697,15 +728,17 @@ impl SystemClauseType {
             ("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
             ("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
             ("$file_time", 3) => Some(SystemClauseType::FileTime),
-            ("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
-            ("$use_module_from_file", 1) =>
-                    Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)),
-            ("$use_qualified_module", 2) =>
-                    Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)),
-            ("$use_qualified_module_from_file", 2) =>
-                    Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
+            ("$clause_to_evacuable", 3) => Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable)),
+            ("$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", 2) => Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary)),
+            ("$push_load_state_payload", 1) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload)),
+            ("$asserta", 4) => Some(SystemClauseType::REPL(REPLCodePtr::UserAsserta)),
+            ("$assertz", 4) => Some(SystemClauseType::REPL(REPLCodePtr::UserAssertz)),
+            ("$retract_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UserRetract)),
             ("$variant", 2) => Some(SystemClauseType::Variant),
-            ("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
+            ("$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),
@@ -727,6 +760,17 @@ impl SystemClauseType {
             ("$setenv", 2) => Some(SystemClauseType::SetEnv),
             ("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
             ("$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", 3) => Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty)),
+            ("$compile_pending_predicates", 1) => Some(SystemClauseType::REPL(REPLCodePtr::CompilePendingPredicates)),
             _ => None,
         }
     }
@@ -754,7 +798,6 @@ pub enum BuiltInClauseType {
 pub enum ClauseType {
     BuiltIn(BuiltInClauseType),
     CallN,
-    Hook(CompileTimeHook),
     Inlined(InlinedClauseType),
     Named(ClauseName, usize, CodeIndex), // name, arity, index.
     Op(ClauseName, SharedOpDesc, CodeIndex),
@@ -818,7 +861,6 @@ impl ClauseType {
         match self {
             &ClauseType::BuiltIn(ref built_in) => built_in.name(),
             &ClauseType::CallN => clause_name!("call"),
-            &ClauseType::Hook(ref hook) => hook.name(),
             &ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
             &ClauseType::Op(ref name, ..) => name.clone(),
             &ClauseType::Named(ref name, ..) => name.clone(),
index d260cfa078a21e99d446d68c827f78c6f776c104..1f349246cedfdf1ea84abe650a4dc0c7d3a4eba8 100644 (file)
@@ -1,5 +1,6 @@
 /// Code generation to WAM-like instructions.
 use crate::prolog_parser::ast::*;
+use crate::prolog_parser::tabled_rc::TabledData;
 
 use crate::allocator::*;
 use crate::arithmetic::*;
@@ -9,20 +10,32 @@ use crate::forms::*;
 use crate::indexing::*;
 use crate::instructions::*;
 use crate::iterators::*;
-use crate::machine::machine_indices::*;
 use crate::targets::*;
 
+use crate::machine::machine_errors::*;
+
 use crate::indexmap::{IndexMap, IndexSet};
 
 use std::cell::Cell;
+use std::collections::VecDeque;
 use std::rc::Rc;
-use std::vec::Vec;
 
-#[derive(Debug)]
-pub struct CodeGenerator<TermMarker> {
-    marker: TermMarker,
-    pub var_count: IndexMap<Rc<Var>, usize>,
-    non_counted_bt: bool,
+#[inline]
+pub fn trust_me(non_counted_bt: bool) -> ChoiceInstruction {
+    if non_counted_bt {
+        ChoiceInstruction::DefaultTrustMe(0)
+    } else {
+        ChoiceInstruction::TrustMe(0)
+    }
+}
+
+#[inline]
+pub fn retry_me_else(offset: usize, non_counted_bt: bool) -> ChoiceInstruction {
+    if non_counted_bt {
+        ChoiceInstruction::DefaultRetryMeElse(offset)
+    } else {
+        ChoiceInstruction::RetryMeElse(offset)
+    }
 }
 
 #[derive(Debug)]
@@ -97,19 +110,48 @@ impl<'a> ConjunctInfo<'a> {
     }
 }
 
+#[derive(Clone, Copy, Debug)]
+pub struct CodeGenSettings {
+    pub is_extensible: bool,
+    pub non_counted_bt: bool,
+}
+
+impl CodeGenSettings {
+    #[inline]
+    pub fn new(is_extensible: bool, non_counted_bt: bool) -> Self {
+        CodeGenSettings {
+            is_extensible,
+            non_counted_bt,
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct CodeGenerator<TermMarker> {
+    atom_tbl: TabledData<Atom>,
+    marker: TermMarker,
+    pub var_count: IndexMap<Rc<Var>, usize>,
+    non_counted_bt: bool,
+    is_extensible: bool,
+    pub skeleton: PredicateSkeleton,
+    pub jmp_by_locs: Vec<usize>,
+    global_jmp_by_locs_offset: usize,
+}
+
 impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
-    pub fn new(non_counted_bt: bool) -> Self {
+    pub fn new(atom_tbl: TabledData<Atom>, settings: CodeGenSettings) -> Self {
         CodeGenerator {
+            atom_tbl,
             marker: Allocator::new(),
             var_count: IndexMap::new(),
-            non_counted_bt,
+            non_counted_bt: settings.non_counted_bt,
+            is_extensible: settings.is_extensible,
+            skeleton: PredicateSkeleton::new(),
+            jmp_by_locs: vec![],
+            global_jmp_by_locs_offset: 0,
         }
     }
 
-    pub fn take_vars(self) -> AllocVarDict {
-        self.marker.take_bindings()
-    }
-
     fn update_var_count<Iter: Iterator<Item = TermRef<'a>>>(&mut self, iter: Iter) {
         for term in iter {
             if let TermRef::Var(_, _, var) = term {
@@ -337,16 +379,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         ConjunctInfo::new(vs, num_of_chunks, has_deep_cut)
     }
 
-    fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize) {
+    fn add_conditional_call(&mut self, code: &mut Code, qt: &QueryTerm, pvs: usize) {
         match qt {
-            &QueryTerm::Jump(ref vars) => code.push(jmp_call!(vars.len(), 0, pvs)),
+            &QueryTerm::Jump(ref vars) => {
+                self.jmp_by_locs.push(code.len());
+                code.push(jmp_call!(vars.len(), 0, pvs));
+            }
             &QueryTerm::Clause(_, ref ct, ref terms, true) => {
-                code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs))
+                code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs));
             }
             &QueryTerm::Clause(_, ref ct, ref terms, false) => {
-                code.push(call_clause!(ct.clone(), terms.len(), pvs))
+                code.push(call_clause!(ct.clone(), terms.len(), pvs));
+            }
+            _ => {
             }
-            _ => {}
         }
     }
 
@@ -356,16 +402,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         match code.last_mut() {
             Some(&mut Line::Control(ref mut ctrl)) => match ctrl {
                 &mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => {
-                    *last_call = true
+                    *last_call = true;
                 }
                 &mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => {
-                    *last_call = true
+                    *last_call = true;
+                }
+                &mut ControlInstruction::Proceed => {
+                }
+                _ => {
+                    dealloc_index += 1;
                 }
-                &mut ControlInstruction::Proceed => {}
-                _ => dealloc_index += 1,
             },
-            Some(&mut Line::Cut(CutInstruction::Cut(_))) => dealloc_index += 1,
-            _ => {}
+            Some(&mut Line::Cut(CutInstruction::Cut(_))) => {
+                dealloc_index += 1;
+            }
+            _ => {
+            }
         };
 
         dealloc_index
@@ -377,7 +429,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         terms: &'a Vec<Box<Term>>,
         term_loc: GenContext,
         code: &mut Code,
-    ) -> Result<(), ParserError> {
+    ) -> Result<(), CompilationError> {
         match ct {
             &InlinedClauseType::CompareNumber(cmp, ..) => {
                 self.marker.reset_arg(2);
@@ -553,7 +605,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         code: &mut Code,
         term_loc: GenContext,
         use_default_call_policy: bool,
-    ) -> Result<(), ParserError> {
+    ) -> Result<(), CompilationError> {
         let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
         code.append(&mut acode);
 
@@ -656,7 +708,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         conjunct_info: &ConjunctInfo<'a>,
         code: &mut Code,
         is_exposed: bool,
-    ) -> Result<(), ParserError> {
+    ) -> Result<(), CompilationError> {
         for (chunk_num, _, terms) in iter.rule_body_iter() {
             for (i, term) in terms.iter().enumerate() {
                 let term_loc = if i + 1 < terms.len() {
@@ -669,18 +721,24 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                     &QueryTerm::GetLevelAndUnify(ref cell, ref var) => {
                         self.compile_get_level_and_unify(code, cell, var.clone(), term_loc)
                     }
-                    &QueryTerm::UnblockedCut(ref cell) => self.compile_unblocked_cut(code, cell),
-                    &QueryTerm::BlockedCut => code.push(if chunk_num == 0 {
-                        Line::Cut(CutInstruction::NeckCut)
-                    } else {
-                        Line::Cut(CutInstruction::Cut(perm_v!(1)))
-                    }),
+                    &QueryTerm::UnblockedCut(ref cell) => {
+                        self.compile_unblocked_cut(code, cell)
+                    }
+                    &QueryTerm::BlockedCut => {
+                        code.push(if chunk_num == 0 {
+                            Line::Cut(CutInstruction::NeckCut)
+                        } else {
+                            Line::Cut(CutInstruction::Cut(perm_v!(1)))
+                        })
+                    }
                     &QueryTerm::Clause(
                         _,
                         ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
                         ref terms,
                         use_default_call_policy,
-                    ) => self.compile_is_call(terms, code, term_loc, use_default_call_policy)?,
+                    ) => {
+                        self.compile_is_call(terms, code, term_loc, use_default_call_policy)?
+                    }
                     &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
                         self.compile_inlined(ct, terms, term_loc, code)?
                     }
@@ -714,7 +772,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         }
     }
 
-    fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) {
+    fn compile_cleanup(&mut self, code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) {
         // add a proceed to bookend any trailing cuts.
         match toc {
             &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()),
@@ -726,11 +784,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         let dealloc_index = Self::lco(code);
 
         if conjunct_info.allocates() {
+            let offset = self.global_jmp_by_locs_offset;
+
+            if let Some(jmp_by_offset) = self.jmp_by_locs[offset ..].last_mut() {
+                if *jmp_by_offset == dealloc_index {
+                    *jmp_by_offset += 1;
+                }
+            }
+
             code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
         }
     }
 
-    pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, ParserError> {
+    pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, CompilationError> {
         let iter = ChunkedIterator::from_rule(rule);
         let conjunct_info = self.collect_var_data(iter);
 
@@ -739,7 +805,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
             ref clauses,
         } = rule;
 
-        let mut code = Vec::new();
+        let mut code = Code::new();
 
         self.marker.reset_at_head(args);
         self.compile_seq_prelude(&conjunct_info, &mut code);
@@ -761,8 +827,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         self.compile_seq(iter, &conjunct_info, &mut code, false)?;
 
         conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
+        self.compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
 
-        Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
         Ok(code)
     }
 
@@ -836,10 +902,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
             }
         }
 
-        Self::add_conditional_call(code, term, num_perm_vars_left);
+        self.add_conditional_call(code, term, num_perm_vars_left);
     }
 
-    pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Result<Code, ParserError> {
+/*
+    pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Result<Code, CompilationError> {
         let iter = ChunkedIterator::from_term_sequence(query);
         let conjunct_info = self.collect_var_data(iter);
 
@@ -857,6 +924,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
 
         Ok(code)
     }
+*/
+
+    #[inline]
+    fn increment_jmp_by_locs_by(&mut self, incr: usize) {
+        let offset = self.global_jmp_by_locs_offset;
+
+        for loc in &mut self.jmp_by_locs[offset ..] {
+            *loc += incr;
+        }
+    }
 
     /// Returns the index of the first instantiated argument.
     fn first_instantiated_index(clauses: &[PredicateClause]) -> Option<usize> {
@@ -925,48 +1002,50 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
         subseqs
     }
 
-    fn trust_me(&self) -> ChoiceInstruction {
-        if self.non_counted_bt {
-            ChoiceInstruction::DefaultTrustMe
-        } else {
-            ChoiceInstruction::TrustMe
-        }
-    }
-
-    fn retry_me_else(&self, offset: usize) -> ChoiceInstruction {
-        if self.non_counted_bt {
-            ChoiceInstruction::DefaultRetryMeElse(offset)
-        } else {
-            ChoiceInstruction::RetryMeElse(offset)
-        }
-    }
-
     fn compile_pred_subseq<'b: 'a>(
         &mut self,
         clauses: &'b [PredicateClause],
         optimal_index: usize,
-    ) -> Result<Code, ParserError> {
-        let mut code_body = Vec::new();
-        let mut code_offsets = CodeOffsets::new();
+    ) -> Result<Code, CompilationError> {
+        let mut code = VecDeque::new();
+        let mut code_offsets = CodeOffsets::new(self.atom_tbl.clone(), optimal_index + 1);
+        let mut skip_stub_try_me_else = false;
 
-        let num_clauses = clauses.len();
+        let jmp_by_locs_len = self.jmp_by_locs.len();
 
         for (i, clause) in clauses.iter().enumerate() {
             self.marker.reset();
 
-            let mut clause_code = match *clause {
-                PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
-                PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
+            let mut clause_index_info = ClauseIndexInfo::new(code.len());
+            self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
+
+            let clause_code = match clause {
+                &PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
+                &PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
             };
 
-            if num_clauses > 1 {
+            if clauses.len() > 1 {
                 let choice = match i {
                     0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
-                    _ if i == num_clauses - 1 => self.trust_me(),
-                    _ => self.retry_me_else(clause_code.len() + 1),
+                    _ if i == clauses.len() - 1 => trust_me(self.non_counted_bt),
+                    _ => retry_me_else(clause_code.len() + 1, self.non_counted_bt),
                 };
 
-                code_body.push(Line::Choice(choice));
+                code.push_back(Line::Choice(choice));
+            } else if self.is_extensible {
+                /*
+                   generate stub choice instructions for extensible
+                   predicates. if predicates are added to either the
+                   inner or outer thread of choice instructions,
+                   these stubs will be used, and surrounding indexing
+                   instructions modified accordingly.
+
+                   until then, the v offset of SwitchOnTerm will skip
+                   over them.
+                */
+
+                code.push_front(Line::Choice(ChoiceInstruction::TryMeElse(0)));
+                skip_stub_try_me_else = true;
             }
 
             let arg = match clause.args() {
@@ -976,47 +1055,86 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
                 },
                 None => None,
             };
+
             if let Some(arg) = arg {
-                let index = code_body.len();
-                code_offsets.index_term(arg, index);
+                let index = code.len();
+                code_offsets.index_term(arg, index, &mut clause_index_info);
+            }
+
+            if !skip_stub_try_me_else {
+                self.increment_jmp_by_locs_by(code.len());
             }
 
-            code_body.append(&mut clause_code);
+            self.skeleton.clauses.push_back(clause_index_info);
+            code.extend(clause_code.into_iter());
         }
 
-        let mut code = Vec::new();
-        code_offsets.add_indices(&mut code, code_body, optimal_index + 1);
+        let index_code = code_offsets.compute_indices(skip_stub_try_me_else);
+        self.global_jmp_by_locs_offset = jmp_by_locs_len;
 
-        Ok(code)
+        if !index_code.is_empty() {
+            code.push_front(Line::IndexingCode(index_code));
+
+            if skip_stub_try_me_else {
+                // skip the TryMeElse(0) also.
+                 self.increment_jmp_by_locs_by(2);
+            } else {
+                self.increment_jmp_by_locs_by(1);
+            }
+        } else if skip_stub_try_me_else {
+            // remove the TryMeElse(0).
+            code.pop_front();
+        }
+
+        Ok(Vec::from(code))
     }
 
     pub fn compile_predicate<'b: 'a>(
         &mut self,
         clauses: &'b Vec<PredicateClause>,
-    ) -> Result<Code, ParserError> {
-        let mut code = Vec::new();
+    ) -> 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 multi_seq = split_pred.len() > 1;
 
         for (l, r) in split_pred {
-            let mut code_segment =
-                self.compile_pred_subseq(&clauses[l..r], optimal_index)?;
+            let skel_lower_bound = self.skeleton.clauses.len();
+            let code_segment = self.compile_pred_subseq(&clauses[l .. r], optimal_index)?;
+            let clause_start_offset = code.len();
 
             if multi_seq {
                 let choice = match l {
                     0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1),
-                    _ if r == clauses.len() => self.trust_me(),
-                    _ => self.retry_me_else(code_segment.len() + 1),
+                    _ if r == clauses.len() => trust_me(self.non_counted_bt),
+                    _ => retry_me_else(code_segment.len() + 1, self.non_counted_bt),
                 };
 
                 code.push(Line::Choice(choice));
+            } else if self.is_extensible {
+                code.push(Line::Choice(ChoiceInstruction::TryMeElse(0)));
             }
 
-            code.append(&mut code_segment);
+            if self.is_extensible {
+                let segment_is_indexed = to_indexing_line(&code_segment[0]).is_some();
+
+                for clause_index_info in self.skeleton.clauses[skel_lower_bound ..].iter_mut() {
+                    clause_index_info.clause_start +=
+                        clause_start_offset + 2 * (segment_is_indexed as usize);
+                    clause_index_info.opt_arg_index_key +=
+                        clause_start_offset + 1;
+                }
+            }
+
+            self.increment_jmp_by_locs_by(code.len());
+            self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
+
+            code.extend(code_segment.into_iter());
         }
 
         Ok(code)
index be572bc4c9c6cc89387f4281f260c06f14c33ccc..006371eb7bf94bce25b00aa883fd88ece635e73e 100644 (file)
@@ -1,6 +1,5 @@
 use crate::prolog_parser::ast::*;
 use crate::prolog_parser::parser::OpDesc;
-use crate::prolog_parser::tabled_rc::*;
 
 use crate::clause_types::*;
 use crate::machine::machine_errors::*;
@@ -8,15 +7,19 @@ use crate::machine::machine_indices::*;
 use crate::ordered_float::OrderedFloat;
 use crate::rug::{Integer, Rational};
 
-use crate::indexmap::IndexMap;
+use crate::indexmap::{IndexMap, IndexSet};
+
+use slice_deque::*;
 
 use std::cell::Cell;
-use std::collections::VecDeque;
+use std::ops::AddAssign;
 use std::path::PathBuf;
 use std::rc::Rc;
 
 pub type PredicateKey = (ClauseName, 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 type JumpStub = Vec<Term>;
@@ -24,19 +27,24 @@ pub type JumpStub = Vec<Term>;
 #[derive(Debug, Clone)]
 pub enum TopLevel {
     Declaration(Declaration),
-    Fact(Term, usize, usize), // Term, line_num, col_num
+    Fact(Term), // Term, line_num, col_num
     Predicate(Predicate),
     Query(Vec<QueryTerm>),
-    Rule(Rule, usize, usize), // Rule, line_num, col_num
+    Rule(Rule), // Rule, line_num, col_num
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum AppendOrPrepend {
+    Append,
+    Prepend
 }
 
-impl TopLevel {
-    pub fn is_end_of_file_atom(&self) -> bool {
+impl AppendOrPrepend {
+    #[inline]
+    pub fn is_append(self) -> bool {
         match self {
-            &TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => {
-                return name.as_str() == "end_of_file"
-            }
-            _ => false,
+            AppendOrPrepend::Append => true,
+            AppendOrPrepend::Prepend => false,
         }
     }
 }
@@ -91,30 +99,9 @@ pub struct Rule {
     pub clauses: Vec<QueryTerm>,
 }
 
-#[derive(Debug, Clone)]
-pub struct Predicate(pub Vec<PredicateClause>);
-
-impl Predicate {
-    #[inline]
-    pub fn new() -> Self {
-        Predicate(vec![])
-    }
-
-    #[inline]
-    pub fn clauses(self) -> Vec<PredicateClause> {
-        self.0
-    }
-
-    #[inline]
-    pub fn predicate_indicator(&self) -> Option<(ClauseName, usize)> {
-        self.0
-            .first()
-            .and_then(|clause| clause.name().map(|name| (name, clause.arity())))
-    }
-}
-
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug, Hash)]
 pub enum ListingSource {
+    DynamicallyGenerated,
     File(ClauseName, PathBuf), // filename, path
     User,
 }
@@ -123,98 +110,13 @@ impl ListingSource {
     pub fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self {
         ListingSource::File(filename, path_buf)
     }
-
-    pub fn name(&self) -> ClauseName {
-        match self {
-            ListingSource::File(ref filename, _) => filename.clone(),
-            ListingSource::User => clause_name!("[user]")
-        }
-    }
-
-    pub fn path(&self) -> PathBuf {
-        match self {
-            ListingSource::File(_, ref path) => path.clone(),
-            ListingSource::User => std::env::current_dir().unwrap(),
-        }
-    }
-}
-
-fn resolved_term_and_module(term: &Term) -> Option<(ClauseName, ClauseName)>
-{
-    match term {
-        Term::Clause(_, ref name, ref terms, _) => {
-            if name.as_str() == ":" && terms.len() == 2 {
-                let module_name = match terms[0].as_ref() {
-                    &Term::Constant(_, Constant::Atom(ref module_name, _)) => {
-                        module_name.clone()
-                    }
-                    _ => {
-                        return Some((name.owning_module(), name.clone()));
-                    }
-                };
-
-                match terms[1].as_ref() {
-                    Term::Clause(_, ref name, ..)
-                  | Term::Constant(_, Constant::Atom(ref name, ..)) => {
-                        return Some((module_name, name.clone()));
-                    }
-                    _ => {
-                    }
-                }
-
-                Some((name.owning_module(), name.clone()))
-            } else {
-                Some((name.owning_module(), name.clone()))
-            }
-        }
-        Term::Constant(_, Constant::Atom(ref name, _)) => {
-            Some((name.owning_module(), name.clone()))
-        }
-        _ => {
-            None
-        }
-    }
 }
 
-fn resolved_term_arity(term: &Term) -> usize
-{
-    match term {
-        Term::Clause(_, ref name, ref terms, _) => {
-            if name.as_str() == ":" && terms.len() == 2 {
-                match terms[0].as_ref() {
-                    &Term::Constant(_, Constant::Atom(..)) => {
-                    }
-                    _ => {
-                        return 2;
-                    }
-                }
-
-                match terms[1].as_ref() {
-                    Term::Clause(_, _, ref terms, _) => {
-                        terms.len()
-                    }
-                    Term::Constant(_, Constant::Atom(..)) => {
-                        0
-                    }
-                    _ => {
-                        2
-                    }
-                }
-            } else {
-                terms.len()
-            }
-        }
-        _ => {
-            0
-        }
-    }
-}
-
-pub trait ClauseConsistency {
+pub trait ClauseInfo {
     fn is_consistent(&self, clauses: &Vec<PredicateClause>) -> bool {
         match clauses.first() {
-            Some(ref cl) => {
-                self.name_and_module() == cl.name_and_module() && self.arity() == cl.arity()
+            Some(cl) => {
+                self.name() == cl.name() && self.arity() == cl.arity()
             }
             None => {
                 true
@@ -222,33 +124,29 @@ pub trait ClauseConsistency {
         }
     }
 
-    fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>;
+    fn name(&self) -> Option<ClauseName>;
     fn arity(&self) -> usize;
 }
 
-/* Of course '$current_module$' isn't the name of the current
- * module. It'll do if no module is explicitly specified through
- * (:)/2.
- */
-impl ClauseConsistency for Term {
-    fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>
-    {
+impl ClauseInfo for Term {
+    fn name(&self) -> Option<ClauseName> {
         match self {
-            Term::Clause(_, ref name, ref terms, _) =>
+            Term::Clause(_, ref name, ref terms, _) => {
                 match name.as_str() {
                     ":-" => {
                         match terms.len() {
                             1 => None, // a declaration.
-                            2 => resolved_term_and_module(&terms[0]),
-                            _ => Some((name.owning_module(), clause_name!(":-"))),
+                            2 => terms[0].name(),
+                            _ => Some(clause_name!(":-")),
                         }
                     }
                     _ => {
-                        resolved_term_and_module(self)
+                        Some(name.clone())
                     }
-                },
+                }
+            }
             Term::Constant(_, Constant::Atom(ref name, _)) => {
-                Some((name.owning_module(), name.clone()))
+                Some(name.clone())
             }
             _ => {
                 None
@@ -263,12 +161,12 @@ impl ClauseConsistency for Term {
                     ":-" => {
                         match terms.len() {
                             1 => 0,
-                            2 => resolved_term_arity(&terms[0]),
+                            2 => terms[0].arity(),
                             _ => terms.len(),
                         }
                     }
                     _ => {
-                        resolved_term_arity(self)
+                        terms.len()
                     }
                 },
             _ => {
@@ -278,9 +176,9 @@ impl ClauseConsistency for Term {
     }
 }
 
-impl ClauseConsistency for Rule {
-    fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
-        Some((self.head.0.owning_module(), self.head.0.clone()))
+impl ClauseInfo for Rule {
+    fn name(&self) -> Option<ClauseName> {
+        Some(self.head.0.clone())
     }
 
     fn arity(&self) -> usize {
@@ -288,15 +186,14 @@ impl ClauseConsistency for Rule {
     }
 }
 
-impl ClauseConsistency for PredicateClause {
-    fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
+impl ClauseInfo for PredicateClause {
+    fn name(&self) -> Option<ClauseName> {
         match self {
             &PredicateClause::Fact(ref term, ..) => {
-                term.name_and_module()
-                    .map(|(_, name)| (name.owning_module(), name))
+                term.name()
             }
             &PredicateClause::Rule(ref rule, ..) => {
-                rule.name_and_module()
+                rule.name()
             }
         }
     }
@@ -313,22 +210,12 @@ impl ClauseConsistency for PredicateClause {
     }
 }
 
-impl ClauseConsistency for Predicate {
-    fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
-        self.0.first().and_then(|clause| clause.name_and_module())
-    }
-
-    fn arity(&self) -> usize {
-        self.0.first().map(|clause| clause.arity()).unwrap_or(0)
-    }
-}
-
-pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
+// pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
 
 #[derive(Debug, Clone)]
 pub enum PredicateClause {
-    Fact(Term, usize, usize), // Term, line number, column number.
-    Rule(Rule, usize, usize), // Term, line number, column number.
+    Fact(Term),
+    Rule(Rule),
 }
 
 impl PredicateClause {
@@ -395,66 +282,61 @@ impl ModuleSource {
     }
 }
 
-pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
+// pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
 
+/*
 #[derive(Debug, Clone)]
 pub enum MultiFileIndicator {
     LocalScoped(ClauseName, usize), // name, arity
     ModuleScoped(ScopedPredicateKey),
 }
+*/
+
+#[derive(Clone, Copy, Hash, Debug)]
+pub enum MetaSpec {
+    Minus,
+    Plus,
+    Either,
+    RequiresExpansion,
+    RequiresExpansionWithArgument(usize),
+}
 
 #[derive(Debug, Clone)]
 pub enum Declaration {
-    Dynamic(ClauseName, usize), // name, arity
-    EndOfFile,
-    Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
-    ModuleInitialization(Vec<QueryTerm>, VecDeque<TopLevel>), // goal
+    Dynamic(ClauseName, usize),
+    MetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>), // module name, name, meta-specs
     Module(ModuleDecl),
-    MultiFile(MultiFileIndicator),
     NonCountedBacktracking(ClauseName, usize), // name, arity
     Op(OpDecl),
-    SetPrologFlag(DoubleQuotes),
     UseModule(ModuleSource),
-    UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
+    UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>),
 }
 
-impl Declaration {
-    #[inline]
-    pub fn is_module_decl(&self) -> bool {
-        if let &Declaration::Module(_) = self {
-            true
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    pub fn is_end_of_file(&self) -> bool {
-        if let &Declaration::EndOfFile = self {
-            true
-        } else {
-            false
-        }
-    }
+#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
+pub struct OpDecl {
+    pub prec: usize,
+    pub spec: Specifier,
+    pub name: ClauseName
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
-
 impl OpDecl {
     #[inline]
-    pub fn name(&self) -> ClauseName {
-        self.2.clone()
+    pub fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self {
+        Self { prec, spec, name }
     }
 
     #[inline]
-    pub fn remove(&self, op_dir: &mut OpDir) {
-        self.insert_into_op_dir(clause_name!(""), op_dir, 0);
+    pub fn remove(&mut self, op_dir: &mut OpDir) {
+        let prec = self.prec;
+        self.prec = 0;
+
+        self.insert_into_op_dir(op_dir);
+        self.prec = prec;
     }
 
     #[inline]
     pub fn fixity(&self) -> Fixity {
-        match self.1 {
+        match self.spec {
             XFY | XFX | YFX => Fixity::In,
             XF | YF => Fixity::Post,
             FX | FY => Fixity::Pre,
@@ -462,29 +344,27 @@ impl OpDecl {
         }
     }
 
-    pub fn insert_into_op_dir(&self, module: ClauseName, op_dir: &mut OpDir, prec: usize) {
-        let (spec, name) = (self.1, self.2.clone());
-
-        let fixity = self.fixity();
+    pub fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
+        let key = (self.name.clone(), self.fixity());
 
-        match op_dir.get(&(name.clone(), fixity)) {
+        match op_dir.get(&key) {
             Some(cell) => {
-                cell.shared_op_desc().set(prec, spec);
-                return;
+                return Some(cell.shared_op_desc().replace((self.prec, self.spec)));
+            }
+            None => {
             }
-            None => {}
         }
 
-        op_dir.insert((name, fixity), OpDirValue::new(spec, prec, module));
+        op_dir.insert(key, OpDirValue::new(self.spec, self.prec))
+              .map(|op_dir_value| op_dir_value.shared_op_desc().get())
     }
 
     pub fn submit(
         &self,
-        module: ClauseName,
         existing_desc: Option<OpDesc>,
         op_dir: &mut OpDir,
     ) -> Result<(), SessionError> {
-        let (prec, spec, name) = (self.0, self.1, self.2.clone());
+        let (spec, name) = (self.spec, self.name.clone());
 
         if is_infix!(spec) {
             if let Some(desc) = existing_desc {
@@ -502,7 +382,8 @@ impl OpDecl {
             }
         }
 
-        Ok(self.insert_into_op_dir(module, op_dir, prec))
+        self.insert_into_op_dir(op_dir);
+        Ok(())
     }
 }
 
@@ -541,7 +422,7 @@ pub fn fetch_op_spec(
     match arity {
         2 => op_dir
             .get(&(name, Fixity::In))
-            .and_then(|OpDirValue(spec, _)| {
+            .and_then(|OpDirValue(spec)| {
                 if spec.prec() > 0 {
                     Some(spec.clone())
                 } else {
@@ -549,15 +430,15 @@ pub fn fetch_op_spec(
                 }
             }),
         1 => {
-            if let Some(OpDirValue(spec, _)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
+            if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
                 if spec.prec() > 0 {
                     return Some(spec.clone());
                 }
             }
 
             op_dir
-                .get(&(name, Fixity::Post))
-                .and_then(|OpDirValue(spec, _)| {
+                .get(&(name.clone(), Fixity::Post))
+                .and_then(|OpDirValue(spec)| {
                     if spec.prec() > 0 {
                         Some(spec.clone())
                     } else {
@@ -573,7 +454,7 @@ pub fn fetch_op_spec(
 
 pub type ModuleDir = IndexMap<ClauseName, Module>;
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Eq, Hash, PartialEq)]
 pub enum ModuleExport {
     OpDecl(OpDecl),
     PredicateKey(PredicateKey),
@@ -587,21 +468,32 @@ pub struct ModuleDecl {
 
 #[derive(Debug)]
 pub struct Module {
-    pub atom_tbl: TabledData<Atom>,
     pub module_decl: ModuleDecl,
     pub code_dir: CodeDir,
     pub op_dir: OpDir,
-    pub term_dir: TermDir, // this contains multifile predicates.
-    pub term_expansions: (Predicate, VecDeque<TopLevel>),
-    pub goal_expansions: (Predicate, VecDeque<TopLevel>),
-    pub user_term_expansions: (Predicate, VecDeque<TopLevel>), // term expansions inherited from the user scope.
-    pub user_goal_expansions: (Predicate, VecDeque<TopLevel>), // same for goal_expansions.
-    pub local_term_expansions: (Predicate, VecDeque<TopLevel>), // expansions local to the module.
-    pub local_goal_expansions: (Predicate, VecDeque<TopLevel>),
-    pub inserted_expansions: bool, // has the module been successfully inserted into toplevel??
+    pub meta_predicates: MetaPredicateDir,
+    pub extensible_predicates: IndexMap<PredicateKey, PredicateSkeleton>,
     pub is_impromptu_module: bool,
     pub listing_src: ListingSource,
- }
+    pub clause_assert_margin: usize,
+}
+
+// Module's and related types are defined in forms.
+impl Module {
+    pub fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self {
+        Module {
+            module_decl,
+            code_dir: CodeDir::new(),
+            op_dir: default_op_dir(),
+            meta_predicates: MetaPredicateDir::new(),
+            is_impromptu_module: false,
+            extensible_predicates: IndexMap::new(),
+            listing_src,
+            clause_assert_margin: 0,
+        }
+    }
+}
+
 
 #[derive(Debug, Clone)]
 pub enum Number {
@@ -709,3 +601,154 @@ impl Number {
         }
     }
 }
+
+#[derive(Debug, Clone)]
+pub enum OptArgIndexKey {
+    Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives
+    List(usize, usize),                              // index, IndexingCode location
+    None,
+    Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity
+}
+
+impl OptArgIndexKey {
+    #[inline]
+    pub fn take(&mut self) -> OptArgIndexKey {
+        std::mem::replace(self, OptArgIndexKey::None)
+    }
+
+    #[inline]
+    pub fn arg_num(&self) -> usize {
+        match &self {
+            OptArgIndexKey::Constant(arg_num, ..) |
+            OptArgIndexKey::Structure(arg_num, ..) |
+            OptArgIndexKey::List(arg_num, _) => {
+                // these are always at least 1.
+                *arg_num
+            }
+            OptArgIndexKey::None => {
+                0
+            }
+        }
+    }
+
+    #[inline]
+    pub fn is_some(&self) -> bool {
+        self.switch_on_term_loc().is_some()
+    }
+
+    #[inline]
+    pub fn switch_on_term_loc(&self) -> Option<usize> {
+        match &self {
+            OptArgIndexKey::Constant(_, loc, ..) |
+            OptArgIndexKey::Structure(_, loc, ..) |
+            OptArgIndexKey::List(_, loc) => {
+                Some(*loc)
+            }
+            OptArgIndexKey::None => {
+                None
+            }
+        }
+    }
+
+    #[inline]
+    pub fn set_switch_on_term_loc(&mut self, value: usize) {
+        match self {
+            OptArgIndexKey::Constant(_, ref mut loc, ..) |
+            OptArgIndexKey::Structure(_, ref mut loc, ..) |
+            OptArgIndexKey::List(_, ref mut loc) => {
+                *loc = value;
+            }
+            OptArgIndexKey::None => {
+            }
+        }
+    }
+}
+
+impl AddAssign<usize> for OptArgIndexKey {
+    #[inline]
+    fn add_assign(&mut self, n: usize) {
+        match self {
+            OptArgIndexKey::Constant(_, ref mut o, ..) |
+            OptArgIndexKey::List(_, ref mut o) |
+            OptArgIndexKey::Structure(_, ref mut o, ..) => {
+                *o += n;
+            }
+            OptArgIndexKey::None => {
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct ClauseIndexInfo {
+    pub clause_start: usize,
+    pub opt_arg_index_key: OptArgIndexKey,
+}
+
+impl ClauseIndexInfo {
+    #[inline]
+    pub fn new(clause_start: usize) -> Self {
+        Self {
+            clause_start,
+            opt_arg_index_key: OptArgIndexKey::None,
+            // index_locs: vec![],
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct PredicateSkeleton {
+    pub is_discontiguous: bool,
+    pub is_dynamic: bool,
+    pub is_multifile: bool,
+    pub clauses: SliceDeque<ClauseIndexInfo>,
+    pub clause_clause_locs: SliceDeque<usize>,
+}
+
+impl PredicateSkeleton {
+    #[inline]
+    pub fn new() -> Self {
+        PredicateSkeleton {
+            is_discontiguous: false,
+            is_dynamic: false,
+            is_multifile: false,
+            clauses: sdeq![],
+            clause_clause_locs: sdeq![],
+        }
+    }
+
+    /*
+    #[inline]
+    pub fn set_discontiguous(self, is_discontiguous: bool) -> Self {
+        PredicateSkeleton {
+            is_discontiguous,
+            is_dynamic: self.is_dynamic,
+            is_multifile: self.is_multifile,
+            clauses: self.clauses,
+        }
+    }
+    */
+
+    #[inline]
+    pub fn set_dynamic(self, is_dynamic: bool) -> Self {
+        PredicateSkeleton {
+            is_discontiguous: self.is_discontiguous,
+            is_dynamic,
+            is_multifile: self.is_multifile,
+            clauses: self.clauses,
+            clause_clause_locs: self.clause_clause_locs,
+        }
+    }
+
+    /*
+    #[inline]
+    pub fn set_multifile(self, is_multifile: bool) -> Self {
+        PredicateSkeleton {
+           is_discontiguous: self.is_discontiguous,
+            is_dynamic: self.is_dynamic,
+            is_multifile,
+            clauses: self.clauses,
+        }
+    }
+    */
+}
index a541d12f2380e960c471572ccc50878ae2c315aa..4454123760e0f02523122a8ad14f0e70ee5e66bd 100644 (file)
@@ -45,10 +45,13 @@ impl<'a> HCPreOrderIterator<'a> {
           | HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => {
                 Addr::Con(h)
             }
+            HeapCellValue::LoadStatePayload(_) => {
+                Addr::LoadStatePayload(h)
+            }
             HeapCellValue::Stream(_) => {
                 Addr::Stream(h)
             }
-            &HeapCellValue::TcpListener(_) => {
+            HeapCellValue::TcpListener(_) => {
                 Addr::TcpListener(h)
             }
         }
@@ -175,13 +178,17 @@ impl<'a> Iterator for HCPostOrderIterator<'a> {
                     }
                     &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
                         match &self.machine_st.heap[h] {
-                            &HeapCellValue::PartialString(ref pstr, _) => {
+                            &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, next_n)));
+                                // }
+
+                                self.parent_stack.push((2, Addr::PStrLocation(h, n)));
                             }
                             _ => {
                                 unreachable!()
index 2a51fa91823c2e66f49338b78276bf0cca990358..e47929690f3bea7bedc1b1a1d3b13aecd1d21b5b 100644 (file)
@@ -402,6 +402,7 @@ pub fn requires_space(atom: &str, op: &str) -> bool {
     }
 }
 
+/*
 fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict {
     machine_st
         .heap_locs
@@ -414,6 +415,7 @@ fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict {
         })
         .collect()
 }
+*/
 
 fn non_quoted_graphic_token<Iter: Iterator<Item = char>>(mut iter: Iter, c: char) -> bool {
     if c == '/' {
@@ -503,7 +505,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
             max_depth: 0,
         }
     }
-
+/*
     pub fn from_heap_locs(
         machine_st: &'a MachineState,
         op_dir: &'a OpDir,
@@ -520,17 +522,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 
         printer
     }
-
+*/
+/*
     pub fn drop_toplevel_spec(&mut self) {
         self.toplevel_spec = None;
     }
-
+*/
+/*
     #[inline]
     pub fn see_all_locs(&mut self) {
         for key in self.heap_locs.keys().cloned() {
             self.printed_vars.insert(key);
         }
     }
+*/
 
     #[inline]
     fn ambiguity_check(&self, atom: &str) -> bool {
@@ -1024,7 +1029,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 
     fn print_rational(&mut self, r: &Rational, add_brackets: bool) {
         match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) {
-            Some(OpDirValue(ref spec, _)) => {
+            Some(OpDirValue(ref spec)) => {
                 if add_brackets {
                     self.state_stack.push(TokenOrRedirect::Close);
                 }
index bf5403bf64e762f59016f20b7f1ab903761c5759..f2029a318a0880ab1880ccc054d583225ae7f690 100644 (file)
 use crate::prolog_parser::ast::*;
 use crate::prolog_parser::tabled_rc::*;
 
+use crate::forms::*;
 use crate::instructions::*;
-use crate::rug::Integer;
 
 use crate::indexmap::IndexMap;
+use crate::rug::Integer;
+
+use slice_deque::{sdeq, SliceDeque};
 
-use std::collections::VecDeque;
 use std::convert::TryFrom;
 use std::hash::Hash;
+use std::iter::once;
 use std::rc::Rc;
 
 #[derive(Debug, Clone, Copy)]
-enum IntIndex {
-    External(usize),
+pub enum IndexingCodePtr {
+    External(usize), // the index points past the indexing instruction prelude.
     Fail,
-    Internal(usize),
+    Internal(usize), // the index points into the indexing instruction prelude.
 }
 
-#[derive(Debug)]
-pub struct CodeOffsets {
-    atom_tbl: TabledData<Atom>,
-    pub constants: IndexMap<Constant, ThirdLevelIndex>,
-    pub lists: ThirdLevelIndex,
-    pub structures: IndexMap<(ClauseName, usize), ThirdLevelIndex>,
+impl IndexingCodePtr {
+    #[inline]
+    fn is_internal(self) -> bool {
+        if let IndexingCodePtr::Internal(_) = self {
+            true
+        } else {
+            false
+        }
+    }
 }
 
-impl CodeOffsets {
-    pub fn new() -> Self {
-        CodeOffsets {
-            atom_tbl: TabledData::new(Rc::new("_index".to_string())),
-            constants: IndexMap::new(),
-            lists: Vec::new(),
-            structures: IndexMap::new(),
+#[derive(Debug, Clone, Copy)]
+enum OptArgIndexKeyType {
+    Structure,
+    Constant,
+    List,
+}
+
+impl OptArgIndexKey {
+    #[inline]
+    fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool {
+        match (self, key_type) {
+            (OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant) |
+            (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure) |
+            (OptArgIndexKey::List(..), OptArgIndexKeyType::List) => {
+                true
+            }
+            _ => {
+                false
+            }
         }
     }
+}
 
-    fn cap_choice_seq_with_trust(prelude: &mut ThirdLevelIndex) {
-        prelude.last_mut().map(|instr| {
-            match instr {
-                &mut IndexedChoiceInstruction::Retry(i) => {
-                    *instr = IndexedChoiceInstruction::Trust(i)
-                }
-                _ => {}
-            };
-        });
+#[inline]
+fn search_skeleton_for_first_key_type(
+    skeleton: &[ClauseIndexInfo],
+    key_type: OptArgIndexKeyType,
+    append_or_prepend: AppendOrPrepend,
+) -> Option<&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) {
+                return Some(&clause_index_info.opt_arg_index_key);
+            }
+        }
+    } else {
+        for clause_index_info in skeleton.iter() {
+            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],
+    // merged_clause_index: usize,
+    indexing_code: &'a mut Vec<IndexingLine>,
+    offset: usize,
+    append_or_prepend: AppendOrPrepend,
+}
+
+impl<'a> IndexingCodeMergingPtr<'a> {
+    #[inline]
+    fn new(
+        skeleton: &'a mut [ClauseIndexInfo],
+        indexing_code: &'a mut Vec<IndexingLine>,
+        append_or_prepend: AppendOrPrepend,
+    ) -> Self {
+        Self { skeleton, indexing_code, offset: 0, append_or_prepend }
     }
 
-    fn add_index(is_first_index: bool, index: usize) -> IndexedChoiceInstruction {
-        if is_first_index {
-            IndexedChoiceInstruction::Try(index)
+    fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr)  {
+        let constant_key =
+            search_skeleton_for_first_key_type(
+                self.skeleton,
+                OptArgIndexKeyType::Constant,
+                self.append_or_prepend,
+            );
+
+        let mut constants = IndexMap::new();
+
+        match constant_key {
+            Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => {
+                constants.insert(constant.clone(), constant_ptr);
+            }
+            _ => {
+                unreachable!()
+            }
+        }
+
+        if let IndexingCodePtr::Internal(_) = constant_ptr {
+            self.indexing_code.push(IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnConstant(constants)
+            ));
+
+            let last_index = self.indexing_code.len() - 1;
+            self.indexing_code.swap(self.offset, last_index);
         } else {
-            IndexedChoiceInstruction::Retry(index)
+            self.offset = self.indexing_code.len();
+
+            self.indexing_code.push(IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnConstant(constants)
+            ));
         }
     }
 
-    fn intercept_overlapping_constant(&mut self, constant: &Constant, index: usize) {
-        match constant {
-            &Constant::Atom(ref name, ref op) if name.is_char() => {
-                let c = name.as_str().chars().next().unwrap();
-                let code = self.constants
-                    .entry(Constant::Char(c))
-                    .or_insert(vec![]);
+    fn add_indexed_choice_for_constant(&mut self, external: usize, constant: Constant, index: usize)
+    {
+        let third_level_index =
+            if self.append_or_prepend.is_append() {
+                sdeq![
+                    IndexedChoiceInstruction::Try(external),
+                    IndexedChoiceInstruction::Trust(index)
+                ]
+            } else {
+                sdeq![
+                    IndexedChoiceInstruction::Try(index),
+                    IndexedChoiceInstruction::Trust(external)
+                ]
+            };
 
-                code.push(Self::add_index(code.is_empty(), index));
+        let indexing_code_len = self.indexing_code.len();
+        self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index));
 
-                if op.is_some() {
-                    let code = self.constants
-                        .entry(Constant::Atom(name.clone(), None))
-                        .or_insert(vec![]);
+        match &mut self.indexing_code[self.offset] {
+            IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnConstant(ref mut constants)
+            ) => {
+                constants.insert(constant, IndexingCodePtr::Internal(indexing_code_len - self.offset));
+            }
+            _ => {
+                unreachable!()
+            }
+        }
+    }
 
-                    code.push(Self::add_index(false, index));
+    fn extend_indexed_choice(&mut self, index: usize) {
+        match &mut self.indexing_code[self.offset] {
+            IndexingLine::IndexedChoice(ref mut indexed_choice_instrs)
+                if self.append_or_prepend.is_append() => {
+                    uncap_choice_seq_with_trust(indexed_choice_instrs);
+                    indexed_choice_instrs.push_back(IndexedChoiceInstruction::Trust(index));
                 }
+            IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
+                uncap_choice_seq_with_try(indexed_choice_instrs);
+                indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index));
             }
-            &Constant::Atom(ref name, Some(_)) => {
-                let code = self.constants
-                    .entry(Constant::Atom(name.clone(), None))
-                    .or_insert(vec![]);
-
-                code.push(Self::add_index(code.is_empty(), index));
+            _ => {
+                unreachable!()
             }
-            &Constant::Char(c) => {
-                let atom = clause_name!(c.to_string(), self.atom_tbl.clone());
+        }
+    }
 
-                let code = self.constants
-                    .entry(Constant::Atom(atom, None))
-                    .or_insert(vec![]);
+    fn index_overlapping_constant(
+        &mut self,
+        orig_constant: &Constant,
+        overlapping_constant: Constant,
+        index: usize,
+    ) {
+        loop {
+            let indexing_code_len = self.indexing_code.len();
 
-                code.push(Self::add_index(code.is_empty(), index));
-            }
-            &Constant::Fixnum(n) => {
-                let code = self.constants
-                    .entry(Constant::Integer(Rc::new(Integer::from(n))))
-                    .or_insert(vec![]);
+            match &mut self.indexing_code[self.offset] {
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)
+                ) => {
+                    match *c {
+                        IndexingCodePtr::Fail => {
+                            *c = IndexingCodePtr::External(index);
+                            break;
+                        }
+                        IndexingCodePtr::External(_) => {
+                            let mut constants = IndexMap::new();
+                            constants.insert(orig_constant.clone(), *c);
 
-                code.push(Self::add_index(code.is_empty(), index));
+                            *c = IndexingCodePtr::Internal(indexing_code_len);
 
-                if n >= 0 {
-                    if let Ok(n) = usize::try_from(n) {
-                        let code = self.constants
-                            .entry(Constant::Usize(n))
-                            .or_insert(vec![]);
+                            self.indexing_code.push(IndexingLine::Indexing(
+                                IndexingInstruction::SwitchOnConstant(constants)
+                            ));
 
-                        code.push(Self::add_index(code.is_empty(), index));
+                            self.offset = indexing_code_len;
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            self.offset += o;
+                        }
                     }
                 }
-            }
-            &Constant::Integer(ref n) => {
-                if let Some(n) = n.to_isize() {
-                    let code = self.constants
-                        .entry(Constant::Fixnum(n))
-                        .or_insert(vec![]);
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnConstant(constants)
+                ) => {
+                    match constants.get(&overlapping_constant).cloned() {
+                        None | Some(IndexingCodePtr::Fail) => {
+                            constants.insert(overlapping_constant, IndexingCodePtr::External(index));
+                        }
+                        Some(IndexingCodePtr::External(o)) => {
+                            self.add_indexed_choice_for_constant(o, overlapping_constant, index);
+                        }
+                        Some(IndexingCodePtr::Internal(o)) => {
+                            self.offset += o;
+                            self.extend_indexed_choice(index);
+                        }
+                    }
 
-                    code.push(Self::add_index(code.is_empty(), index));
+                    break;
+                }
+                IndexingLine::IndexedChoice(_) => {
+                    self.internalize_constant(
+                        IndexingCodePtr::Internal(indexing_code_len - self.offset),
+                    );
+                }
+                _ => {
+                    unreachable!()
                 }
+            }
+        }
+    }
 
-                if let Some(n) = n.to_usize() {
-                    let code = self.constants
-                        .entry(Constant::Usize(n))
-                        .or_insert(vec![]);
+    fn index_constant(&mut self, constant: Constant, index: usize) {
+        loop {
+            let indexing_code_len = self.indexing_code.len();
+
+            match &mut self.indexing_code[self.offset] {
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)
+                ) => {
+                    match *c {
+                        IndexingCodePtr::Fail => {
+                            *c = IndexingCodePtr::External(index);
+                            break;
+                        }
+                        IndexingCodePtr::External(o) => {
+                            *c = IndexingCodePtr::Internal(indexing_code_len - self.offset);
+                            self.internalize_constant(IndexingCodePtr::External(o));
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            self.offset += o;
+                        }
+                    }
+                }
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnConstant(constants)
+                ) => {
+                    match constants.get(&constant).cloned() {
+                        None | Some(IndexingCodePtr::Fail) => {
+                            constants.insert(constant, IndexingCodePtr::External(index));
+                        }
+                        Some(IndexingCodePtr::External(o)) => {
+                            self.add_indexed_choice_for_constant(o, constant, index);
+                        }
+                        Some(IndexingCodePtr::Internal(o)) => {
+                            self.offset += o;
+                            self.extend_indexed_choice(index);
+                        }
+                    }
 
-                    code.push(Self::add_index(code.is_empty(), index));
+                    break;
+                }
+                IndexingLine::IndexedChoice(_) => {
+                    self.internalize_constant(
+                        IndexingCodePtr::Internal(indexing_code_len - self.offset),
+                    );
+                }
+                _ => {
+                    unreachable!()
                 }
             }
-            &Constant::Usize(n) => {
-                let code = self.constants
-                    .entry(Constant::Integer(Rc::new(Integer::from(n))))
-                    .or_insert(vec![]);
+        }
+    }
 
-                code.push(Self::add_index(code.is_empty(), index));
+    fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr)  {
+        let structure_key =
+            search_skeleton_for_first_key_type(
+                self.skeleton,
+                OptArgIndexKeyType::Structure,
+                self.append_or_prepend,
+            );
 
-                if let Ok(n) = isize::try_from(n) {
-                    let code = self.constants
-                        .entry(Constant::Fixnum(n))
-                        .or_insert(vec![]);
+        let mut structures = IndexMap::new();
 
-                    code.push(Self::add_index(code.is_empty(), index));
-                }
+        match structure_key {
+            Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => {
+                structures.insert((name.clone(), *arity), structure_ptr);
             }
             _ => {
+                unreachable!()
             }
         }
+
+        if let IndexingCodePtr::Internal(_) = structure_ptr {
+            self.indexing_code.push(IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnStructure(structures)
+            ));
+
+            let last_index = self.indexing_code.len() - 1;
+            self.indexing_code.swap(self.offset, last_index);
+        } else {
+            self.offset = self.indexing_code.len();
+
+            self.indexing_code.push(IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnStructure(structures)
+            ));
+        }
     }
 
-    pub fn index_term(&mut self, optimal_arg: &Term, index: usize) {
-        match optimal_arg {
-            &Term::Clause(_, ref name, ref terms, _) => {
-                let code = self
-                    .structures
-                    .entry((name.clone(), terms.len()))
-                    .or_insert(Vec::new());
+    fn add_indexed_choice_for_structure(&mut self, external: usize, key: PredicateKey, index: usize)
+    {
+        let third_level_index =
+            if self.append_or_prepend.is_append() {
+                sdeq![
+                    IndexedChoiceInstruction::Try(external),
+                    IndexedChoiceInstruction::Trust(index)
+                ]
+            } else {
+                sdeq![
+                    IndexedChoiceInstruction::Try(index),
+                    IndexedChoiceInstruction::Trust(external)
+                ]
+            };
+
+        let indexing_code_len = self.indexing_code.len();
+        self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index));
 
-                let is_initial_index = code.is_empty();
-                code.push(Self::add_index(is_initial_index, index));
+        match &mut self.indexing_code[self.offset] {
+            IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnStructure(ref mut structures)
+            ) => {
+                structures.insert(key, IndexingCodePtr::Internal(indexing_code_len - self.offset));
             }
-            &Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => {
-                let is_initial_index = self.lists.is_empty();
-                self.lists.push(Self::add_index(is_initial_index, index));
+            _ => {
+                unreachable!()
             }
-            &Term::Constant(_, ref constant) => {
-                self.intercept_overlapping_constant(constant, index);
+        }
+    }
+
+    fn index_structure(&mut self, key: PredicateKey, index: usize) {
+        loop {
+            let indexing_code_len = self.indexing_code.len();
+
+            match &mut self.indexing_code[self.offset] {
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s)
+                ) => {
+                    match *s {
+                        IndexingCodePtr::Fail => {
+                            *s = IndexingCodePtr::External(index);
+                            break;
+                        }
+                        IndexingCodePtr::External(o) => {
+                            *s = IndexingCodePtr::Internal(indexing_code_len - self.offset);
+                            self.internalize_structure(IndexingCodePtr::External(o));
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            self.offset += o;
+                        }
+                    }
+                }
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnStructure(structures)
+                ) => {
+                    match structures.get(&key).cloned() {
+                        None | Some(IndexingCodePtr::Fail) => {
+                            structures.insert(key, IndexingCodePtr::External(index));
+                        }
+                        Some(IndexingCodePtr::External(o)) => {
+                            self.add_indexed_choice_for_structure(o, key, index);
+                        }
+                        Some(IndexingCodePtr::Internal(o)) => {
+                            self.offset += o;
+                            self.extend_indexed_choice(index);
+                        }
+                    }
+
+                    break;
+                }
+                IndexingLine::IndexedChoice(_) => {
+                    // replace this value, at self.offset, with
+                    // SwitchOnStructures, and swap this IndexedChoice
+                    // vector to the end of self.indexing_code.
+                    self.internalize_structure(
+                        IndexingCodePtr::Internal(indexing_code_len - self.offset),
+                    );
+                }
+                _ => {
+                    unreachable!()
+                }
+            }
+        }
+    }
+
+    fn index_list(&mut self, index: usize) {
+        let indexing_code_len = self.indexing_code.len();
+
+        match &mut self.indexing_code[self.offset] {
+            IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _)
+            ) => {
+                match *l {
+                    IndexingCodePtr::Fail => {
+                        *l = IndexingCodePtr::External(index);
+                    }
+                    IndexingCodePtr::External(o) => {
+                        *l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
 
-                let code = self.constants
-                    .entry(constant.clone())
-                    .or_insert(vec![]);
+                        let third_level_index =
+                            if self.append_or_prepend.is_append() {
+                                sdeq![
+                                    IndexedChoiceInstruction::Try(o),
+                                    IndexedChoiceInstruction::Trust(index)
+                                ]
+                            } else {
+                                sdeq![
+                                    IndexedChoiceInstruction::Try(index),
+                                    IndexedChoiceInstruction::Trust(o)
+                                ]
+                            };
 
-                let is_initial_index = code.is_empty();
-                code.push(Self::add_index(is_initial_index, index));
+                        self.indexing_code.push(
+                            IndexingLine::IndexedChoice(third_level_index),
+                        );
+                    }
+                    IndexingCodePtr::Internal(o) => {
+                        self.offset += o;
+                        self.extend_indexed_choice(index);
+                    }
+                }
             }
             _ => {
+                unreachable!()
+            }
+        }
+    }
+}
+
+pub 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.
+    new_clause_loc: usize, // the absolute location of the new clause in the code vector.
+    append_or_prepend: AppendOrPrepend,
+) {
+    let opt_arg_index_key =
+        match append_or_prepend {
+            AppendOrPrepend::Append => {
+                skeleton.last_mut().unwrap().opt_arg_index_key.take()
+            }
+            AppendOrPrepend::Prepend => {
+                skeleton.first_mut().unwrap().opt_arg_index_key.take()
             }
         };
+
+    let mut merging_ptr = IndexingCodeMergingPtr::new(
+        skeleton,
+        target_indexing_code,
+        append_or_prepend,
+    );
+
+    match &opt_arg_index_key {
+        OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => {
+            let offset = new_clause_loc - index_loc + 1;
+            merging_ptr.index_constant(constant.clone(), offset);
+
+            for overlapping_constant in overlapping_constants {
+                merging_ptr.index_overlapping_constant(
+                    constant, overlapping_constant.clone(), offset,
+                );
+            }
+        }
+        OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => {
+            merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1);
+        }
+        OptArgIndexKey::List(_, index_loc) => {
+            merging_ptr.index_list(new_clause_loc - index_loc + 1);
+        }
+        OptArgIndexKey::None => {
+            unreachable!()
+        }
     }
 
-    fn second_level_index<Index>(
-        indices: IndexMap<Index, ThirdLevelIndex>,
-        prelude: &mut CodeDeque,
-    ) -> IndexMap<Index, IntIndex>
-    where
-        Index: Eq + Hash,
-    {
-        let mut index_locs = IndexMap::new();
+    match append_or_prepend {
+        AppendOrPrepend::Append => {
+            skeleton.last_mut().unwrap().opt_arg_index_key = opt_arg_index_key;
+        }
+        AppendOrPrepend::Prepend => {
+            skeleton.first_mut().unwrap().opt_arg_index_key = opt_arg_index_key;
+        }
+    }
+}
 
-        for (key, mut code) in indices.into_iter() {
-            if code.len() > 1 {
-                index_locs.insert(key, IntIndex::Internal(prelude.len()));
-                Self::cap_choice_seq_with_trust(&mut code);
-                prelude.extend(code.into_iter().map(|code| Line::from(code)));
-            } else {
-                code.first().map(|i| {
-                    index_locs.insert(key, IntIndex::External(i.offset()));
-                });
+#[inline]
+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);
+            cap_choice_seq(code);
+            return;
+        }
+    }
+}
+
+pub fn remove_constant_indices(
+    constant: &Constant,
+    overlapping_constants: &[Constant],
+    indexing_code: &mut Vec<IndexingLine>,
+    offset: usize,
+) {
+    let mut index = 0;
+    let iter = once(constant).chain(overlapping_constants.iter());
+
+    match &mut indexing_code[index] {
+        IndexingLine::Indexing(
+            IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)
+        ) => {
+            match *c {
+                IndexingCodePtr::External(_) => {
+                    *c = IndexingCodePtr::Fail;
+                    return;
+                }
+                IndexingCodePtr::Internal(o) => {
+                    index += o;
+                }
+                IndexingCodePtr::Fail => {
+                    return;
+                }
             }
         }
+        _ => {
+            unreachable!()
+        }
+    }
 
-        index_locs
+    let mut constants_index = 0;
+
+    for constant in iter { // (constant, index_loc) in iter.zip(index_locs.iter()) {
+        loop {
+            match &mut indexing_code[index] {
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnConstant(ref mut constants)
+                ) => {
+                    constants_index = index;
+
+                    match constants.get(constant).cloned() {
+                        Some(IndexingCodePtr::External(_)) => {
+                            constants.remove(constant);
+                            break;
+                        }
+                        Some(IndexingCodePtr::Internal(o)) => {
+                            index += o;
+                        }
+                        Some(IndexingCodePtr::Fail) | None => {
+                            unreachable!()
+                        }
+                    }
+                }
+                IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
+                    remove_instruction_with_offset(indexed_choice_instrs, offset);
+
+                    if indexed_choice_instrs.len() == 1 {
+                        let ext = IndexingCodePtr::External(
+                            indexed_choice_instrs.pop_back().unwrap().offset()
+                        );
+
+                        match &mut indexing_code[constants_index] {
+                            IndexingLine::Indexing(
+                                IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)
+                            ) => {
+                                *c = ext;
+                            }
+                            IndexingLine::Indexing(
+                                IndexingInstruction::SwitchOnConstant(ref mut constants)
+                            ) => {
+                                constants.insert(constant.clone(), ext);
+                            }
+                            _ => {
+                                unreachable!()
+                            }
+                        }
+                    }
+
+                    break;
+                }
+                _ => {
+                    unreachable!()
+                }
+            }
+        }
     }
 
-    fn no_indices(&self) -> bool {
-        let no_constants = self.constants.is_empty();
-        let no_structures = self.structures.is_empty();
-        let no_lists = self.lists.is_empty();
+    match &indexing_code[constants_index] {
+        IndexingLine::Indexing(
+            IndexingInstruction::SwitchOnConstant(ref constants)
+        ) if constants.is_empty() => {
+            match &mut indexing_code[0] {
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)
+                ) => {
+                    *c = IndexingCodePtr::Fail;
+                }
+                _ => {
+                    unreachable!()
+                }
+            }
+        }
+        _ => {
+        }
+    }
+}
 
-        no_constants && no_structures && no_lists
+pub fn remove_structure_index(
+    name: &ClauseName,
+    arity: usize,
+    indexing_code: &mut Vec<IndexingLine>,
+    offset: usize,
+) {
+    let mut index = 0;
+
+    match &mut indexing_code[index] {
+        IndexingLine::Indexing(
+            IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s)
+        ) => {
+            match *s {
+                IndexingCodePtr::External(_) => {
+                    *s = IndexingCodePtr::Fail;
+                    return;
+                }
+                IndexingCodePtr::Internal(o) => {
+                    index += o;
+                }
+                IndexingCodePtr::Fail => {
+                    return;
+                }
+            }
+        }
+        _ => {
+            unreachable!()
+        }
     }
 
-    fn flatten_index<Index>(index: IndexMap<Index, IntIndex>, len: usize) -> IndexMap<Index, usize>
-    where
-        Index: Eq + Hash,
-    {
-        let mut flattened_index = IndexMap::new();
+    let mut structures_index = 0;
+
+    loop {
+        match &mut indexing_code[index] {
+            IndexingLine::Indexing(
+                IndexingInstruction::SwitchOnStructure(ref mut structures)
+            ) => {
+                structures_index = index;
 
-        for (key, int_index) in index.into_iter() {
-            match int_index {
-                IntIndex::External(offset) => {
-                    flattened_index.insert(key, offset + len + 1);
+                match structures.get(&(name.clone(), arity)).cloned() {
+                    Some(IndexingCodePtr::External(_)) => {
+                        structures.remove(&(name.clone(), arity));
+                        break;
+                    }
+                    Some(IndexingCodePtr::Internal(o)) => {
+                        index += o;
+                    }
+                    Some(IndexingCodePtr::Fail) | None => {
+                        return;
+                    }
                 }
-                IntIndex::Internal(offset) => {
-                    flattened_index.insert(key, offset + 1);
+            }
+            IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
+                remove_instruction_with_offset(indexed_choice_instrs, offset);
+
+                if indexed_choice_instrs.len() == 1 {
+                    let ext = IndexingCodePtr::External(
+                        indexed_choice_instrs.pop_back().unwrap().offset()
+                    );
+
+                    match &mut indexing_code[structures_index] {
+                        IndexingLine::Indexing(
+                            IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s)
+                        ) => {
+                            *s = ext;
+                        }
+                        IndexingLine::Indexing(
+                            IndexingInstruction::SwitchOnStructure(ref mut structures)
+                        ) => {
+                            structures.insert((name.clone(), arity), ext);
+                        }
+                        _ => {
+                            unreachable!()
+                        }
+                    }
                 }
-                _ => {}
-            };
+
+                break;
+            }
+            _ => {
+                unreachable!()
+            }
         }
+    }
 
-        flattened_index
+    match &indexing_code[structures_index] {
+        IndexingLine::Indexing(
+            IndexingInstruction::SwitchOnStructure(ref structures)
+        ) if structures.is_empty() => {
+            match &mut indexing_code[0] {
+                IndexingLine::Indexing(
+                    IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s)
+                ) => {
+                    *s = IndexingCodePtr::Fail;
+                }
+                _ => {
+                    unreachable!()
+                }
+            }
+        }
+        _ => {
+        }
     }
+}
 
-    fn adjust_internal_index(index: IntIndex) -> IntIndex {
-        match index {
-            IntIndex::Internal(o) => IntIndex::Internal(o + 1),
-            IntIndex::External(o) => IntIndex::External(o),
-            _ => IntIndex::Fail,
+pub fn remove_list_index(
+    indexing_code: &mut Vec<IndexingLine>,
+    offset: usize,
+) {
+    let mut index = 0;
+
+    match &mut indexing_code[index] {
+        IndexingLine::Indexing(
+            IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _)
+        ) => {
+            match *l {
+                IndexingCodePtr::External(_) => {
+                    *l = IndexingCodePtr::Fail;
+                    return;
+                }
+                IndexingCodePtr::Internal(o) => {
+                    index += o;
+                }
+                IndexingCodePtr::Fail => {
+                    return;
+                }
+            }
+        }
+        _ => {
+            unreachable!()
         }
     }
 
-    fn switch_on_constant(
-        con_ind: IndexMap<Constant, ThirdLevelIndex>,
-        prelude: &mut CodeDeque,
-        optimal_index: usize,
-    ) -> IntIndex {
-        let con_ind = Self::second_level_index(con_ind, prelude);
+    match &mut indexing_code[index] {
+        IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
+            remove_instruction_with_offset(indexed_choice_instrs, offset);
 
-        if con_ind.len() > 1 {
-            let index = Self::flatten_index(con_ind, prelude.len());
-            let instr = IndexingInstruction::SwitchOnConstant(
-                optimal_index,
-                index.len(),
-                index
-            );
+            if indexed_choice_instrs.len() == 1 {
+                let ext = IndexingCodePtr::External(
+                    indexed_choice_instrs.pop_back().unwrap().offset()
+                );
 
-            prelude.push_front(Line::from(instr));
+                match &mut indexing_code[0] {
+                    IndexingLine::Indexing(
+                        IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _)
+                    ) => {
+                        *l = ext;
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
+            }
+        }
+        _ => {
+            unreachable!()
+        }
+    }
+}
 
-            IntIndex::Internal(1)
-        } else {
-            con_ind
-                .values()
-                .next()
-                .map(|index| Self::adjust_internal_index(*index))
-                .unwrap_or(IntIndex::Fail)
-        }
-    }
-
-    fn switch_on_structure(
-        str_ind: IndexMap<(ClauseName, usize), ThirdLevelIndex>,
-        prelude: &mut CodeDeque,
-        optimal_index: usize,
-    ) -> IntIndex {
-        let str_ind = Self::second_level_index(str_ind, prelude);
-
-        if str_ind.len() > 1 {
-            let index = Self::flatten_index(str_ind, prelude.len());
-            let instr = IndexingInstruction::SwitchOnStructure(
-                optimal_index,
-                index.len(),
-                index
+pub fn remove_index(
+    //skeleton: &[ClauseIndexInfo],
+    opt_arg_index_key: &OptArgIndexKey,
+    indexing_code: &mut Vec<IndexingLine>,
+    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,
+                //&skeleton[index].index_locs,
+            );
+        }
+        OptArgIndexKey::Structure(_, _, ref name, ref arity) => {
+            remove_structure_index(
+                name,
+                *arity,
+                indexing_code,
+                clause_loc,
+                //&skeleton[index].index_locs,
+            );
+        }
+        OptArgIndexKey::List(..) => {
+            remove_list_index(
+                indexing_code,
+                clause_loc,
+                //&skeleton[index].index_locs,
             );
+        }
+        OptArgIndexKey::None => {
+            unreachable!()
+        }
+    }
+}
 
-            prelude.push_front(Line::from(instr));
+fn second_level_index<IndexKey: Eq + Hash>(
+    indices: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
+    prelude: &mut SliceDeque<IndexingLine>,
+) -> IndexMap<IndexKey, IndexingCodePtr>
+{
+    let mut index_locs = IndexMap::new();
 
-            IntIndex::Internal(1)
+    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);
+            prelude.push_back(IndexingLine::from(code));
         } else {
-            str_ind
-                .values()
-                .next()
-                .map(|index| Self::adjust_internal_index(*index))
-                .unwrap_or(IntIndex::Fail)
+            code.first().map(|i| {
+                index_locs.insert(key, IndexingCodePtr::External(i.offset()));
+            });
         }
     }
 
-    fn switch_on_list(mut lists: ThirdLevelIndex, prelude: &mut CodeDeque) -> IntIndex {
-        if lists.len() > 1 {
-            Self::cap_choice_seq_with_trust(&mut lists);
-            prelude.extend(lists.into_iter().map(|i| Line::from(i)));
-            IntIndex::Internal(0)
-        } else {
-            lists
-                .first()
-                .map(|i| IntIndex::External(i.offset()))
-                .unwrap_or(IntIndex::Fail)
-        }
+    index_locs
+}
+
+fn switch_on<IndexKey: Eq + Hash>(
+    instr_fn: impl Fn(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
+    index: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
+    prelude: &mut SliceDeque<IndexingLine>,
+) -> IndexingCodePtr {
+    let index = second_level_index(index, prelude);
+
+    if index.len() > 1 {
+        let instr = instr_fn(index);
+        prelude.push_front(IndexingLine::from(instr));
+
+        IndexingCodePtr::Internal(1)
+    } else {
+        index.into_iter()
+             .next()
+             .map(|(_, v)| v)
+             .unwrap_or(IndexingCodePtr::Fail)
+    }
+}
+
+fn switch_on_list(
+    mut lists: SliceDeque<IndexedChoiceInstruction>,
+    prelude: &mut SliceDeque<IndexingLine>,
+) -> IndexingCodePtr {
+    if lists.len() > 1 {
+        cap_choice_seq_with_trust(&mut lists);
+        prelude.push_back(IndexingLine::from(lists));
+        IndexingCodePtr::Internal(1)
+    } else {
+        lists.first()
+             .map(|i| IndexingCodePtr::External(i.offset()))
+             .unwrap_or(IndexingCodePtr::Fail)
     }
+}
+
+#[inline]
+fn cap_choice_seq(prelude: &mut [IndexedChoiceInstruction]) {
+    prelude.first_mut().map(|instr| {
+        *instr = IndexedChoiceInstruction::Try(instr.offset());
+    });
+
+    cap_choice_seq_with_trust(prelude);
+}
 
-    fn switch_on_str_offset_from(
-        str_loc: IntIndex,
-        prelude_len: usize,
-        con_loc: IntIndex,
-    ) -> usize {
-        match str_loc {
-            IntIndex::External(o) => o + prelude_len + 1,
-            IntIndex::Fail => 0,
-            IntIndex::Internal(_) => match con_loc {
-                IntIndex::Internal(_) => 2,
-                _ => 1,
-            },
+#[inline]
+fn cap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) {
+    prelude.last_mut().map(|instr| {
+        if let IndexedChoiceInstruction::Retry(i) = instr {
+            *instr = IndexedChoiceInstruction::Trust(*i);
         }
+    });
+}
+
+#[inline]
+fn uncap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) {
+    prelude.last_mut().map(|instr| {
+        if let IndexedChoiceInstruction::Trust(i) = instr {
+            *instr = IndexedChoiceInstruction::Retry(*i);
+        }
+    });
+}
+
+#[inline]
+fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
+    prelude.first_mut().map(|instr| {
+        if let IndexedChoiceInstruction::Try(i) = instr {
+            *instr = IndexedChoiceInstruction::Retry(*i);
+        }
+    });
+}
+
+fn compute_index(is_first_index: bool, index: usize) -> IndexedChoiceInstruction {
+    // in either case, increment index to skip the IndexingLine vector.
+    if is_first_index {
+        IndexedChoiceInstruction::Try(index + 1)
+    } else {
+        IndexedChoiceInstruction::Retry(index + 1)
     }
+}
+
+pub fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData<Atom>) -> Vec<Constant> {
+    let mut constants = vec![];
 
-    fn switch_on_con_offset_from(con_loc: IntIndex, prelude_len: usize) -> usize {
-        match con_loc {
-            IntIndex::External(offset) => offset + prelude_len + 1,
-            IntIndex::Fail => 0,
-            IntIndex::Internal(offset) => offset,
+    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));
+            }
+        }
+        Constant::Char(c) => {
+            let atom = clause_name!(c.to_string(), atom_tbl);
+            constants.push(Constant::Atom(atom, None));
+        }
+        Constant::Fixnum(ref n) => {
+            constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
+
+            if *n >= 0 {
+                if let Ok(n) = usize::try_from(*n) {
+                    constants.push(Constant::Usize(n));
+                }
+            }
+        }
+        Constant::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));
+            }
+        }
+        Constant::Usize(n) => {
+            constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
+
+            if let Ok(n) = isize::try_from(*n) {
+                constants.push(Constant::Fixnum(n));
+            }
+        }
+        _ => {
         }
     }
 
-    fn switch_on_lst_offset_from(
-        lst_loc: IntIndex,
-        prelude_len: usize,
-    ) -> usize {
-        match lst_loc {
-            IntIndex::External(o) => o + prelude_len + 1,
-            IntIndex::Fail => 0,
-            IntIndex::Internal(_) => 1, // this internal is always 0.
+    constants
+}
+
+#[derive(Debug)]
+pub struct CodeOffsets {
+    atom_tbl: TabledData<Atom>,
+    pub constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>,
+    pub lists: SliceDeque<IndexedChoiceInstruction>,
+    pub structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>,
+    optimal_index: usize,
+}
+
+impl CodeOffsets {
+    pub fn new(atom_tbl: TabledData<Atom>, optimal_index: usize) -> Self {
+        CodeOffsets {
+            atom_tbl,
+            constants: IndexMap::new(),
+            lists: sdeq![],
+            structures: IndexMap::new(),
+            optimal_index
         }
     }
 
-    pub fn add_indices(self, code: &mut Code, mut code_body: Code, optimal_index: usize) {
-        if self.no_indices() {
-            *code = code_body;
-            return;
+    fn index_list(&mut self, index: usize) {
+        let is_initial_index = self.lists.is_empty();
+        self.lists.push_back(compute_index(is_initial_index, 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.constants
+            .entry(constant.clone())
+            .or_insert(sdeq![]);
+
+        let is_initial_index = code.is_empty();
+
+        code.push_back(compute_index(is_initial_index, index));
+
+        for constant in &overlapping_constants {
+            let code = self.constants
+                .entry(constant.clone())
+                .or_insert(sdeq![]);
+
+            let is_initial_index = code.is_empty();
+            let index = compute_index(is_initial_index, index);
+
+            code.push_back(index);
         }
 
-        let mut prelude = VecDeque::new();
+        overlapping_constants
+    }
 
-        let lst_loc = Self::switch_on_list(self.lists, &mut prelude);
-        let str_loc =
-            Self::switch_on_structure(self.structures, &mut prelude, optimal_index);
-        let con_loc =
-            Self::switch_on_constant(self.constants, &mut prelude, optimal_index);
+    fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize {
+        let code = self
+            .structures
+            .entry((name.clone(), arity))
+            .or_insert(sdeq![]);
 
-        let prelude_length = prelude.len();
+        let code_len = code.len();
+        let is_initial_index = code.is_empty();
 
-        for (index, line) in prelude.iter_mut().enumerate() {
-            match line {
-                &mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) |
-                &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) |
-                &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
-                    *i += prelude_length - index;
-                }
-                _ => {
-                }
+        code.push_back(compute_index(is_initial_index, index));
+        code_len
+    }
+
+    pub fn index_term(
+        &mut self,
+        optimal_arg: &Term,
+        index: usize,
+        clause_index_info: &mut ClauseIndexInfo,
+    ) {
+        match optimal_arg {
+            &Term::Clause(_, ref 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(_)) => {
+                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,
+                    );
+            }
+            _ => {
+            }
+        }
+    }
+
+    pub fn no_indices(&self) -> bool {
+        let no_constants = self.constants.is_empty();
+        let no_structures = self.structures.is_empty();
+        let no_lists = self.lists.is_empty();
+
+        no_constants && no_structures && no_lists
+    }
+
+    pub fn compute_indices(self, skip_stub_try_me_else: bool) -> Vec<IndexingLine> {
+        if self.no_indices() {
+            return vec![];
         }
 
-        let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc);
-        let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len());
-        let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len());
+        let mut prelude = sdeq![];
+
+        let mut lst_loc = switch_on_list(self.lists, &mut prelude);
 
-        let switch_instr = IndexingInstruction::SwitchOnTerm(
-            optimal_index,
-            prelude.len() + 1,
-            con_loc,
-            lst_loc,
-            str_loc
+        let mut str_loc = switch_on(
+            IndexingInstruction::SwitchOnStructure,
+            self.structures,
+            &mut prelude,
         );
 
-        prelude.push_front(Line::from(switch_instr));
+        let con_loc = switch_on(
+            IndexingInstruction::SwitchOnConstant,
+            self.constants,
+            &mut prelude,
+        );
+
+        match &mut str_loc {
+            IndexingCodePtr::Internal(ref mut i) => {
+                *i += con_loc.is_internal() as usize;
+            }
+            _ => {
+            }
+        };
+
+        match &mut lst_loc {
+            IndexingCodePtr::Internal(ref mut i) => {
+                *i += con_loc.is_internal() as usize;
+                *i += str_loc.is_internal() as usize;
+            }
+            _ => {
+            }
+        };
+
+        let var_offset = 1 + skip_stub_try_me_else as usize;
+
+        prelude.push_front(IndexingLine::from(
+            IndexingInstruction::SwitchOnTerm(self.optimal_index, var_offset, con_loc, lst_loc, str_loc)
+        ));
 
-        *code = Vec::from(prelude);
-        code.append(&mut code_body);
+        prelude.into_iter().collect()
     }
 }
index c3de3469b0cb238d4e69358e4137400572d3c8c6..a913f49ed00a49ed8d74d826c8f162b195a868ec 100644 (file)
@@ -2,6 +2,7 @@ use crate::prolog_parser::ast::*;
 
 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::*;
@@ -9,7 +10,8 @@ use crate::rug::Integer;
 
 use crate::indexmap::IndexMap;
 
-use std::collections::VecDeque;
+use slice_deque::SliceDeque;
+
 use std::rc::Rc;
 
 fn reg_type_into_functor(r: RegType) -> MachineStub {
@@ -48,9 +50,9 @@ impl ArithmeticTerm {
 #[derive(Debug)]
 pub enum ChoiceInstruction {
     DefaultRetryMeElse(usize),
-    DefaultTrustMe,
+    DefaultTrustMe(usize),
     RetryMeElse(usize),
-    TrustMe,
+    TrustMe(usize),
     TryMeElse(usize),
 }
 
@@ -63,14 +65,14 @@ impl ChoiceInstruction {
             &ChoiceInstruction::RetryMeElse(offset) => {
                 functor!("retry_me_else", [integer(offset)])
             }
-            &ChoiceInstruction::TrustMe => {
-                functor!("trust_me")
+            &ChoiceInstruction::TrustMe(offset) => {
+                functor!("trust_me", [integer(offset)])
             }
             &ChoiceInstruction::DefaultRetryMeElse(offset) => {
                 functor!("default_retry_me_else", [integer(offset)])
             }
-            &ChoiceInstruction::DefaultTrustMe => {
-                functor!("default_trust_me")
+            &ChoiceInstruction::DefaultTrustMe(offset) => {
+                functor!("default_trust_me", [integer(offset)])
             }
         }
     }
@@ -106,19 +108,13 @@ impl CutInstruction {
     }
 }
 
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
 pub enum IndexedChoiceInstruction {
     Retry(usize),
     Trust(usize),
     Try(usize),
 }
 
-impl From<IndexedChoiceInstruction> for Line {
-    fn from(i: IndexedChoiceInstruction) -> Self {
-        Line::IndexedChoice(i)
-    }
-}
-
 impl IndexedChoiceInstruction {
     pub fn offset(&self) -> usize {
         match self {
@@ -144,6 +140,26 @@ impl IndexedChoiceInstruction {
 }
 
 /// A `Line` is an instruction (cf. page 98 of wambook).
+#[derive(Debug)]
+pub enum IndexingLine {
+    Indexing(IndexingInstruction),
+    IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
+}
+
+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 enum Line {
     Arithmetic(ArithmeticInstruction),
@@ -151,12 +167,13 @@ pub enum Line {
     Control(ControlInstruction),
     Cut(CutInstruction),
     Fact(FactInstruction),
-    Indexing(IndexingInstruction),
+    IndexingCode(Vec<IndexingLine>),
     IndexedChoice(IndexedChoiceInstruction),
     Query(QueryInstruction),
 }
 
 impl Line {
+    #[inline]
     pub fn is_head_instr(&self) -> bool {
         match self {
             &Line::Cut(_) => true,
@@ -166,16 +183,64 @@ impl Line {
         }
     }
 
-    pub fn to_functor(&self, h: usize) -> MachineStub {
+    pub fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
         match self {
-            &Line::Arithmetic(ref arith_instr) => arith_instr.to_functor(h),
-            &Line::Choice(ref choice_instr) => choice_instr.to_functor(),
-            &Line::Control(ref control_instr) => control_instr.to_functor(),
-            &Line::Cut(ref cut_instr) => cut_instr.to_functor(h),
-            &Line::Fact(ref fact_instr) => fact_instr.to_functor(h),
-            &Line::Indexing(ref indexing_instr) => indexing_instr.to_functor(),
-            &Line::IndexedChoice(ref indexed_choice_instr) => indexed_choice_instr.to_functor(),
-            &Line::Query(ref query_instr) => query_instr.to_functor(h),
+            &Line::Arithmetic(ref arith_instr) =>
+                functors.push(arith_instr.to_functor(h)),
+            &Line::Choice(ref choice_instr) =>
+                functors.push(choice_instr.to_functor()),
+            &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);
+                            }
+                        }
+                    }
+                }
+            }
+            &Line::IndexedChoice(ref indexed_choice_instr) =>
+                functors.push(indexed_choice_instr.to_functor()),
+            &Line::Query(ref query_instr) =>
+                functors.push(query_instr.to_functor(h)),
+        }
+    }
+}
+
+#[inline]
+pub 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 fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
+    match line {
+        Line::IndexingCode(ref indexing_code) => {
+            Some(indexing_code)
+        }
+        _ => {
+            None
         }
     }
 }
@@ -386,6 +451,9 @@ pub enum ControlInstruction {
     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,
 }
 
@@ -418,6 +486,9 @@ impl ControlInstruction {
             &ControlInstruction::JmpBy(_, offset, ..) => {
                 functor!("jmp_by", [integer(offset)])
             }
+            &ControlInstruction::RevJmpBy(offset) => {
+                functor!("rev_jmp_by", [integer(offset)])
+            }
             &ControlInstruction::Proceed => {
                 functor!("proceed")
             }
@@ -429,40 +500,94 @@ impl ControlInstruction {
 #[derive(Debug)]
 pub enum IndexingInstruction {
     // The first index is the optimal argument being indexed.
-    SwitchOnTerm(usize, usize, usize, usize, usize),
-    SwitchOnConstant(usize, usize, IndexMap<Constant, usize>),
-    SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>),
-}
-
-impl From<IndexingInstruction> for Line {
-    fn from(i: IndexingInstruction) -> Self {
-        Line::Indexing(i)
-    }
+    SwitchOnTerm(usize, usize, IndexingCodePtr, IndexingCodePtr, IndexingCodePtr),
+    SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
+    SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
 }
 
 impl IndexingInstruction {
-    pub fn to_functor(&self) -> MachineStub {
+    pub fn to_functor(&self, mut h: usize) -> MachineStub {
         match self {
             &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
                 functor!(
                     "switch_on_term",
                     [integer(arg),
                      integer(vars),
-                     integer(constants),
-                     integer(lists),
-                     integer(structures)]
+                     indexing_code_ptr(h, constants),
+                     indexing_code_ptr(h, lists),
+                     indexing_code_ptr(h, structures)]
                 )
             }
-            &IndexingInstruction::SwitchOnConstant(arg, constants, _) => {
+            &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",
-                    [integer(arg), integer(constants)]
+                    [aux(orig_h, 0)],
+                    [key_value_list_stub]
                 )
             }
-            &IndexingInstruction::SwitchOnStructure(arg, structures, _) => {
+            &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",
-                    [integer(arg), integer(structures)]
+                    [aux(orig_h, 0)],
+                    [key_value_list_stub]
                 )
             }
         }
@@ -710,8 +835,4 @@ impl QueryInstruction {
 
 pub type CompiledFact = Vec<FactInstruction>;
 
-pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>;
-
 pub type Code = Vec<Line>;
-
-pub type CodeDeque = VecDeque<Line>;
index 218ed78e31cf6739598f68079dd0d31351fb6caf..9c549166877cb18a616a9d397f95868f6ba25824 100644 (file)
@@ -481,7 +481,7 @@ impl<'a> ChunkedIterator<'a> {
             }
         }))
     }
-
+/*
     pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self {
         ChunkedIterator {
             chunk_num: 0,
@@ -490,7 +490,7 @@ impl<'a> ChunkedIterator<'a> {
             cut_var_in_head: false,
         }
     }
-
+*/
     pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
         let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
         let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));
index fbf440d038c44a0a9017715a07e258ac370b6530..8fa16e11b02d4541c219164724ce84bbc28478dd 100644 (file)
@@ -1,4 +1,5 @@
-:- module(atts, [op(1199, fx, attribute), call_residue_vars/2,
+:- module(atts, [op(1199, fx, attribute),
+                 call_residue_vars/2,
                  term_attributed_variables/2,
                         '$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2,
                         '$put_attr'/2, '$absent_from_list'/2,
@@ -19,9 +20,7 @@
     ).
 
 '$default_attr_list'([PG | PGs], Module, AttrVar) -->
-    (  { '$module_of'(Module, PG) } -> [Module:put_atts(AttrVar, PG)]
-    ;  { true }
-    ),
+    [Module:put_atts(AttrVar, PG)],
     '$default_attr_list'(PGs, Module, AttrVar).
 '$default_attr_list'([], _, _) --> [].
 
@@ -66,7 +65,8 @@
 
 '$del_attr_step'(Ls1, V, Attr) :-
     (  nonvar(Ls1) -> Ls1 = [_ | Ls2], '$del_attr_buried'(Ls1, Ls2, V, Attr)
-    ;  true ).
+    ;  true
+    ).
 
 %% assumptions: Ls0 is a list, Ls1 is its tail;
 %%              the head of Ls0 can be ignored.
@@ -75,8 +75,8 @@
     ;  Ls1 = [Att | Ls2] ->
        (  Att \= Attr -> '$del_attr_buried'(Ls1, Ls2, V, Attr)
        ;  '$enqueue_attr_var'(V),
-         '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
-         '$del_attr_step'(Ls1, V, Attr)
+             '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
+             '$del_attr_step'(Ls1, V, Attr)
        )
     ).
 
@@ -88,66 +88,66 @@ user:term_expansion(Term0, Terms) :-
     nonvar(Term0),
     Term0 = (:- attribute Atts),
     nonvar(Atts),
-    phrase(expand_terms(Atts), Terms).
+    loader:prolog_load_context(module, Module),
+    phrase(expand_terms(Atts, Module), Terms).
 
-expand_terms(Atts) -->
+expand_terms(Atts, Module) -->
     put_attrs_var_check,
-    put_attrs(Atts),
+    put_attrs(Atts, Module),
     get_attrs_var_check,
-    get_attrs(Atts).
+    get_attrs(Atts, Module).
 
 put_attrs_var_check -->
-    { numbervars([Var, Attr], 0, _) },
     [(put_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), put_atts/2))),
      (put_atts(Var, Attr) :- var(Attr), throw(error(instantiation_error, put_atts/2)))].
 
 get_attrs_var_check -->
-    { numbervars([Var, Ls, Attr], 0, _) },
     [(get_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), get_atts/2))),
      (get_atts(Var, Attr) :- var(Attr), !, '$get_attr_list'(Var, Ls), nonvar(Ls),
                             '$copy_attr_list'(Ls, Attr))].
 
-put_attrs(Name/Arity) -->
-    put_attr(Name, Arity),
-    { numbervars([Var, Attr], 0, _) },
+put_attrs(Name/Arity, Module) -->
+    put_attr(Name, Arity, Module),
     [(put_atts(Var, Attr) :- lists:maplist(put_atts(Var), Attr), !)].
-put_attrs((Name/Arity, Atts)) -->
+put_attrs((Name/Arity, Atts), Module) -->
     { nonvar(Atts) },
-    put_attr(Name, Arity),
-    put_attrs(Atts).
+    put_attr(Name, Arity, Module),
+    put_attrs(Atts, Module).
 
-get_attrs(Name/Arity) -->
-    get_attr(Name, Arity).
-get_attrs((Name/Arity, Atts)) -->
+get_attrs(Name/Arity, Module) -->
+    get_attr(Name, Arity, Module).
+get_attrs((Name/Arity, Atts), Module) -->
     { nonvar(Atts) },
-    get_attr(Name, Arity),
-    get_attrs(Atts).
-
-put_attr(Name, Arity) -->
-    { functor(Attr, Name, Arity),
-      numbervars(Attr, 0, Arity),
-      V = '$VAR'(Arity) },
-    [(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity),
-                           functor(AttrForm, Head, Arity),
-                           '$get_attr_list'(V, Ls),
-                           '$del_attr'(Ls, V, AttrForm),
-                           '$put_attr'(V, Attr)),
-     (put_atts(V,  Attr) :- !, functor(Attr, Head, Arity),
-                           functor(AttrForm, Head, Arity),
-                           '$get_attr_list'(V, Ls),
-                           '$del_attr'(Ls, V, AttrForm),
-                           '$put_attr'(V, Attr)),
-     (put_atts(V, -Attr) :- !, functor(Attr, _, _),
-                           '$get_attr_list'(V, Ls),
-                           '$del_attr'(Ls, V, Attr))].
-
-get_attr(Name, Arity) -->
-    { functor(Attr, Name, Arity),
-      numbervars(Attr, 0, Arity),
-      V = '$VAR'(Arity) },
-    [(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)),
-     (get_atts(V,  Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)),
-     (get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Attr))].
+    get_attr(Name, Arity, Module),
+    get_attrs(Atts, Module).
+
+put_attr(Name, Arity, Module) -->
+    { functor(Attr, Name, Arity) },
+    [(put_atts(V, +Attr) :-
+          !,
+          functor(Attr, Head, Arity),
+                 functor(AttrForm, Head, Arity),
+                 '$get_attr_list'(V, Ls),
+                 '$del_attr'(Ls, V, Module:AttrForm),
+                 '$put_attr'(V, Module:Attr)),
+     (put_atts(V,  Attr) :-
+          !,
+          functor(Attr, Head, Arity),
+                 functor(AttrForm, Head, Arity),
+                 '$get_attr_list'(V, Ls),
+                 '$del_attr'(Ls, V, Module:AttrForm),
+                 '$put_attr'(V, Module:Attr)),
+     (put_atts(V, -Attr) :-
+          !,
+          functor(Attr, _, _),
+                 '$get_attr_list'(V, Ls),
+                 '$del_attr'(Ls, V, Module:Attr))].
+
+get_attr(Name, Arity, Module) -->
+    { functor(Attr, Name, Arity) },
+    [(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)),
+     (get_atts(V,  Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)),
+     (get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Module:Attr))].
 
 user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
     nonvar(Term),
index 3d7aa79f867037734f6a03cf1eeddade42b9d18b..d17faf8cea5752eefb37f4ca9b2100c2d2cfdd9a 100644 (file)
@@ -1,45 +1,3 @@
-:- op(400, yfx, /).
-
-% module resolution operator.
-:- op(600, xfy, :).
-
-user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
-    '$expand_op_list'([Op | OtherOps], Pred, Spec, OpResults).
-
-'$expand_op_list'([], _, _, []).
-'$expand_op_list'([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResults]) :-
-    '$expand_op_list'(OtherOps, Pred, Spec, OtherResults).
-
-/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
-   and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
-   instructions are unchanged. */
-:- op(700, fx, non_counted_backtracking).
-
-% arithmetic operators.
-:- op(700, xfx, is).
-:- op(500, yfx, [+, -]).
-:- op(400, yfx, *).
-:- op(200, xfy, [**, ^]).
-:- op(500, yfx, [/\, \/, xor]).
-:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]).
-:- op(200, fy, [+, -, \]).
-
-:- op(1200, xfx, -->).
-
-% arithmetic comparison operators.
-:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
-
-% term comparison.
-:- op(700, xfx, [==, \==, @=<, @>=, @<, @>]).
-
-% conditional operators.
-:- op(1050, xfy, ->).
-:- op(1100, xfy, ;).
-
-% control.
-:- op(700, xfx, [=, =.., \=]).
-:- op(900, fy, \+).
-
 :- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
                      (=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
                      (:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
@@ -50,21 +8,21 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
                      clause/2, close/1, close/2, current_input/1,
                      current_output/1, current_op/3,
                      current_predicate/1, current_prolog_flag/2,
-                     expand_goal/2, expand_term/2, fail/0, false/0,
-                     findall/3, findall/4, flush_output/0,
-                     flush_output/1, get_byte/1, get_byte/2,
-                     get_char/1, get_char/2, get_code/1, get_code/2,
-                     halt/0, halt/1, max_arity/1, number_chars/2,
-                     number_codes/2, once/1, op/3, open/3, open/4,
-                     peek_byte/1, peek_byte/2, peek_char/1,
-                     peek_char/2, peek_code/1, peek_code/2,
-                     put_byte/1, put_byte/2, put_code/1, put_code/2,
-                     put_char/1, put_char/2, read_term/2, read_term/3,
-                     repeat/0, retract/1, set_prolog_flag/2,
-                     set_input/1, set_stream_position/2, set_output/1,
-                     setof/3, stream_property/2, sub_atom/5,
-                     subsumes_term/2, term_variables/2, throw/1,
-                     true/0, unify_with_occurs_check/2, write/1,
+                     fail/0, false/0, findall/3, findall/4,
+                     flush_output/0, flush_output/1, get_byte/1,
+                     get_byte/2, get_char/1, get_char/2, get_code/1,
+                     get_code/2, halt/0, halt/1, max_arity/1,
+                     number_chars/2, number_codes/2, once/1, op/3,
+                     open/3, open/4, peek_byte/1, peek_byte/2,
+                     peek_char/1, peek_char/2, peek_code/1,
+                     peek_code/2, put_byte/1, put_byte/2, put_code/1,
+                     put_code/2, put_char/1, put_char/2, read_term/2,
+                     read_term/3, repeat/0, retract/1,
+                     set_prolog_flag/2, set_input/1,
+                     set_stream_position/2, set_output/1, setof/3,
+                     stream_property/2, sub_atom/5, subsumes_term/2,
+                     term_variables/2, throw/1, true/0,
+                     unify_with_occurs_check/2, write/1,
                      write_canonical/1, write_term/2, write_term/3,
                      writeq/1]).
 
@@ -80,13 +38,16 @@ true.
 
 false :- '$fail'.
 
-% 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))
@@ -137,7 +98,6 @@ Module : Predicate :-
     ; throw(error(type_error(atom, Module), (:)/2))
     ).
 
-
 % flags.
 
 current_prolog_flag(Flag, false) :- Flag == bounded, !.
@@ -171,7 +131,7 @@ set_prolog_flag(min_integer, Value) :-
 set_prolog_flag(integer_rounding_function, down) :- !. % 7.11.1.4
 set_prolog_flag(integer_rounding_function, Value) :-
     throw(error(domain_error(flag_value, integer_rounding_function + Value),
-               set_prolog_flag/2)). % 8.17.1.3 e
+                       set_prolog_flag/2)). % 8.17.1.3 e
 set_prolog_flag(double_quotes, chars) :-
     !, '$set_double_quotes'(chars). % 7.11.2.5, list of one-char atoms.
 set_prolog_flag(double_quotes, atom) :-
@@ -180,7 +140,7 @@ set_prolog_flag(double_quotes, codes) :-
     !, '$set_double_quotes'(codes).
 set_prolog_flag(double_quotes, Value) :-
     throw(error(domain_error(flag_value, double_quotes + Value),
-               set_prolog_flag/2)). % 8.17.1.3 e
+                       set_prolog_flag/2)). % 8.17.1.3 e
 set_prolog_flag(Flag, _) :-
     atom(Flag),
     throw(error(domain_error(prolog_flag, Flag), set_prolog_flag/2)). % 8.17.1.3 d
@@ -192,6 +152,8 @@ set_prolog_flag(Flag, _) :-
 fail :- '$fail'.
 
 
+:- meta_predicate \+(:).
+
 \+ G :- call(G), !, false.
 \+ _.
 
@@ -200,6 +162,8 @@ X \= X :- !, false.
 _ \= _.
 
 
+:- meta_predicate once(:).
+
 once(G) :- call(G), !.
 
 
@@ -207,6 +171,20 @@ repeat.
 repeat :- repeat.
 
 
+
+:- meta_predicate ','(:, :).
+
+:- meta_predicate ','(:, +, +).
+
+:- meta_predicate ;(:, :).
+
+:- meta_predicate ;(:, :, +).
+
+:- meta_predicate ->(:, :).
+
+:- meta_predicate ->(:, :, +).
+
+
 ','(G1, G2) :-
     '$get_b_value'(B),
     (  '$call_with_default_policy'(var(G1)) ->
@@ -321,19 +299,26 @@ call_or_cut(G, _) :-
 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
-       )
+      (  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] ->
-       (  var(H), var(Term), % R == [] => List is a proper list.
+       (  var(H),
+          var(Term), % R == [] => List is a proper list.
                  throw(error(instantiation_error, (=..)/2))                 % 8.5.3.3 c)
-       ;  T \== [], nonvar(H), \+ atom(H),
+       ;  T \== [],
+          nonvar(H),
+          \+ atom(H),
                  throw(error(type_error(atom, H), (=..)/2))                 % 8.5.3.3 d)
-       ;  compound(H), T == [],
+       ;  compound(H),
+          T == [],
                  throw(error(type_error(atomic, H), (=..)/2))               % 8.5.3.3 e)
-       ;  var(Term), max_arity(M), N - 1 > M,
+       ;  var(Term),
+          max_arity(M),
+          N - 1 > M,
                  throw(error(representation_error(max_arity), (=..)/2))     % 8.5.3.3 g)
        ;  true
        )
@@ -342,14 +327,17 @@ univ_errors(Term, List, N) :-
     ;  true
     ).
 
-Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)),
-                '$call_with_default_policy'(univ_worker(Term, List, N)).
+Term =.. List :-
+    '$call_with_default_policy'(univ_errors(Term, List, N)),
+       '$call_with_default_policy'(univ_worker(Term, List, N)).
 
 
 :- non_counted_backtracking univ_worker/3.
 
 univ_worker(Term, List, _) :-
-    atomic(Term), !, '$call_with_default_policy'(List = [Term]).
+    atomic(Term),
+    !,
+    '$call_with_default_policy'(List = [Term]).
 univ_worker(Term, [Name|Args], N) :-
     var(Term), !,
     '$call_with_default_policy'(Arity is N-1),
@@ -364,46 +352,78 @@ univ_worker(Term, List, _) :-
 :- non_counted_backtracking get_args/4.
 
 get_args(Args, _, _, 0) :-
-    !, '$call_with_default_policy'(Args = []).
+    !,
+    '$call_with_default_policy'(Args = []).
 get_args([Arg], Func, N, N) :-
-    !, '$call_with_default_policy'(arg(N, Func, Arg)).
+    !,
+    '$call_with_default_policy'(arg(N, Func, Arg)).
 get_args([Arg|Args], Func, I0, N) :-
     '$call_with_default_policy'(arg(I0, Func, Arg)),
     '$call_with_default_policy'(I1 is I0 + 1),
     '$call_with_default_policy'(get_args(Args, Func, I1, N)).
 
+
+:- meta_predicate parse_options_list(?, :, ?, ?, ?).
+
+parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
+    '$skip_max_list'(_, -1, Options, Tail),
+    (  Tail == [] ->
+       true
+    ;  var(Tail) ->
+       throw(error(instantiation_error, Stub))       % 8.11.5.3c)
+    ;  Tail \== [] ->
+       throw(error(type_error(list, Options), Stub)) % 8.11.5.3e)
+    ),
+    (  lists:maplist(nonvar, Options),
+       catch(lists:maplist(Selector, Options, OptionPairs0),
+             error(E, _),
+             builtins:throw(error(E, Stub))) ->
+       lists:append(DefaultPairs, OptionPairs0, OptionPairs1),
+       keysort(OptionPairs1, OptionPairs),
+       select_rightmost_options(OptionPairs, OptionValues)
+    ;
+       throw(error(instantiation_error, Stub))       % 8.11.5.3c)
+    ).
+
+
 parse_write_options(Options, OptionValues, Stub) :-
     DefaultOptions = [ignore_ops-false, max_depth-0, numbervars-false,
                       quoted-false, variable_names-[]],
-    parse_options_list(Options, parse_write_options_, DefaultOptions, OptionValues, Stub).
+    parse_options_list(Options, builtins:parse_write_options_, DefaultOptions, OptionValues, Stub).
 
 parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :-
-    (  nonvar(IgnoreOps), lists:member(IgnoreOps, [true, false])
+    (  nonvar(IgnoreOps),
+       lists:member(IgnoreOps, [true, false])
     ;
        throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _))
     ).
 parse_write_options_(quoted(Quoted), quoted-Quoted) :-
-    (  nonvar(Quoted), lists:member(Quoted, [true, false])
+    (  nonvar(Quoted),
+       lists:member(Quoted, [true, false])
     ;
        throw(error(domain_error(write_option, quoted(Quoted)), _))
     ).
 parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :-
-    (  nonvar(NumberVars), lists:member(NumberVars, [true, false])
+    (  nonvar(NumberVars),
+       lists:member(NumberVars, [true, false])
     ;
        throw(error(domain_error(write_option, numbervars(NumberVars)), _))
     ).
 parse_write_options_(variable_names(VNNames), variable_names-VNNames) :-
     must_be_var_names_list(VNNames).
 parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
-    (  integer(MaxDepth), MaxDepth >= 0
+    (  integer(MaxDepth),
+       MaxDepth >= 0
     ;
        throw(error(domain_error(write_option, max_depth(MaxDepth)), _))
     ).
 
 must_be_var_names_list(VarNames) :-
     '$skip_max_list'(_, -1, VarNames, Tail),
-    (  Tail == [] -> must_be_var_names_list_(VarNames, VarNames)
-    ;  var(Tail)  -> throw(error(instantiation_error, write_term/2))
+    (  Tail == [] ->
+       must_be_var_names_list_(VarNames, VarNames)
+    ;  var(Tail)  ->
+       throw(error(instantiation_error, write_term/2))
     ;  throw(error(domain_error(write_option, variable_names(VarNames)), write_term/2))
     ).
 
@@ -411,8 +431,10 @@ must_be_var_names_list_([], List).
 must_be_var_names_list_([VarName | VarNames], List) :-
     (  nonvar(VarName) ->
        (  VarName = (Atom = _) ->
-             (  atom(Atom) -> must_be_var_names_list_(VarNames, List)
-             ;  var(Atom)  -> throw(error(instantiation_error, write_term/2))
+             (  atom(Atom) ->
+             must_be_var_names_list_(VarNames, List)
+             ;  var(Atom)  ->
+             throw(error(instantiation_error, write_term/2))
              ;  throw(error(domain_error(write_option, variable_names(List)), write_term/2))
              )
        ;  throw(error(domain_error(write_option, variable_names(List)), write_term/2))
@@ -455,30 +477,9 @@ select_rightmost_options([Option-Value | OptionPairs], OptionValues) :-
 select_rightmost_options([], []).
 
 
-parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
-    '$skip_max_list'(_, -1, Options, Tail),
-    (  Tail == [] ->
-       true
-    ;  var(Tail) ->
-       throw(error(instantiation_error, Stub))       % 8.11.5.3c)
-    ;  Tail \== [] ->
-       throw(error(type_error(list, Options), Stub)) % 8.11.5.3e)
-    ),
-    (  lists:maplist(nonvar, Options),
-       catch(lists:maplist(Selector, Options, OptionPairs0),
-             error(E, _),
-             throw(error(E, Stub))) ->
-       lists:append(DefaultPairs, OptionPairs0, OptionPairs1),
-       keysort(OptionPairs1, OptionPairs),
-       select_rightmost_options(OptionPairs, OptionValues)
-    ;
-       throw(error(instantiation_error, Stub))       % 8.11.5.3c)
-    ).
-
-
 parse_read_term_options(Options, OptionValues, Stub) :-
     DefaultOptions = [singletons-_, variables-_, variable_names-_],
-    parse_options_list(Options, parse_read_term_options_, DefaultOptions, OptionValues, Stub).
+    parse_options_list(Options, builtins:parse_read_term_options_, DefaultOptions, OptionValues, Stub).
 
 
 parse_read_term_options_(singletons(Vars), singletons-Vars).
@@ -498,20 +499,21 @@ read_term(Term, Options) :-
     read_term(Stream, Term, Options).
 
 
-% expand_goal.
-
-expand_goal(Term0, Term) :- '$expand_goal'(Term0, Term).
-
-% expand_term.
-
-expand_term(Term0, Term) :- '$expand_term'(Term0, Term).
-
 % term_variables.
 
 % ensures List is either a variable or a list.
-can_be_list(List, _)  :- var(List), !.
-can_be_list(List, _)  :- '$skip_max_list'(_, -1, List, Tail), ( var(Tail) -> true ; Tail == []), !.
-can_be_list(List, PI) :- throw(error(type_error(list, List), PI)).
+can_be_list(List, _)  :-
+    var(List),
+    !.
+can_be_list(List, _)  :-
+    '$skip_max_list'(_, -1, List, Tail),
+    (  var(Tail) ->
+       true
+    ;  Tail == []
+    ),
+    !.
+can_be_list(List, PI) :-
+    throw(error(type_error(list, List), PI)).
 
 term_variables(Term, Vars) :-
     can_be_list(Vars, term_variables/2),
@@ -519,7 +521,14 @@ term_variables(Term, Vars) :-
 
 % exceptions.
 
-catch(G,C,R) :- '$get_current_block'(Bb), '$call_with_default_policy'(catch(G,C,R,Bb)).
+:- meta_predicate catch(:, ?, :).
+
+catch(G,C,R) :-
+    '$get_current_block'(Bb),
+    '$call_with_default_policy'(catch(G,C,R,Bb)).
+
+
+:- meta_predicate catch(:, ?, :, +).
 
 :- non_counted_backtracking catch/4.
 catch(G,C,R,Bb) :-
@@ -531,16 +540,30 @@ catch(G,C,R,Bb) :-
     '$get_ball'(Ball),
     '$call_with_default_policy'(handle_ball(Ball, C, R)).
 
+
 :- non_counted_backtracking end_block/2.
-end_block(Bb, NBb) :- '$clean_up_block'(NBb), '$reset_block'(Bb).
-end_block(Bb, NBb) :- '$reset_block'(NBb), '$fail'.
+end_block(Bb, NBb) :-
+    '$clean_up_block'(NBb),
+    '$reset_block'(Bb).
+end_block(Bb, NBb) :-
+    '$reset_block'(NBb),
+    '$fail'.
+
+:- meta_predicate handle_ball(?, ?, :).
 
 :- non_counted_backtracking handle_ball/3.
-handle_ball(C, C, R) :- !, '$erase_ball', call(R).
-handle_ball(_, _, _) :- '$unwind_stack'.
+handle_ball(C, C, R) :-
+    !,
+    '$erase_ball',
+    call(R).
+handle_ball(_, _, _) :-
+    '$unwind_stack'.
 
 throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
 
+
+% :- meta_predicate '$iterate_find_all'(?, :, ?, ?).
+
 :- non_counted_backtracking '$iterate_find_all'/4.
 '$iterate_find_all'(Template, Goal, _, LhOffset) :-
     call(Goal),
@@ -550,14 +573,23 @@ throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
     '$truncate_if_no_lh_growth'(LhOffset),
     '$get_lh_from_offset'(LhOffset, Solutions).
 
+
 truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
 
+
+:- meta_predicate findall(?, :, ?).
+
 findall(Template, Goal, Solutions) :-
     error:can_be(list, Solutions),
     '$lh_length'(LhLength),
-    '$call_with_default_policy'(catch('$iterate_find_all'(Template, Goal, Solutions, LhLength),
-                                     Error,
-                                     ( truncate_lh_to(LhLength), throw(Error) ))).
+    '$call_with_default_policy'(
+        catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength),
+                         Error,
+                         ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))
+    ).
+
+
+% :- meta_predicate '$iterate_find_all_diff'(?, :, ?, ?, ?).
 
 :- non_counted_backtracking '$iterate_find_all_diff'/5.
 '$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
@@ -569,14 +601,16 @@ findall(Template, Goal, Solutions) :-
     '$get_lh_from_offset_diff'(LhOffset, Solutions0, Solutions1).
 
 
+% :- meta_predicate findall(?, :, ?, ?).
+
 findall(Template, Goal, Solutions0, Solutions1) :-
     error:can_be(list, Solutions0),
     error:can_be(list, Solutions1),
     '$lh_length'(LhLength),
-    '$call_with_default_policy'(catch('$iterate_find_all_diff'(Template, Goal, Solutions0,
-                                                              Solutions1, LhLength),
-                                     Error,
-                                     ( truncate_lh_to(LhLength), throw(Error) ))).
+    '$call_with_default_policy'(catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0,
+                                                                                                   Solutions1, LhLength),
+                                                     Error,
+                                                     ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))).
 
 set_difference([X|Xs], [Y|Ys], Zs) :-
     X == Y, !, set_difference(Xs, [Y|Ys], Zs).
@@ -588,7 +622,10 @@ set_difference([], _, []) :- !.
 set_difference(Xs, [], Xs).
 
 group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
-    iso_ext:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
+    iso_ext:variant(V1, V2),
+    !,
+    V1 = V2,
+    group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
 group_by_variant(Pairs, _, [], Pairs).
 
 group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
@@ -611,8 +648,12 @@ rightmost_power(Term, FinalTerm, Xs) :-
     ;  Xs = [], FinalTerm = Term
     ).
 
+
+% :- meta_predicate findall_with_existential(?, :, ?, ?, ?).
+
 findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :-
-    (  nonvar(Goal), Goal = _ ^ _ ->
+    (  nonvar(Goal),
+       Goal = _ ^ _ ->
        rightmost_power(Goal, Goal1, ExistentialVars0),
        term_variables(ExistentialVars0, ExistentialVars),
        sort(Witnesses0, Witnesses1),
@@ -623,6 +664,9 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
        findall(Witnesses-Template, Goal, PairedSolutions)
     ).
 
+
+:- meta_predicate bagof(?, :, ?).
+
 bagof(Template, Goal, Solution) :-
     error:can_be(list, Solution),
     term_variables(Template, TemplateVars0),
@@ -643,6 +687,9 @@ iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
 iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :-
     iterate_variants_and_sort(GroupSolutions, Ws, Solution).
 
+
+:- meta_predicate setof(?, :, ?).
+
 setof(Template, Goal, Solution) :-
     error:can_be(list, Solution),
     term_variables(Template, TemplateVars0),
@@ -659,36 +706,47 @@ setof(Template, Goal, Solution) :-
 
 '$clause_body_is_valid'(B) :-
     (  var(B) -> true
-    ;  functor(B, Name, _) -> (  atom(Name), Name \== '.' -> true
-                             ;  throw(error(type_error(callable, B), clause/2))
-                             )
+    ;  functor(B, Name, _) ->
+       (  atom(Name), Name \== '.' -> true
+          ;  throw(error(type_error(callable, B), clause/2))
+          )
     ;  throw(error(type_error(callable, B), clause/2))
     ).
 
 '$module_clause'(H, B, Module) :-
     (  var(H) -> throw(error(instantiation_error, clause/2))
-    ;  functor(H, Name, Arity) -> (  Name == '.' -> throw(error(type_error(callable, H), clause/2))
-                                 ;  '$module_head_is_dynamic'(H, Module) ->
-                                    '$clause_body_is_valid'(B),
-                                    '$get_module_clause'(H, B, Module)
-                                 ;  throw(error(permission_error(access, private_procedure, Name/Arity),
-                                                clause/2))
-                                 )
+    ;  functor(H, Name, Arity) ->
+       (  Name == '.' ->
+          throw(error(type_error(callable, H), clause/2))
+          ;  '$head_is_dynamic'(Module, H) ->
+                 '$clause_body_is_valid'(B),
+                 Module:'$clause'(H, B) %%TODO: how do we show this exists?
+          ;  throw(error(permission_error(access, private_procedure, Name/Arity),
+                                         clause/2))
+          )
     ;  throw(error(type_error(callable, H), clause/2))
     ).
 
+
+:- dynamic('$clause'/2).
+
 clause(H, B) :-
-    (  var(H) -> throw(error(instantiation_error, clause/2))
+    (  var(H) ->
+       throw(error(instantiation_error, clause/2))
     ;  functor(H, Name, Arity) ->
-       (  Name == '.' -> throw(error(type_error(callable, H), clause/2))
-          ;  Name == (:), Arity =:= 2 ->
+       (  Name == '.' ->
+          throw(error(type_error(callable, H), clause/2))
+          ;  Name == (:),
+          Arity =:= 2 ->
                  arg(1, H, Module),
                  arg(2, H, F),
                  '$module_clause'(F, B, Module)
-          %% '$no_such_predicate' fails if H is not callable.
-          ;  '$no_such_predicate'(H) -> '$fail'
-          ;  '$head_is_dynamic'(H) -> '$clause_body_is_valid'(B),
-                                                              '$get_clause'(H, B)
+          ;  '$no_such_predicate'(user, H) ->  %% '$no_such_predicate' fails if
+                                               %% H is not callable.
+          '$fail'
+          ;  '$head_is_dynamic'(user, H) ->
+          '$clause_body_is_valid'(B),
+                 '$clause'(H, B)
           ;  throw(error(permission_error(access, private_procedure, Name/Arity),
                                          clause/2))
           )
@@ -698,19 +756,21 @@ clause(H, B) :-
 call_module_asserta(Head, Body, Name, Arity, Module) :-
     '$clause_body_is_valid'(Body),
     functor(VarHead, Name, Arity),
-    findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses),
+    findall((VarHead :- VarBody), builtins:clause(Module:VarHead, VarBody), Clauses),
     '$module_asserta'((Head :- Body), Clauses, Name, Arity, Module).
 
 call_asserta(Head, Body, Name, Arity) :-
     '$clause_body_is_valid'(Body),
     functor(VarHead, Name, Arity),
-    findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses),
-    '$asserta'((Head :- Body), Clauses, Name, Arity).
+    '$asserta'(Head, Body, Name, Arity).
 
 module_asserta_clause(Head, Body, Module) :-
     (  var(Head) -> throw(error(instantiation_error, asserta/1))
-    ;  functor(Head, Name, Arity), atom(Name), Name \== '.' ->
-       (  '$module_head_is_dynamic'(Head, Module) -> call_module_asserta(Head, Body, Name, Arity, Module)
+    ;  functor(Head, Name, Arity),
+       atom(Name),
+       Name \== '.' ->
+       (  '$module_head_is_dynamic'(Head, Module) ->
+          call_module_asserta(Head, Body, Name, Arity, Module)
        ;  throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1))
        )
     ;  throw(error(type_error(callable, Head), asserta/1))
@@ -718,166 +778,218 @@ module_asserta_clause(Head, Body, Module) :-
 
 asserta_clause(Head, Body) :-
     (  var(Head) -> throw(error(instantiation_error, asserta/1))
-    ;  functor(Head, Name, Arity), atom(Name), Name \== '.' ->
-       ( Name == (:), Arity =:= 2 ->
-        arg(1, Head, Module),
-        arg(2, Head, F),
-        module_asserta_clause(F, Body, Module)
-       ; '$no_such_predicate'(Head) -> call_asserta(Head, Body, Name, Arity)
-       ; '$head_is_dynamic'(Head) -> call_asserta(Head, Body, Name, Arity)
+    ;  functor(Head, Name, Arity),
+       atom(Name),
+       Name \== '.' ->
+       ( Name == (:),
+         Arity =:= 2 ->
+            arg(1, Head, Module),
+            arg(2, Head, F),
+            module_asserta_clause(F, Body, Module)
+       ; '$no_such_predicate'(user, Head) ->
+         call_asserta(Head, Body, Name, Arity)
+       ; '$head_is_dynamic'(user, Head) ->
+         call_asserta(Head, Body, Name, Arity)
        ;  throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1))
        )
     ;  throw(error(type_error(callable, Head), asserta/1))
     ).
 
 asserta(Clause) :-
-    (  Clause \= (_ :- _) -> Head = Clause, Body = true, asserta_clause(Head, Body)
-    ;  Clause = (Head :- Body) -> asserta_clause(Head, Body)
+    (  Clause \= (_ :- _) ->
+       Head = Clause,
+       Body = true, asserta_clause(Head, Body)
+    ;  Clause = (Head :- Body) ->
+       asserta_clause(Head, Body)
     ).
 
+% NOT MODIFIED.
 call_module_assertz(Head, Body, Name, Arity, Module) :-
     '$clause_body_is_valid'(Body),
     functor(VarHead, Name, Arity),
-    findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses),
+    findall((VarHead :- VarBody), builtins:clause(Module:VarHead, VarBody), Clauses),
     '$module_assertz'((Head :- Body), Clauses, Name, Arity, Module).
 
-call_assertz(Head, Body, Name, Arity) :-
-    '$clause_body_is_valid'(Body),
-    functor(VarHead, Name, Arity),
-    findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses),
-    '$assertz'((Head :- Body), Clauses, Name, Arity).
-
 module_assertz_clause(Head, Body, Module) :-
-    (  var(Head) -> throw(error(instantiation_error, assertz/1))
-    ;  functor(Head, Name, Arity), atom(Name), Name \== '.' ->
-       (  '$module_head_is_dynamic'(Head, Module) -> call_module_assertz(Head, Body, Name, Arity, Module)
+    (  var(Head) ->
+       throw(error(instantiation_error, assertz/1))
+    ;  functor(Head, Name, Arity),
+       atom(Name),
+       Name \== '.' ->
+       (  '$head_is_dynamic'(Module, Head) ->
+          call_module_assertz(Head, Body, Name, Arity, Module)
        ;  throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1))
        )
     ;  throw(error(type_error(callable, Head), assertz/1))
     ).
 
+% MODIFIED.
+call_assertz(Head, Body, Name, Arity) :-
+    '$clause_body_is_valid'(Body),
+    functor(VarHead, Name, Arity),
+    '$assertz'(Head, Body, Name, Arity).
+
 assertz_clause(Head, Body) :-
-    (  var(Head) -> throw(error(instantiation_error, assertz/1))
-    ;  functor(Head, Name, Arity), atom(Name), Name \== '.' ->
-       ( Name == (:), Arity =:= 2 ->
-        arg(1, Head, Module),
-        arg(2, Head, F),
-        module_assertz_clause(F, Body, Module)
-       ; '$no_such_predicate'(Head) ->
-        call_assertz(Head, Body, Name, Arity)
-       ; '$head_is_dynamic'(Head) ->
-        call_assertz(Head, Body, Name, Arity)
+    (  var(Head) ->
+       throw(error(instantiation_error, assertz/1))
+    ;  functor(Head, Name, Arity),
+       atom(Name),
+       Name \== '.' ->
+       ( Name == (:),
+         Arity =:= 2 ->
+            arg(1, Head, Module),
+            arg(2, Head, F),
+            module_assertz_clause(F, Body, Module)
+       ; '$no_such_predicate'(user, Head) ->
+            call_assertz(Head, Body, Name, Arity)
+       ; '$head_is_dynamic'(user, Head) ->
+            call_assertz(Head, Body, Name, Arity)
        ; throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1))
        )
     ;  throw(error(type_error(callable, Head), assertz/1))
     ).
 
 assertz(Clause) :-
-    (  Clause \= (_ :- _) -> Head = Clause, Body = true, assertz_clause(Head, Body)
-    ;  Clause = (Head :- Body) -> assertz_clause(Head, Body)
-    ).
-
-first_match_index([Clause0 | Clauses], Clause1, N0, N) :-
-    (  Clause0 \= Clause1 ->
-       N1 is N0 + 1,
-       first_match_index(Clauses, Clause1, N1, N)
-    ;  N0 = N, Clause0 = Clause1
+    (  Clause \= (_ :- _) ->
+       Head = Clause,
+       Body = true,
+       assertz_clause(Head, Body)
+    ;  Clause = (Head :- Body) ->
+       assertz_clause(Head, Body)
     ).
 
-retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :-
-    functor(VarHead, Name, Arity),
-    findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses1),
-    first_match_index(Clauses1, (Head :- Body), 0, N),
-    (  Clauses0 == [] -> !
-    ;  true
-    ),
-    '$retract_clause'(Name, Arity, N, Clauses1).
-retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :-
-    retract_clauses(Clauses0, Head, Body, Name, Arity).
-
-call_retract(Head, Body, Name, Arity) :-
-    findall((Head :- Body), clause(Head, Body), Clauses),
-    retract_clauses(Clauses, Head, Body, Name, Arity).
 
 module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :-
     functor(VarHead, Name, Arity),
-    findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses1),
+    findall((VarHead :- VarBody), builtins:clause(Module:VarHead, VarBody), Clauses1),
     first_match_index(Clauses1, (Head :- Body), 0, N),
     (  Clauses0 == [] -> !
     ;  true
     ),
     '$module_retract_clause'(Name, Arity, N, Clauses1, Module).
+
 module_retract_clauses([_|Clauses0], Head, Body, Name, Arity, Module) :-
     module_retract_clauses(Clauses0, Head, Body, Name, Arity, Module).
 
 call_module_retract(Head, Body, Name, Arity, Module) :-
-    findall((Head :- Body), clause(Module:Head, Body), Clauses),
+    findall((Head :- Body), builtins:clause(Module:Head, Body), Clauses),
     module_retract_clauses(Clauses, Head, Body, Name, Arity, Module).
 
 retract_module_clause(Head, Body, Module) :-
-    (  var(Head) -> throw(error(instantiation_error, retract/1))
-    ;  functor(Head, Name, Arity), atom(Name), Name \== '.' ->
+    (  var(Head) ->
+       throw(error(instantiation_error, retract/1))
+    ;  functor(Head, Name, Arity),
+       atom(Name),
+       Name \== '.' ->
        ( '$module_head_is_dynamic'(Head, Module) ->
-        call_module_retract(Head, Body, Name, Arity, Module)
+            call_module_retract(Head, Body, Name, Arity, Module)
        ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1))
        )
     ;  throw(error(type_error(callable, Head), retract/1))
     ).
 
+
+first_match_index([Clause0 | Clauses], Clause1, N0, N) :-
+    (  Clause0 \= Clause1 ->
+       N1 is N0 + 1,
+       first_match_index(Clauses, Clause1, N1, N)
+    ;  N0 = N,
+       Clause0 = Clause1
+    ).
+
+retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :-
+    functor(VarHead, Name, Arity),
+    findall((VarHead :- VarBody), builtins:'$clause'(VarHead, VarBody), Clauses1),
+    first_match_index(Clauses1, (Head :- Body), 0, N),
+    (  Clauses0 == [] -> !
+    ;  true
+    ),
+    '$retract_clause'(Name, Arity, N).
+
+retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :-
+    retract_clauses(Clauses0, Head, Body, Name, Arity).
+
+call_retract(Head, Body, Name, Arity) :-
+    findall((Head :- Body), builtins:'$clause'(Head, Body), Clauses),
+    retract_clauses(Clauses, Head, Body, Name, Arity).
+
 retract_clause(Head, Body) :-
-    (  var(Head) -> throw(error(instantiation_error, retract/1))
-    ;  functor(Head, Name, Arity), atom(Name), Name \== '.' ->
-       ( Name == (:), Arity =:= 2 ->
-        arg(1, Head, Module),
-        arg(2, Head, F),
-        retract_module_clause(F, Body, Module)
-       ; '$head_is_dynamic'(Head) -> call_retract(Head, Body, Name, Arity)
-       ; '$no_such_predicate'(Head) -> '$fail'
+    (  var(Head) ->
+       throw(error(instantiation_error, retract/1))
+    ;  functor(Head, Name, Arity),
+       atom(Name),
+       Name \== '.' ->
+       ( Name == (:),
+         Arity =:= 2 ->
+            arg(1, Head, Module),
+            arg(2, Head, F),
+            retract_module_clause(F, Body, Module)
+       ; '$head_is_dynamic'(user, Head) ->
+         call_retract(Head, Body, Name, Arity)
+       ; '$no_such_predicate'(user, Head) ->
+         '$fail'
        ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1))
        )
     ;  throw(error(type_error(callable, Head), retract/1))
     ).
 
 retract(Clause) :-
-    (  Clause \= (_ :- _) -> Head = Clause, Body = true, retract_clause(Head, Body)
-    ;  Clause = (Head :- Body) -> retract_clause(Head, Body)
+    (  Clause \= (_ :- _) ->
+       Head = Clause,
+       Body = true,
+       retract_clause(Head, Body)
+    ;  Clause = (Head :- Body) ->
+       retract_clause(Head, Body)
     ).
 
+
 module_abolish(Pred, Module) :-
-    (  var(Pred) -> throw(error(instantiation_error), abolish/1)
+    (  var(Pred) ->
+       throw(error(instantiation_error), abolish/1)
     ;  Pred = Name/Arity ->
-       (  var(Name)  -> throw(error(instantiation_error, abolish/1))
+       (  var(Name)  ->
+          throw(error(instantiation_error, abolish/1))
        ;  integer(Arity) ->
-         ( \+ atom(Name) -> throw(error(type_error(atom, Name), abolish/1))
-         ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
-         ; max_arity(N), Arity > N -> throw(error(representation_error(max_arity), abolish/1))
-         ; functor(Head, Name, Arity) ->
-           (  '$module_head_is_dynamic'(Head, Module) ->
-              '$abolish_module_clause'(Name, Arity, Module)
-           ;  throw(error(permission_error(modify, static_procedure, Pred), abolish/1))
-           )
-         )
+             ( \+ atom(Name) ->
+            throw(error(type_error(atom, Name), abolish/1))
+             ; Arity < 0 ->
+            throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
+             ; max_arity(N), Arity > N ->
+            throw(error(representation_error(max_arity), abolish/1))
+             ; functor(Head, Name, Arity) ->
+               (  '$module_head_is_dynamic'(Head, Module) ->
+                  '$abolish_module_clause'(Name, Arity, Module)
+               ;  throw(error(permission_error(modify, static_procedure, Pred), abolish/1))
+               )
+             )
        ;  throw(error(type_error(integer, Arity), abolish/1))
        )
     ; throw(error(type_error(predicate_indicator, Module:Pred), abolish/1))
     ).
 
 abolish(Pred) :-
-    (  var(Pred) -> throw(error(instantiation_error), abolish/1)
-    ;  Pred = Module:InnerPred -> module_abolish(InnerPred, Module)
+    (  var(Pred) ->
+       throw(error(instantiation_error), abolish/1)
+    ;  Pred = Module:InnerPred ->
+       module_abolish(InnerPred, Module)
     ;  Pred = Name/Arity ->
-       (  var(Name)  -> throw(error(instantiation_error, abolish/1))
-       ;  var(Arity) -> throw(error(instantiation_error, abolish/1))
+       (  var(Name)  ->
+          throw(error(instantiation_error, abolish/1))
+       ;  var(Arity) ->
+          throw(error(instantiation_error, abolish/1))
        ;  integer(Arity) ->
-         ( \+ atom(Name) -> throw(error(type_error(atom, Name), abolish/1))
-         ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
-         ; max_arity(N), Arity > N -> throw(error(representation_error(max_arity), abolish/1))
-         ; functor(Head, Name, Arity) ->
-           (  '$no_such_predicate'(Head) -> true
-           ;  '$head_is_dynamic'(Head) -> '$abolish_clause'(Name, Arity)
-           ;  throw(error(permission_error(modify, static_procedure, Pred), abolish/1))
-           )
-         )
+             ( \+ atom(Name) ->
+            throw(error(type_error(atom, Name), abolish/1))
+             ; Arity < 0 ->
+            throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
+             ; max_arity(N), Arity > N ->
+            throw(error(representation_error(max_arity), abolish/1))
+             ; functor(Head, Name, Arity) ->
+               (  '$no_such_predicate'(Head) -> true
+               ;  '$head_is_dynamic'(Head) -> '$abolish_clause'(Name, Arity)
+               ;  throw(error(permission_error(modify, static_procedure, Pred), abolish/1))
+               )
+             )
        ;  throw(error(type_error(integer, Arity), abolish/1))
        )
     ;  throw(error(type_error(predicate_indicator, Pred), abolish/1))
@@ -889,6 +1001,7 @@ abolish(Pred) :-
     '$get_next_db_ref'(Ref, NextRef),
     '$iterate_db_refs'(NextRef, Name/Arity).
 
+
 current_predicate(Pred) :-
     (  nonvar(Pred), Pred \= _ / _
     -> throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
@@ -909,8 +1022,10 @@ can_be_op_specifier(Spec) :- var(Spec).
 can_be_op_specifier(Spec) :- op_specifier(Spec).
 
 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, _),
+    (  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)
     ).
 
@@ -929,36 +1044,52 @@ op_priority(Priority) :-
        throw(error(domain_error(operator_priority, Priority))) % 8.14.3.3 h)
     ;  true
     ).
+
 op_priority(Priority) :-
     throw(error(type_error(integer, Priority), op/3)). % 8.14.3.3 d)
 
-op_specifier(OpSpec) :- atom(OpSpec),
+op_specifier(OpSpec) :-
+    atom(OpSpec),
     (  lists:member(OpSpec, [yfx, xfy, xfx, yf, fy, xf, fx]), !
     ;  throw(error(domain_error(operator_specifier, OpSpec), op/3)) % 8.14.3.3 i)
     ).
-op_specifier(OpSpec) :- throw(error(type_error(atom, OpSpec), op/3)).
 
-valid_op(Op) :- atom(Op),
-    (  Op == (',') -> throw(error(permission_error(modify, operator, (',')), op/3)) % 8.14.3.3 j), k).
-    ;  Op == {} -> throw(error(permission_error(create, operator, {}), op/3))
-    ;  Op == [] -> throw(error(permission_error(create, operator, []), op/3))
+op_specifier(OpSpec) :-
+    throw(error(type_error(atom, OpSpec), op/3)).
+
+valid_op(Op) :-
+    atom(Op),
+    (  Op == (',') ->
+       throw(error(permission_error(modify, operator, (',')), op/3)) % 8.14.3.3 j), k).
+    ;  Op == {} ->
+       throw(error(permission_error(create, operator, {}), op/3))
+    ;  Op == [] ->
+       throw(error(permission_error(create, operator, []), op/3))
     ;  true
     ).
 
-op_(Priority, OpSpec, Op) :- '$op'(Priority, OpSpec, Op).
+op_(Priority, OpSpec, Op) :-
+    '$op'(Priority, OpSpec, Op).
 
 op(Priority, OpSpec, Op) :-
-    (  var(Priority) -> throw(error(instantiation_error, op/3)) % 8.14.3.3 a)
-    ;  var(OpSpec)   -> throw(error(instantiation_error, op/3)) % 8.14.3.3 b)
-    ;  var(Op)       -> throw(error(instantiation_error, op/3)) % 8.14.3.3 c)
-    ;  Op == '|'     -> (  op_priority(Priority), op_specifier(OpSpec),
-                          lists:member(OpSpec, [xfx, xfy, yfx]), ( Priority >= 1001 ; Priority == 0 )
-                       -> '$op'(Priority, OpSpec, Op)
-                       ;  throw(error(permission_error(create, operator, (|)), op/3))) % www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing#72
+    (  var(Priority) ->
+       throw(error(instantiation_error, op/3)) % 8.14.3.3 a)
+    ;  var(OpSpec)   ->
+       throw(error(instantiation_error, op/3)) % 8.14.3.3 b)
+    ;  var(Op)       ->
+       throw(error(instantiation_error, op/3)) % 8.14.3.3 c)
+    ;  Op == '|'     ->
+       (  op_priority(Priority),
+          op_specifier(OpSpec),
+                 lists:member(OpSpec, [xfx, xfy, yfx]),
+          ( Priority >= 1001 ; Priority == 0 )
+          -> '$op'(Priority, OpSpec, Op)
+          ;  throw(error(permission_error(create, operator, (|)), op/3))) % www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing#72
     ;  valid_op(Op), op_priority(Priority), op_specifier(OpSpec) ->
        '$op'(Priority, OpSpec, Op)
     ;  list_of_op_atoms(Op), op_priority(Priority), op_specifier(OpSpec) ->
-       lists:maplist(op_(Priority, OpSpec), Op), !
+       lists:maplist(op_(Priority, OpSpec), Op),
+       !
     ;  throw(error(type_error(list, Op), op/3)) % 8.14.3.3 f)
     ).
 
@@ -973,41 +1104,54 @@ halt(N) :-
         ).
 
 atom_length(Atom, Length) :-
-    (  var(Atom)  -> throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a)
-    ;  atom(Atom) -> (  var(Length) -> '$atom_length'(Atom, Length)
-                    ;  integer(Length), Length >= 0 -> '$atom_length'(Atom, Length)
-                    ;  integer(Length) -> throw(error(domain_error(not_less_than_zero, Length), atom_length/2))
-                    % 8.16.1.3 d)
-                    ;  throw(error(type_error(integer, Length), atom_length/2)) % 8.16.1.3 c)
-                    )
+    (  var(Atom)  ->
+       throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a)
+    ;  atom(Atom) ->
+       (  var(Length) ->
+          '$atom_length'(Atom, Length)
+          ;  integer(Length), Length >= 0 ->
+          '$atom_length'(Atom, Length)
+          ;  integer(Length) ->
+          throw(error(domain_error(not_less_than_zero, Length), atom_length/2))
+          % 8.16.1.3 d)
+          ;  throw(error(type_error(integer, Length), atom_length/2)) % 8.16.1.3 c)
+          )
     ;  throw(error(type_error(atom, Atom), atom_length/2)) % 8.16.1.3 b)
     ).
 
 atom_chars(Atom, List) :-
     '$skip_max_list'(_, -1, List, Tail),
-    (  ( Tail == [] ; var(Tail) ) -> true
+    (  ( Tail == [] ; var(Tail) ) ->
+       true
     ;  throw(error(type_error(list, List), atom_chars/2))
     ),
     (  var(Atom) ->
-       (  var(Tail) -> throw(error(instantiation_error, atom_chars/2))
-       ;  ground(List) -> '$atom_chars'(Atom, List)
+       (  var(Tail) ->
+          throw(error(instantiation_error, atom_chars/2))
+       ;  ground(List) ->
+          '$atom_chars'(Atom, List)
        ;  throw(error(instantiation_error, atom_chars/2))
        )
-    ;  atom(Atom) -> '$atom_chars'(Atom, List)
+    ;  atom(Atom) ->
+       '$atom_chars'(Atom, List)
     ;  throw(error(type_error(atom, Atom), atom_chars/2))
     ).
 
 atom_codes(Atom, List) :-
     '$skip_max_list'(_, -1, List, Tail),
-    (  ( Tail == [] ; var(Tail) ) -> true
+    (  ( Tail == [] ; var(Tail) ) ->
+       true
     ;  throw(error(type_error(list, List), atom_codes/2))
     ),
     (  var(Atom) ->
-       (  var(Tail) -> throw(error(instantiation_error, atom_codes/2))
-       ;  ground(List), Tail == [] -> '$atom_codes'(Atom, List)
+       (  var(Tail) ->
+          throw(error(instantiation_error, atom_codes/2))
+       ;  ground(List), Tail == [] ->
+          '$atom_codes'(Atom, List)
        ;  throw(error(instantiation_error, atom_codes/2))
        )
-    ;  atom(Atom) -> '$atom_codes'(Atom, List)
+    ;  atom(Atom) ->
+       '$atom_codes'(Atom, List)
     ;  throw(error(type_error(atom, Atom), atom_codes/2))
     ).
 
@@ -1016,18 +1160,19 @@ atom_concat(Atom_1, Atom_2, Atom_12) :-
     error:can_be(atom, Atom_2),
     error:can_be(atom, Atom_12),
     (  var(Atom_1) ->
-       (  var(Atom_12) -> throw(error(instantiation_error, atom_concat/3))
+       (  var(Atom_12) ->
+          throw(error(instantiation_error, atom_concat/3))
        ;  atom_chars(Atom_12, Atom_12_Chars),
-         lists:append(BeforeChars, AfterChars, Atom_12_Chars),
-         atom_chars(Atom_1, BeforeChars),
-         atom_chars(Atom_2, AfterChars)
+             lists:append(BeforeChars, AfterChars, Atom_12_Chars),
+             atom_chars(Atom_1, BeforeChars),
+             atom_chars(Atom_2, AfterChars)
        )
     ;  var(Atom_2) ->
        (  var(Atom_12) -> throw(error(instantiation_error, atom_concat/3))
        ;  atom_chars(Atom_1, Atom_1_Chars),
-         atom_chars(Atom_12, Atom_12_Chars),
-         lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars),
-         atom_chars(Atom_2, Atom_2_Chars)
+             atom_chars(Atom_12, Atom_12_Chars),
+             lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars),
+             atom_chars(Atom_2, Atom_2_Chars)
        )
     ;  atom_chars(Atom_1, Atom_1_Chars),
        atom_chars(Atom_2, Atom_2_Chars),
@@ -1041,9 +1186,12 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :-
     error:can_be(integer, Before),
     error:can_be(integer, Length),
     error:can_be(integer, After),
-    (  integer(Before), Before < 0 -> throw(error(domain_error(not_less_than_zero, Before), sub_atom/5))
-    ;  integer(Length), Length < 0 -> throw(error(domain_error(not_less_than_zero, Length), sub_atom/5))
-    ;  integer(After), After < 0 -> throw(error(domain_error(not_less_than_zero, After), sub_atom/5))
+    (  integer(Before), Before < 0 ->
+       throw(error(domain_error(not_less_than_zero, Before), sub_atom/5))
+    ;  integer(Length), Length < 0 ->
+       throw(error(domain_error(not_less_than_zero, Length), sub_atom/5))
+    ;  integer(After), After < 0 ->
+       throw(error(domain_error(not_less_than_zero, After), sub_atom/5))
     ;  atom_chars(Atom, AtomChars),
        lists:append(BeforeChars, LengthAndAfterChars, AtomChars),
        lists:append(LengthChars, AfterChars, LengthAndAfterChars),
@@ -1055,11 +1203,14 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :-
 
 char_code(Char, Code) :-
     (  var(Char) ->
-       (  var(Code) -> throw(error(instantiation_error, char_code/2))
-       ;  integer(Code) -> '$char_code'(Char, Code)
+       (  var(Code) ->
+          throw(error(instantiation_error, char_code/2))
+       ;  integer(Code) ->
+          '$char_code'(Char, Code)
        ;  throw(error(type_error(integer, Code), char_code/2))
        )
-    ;  atom_length(Char, 1) -> '$char_code'(Char, Code)
+    ;  atom_length(Char, 1) ->
+       '$char_code'(Char, Code)
     ;  throw(error(type_error(character, Char), char_code/2))
     ).
 
@@ -1081,7 +1232,8 @@ must_be_number(N, _) :-
     ),
     !.
 must_be_number(N, PI) :-
-    (  nonvar(N) -> throw(error(type_error(number, N), PI))
+    (  nonvar(N) ->
+       throw(error(type_error(number, N), PI))
     ;  throw(error(instantiation_error, PI))
     ).
 
@@ -1144,7 +1296,7 @@ set_output(S) :-
 
 parse_stream_options(Options, OptionValues, Stub) :-
     DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, type-text],
-    parse_options_list(Options, parse_stream_options_, DefaultOptions, OptionValues, Stub).
+    parse_options_list(Options, builtins:parse_stream_options_, DefaultOptions, OptionValues, Stub).
 
 
 parse_stream_options_(type(Type), type-Type) :-
@@ -1191,7 +1343,7 @@ open(SourceSink, Mode, Stream, StreamOptions) :-
 
 parse_close_options(Options, OptionValues, Stub) :-
     DefaultOptions = [force-false],
-    parse_options_list(Options, parse_close_options_, DefaultOptions, OptionValues, Stub).
+    parse_options_list(Options, builtins:parse_close_options_, DefaultOptions, OptionValues, Stub).
 
 parse_close_options_(force(Force), force-Force) :-
     (  nonvar(Force), lists:member(Force, [true, false]), !
index 0b802a462918a44865bede82c4a68fad938f5548..0310e775e6ec23c8843e8dd258d53a945b8dcc2a 100644 (file)
@@ -17,8 +17,8 @@
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
 :- module(clpb, [op(300, fy, ~),
-                op(500, yfx, #),
-                sat/1,
+                        op(500, yfx, #),
+                        sat/1,
                  taut/2,
                  labeling/1,
                  sat_count/2,
index 942f6b8ebeb32d06adcbc79e1fbd5336a14324c7..b4e2fafcc9ebf5c5fad90862ff885e958c32b199 100644 (file)
@@ -5,13 +5,21 @@
 
 :- use_module(library(error)).
 :- use_module(library(lists), [append/3]).
+:- use_module(library(loader), [strip_module/3]).
+
+:- meta_predicate phrase(2, ?).
+
+:- meta_predicate phrase(2, ?, ?).
 
 phrase(GRBody, S0) :-
     phrase(GRBody, S0, []).
 
+
 phrase(GRBody, S0, S) :-
     (  var(GRBody) -> throw(error(instantiation_error, phrase/3))
-    ;  dcg_constr(GRBody) -> phrase_(GRBody, S0, S)
+    ;  strip_module(GRBody, _, GRBody0),
+       dcg_constr(GRBody0) ->
+       phrase_(GRBody0, S0, S)
     ;  functor(GRBody, _, _) -> call(GRBody, S0, S)
     ;  throw(error(type_error(callable, GRBody), phrase/3))
     ).
index d135238bb7e70fdb53092e6153165ed3cd0cd1fb..0fa3896f90759537bdda7bc23d7111a6f0b7c0dd 100644 (file)
@@ -2,13 +2,23 @@
 
 :- use_module(library(error)).
 
+
 wam_instructions(Clause, Listing) :-
     (  nonvar(Clause) ->
-       Clause = Name / Arity,
-       must_be(atom, Name),
-       must_be(integer, Arity),
-       (  Arity >= 0 -> '$wam_instructions'(Name, Arity, Listing)
-       ;  throw(error(domain_error(not_less_than_zero, Arity), wam_instructions/2))
+       (  Clause = Name / Arity ->
+          fetch_instructions(user, Name, Arity, Listing)
+       ;  Clause = Module : (Name / Arity) ->
+          fetch_instructions(Module, Name, Arity, Listing)
        )
     ;  throw(error(instantiation_error, wam_instructions/2))
     ).
+
+
+fetch_instructions(Module, Name, Arity, Listing) :-
+    must_be(atom, Module),
+    must_be(atom, Name),
+    must_be(integer, Arity),
+    (  Arity >= 0 ->
+       '$wam_instructions'(Module, Name, Arity, Listing)
+    ;  throw(error(domain_error(not_less_than_zero, Arity), wam_instructions/2))
+    ).
index bb92979af7a762029a1ec7399a90f9745be781ca..9c3b8ed837272f270b603d726a63d029b7228374 100644 (file)
@@ -8,8 +8,8 @@
 
 put_dif_att(Var, X, Y) :-
     (   get_atts(Var, +dif(Z)) ->
-       sort([X \== Y | Z], NewZ),
-       put_atts(Var, +dif(NewZ))
+           sort([X \== Y | Z], NewZ),
+           put_atts(Var, +dif(NewZ))
     ;   put_atts(Var, +dif([X \== Y]))
     ).
 
@@ -21,8 +21,8 @@ dif_set_variables([Var|Vars], X, Y) :-
 append_goals([], _).
 append_goals([Var|Vars], Goals) :-
     (   get_atts(Var, +dif(VarGoals)) ->
-       append(Goals, VarGoals, NewGoals0),
-       sort(NewGoals0, NewGoals)
+           append(Goals, VarGoals, NewGoals0),
+           sort(NewGoals0, NewGoals)
     ;   NewGoals = Goals
     ),
     put_atts(Var, +dif(NewGoals)),
@@ -30,8 +30,8 @@ append_goals([Var|Vars], Goals) :-
 
 verify_attributes(Var, Value, Goals) :-
     (   get_atts(Var, +dif(Goals)) ->
-       term_variables(Value, ValueVars),
-       append_goals(ValueVars, Goals)
+           term_variables(Value, ValueVars),
+           append_goals(ValueVars, Goals)
     ;   Goals = []
     ).
 
@@ -50,7 +50,7 @@ dif(X, Y) :-
 gather_dif_goals([]) --> [].
 gather_dif_goals([(X \== Y) | Goals]) -->
     (   { X \= Y } -> []
-    ;   [dif(X, Y)]
+    ;   [dif:dif(X, Y)]
     ),
     gather_dif_goals(Goals).
 
index 7e2189c4a6164f40d62fe47c79ddaff7c7ca0385..9959279076e08156e779668de89ab2253328c823 100644 (file)
@@ -44,10 +44,10 @@ must_be_(var, Term) :-
         ).
 must_be_(integer, Term) :- check_(integer, integer, Term).
 must_be_(atom, Term)    :- check_(atom, atom, Term).
-must_be_(character, T)  :- check_(character, character, T).
-must_be_(list, Term)    :- check_(ilist, list, Term).
-must_be_(type, Term)    :- check_(type, type, Term).
-must_be_(boolean, Term) :- check_(boolean, boolean, Term).
+must_be_(character, T)  :- check_(error:character, character, T).
+must_be_(list, Term)    :- check_(error:ilist, list, Term).
+must_be_(type, Term)    :- check_(error:type, type, Term).
+must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
 
 check_(Pred, Type, Term) :-
         (   var(Term) -> instantiation_error(must_be/2)
index e5ba94c16bfb86a526224eee0aa88e072380e988..dc83c2a485d7cbf3653b8b89665ca68eaea1a1ab 100644 (file)
@@ -23,9 +23,9 @@ bb_put(Key, _) :- throw(error(type_error(atom, Key), bb_put/2)).
 
 bb_b_put(Key, NewValue) :-
     (  '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
-       call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
+       call_cleanup((iso_ext:store_global_var_with_offset(Key, NewValue) ; false),
                     reset_global_var_at_offset(Key, OldValue, OldOffset))
-    ;  call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
+    ;  call_cleanup((iso_ext:store_global_var_with_offset(Key, NewValue) ; false),
                     reset_global_var_at_key(Key))
     ).
 
@@ -45,11 +45,16 @@ reset_global_var_at_offset(Key, Value, Offset) :- '$reset_global_var_at_offset'(
 bb_get(Key, Value) :- atom(Key), !, '$fetch_global_var'(Key, Value).
 bb_get(Key, _) :- throw(error(type_error(atom, Key), bb_get/2)).
 
+
+:- meta_predicate call_cleanup(:, :).
+
 call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
 
 
 % setup_call_cleanup.
 
+:- meta_predicate setup_call_cleanup(:, :, :).
+
 setup_call_cleanup(S, G, C) :-
     '$get_b_value'(B),
     call(S),
@@ -117,6 +122,8 @@ handle_ile(B, E, _) :-
     '$remove_call_policy_check'(B),
     '$call_with_default_policy'(throw(E)).
 
+:- meta_predicate call_with_inference_limit(:, ?, ?).
+
 call_with_inference_limit(G, L, R) :-
     '$get_current_block'(Bb),
     '$get_b_value'(B),
index a1acdb6d17e9ee8a8183923f42406b935f779966..750957152f4e5dbd240954820c79abbf681b8e3e 100644 (file)
@@ -1,15 +1,29 @@
 :- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
-                 memberchk/2, reverse/2, length/2, maplist/2,
-                 maplist/3, maplist/4, maplist/5, maplist/6,
-                 maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
-                 sum_list/2, transpose/2, list_to_set/2, list_max/2, list_min/2]).
+                         memberchk/2, reverse/2, length/2, maplist/2,
+                         maplist/3, maplist/4, maplist/5, maplist/6,
+                         maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
+                         sum_list/2, transpose/2, list_to_set/2, list_max/2, list_min/2]).
 
 
 :- use_module(library(error)).
 
 
+:- meta_predicate maplist(1, ?).
+:- meta_predicate maplist(2, ?, ?).
+:- meta_predicate maplist(3, ?, ?, ?).
+:- meta_predicate maplist(4, ?, ?, ?, ?).
+:- meta_predicate maplist(5, ?, ?, ?, ?, ?).
+:- meta_predicate maplist(6, ?, ?, ?, ?, ?, ?).
+:- meta_predicate maplist(7, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate maplist(8, ?, ?, ?, ?, ?, ?, ?, ?).
+
+:- meta_predicate foldl(3, ?, ?, ?).
+:- meta_predicate foldl(4, ?, ?, ?, ?).
+
+
 length(Xs, N) :-
-    var(N), !,
+    var(N),
+    !,
     '$skip_max_list'(M, -1, Xs, Xs0),
     (  Xs0 == [] -> N = M
     ;  var(Xs0)  -> length_addendum(Xs0, N, M)).
@@ -66,7 +80,6 @@ reverse([], [], YsRev, YsRev).
 reverse([_|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
     reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
 
-
 maplist(_, []).
 maplist(Cont1, [E1|E1s]) :-
     call(Cont1, E1),
@@ -87,21 +100,25 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s]) :-
     call(Cont, E1, E2, E3, E4),
     maplist(Cont, E1s, E2s, E3s, E4s).
 
+
 maplist(_, [], [], [], [], []).
 maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s]) :-
     call(Cont, E1, E2, E3, E4, E5),
     maplist(Cont, E1s, E2s, E3s, E4s, E5s).
 
+
 maplist(_, [], [], [], [], [], []).
 maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s]) :-
     call(Cont, E1, E2, E3, E4, E5, E6),
     maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s).
 
+
 maplist(_, [], [], [], [], [], [], []).
 maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s]) :-
     call(Cont, E1, E2, E3, E4, E5, E6, E7),
     maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s).
 
+
 maplist(_, [], [], [], [], [], [], [], []).
 maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :-
     call(Cont, E1, E2, E3, E4, E5, E6, E7, E8),
@@ -111,7 +128,7 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7
 sum_list(Ls, S) :-
         foldl(sum_, Ls, 0, S).
 
-sum_(L, S0, S) :- S is S0 + L.
+sum_(L, S0, S) :- is(S, +(S0, L)).
 
 
 
@@ -132,6 +149,7 @@ foldl_([L|Ls], G_3, A0, A) :-
 foldl(Goal_4, Xs, Ys, A0, A) :-
         foldl_(Xs, Ys, Goal_4, A0, A).
 
+
 foldl_([], [], _, A, A).
 foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
         call(G_4, X, Y, A0, A1),
diff --git a/src/lib/ops_and_meta_predicates.pl b/src/lib/ops_and_meta_predicates.pl
new file mode 100644 (file)
index 0000000..c16af3a
--- /dev/null
@@ -0,0 +1,127 @@
+:- op(400, yfx, /).
+
+% module resolution operator.
+:- op(600, xfy, :).
+
+:- op(1199, fx, meta_predicate).
+
+/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
+   and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
+   instructions are unchanged. */
+:- op(700, fx, non_counted_backtracking).
+
+% arithmetic operators.
+:- op(700, xfx, is).
+:- op(500, yfx, +).
+:- op(500, yfx, -).
+:- op(400, yfx, *).
+:- op(200, xfy, **).
+:- op(200, xfy, ^).
+:- op(500, yfx, /\).
+:- op(500, yfx, \/).
+:- op(500, yfx, xor).
+:- op(400, yfx, div).
+:- op(400, yfx, //).
+:- op(400, yfx, rdiv).
+:- op(400, yfx, <<).
+:- op(400, yfx, >>).
+:- op(400, yfx, mod).
+:- op(400, yfx, rem).
+:- op(200, fy, +).
+:- op(200, fy, -).
+:- op(200, fy, \).
+
+% arithmetic comparison operators.
+:- op(700, xfx, >).
+:- op(700, xfx, <).
+:- op(700, xfx, =\=).
+:- op(700, xfx, =:=).
+:- op(700, xfx, >=).
+:- op(700, xfx, =<).
+
+% term comparison.
+:- op(700, xfx, ==).
+:- op(700, xfx, \==).
+:- op(700, xfx, @=<).
+:- op(700, xfx, @>=).
+:- op(700, xfx, @<).
+:- op(700, xfx, @>).
+
+% conditional operators.
+:- op(1050, xfy, ->).
+:- op(1100, xfy, ;).
+
+% control.
+:- op(700, xfx, =).
+:- op(700, xfx, =..).
+:- op(700, xfx, \=).
+:- op(900, fy, \+).
+
+:- op(1200, xfx, -->).
+
+% meta_predicate declarations for call/{0, 64}.
+:- meta_predicate call(:).
+:- meta_predicate call(:, ?).
+:- meta_predicate call(:, ?, ?).
+:- meta_predicate call(:, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
+:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
index adcfb138d9a906a39d5e4c705ed41eaa72f0f975..85914639fd2175760862edf179cfdff8bd33ddd4 100644 (file)
@@ -5,6 +5,8 @@
                  map_list_to_pairs/3]).
 
 
+:- meta_predicate map_list_to_pairs(:, ?, ?).
+
 pairs_keys_values([], [], []).
 pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
         pairs_keys_values(ABs, As, Bs).
index c66be996f0646756a16beb0c93a9e71717e543d1..4c902e84ac2277f01d7ba4038a0c7c3d8ba32037 100644 (file)
@@ -75,7 +75,7 @@ wrappers(Name/Arity) -->
          atom_concat(Name, ' tabled', WrapName),
          Head =.. [Name|Args],
          WrappedHead =.. [WrapName|Args],
-         '$module_of'(Module, Name) %prolog_load_context(module, Module)
+         prolog_load_context(module, Module)
        },
        [ (   Head :-
                 start_tabling(Module:Head, WrappedHead)
@@ -109,10 +109,10 @@ rename_term(Name, WrapName) :-
 
 
 user:term_expansion(Term0, Clauses) :-
-        nonvar(Term0),
+    nonvar(Term0),
        Term0 = (:- table Preds),
        phrase(wrappers(Preds), Clauses).
 user:term_expansion(Clause, NewClause) :-
-        nonvar(Clause),
-       '$module_of'(Module, Clause),
+    nonvar(Clause),
+    prolog_load_context(module, Module),
        rename(Clause, NewClause, Module).
index 30ec0f457c583daa497b5e7a92126caa64936565..933387be4fc1be83d299728cf0d6d3db862d37a2 100644 (file)
@@ -82,6 +82,8 @@ sleep(T) :-
 
 % '$cpu_now' can be replaced by statistics/2 once that is implemented.
 
+:- meta_predicate time(:).
+
 time(Goal) :-
         '$cpu_now'(T0),
         setup_call_cleanup(true,
diff --git a/src/loader.pl b/src/loader.pl
new file mode 100644 (file)
index 0000000..9360e26
--- /dev/null
@@ -0,0 +1,433 @@
+
+:- module(loader, [consult/1,
+                   expand_goal/3,
+                   expand_term/2,
+                   file_load/2,
+                   load/1,
+                   predicate_property/2,
+                   prolog_load_context/2,
+                   strip_module/3,
+                   use_module/1,
+                   use_module/2
+                  ]).
+
+
+:- use_module(library(error)).
+:- use_module(library(lists)).
+:- use_module(library(pairs)).
+
+
+create_file_load_context(Stream, Path, Evacuable) :-
+    '$push_load_context'(Stream, Path),
+    '$push_load_state_payload'(Evacuable).
+
+create_load_context(Stream, Evacuable) :-
+    '$push_load_context'(Stream, ''),
+    '$push_load_state_payload'(Evacuable).
+
+unload_evacuable(Evacuable) :-
+    '$pop_load_state_payload'(Evacuable),
+    '$pop_load_context'.
+
+
+file_load(Stream, Path) :-
+    file_load(Stream, Path, _).
+
+file_load(Stream, Path, Evacuable) :-
+    create_file_load_context(Stream, Path, Evacuable),
+    catch(loader:load_loop(Stream, Evacuable),
+          E,
+          (loader:unload_evacuable(Evacuable), throw(E))),
+    '$pop_load_context'.
+
+
+load(Stream) :-
+    create_load_context(Stream, Evacuable),
+    catch(loader:load_loop(Stream, Evacuable),
+          E,
+          (loader:unload_evacuable(Evacuable), throw(E))),
+    '$pop_load_context'.
+
+load_loop(Stream, Evacuable) :-
+    read_term(Stream, Term, [variable_names(VNs), singletons(Singletons)]),
+    (  Term == end_of_file ->
+       close(Stream),
+       '$conclude_load'(Evacuable)
+    ;  var(Term) ->
+       instantiation_error(load/1)
+    ;  expand_terms_and_goals(Term, Terms),
+       !,
+       (  var(Terms) ->
+          instantiation_error(load/1)
+       ;  Terms = [_|_] ->
+          compile_dispatch_or_clause_on_list(Terms, Evacuable, VNs)
+       ;  compile_dispatch_or_clause(Terms, Evacuable, VNs)
+       ),
+       load_loop(Stream, Evacuable)
+    ).
+
+
+inner_meta_specs((:), HeadArg, InnerHeadArgs, InnerMetaSpecs) :-
+    !,
+    predicate_property(HeadArg, meta_predicate(InnerMetaSpecs)),
+    HeadArg =.. [_ | InnerHeadArgs].
+
+inner_meta_specs(N, HeadArg, InnerHeadArgs, InnerMetaSpecs) :-
+    integer(N),
+    N >= 0,
+    HeadArg =.. [Functor | InnerHeadArgs],
+    length(InnerHeadArgs1, N),
+    append(InnerHeadArgs, InnerHeadArgs1, InnerHeadArgs0),
+    CompleteHeadArg =.. [Functor | InnerHeadArgs0],
+    predicate_property(CompleteHeadArg, meta_predicate(InnerMetaSpecs)).
+
+
+module_expanded_head_variables_([], _, HeadVars, HeadVars).
+module_expanded_head_variables_([HeadArg | HeadArgs], [MetaSpec | MetaSpecs], HeadVars, HeadVars0) :-
+    (  (  MetaSpec == (:)
+       ;  integer(MetaSpec),
+          MetaSpec >= 0
+       )  ->
+       (  var(HeadArg) ->
+          HeadVars = [HeadArg-HeadArg | HeadVars1],
+          module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars1, HeadVars0)
+       ;  inner_meta_specs(MetaSpec, HeadArg, InnerHeadArgs, InnerMetaSpecs) ->
+          module_expanded_head_variables_(InnerHeadArgs, InnerMetaSpecs, HeadVars, HeadVars1),
+          module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars1, HeadVars0)
+       ;  module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, HeadVars0)
+       )
+    ;  module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, HeadVars0)
+    ).
+
+module_expanded_head_variables(Head, MetaSpecs, HeadVars) :-
+    (  var(Head) ->
+       instantiation_error(load/1)
+    ;  predicate_property(Head, meta_predicate(MetaSpecs)),
+       Head =.. [_ | HeadArgs] ->
+       module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, [])
+    ;  HeadVars = []
+    ).
+
+
+expand_terms_and_goals(Term, Terms) :-
+    expand_term(Term, Terms0),
+    (  var(Terms0) ->
+       instantiation_error(load/1)
+    ;  Terms0 = (Head1 :- Body0) ->
+       (  var(Head1) ->
+          instantiation_error(load/1)
+       ;  prolog_load_context(module, Target),
+          module_expanded_head_variables(Head1, MetaSpecs, HeadVars),
+          expand_goal(Body0, Target, Body1, HeadVars)
+       ),
+       Terms = (Head1 :- Body1)
+    ;  Terms = Terms0
+    ).
+
+
+expand_term(UnexpandedTerm, ExpandedTerm) :-
+    user:term_expansion(UnexpandedTerm, ExpandedTerm).
+
+
+compile_dispatch_or_clause_on_list([], Evacuable, VNs).
+compile_dispatch_or_clause_on_list([Term | Terms], Evacuable, VNs) :-
+    compile_dispatch_or_clause(Term, Evacuable, VNs),
+    compile_dispatch_or_clause_on_list(Terms, Evacuable, VNs).
+
+
+compile_dispatch_or_clause(Term, Evacuable, VNs) :-
+    (  var(Term) ->
+       instantiation_error(load/1)
+    ;  compile_dispatch(Term, Evacuable, VNs) ->
+       true
+    ;
+       compile_clause(Term, Evacuable, VNs)
+    ).
+
+
+compile_dispatch((:- Declaration), Evacuable, _VNs) :-
+    (  var(Declaration) ->
+       instantiation_error(load/1)
+    ;
+       compile_declaration(Declaration, Evacuable)
+    ).
+compile_dispatch(term_expansion(Term, Terms), Evacuable, VNs) :-
+    '$add_term_expansion_clause'('$term_expansion'(Term, Terms), Evacuable, VNs).
+compile_dispatch((term_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
+    '$add_term_expansion_clause'(('$term_expansion'(Term, Terms) :- Body), Evacuable, VNs).
+compile_dispatch(user:term_expansion(Term, Terms), Evacuable, VNs) :-
+    '$add_term_expansion_clause'('$term_expansion'(Term, Terms), Evacuable, VNs).
+compile_dispatch((user:term_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
+    '$add_term_expansion_clause'(('$term_expansion'(Term, Terms) :- Body), Evacuable, VNs).
+compile_dispatch(goal_expansion(Term, Terms), Evacuable, VNs) :-
+    prolog_load_context(module, Target),
+    '$add_goal_expansion_clause'(Target, goal_expansion(Term, Terms), Evacuable, VNs).
+compile_dispatch((goal_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
+    prolog_load_context(module, Target),
+    '$add_goal_expansion_clause'(Target, (goal_expansion(Term, Terms) :- Body), Evacuable, VNs).
+compile_dispatch(Target:goal_expansion(Term, Terms), Evacuable, VNs) :-
+    '$add_goal_expansion_clause'(Target, goal_expansion(Term, Terms), Evacuable, VNs).
+compile_dispatch((Target:goal_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
+    '$add_goal_expansion_clause'(Target, (goal_expansion(Term, Terms) :- Body), Evacuable, VNs).
+
+
+compile_declaration(use_module(Module), Evacuable) :-
+    use_module(Module, [], Evacuable).
+compile_declaration(use_module(Module, Exports), Evacuable) :-
+    (  Exports == [] ->
+       '$remove_module_exports'(Module, Evacuable) % TODO: implement this.
+    ;
+       use_module(Module, Exports, Evacuable)
+    ).
+compile_declaration(module(Module, Exports), Evacuable) :-
+    ( atom(Module) ->
+      '$declare_module'(Module, Exports, Evacuable)
+    ;
+      type_error(atom, Module, load/1)
+    ).
+compile_declaration(dynamic(Name/Arity), Evacuable) :-
+    must_be(atom, Name),
+    must_be(integer, Arity),
+    '$add_dynamic_predicate'(Name, Arity, Evacuable).
+compile_declaration(initialization(Goal), Evacuable) :-
+    prolog_load_context(module, Module),
+    '$compile_pending_predicates'(Evacuable),
+    expand_goal(call(Goal), Module, call(ExpandedGoal)),
+    call(ExpandedGoal).
+
+
+compile_clause(Clause, Evacuable, VNs) :-
+    '$clause_to_evacuable'(Clause, Evacuable, VNs).
+
+
+prolog_load_context(source, Source) :-
+    %% The absolute path name of the file being compiled. During
+    %% loading of a PO file, the corresponding source file name is
+    %% returned.
+    '$prolog_lc_source'(Source).
+prolog_load_context(file, File) :-
+    %% Outside included files (see Include Declarations) this is the
+    %% same as the source key. In included files this is the absolute
+    %% path name of the file being included.
+    '$prolog_lc_file'(File).
+prolog_load_context(directory, Dir) :-
+    %% The absolute path name of the directory of the file being
+    %% compiled/loaded. In included files this is the directory of the
+    %% file being included.
+    '$prolog_lc_dir'(Dir).
+prolog_load_context(module, Module) :-
+    %% The source module (see ref-mod-mne). This is useful for example
+    %% if you are defining clauses for user:term_expansion/6 and need
+    %% to access the source module at compile time.
+    '$prolog_lc_module'(Module).
+prolog_load_context(stream, Stream) :-
+    %% The stream being compiled or loaded from.
+    '$prolog_lc_stream'(Stream).
+prolog_load_context(term_position, TermPosition) :-
+    %% TermPosition represents the stream position of the last term read.
+    '$prolog_lc_stream'(Stream),
+    stream_property(Stream, position(TermPosition)).
+
+
+consult(Item) :-
+    (  atom(Item) -> use_module(Item)
+    ;  type_error(atom, Item, consult/1)
+    ).
+
+
+use_module(Module) :-
+    '$push_load_state_payload'(Evacuable),
+    use_module(Module, [], Evacuable).
+
+use_module(Module, Exports) :-
+    '$push_load_state_payload'(Evacuable),
+    (  Exports == [] ->
+       '$remove_module_exports'(Module, Evacuable)
+    ;
+       use_module(Module, Exports, Evacuable)
+    ).
+
+
+%% If use_module is invoked in an existing load context, use its
+%% directory. Otherwise, use the relative path of Path.
+load_context_path(Module, Path) :-
+    (  prolog_load_context(directory, CurrentDir) ->
+       atom_concat(CurrentDir, Path, Module)
+    ;
+       Module = Path
+    ).
+
+use_module(Module, Exports, Evacuable) :-
+    (  var(Module) ->
+       instantiation_error(load/1)
+    ;  Module = library(Library) ->
+       (  atom(Library) ->
+          (  '$load_compiled_library'(Library, Evacuable) -> %% TODO: What about Exports?
+             true
+          ;
+             '$load_library_as_stream'(Library, Stream, Path),
+             file_load(Stream, Path, Subevacuable),
+             '$use_module'(Evacuable, Subevacuable, Exports)
+          )
+       ;  var(Library) ->
+          instantiation_error(load/1)
+       ;
+          type_error(atom, Library, load/1)
+       )
+    ;  atom(Module) ->
+       load_context_path(Module, Path),
+       open(Path, read, Stream),
+       file_load(Stream, Path, Subevacuable),
+       '$use_module'(Evacuable, Subevacuable, Exports)
+    ;
+       type_error(atom, Library, load/1)
+    ).
+
+
+
+check_predicate_property(meta_predicate, Name, Arity, MetaPredicateTerm) :-
+    must_be(atom, Name),
+    must_be(integer, Arity),
+    '$cpp_meta_predicate_property'(Name, Arity, MetaPredicateTerm).
+
+
+predicate_property(Callable, Property) :-
+    (  var(Callable) ->
+       instantiation_error(load/1)
+    ;  functor(Callable, Name, Arity),
+       (  var(Property) ->
+          true
+       ;  functor(Property, PropertyType, _)
+       ),
+       check_predicate_property(PropertyType, Name, Arity, Property)
+    ).
+
+
+strip_module_(M0, G0, M1, G1) :-
+    (  nonvar(G0),
+       G0 = (MG1:G2) ->
+       strip_module_(MG1, G2, M1, G1)
+    ;  M0 = M1,
+       G0 = G1
+    ).
+
+strip_module(Goal, M, G) :-
+    strip_module_(_, Goal, M, G).
+
+
+
+expand_subgoal(UnexpandedGoals, MS, Module, ExpandedGoals, HeadVars) :-
+    (  var(UnexpandedGoals) ->
+       UnexpandedGoals = ExpandedGoals
+    ;  user:goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
+       (  Module \== user ->
+          user:goal_expansion(UnexpandedGoals1, user, Goals)
+       ;  Goals = UnexpandedGoals1
+       ),
+       (  inner_meta_specs(MS, Goals, _, MetaSpecs) ->
+          expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars)
+       ;  Goals = ExpandedGoals
+       )
+    ;  UnexpandedGoals = ExpandedGoals
+    ).
+
+
+expand_module_name(ESG0, M, ESG) :-
+    (  var(ESG0) ->
+       ESG = M:ESG0
+    ;  ESG0 = _:ESG1 ->
+       ESG = ESG0
+    ;  ESG = M:ESG0
+    ).
+
+
+expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars) :-
+    (  (  MS == (:)
+       ;  integer(MS),
+          MS >= 0
+       )  ->
+       (  var(SG),
+          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_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars)
+    ;  ESG = SG,
+       expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars)
+    ).
+
+expand_meta_predicate_subgoals([], _, _, [], _).
+
+
+expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
+    Goals =.. [GoalFunctor | SubGoals],
+    (  GoalFunctor == (:) ->
+       false
+    ;  expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars),
+       ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
+    ).
+
+
+expand_goal(UnexpandedGoals, Module, ExpandedGoals) :-
+    expand_goal(UnexpandedGoals, Module, ExpandedGoals, []),
+    !.
+
+expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :-
+    (  var(UnexpandedGoals) ->
+       UnexpandedGoals = ExpandedGoals
+    ;  user:goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
+       (  Module \== user ->
+          user:goal_expansion(UnexpandedGoals1, user, Goals)
+       ;  Goals = UnexpandedGoals1
+       ),
+       (  Goals = (Goal0, Goals0) ->
+          (  expand_goal(Goal0, Module, Goal1, HeadVars) ->
+             expand_goal(Goals0, Module, Goals1, HeadVars),
+             thread_goals(Goal1, ExpandedGoals, Goals1, (','))
+          ;  expand_goal(Goals0, Module, Goals1, HeadVars),
+             ExpandedGoals = (Goal0, Goals1)
+          )
+       ;  Goals = (Goals0 -> Goals1) ->
+          expand_goal(Goals0, Module, ExpandedGoals0, HeadVars),
+          expand_goal(Goals1, Module, ExpandedGoals1, HeadVars),
+          ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1)
+       ;  Goals = (Goals0 ; Goals1) ->
+          expand_goal(Goals0, Module, ExpandedGoals0, HeadVars),
+          expand_goal(Goals1, Module, ExpandedGoals1, HeadVars),
+          ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
+       ;  Goals = (\+ Goals0) ->
+          expand_goal(Goals0, Module, Goals1, HeadVars),
+          ExpandedGoals = (\+ Goals1)
+       ;  predicate_property(Goals, meta_predicate(MetaSpecs)) ->
+          expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars)
+       ;  thread_goals(Goals, ExpandedGoals, (','))
+       ;  Goals = ExpandedGoals
+       )
+    ).
+
+thread_goals(Goals0, Goals1, Functor) :-
+    (  var(Goals0) ->
+       Goals0 = Goals1
+    ;  (  Goals0 = [G | Gs] ->
+          (  Gs = [] ->
+             Goals1 = G
+          ;  Goals1 =.. [Functor, G, Goals2],
+             thread_goals(Gs, Goals2, Functor)
+          )
+       ;  Goals1 = Goals0
+       )
+    ).
+
+thread_goals(Goals0, Goals1, Hole, Functor) :-
+    (  var(Goals0) ->
+       Goals0 = Goals1
+    ;  (  Goals0 = [G | Gs] ->
+          (  Gs == [] ->
+             Goals1 =.. [Functor, G, Hole]
+          ;  Goals1 =.. [Functor, G, Goals2],
+             thread_goals(Gs, Goals2, Hole, Functor)
+          )
+       ;  Goals1 =.. [Functor, Goals0, Hole]
+       )
+    ).
index 8756eb3ce6a9fa1be440c233b92a2f30e8ff1cff..386ff10128d7fbf205a2689221974c2fdde77522 100644 (file)
@@ -13,10 +13,16 @@ iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]
     iterate(VarBindings, ValueBindings, ListsCubed).
 iterate([], [], []).
 
+/*
 gather_modules(Attrs, []) :- var(Attrs), !.
 gather_modules([Attr|Attrs], [Module|Modules]) :-
     '$module_of'(Module, Attr),  % write the owning module of Attr to Module.
     gather_modules(Attrs, Modules).
+*/
+
+gather_modules(Attrs, []) :- var(Attrs), !.
+gather_modules([Module:_|Attrs], [Module|Modules]) :-
+    gather_modules(Attrs, Modules).
 
 call_verify_attributes(Attrs, _, _, []) :-
     var(Attrs), !.
@@ -24,14 +30,23 @@ call_verify_attributes([], _, _, []).
 call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
     gather_modules([Attr|Attrs], Modules0),
     sort(Modules0, Modules),
+    verify_attrs(Modules, Var, Value, ListOfGoalLists). % verify_attrs(Modules, Var, Value, ListOfGoalLists).
+
+verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
+    catch(Module:verify_attributes(Var, Value, Goals),
+          error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
+          Goals = []),
     verify_attrs(Modules, Var, Value, ListOfGoalLists).
+verify_attrs([], _, _, []).
 
+/*
 verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
     catch(Module:verify_attributes(Var, Value, Goals),
           error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
           Goals = []),
     verify_attrs(Modules, Var, Value, ListOfGoalLists).
 verify_attrs([], _, _, []).
+*/
 
 call_goals([ListOfGoalLists | ListsCubed]) :-
     call_goals_0(ListOfGoalLists),
index c7b198d55035e96bac2e99e1081fa017bb9f02e5..790114fc2ee72616f43ef179e8efffee7ae66df8 100644 (file)
@@ -6,9 +6,6 @@ use crate::indexmap::IndexSet;
 use std::cmp::Ordering;
 use std::vec::IntoIter;
 
-pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
-pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl");
-
 pub(super) type Bindings = Vec<(usize, Addr)>;
 
 #[derive(Debug)]
@@ -126,7 +123,7 @@ impl MachineState {
         self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
 
         for i in 1 .. self.num_of_args + 1 {
-            self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone();
+            self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
         }
 
         self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
index b9045c729e3cc5fc15456226aa2f17e636efcacc..092f6407e80672c2799297786b064c1f9da61b14 100644 (file)
 use crate::clause_types::*;
-use crate::codegen::*;
-use crate::debray_allocator::*;
-use crate::forms::*;
 use crate::instructions::*;
-use crate::machine::compile::*;
-use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 
-use crate::indexmap::IndexSet;
-
-use std::collections::VecDeque;
-use std::mem;
-
 #[derive(Debug)]
 pub struct CodeRepo {
-    pub(super) cached_query: Code,
-    pub(super) goal_expanders: Code,
-    pub(super) term_expanders: Code,
     pub(super) code: Code,
-    pub(super) in_situ_code: Code,
-    pub(super) term_dir: TermDir,
 }
 
 impl CodeRepo {
     #[inline]
-    pub(super) fn new() -> Self {
+    pub(super)
+    fn new() -> Self {
         CodeRepo {
-            cached_query: vec![],
-            goal_expanders: Code::new(),
-            term_expanders: Code::new(),
             code: Code::new(),
-            in_situ_code: Code::new(),
-            term_dir: TermDir::new(),
         }
     }
 
     #[inline]
-    pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) {
-        self.term_dir
-            .get(&key)
-            .map(|entry| ((entry.0).0.len(), entry.1.len()))
-            .unwrap_or((0, 0))
-    }
-
-    #[inline]
-    pub fn truncate_terms(
-        &mut self,
-        key: PredicateKey,
-        len: usize,
-        queue_len: usize,
-    ) -> (Predicate, VecDeque<TopLevel>) {
-        self.term_dir
-            .get_mut(&key)
-            .map(|entry| {
-                let terms =
-                    if len < (entry.0).0.len() {
-                        (entry.0).0.drain(len ..).collect()
-                    } else {
-                        vec![]
-                    };
-
-                let queue =
-                    if queue_len < entry.1.len() {
-                        entry.1.drain(queue_len ..).collect()
-                    } else {
-                        VecDeque::new()
-                    };
-
-                (Predicate(terms), queue)
-            })
-            .unwrap_or((Predicate::new(), VecDeque::new()))
-    }
-
-    pub(crate)
-    fn add_in_situ_result(
-        &mut self,
-        result: &CompiledResult,
-        in_situ_code_dir: &mut InSituCodeDir,
-        in_situ_module_dir: &mut ModuleStubDir,
-        non_counted_bt_preds: &IndexSet<PredicateKey>,
-    ) -> Result<(), SessionError> {
-        let (ref decl, ref queue) = result;
-        let (name, arity) = decl
-            .0
-            .first()
-            .and_then(|cl| {
-                let arity = cl.arity();
-                cl.name().map(|name| (name, arity))
-            })
-            .ok_or(SessionError::NamelessEntry)?;
-
-        let non_counted_bt = non_counted_bt_preds.contains(&(name.clone(), arity));
-        let module_name = name.owning_module();
-
-        let p = self.in_situ_code.len();
-
-        match in_situ_module_dir.get_mut(&module_name) {
-            Some(ref mut module_stub) if name.has_table(&module_stub.atom_tbl) => {
-                module_stub.in_situ_code_dir.insert((name, arity), p);
+    pub(super)
+    fn lookup_local_instr<'a>(
+        &'a self,
+        p: LocalCodePtr,
+    ) -> RefOrOwned<'a, Line> {
+        match p {
+            LocalCodePtr::Halt => {
+                unreachable!()
             }
-            _ => {
-                in_situ_code_dir.insert((name, arity), p);
+            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]))
+                            }
+                            _ => {
+                                unreachable!()
+                            }
+                        }
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
             }
         }
-
-        let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt);
-        let mut decl_code = cg.compile_predicate(&decl.0)?;
-
-        compile_appendix(&mut decl_code, queue, non_counted_bt)?;
-
-        Ok(self.in_situ_code.extend(decl_code.into_iter()))
-    }
-
-    #[inline]
-    pub(super)
-    fn size_of_cached_query(&self) -> usize {
-        self.cached_query.len()
-    }
-
-    #[inline]
-    pub(super)
-    fn take_in_situ_code(&mut self) -> Code {
-        mem::replace(&mut self.in_situ_code, Code::new())
     }
 
     pub(super)
@@ -131,32 +56,12 @@ impl CodeRepo {
         p: &CodePtr,
     ) -> Option<RefOrOwned<'a, Line>> {
         match p {
-            &CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) => {
-                if p < self.goal_expanders.len() {
-                    Some(RefOrOwned::Borrowed(&self.goal_expanders[p]))
-                } else {
-                    None
-                }
+            &CodePtr::Local(local) => {
+                return Some(self.lookup_local_instr(local));
             }
-            &CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) => {
-                if p < self.term_expanders.len() {
-                    Some(RefOrOwned::Borrowed(&self.term_expanders[p]))
-                } else {
-                    None
-                }
+            &CodePtr::REPL(..) => {
+                None
             }
-            &CodePtr::Local(LocalCodePtr::TopLevel(_, p)) => {
-                if p < self.cached_query.len() {
-                    Some(RefOrOwned::Borrowed(&self.cached_query[p]))
-                } else {
-                    None
-                }
-            }
-            &CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) => {
-                Some(RefOrOwned::Borrowed(&self.in_situ_code[p]))
-            }
-            &CodePtr::Local(LocalCodePtr::DirEntry(p)) => Some(RefOrOwned::Borrowed(&self.code[p])),
-            &CodePtr::REPL(..) => None,
             &CodePtr::BuiltInClause(ref built_in, _) => {
                 let call_clause = call_clause!(
                     ClauseType::BuiltIn(built_in.clone()),
@@ -164,14 +69,27 @@ impl CodeRepo {
                     0,
                     last_call
                 );
+
                 Some(RefOrOwned::Owned(call_clause))
             }
             &CodePtr::CallN(arity, _, last_call) => {
-                let call_clause = call_clause!(ClauseType::CallN, arity, 0, 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])),
-            &CodePtr::DynamicTransaction(..) => None,
+            &CodePtr::VerifyAttrInterrupt(p) => {
+                Some(RefOrOwned::Borrowed(&self.code[p]))
+            }
+/*
+            &CodePtr::DynamicTransaction(..) => {
+                None
+            }
+*/
         }
     }
 }
index 152395c510377d050daf5f5474b05367b0268f22..94944889c23d3fc3d6526049676bcfc558648f35 100644 (file)
@@ -1,73 +1,39 @@
 use crate::instructions::*;
 
-use std::collections::VecDeque;
+use indexmap::IndexSet;
 
-fn scan_for_trust_me(
-    code: &Code,
-    jmp_offsets: &mut VecDeque<usize>,
-    before_idx: usize,
-    after_idx: &mut usize,
-) {
-    // record the location of the line after the TrustMe capping the
-    // choice instruction sequence to after_idx.
-    loop {
-        match &code[*after_idx] {
-            &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) |
-            &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) |
-            &Line::IndexedChoice(IndexedChoiceInstruction::Retry(offset)) => {
-                *after_idx += offset;
-            }
-            &Line::Choice(ChoiceInstruction::DefaultTrustMe) |
-            &Line::Choice(ChoiceInstruction::TrustMe) |
-            &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => {
-                break;
-            }
-            _ => {
-                *after_idx += 1;
-            }
+fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
+    match line {
+        &Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => {
+            stack.push(index + offset);
         }
-    }
-
-    // search the code in the range for JmpBy instructions and record their
-    // offsets for future scanning.
-    for (idx, instr) in code[before_idx .. *after_idx].iter().enumerate() {
-        match instr {
-            &Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
-                jmp_offsets.push_back(before_idx + idx + offset)
-            }
-            _ => {
+        &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) |
+        &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) if offset > 0 => {
+            stack.push(index + offset);
+        }
+        &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
+            stack.push(index + offset);
+        }
+        &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
+            stack.push(index + offset);
+            return true;
+        }
+        &Line::Control(ControlInstruction::Proceed) |
+        &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
+            return true;
+        }
+        &Line::Control(ControlInstruction::RevJmpBy(offset)) => {
+            if offset > 0 {
+                stack.push(index - offset);
+            } else {
+                return true;
             }
         }
-    }
-
-    *after_idx += 1;
-}
-
-fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) {
-    loop {
-        match &code[*last_idx] {
-            &Line::Choice(ChoiceInstruction::TryMeElse(offset)) |
-            &Line::IndexedChoice(IndexedChoiceInstruction::Try(offset)) => {
-                let before_idx = *last_idx;
-                *last_idx += offset;
+        _ => {
+        }
+    };
 
-                scan_for_trust_me(code, queue, before_idx, last_idx);
-            }
-            &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
-                queue.push_back(*last_idx + offset);
-                *last_idx += 1;
-            }
-            &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
-                queue.push_back(*last_idx + offset);
-                break;
-            }
-            &Line::Control(ControlInstruction::Proceed) |
-            &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) =>
-                break,
-            _ =>
-                *last_idx += 1,
-        };
-    }
+    false
 }
 
 /* This function walks the code of a single predicate, supposed to
@@ -76,15 +42,22 @@ fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut u
  */
 pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
 {
-    let mut queue = VecDeque::from(vec![p]);
+    let mut stack = vec![p];
+    let mut visited_indices = IndexSet::new();
 
-    while let Some(first_idx) = queue.pop_front() {
-        let mut last_idx = first_idx;
-
-        capture_next_range(code, &mut queue, &mut last_idx);
+    while let Some(first_index) = stack.pop() {
+        if visited_indices.contains(&first_index) {
+            continue;
+        } else {
+            visited_indices.insert(first_index);
+        }
 
-        for instr in &code[first_idx .. last_idx + 1] {
+        for (index, instr) in code[first_index ..].iter().enumerate() {
             walker(instr);
+
+            if capture_offset(instr, first_index + index, &mut stack) {
+                break;
+            }
         }
     }
 }
@@ -92,6 +65,7 @@ pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
 /* A function for code walking that might result in modification to
  * the code. Otherwise identical to walk_code.
  */
+/*
 pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
 {
     let mut queue = VecDeque::from(vec![p]);
@@ -106,3 +80,4 @@ pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line
         }
     }
 }
+*/
index 36544ebab9e605ef0c87e54a5ba8916001e41b6c..7b3fb49f176f7fb2ad0d746ce9d102245a478dcd 100644 (file)
-use crate::prolog_parser::ast::*;
-use crate::prolog_parser::parser::get_desc;
-use crate::prolog_parser::tabled_rc::TabledData;
-
 use crate::codegen::*;
 use crate::debray_allocator::*;
-use crate::forms::*;
-use crate::instructions::*;
-use crate::iterators::*;
-use crate::machine::code_walker::*;
-use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::*;
-use crate::machine::term_expansion::ExpansionAdditionResult;
-use crate::machine::toplevel::*;
+use crate::indexing::{merge_clause_index, remove_index};
+use crate::machine::load_state::set_code_index;
+use crate::machine::loader::*;
+use crate::machine::load_state::LoadState;
 use crate::machine::*;
+use crate::machine::term_stream::*;
 
-use crate::indexmap::{IndexMap, IndexSet};
-
-use crate::ref_thread_local::RefThreadLocal;
+use slice_deque::sdeq;
 
 use std::cell::Cell;
 use std::collections::VecDeque;
-use std::fs::File;
-use std::mem;
-use std::path::PathBuf;
-
-#[allow(dead_code)]
-pub fn print_code(code: &Code) {
-    for clause in code {
-        match clause {
-            &Line::Arithmetic(ref arith) => println!("{}", arith),
-            &Line::Fact(ref fact_instr) => println!("{}", fact_instr),
-            &Line::Cut(ref cut) => println!("{}", cut),
-            &Line::Choice(ref choice) => println!("{}", choice),
-            &Line::Control(ref control) => println!("{}", control),
-            &Line::IndexedChoice(ref choice) => println!("{}", choice),
-            &Line::Indexing(ref indexing) => println!("{}", indexing),
-            &Line::Query(ref query_instr) => println!("{}", query_instr),
-        }
-    }
-}
-
-fn fix_filename(
-    atom_tbl: TabledData<Atom>,
-    mut path: PathBuf,
-) -> Result<PathBuf, SessionError>
-{
-    if !path.is_file() {
-        if path.extension().is_none() {
-            path.set_extension("pl");
-        }
-
-        if !path.is_file() {
-            let filename = clause_name!(path.to_string_lossy().to_string(), atom_tbl);
-            return Err(SessionError::InvalidFileName(filename));
-        }
-    }
-
-    Ok(path)
-}
-
-fn load_module(
-    wam: &mut Machine,
-    stream: Stream,
-    suppress_warnings: bool,
-    listing_src: &ListingSource,
-) -> Result<ClauseName, SessionError> {
-    // follow the operation of compile_user_module, but before
-    // compiling, check that a module is declared in the file. if not,
-    // throw an exception.
-    let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
-    setup_indices(wam, clause_name!("builtins"), &mut indices)?;
-
-    let mut compiler = ListingCompiler::new(
-        &wam.code_repo,
-        suppress_warnings,
-        listing_src.clone(),
-    );
-
-    let mut stream = parsing_stream(stream)?;
-
-    let results = compiler.gather_items(
-        wam,
-        &mut stream,
-        &mut indices,
-    );
-
-    let module_name = if let Some(ref module) = &compiler.module {
-        module.module_decl.name.clone()
-    } else {
-        // this impromptu definition (namely, its exports) will be filled out later.
-        let module_decl = ModuleDecl { name: listing_src.name(), exports: vec![] };
-
-        let mut module  = Module::new(module_decl, wam.indices.atom_tbl.clone(), listing_src.clone());
-        let module_name = module.module_decl.name.clone();
-
-        module.is_impromptu_module = true;
+use std::ops::Range;
 
-        compiler.module = Some(module);
-        module_name
-    };
-
-    results.and_then(|results| compile_work_impl(&mut compiler, wam, indices, results))
-           .or_else(|e| {
-               wam.indices.take_module(module_name.clone());
-               compiler.print_error(&e);
-               Err(e)
-           })?;
-
-    Ok(module_name)
+struct StandaloneCompileResult {
+    clause_code: Code,
+    standalone_skeleton: PredicateSkeleton,
 }
 
 pub(super)
-fn load_module_from_file(
+fn bootstrapping_compile(
+    stream: Stream,
     wam: &mut Machine,
-    path_buf: PathBuf,
-    suppress_warnings: bool,
-) -> Result<ClauseName, SessionError> {
-    let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
-    let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
-
-    let file_handle = Stream::from_file_as_input(filename.clone(), File::open(&path_buf).or_else(|_| {
-        Err(SessionError::InvalidFileName(filename.clone()))
-    })?);
+    listing_src: ListingSource,
+) -> Result<(), SessionError> {
+    let stream = &mut parsing_stream(stream)?;
+    let term_stream =
+        BootstrappingTermStream::from_prolog_stream(
+            stream,
+            wam.machine_st.atom_tbl.clone(),
+            wam.machine_st.flags,
+            listing_src,
+        );
 
-    path_buf.pop();
+    let loader = Loader::new(term_stream, wam);
+    loader.load()?;
 
-    let listing_src = ListingSource::from_file_and_path(filename, path_buf);
-    load_module(wam, file_handle, suppress_warnings, &listing_src)
+    Ok(())
 }
 
-pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
-
 // throw errors if declaration or query found.
+pub(super)
 fn compile_relation(
     cg: &mut CodeGenerator<DebrayAllocator>,
     tl: &TopLevel
-) -> Result<Code, ParserError> {
+) -> Result<Code, CompilationError> {
     match tl {
-        &TopLevel::Declaration(_) | &TopLevel::Query(_) => Err(ParserError::ExpectedRel),
-        &TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses.0),
-        &TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)),
-        &TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
+        &TopLevel::Declaration(_) | &TopLevel::Query(_) =>
+            Err(CompilationError::ExpectedRel),
+        &TopLevel::Predicate(ref clauses) =>
+            cg.compile_predicate(&clauses),
+        &TopLevel::Fact(ref fact, ..) =>
+            Ok(cg.compile_fact(fact)),
+        &TopLevel::Rule(ref rule, ..) =>
+            cg.compile_rule(rule),
     }
 }
 
-fn issue_singleton_warnings(
-    src_name: ClauseName,
-    terms_and_locs: Vec<(Term, usize, usize)>,
-) {
-    for (term, line_num, _col_num) in terms_and_locs {
-        let mut singletons = vec![];
-        let mut var_count = IndexMap::new();
-
-        for subterm in breadth_first_iter(&term, true) {
-            if let TermRef::Var(_, _, var) = subterm {
-                let entry = var_count.entry(var).or_insert(0);
-                *entry += 1;
-            }
-        }
+pub(super)
+fn compile_appendix(
+    code: &mut Code,
+    queue: &VecDeque<TopLevel>,
+    jmp_by_locs: Vec<usize>,
+    non_counted_bt: bool,
+    atom_tbl: TabledData<Atom>,
+) -> Result<(), CompilationError> {
+    let mut jmp_by_locs = VecDeque::from(jmp_by_locs);
+
+    for tl in queue.iter() {
+        let code_len = code.len();
+        let jmp_by_offset = jmp_by_locs.pop_front().unwrap();
 
-        for (var, count) in var_count {
-            if count == 1 && !var.starts_with("_") && var.as_str() != "!" {
-                singletons.push(var);
+        match &mut code[jmp_by_offset] {
+            &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => {
+                *offset = code_len - jmp_by_offset;
+            }
+            _ => {
+                unreachable!()
             }
         }
 
-        if let Some(last_var) = singletons.pop() {
-            print!("Warning: {}:{}: Singleton variables: [",
-                   src_name, line_num);
+        // false because the inner predicate is a one-off, hence not extensible.
+        let settings = CodeGenSettings::new(false, non_counted_bt);
 
-            for var in singletons {
-                print!("{}, ", var);
-            }
+        let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
+        let decl_code = compile_relation(&mut cg, tl)?;
 
-            println!("{}]", last_var);
-        }
+        jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len()));
+        code.extend(decl_code.into_iter());
     }
+
+    Ok(())
 }
 
-// set first jmp_by_call or jmp_by_index instruction to code.len() -
-// idx, where idx is the place it occurs. It only does this to the
-// *first* uninitialized jmp index it encounters, then returns.
-fn set_first_index(code: &mut Code) {
-    let code_len = code.len();
-
-    for (idx, line) in code.iter_mut().enumerate() {
-        match line {
-            &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..))
-                if *offset == 0 =>
-            {
-                *offset = code_len - idx;
-                debug_assert!(*offset > 0);
-
-                break;
-            }
-            _ => {}
-        };
+fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize {
+    if target_pos == 0 {
+        return 0;
     }
-}
 
-pub fn compile_appendix(
-    code: &mut Code,
-    queue: &VecDeque<TopLevel>,
-    non_counted_bt: bool,
-) -> Result<(), ParserError> {
-    for tl in queue.iter() {
-        set_first_index(code);
-        let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt);
-        let decl_code = compile_relation(&mut cg, tl)?;
-        code.extend(decl_code.into_iter());
+    let arg_num = skeleton.clauses[target_pos - 1].opt_arg_index_key.arg_num();
+
+    if arg_num == 0 {
+        return target_pos - 1;
     }
 
-    Ok(())
+    for index in (0 .. target_pos - 1).rev() {
+        let current_arg_num = skeleton.clauses[index].opt_arg_index_key.arg_num();
+
+        if current_arg_num == 0 || current_arg_num != arg_num {
+            return index + 1;
+        }
+    }
+
+    0
 }
 
-fn append_trivial_goal(name: &ClauseName, pred: &mut Predicate)
-{
-    let var = Box::new(Term::Var(Cell::default(), Rc::new(String::from("X"))));
-    let body = QueryTerm::Clause(
-        Cell::default(),
-        ClauseType::from(clause_name!("$at_end_of_expansion"), 0, None),
-        vec![],
-        false
-    );
+fn compile_standalone_clause(
+    clause: PredicateClause,
+    queue: VecDeque<TopLevel>,
+    settings: CodeGenSettings,
+    atom_tbl: TabledData<Atom>,
+) -> Result<StandaloneCompileResult, SessionError> {
+    let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
+    let mut clause_code = cg.compile_predicate(&vec![clause])?;
+
+    compile_appendix(
+        &mut clause_code,
+        &queue,
+        cg.jmp_by_locs,
+        settings.non_counted_bt,
+        atom_tbl,
+    )?;
+
+    Ok(StandaloneCompileResult {
+        clause_code,
+        standalone_skeleton: cg.skeleton,
+    })
+}
 
-    let rule = Rule {
-        head: (name.clone(), vec![var.clone(), var], body),
-        clauses: vec![]
-    };
+fn derelictize_try_me_else(
+    code: &mut Code,
+    index: usize,
+    retraction_info: &mut RetractionInfo,
+) -> Option<usize> {
+    match &mut code[index] {
+        Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+            None
+        }
+        Line::Choice(ChoiceInstruction::TryMeElse(ref mut offset)) => {
+            retraction_info.push_record(
+                RetractionRecord::ModifiedTryMeElse(index, *offset),
+            );
 
-    pred.0.push(PredicateClause::Rule(rule, 0, 0));
+            Some(mem::replace(offset, 0))
+        }
+        _ => {
+            unreachable!()
+        }
+    }
 }
 
-impl CodeRepo {
-    pub fn compile_hook(
-        &mut self,
-        hook: CompileTimeHook,
-    ) -> Result<(), ParserError> {
-        let key = (hook.name(), hook.arity());
+fn merge_indices(
+    code: &mut Code,
+    target_index_loc: usize,
+    index_range: Range<usize>,
+    skeleton: &mut [ClauseIndexInfo],
+    retraction_info: &mut RetractionInfo,
+) {
+    for clause_index in index_range {
+        if let Some(index_loc) = skeleton[clause_index].opt_arg_index_key.switch_on_term_loc() {
+            let clause_loc =
+                find_inner_choice_instr(code, skeleton[clause_index].clause_start, index_loc);
 
-        match self.term_dir.get_mut(&key) {
-            Some(ref mut preds) => {
-                append_trivial_goal(&key.0, &mut preds.0);
+            let target_indexing_line =
+                to_indexing_line_mut(&mut code[target_index_loc]).unwrap();
 
-                let mut cg = CodeGenerator::<DebrayAllocator>::new(false);
-                let mut code = cg.compile_predicate(&(preds.0).0)?;
+            skeleton[clause_index].opt_arg_index_key.set_switch_on_term_loc(target_index_loc);
 
-                compile_appendix(&mut code, &preds.1, false)?;
+            merge_clause_index(
+                target_indexing_line,
+                &mut skeleton[0 .. clause_index + 1],
+                clause_loc,
+                AppendOrPrepend::Append,
+            );
 
-                (preds.0).0.pop();
+            retraction_info.push_record(
+                RetractionRecord::AddedIndex(
+                    skeleton[clause_index].opt_arg_index_key.clone(),
+                    clause_loc,
+                ),
+            );
+        } else {
+            break;
+        }
+    }
+}
 
-                Ok(match hook {
-                    CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
-                        self.term_expanders = code
-                    }
-                    CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
-                        self.goal_expanders = code
-                    }
-                })
+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)) => {
+                if *o > 0 {
+                    return index;
+                } else {
+                    index = index_loc;
+                }
+            }
+            Line::Choice(ChoiceInstruction::TrustMe(_)) => {
+                return index;
             }
-            None => Ok(match hook {
-                CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
-                    if self.term_expanders.is_empty() {
-                        let mut preds = Predicate::new();
-                        append_trivial_goal(&key.0, &mut preds);
-
-                        let mut cg = CodeGenerator::<DebrayAllocator>::new(false);
-                        self.term_expanders = cg.compile_predicate(&preds.0)?;
+            Line::IndexingCode(indexing_code) => {
+                match &indexing_code[0] {
+                    IndexingLine::Indexing(
+                        IndexingInstruction::SwitchOnTerm(_, v, ..)
+                    ) => {
+                        index += v;
                     }
-                }
-                CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
-                    if self.goal_expanders.is_empty() {
-                        let mut preds = Predicate::new();
-                        append_trivial_goal(&key.0, &mut preds);
-
-                        let mut cg = CodeGenerator::<DebrayAllocator>::new(false);
-                        self.goal_expanders = cg.compile_predicate(&preds.0)?;
+                    _ => {
+                        unreachable!();
                     }
                 }
-            })
+            }
+            Line::Control(ControlInstruction::RevJmpBy(offset)) => {
+                index -= offset;
+            }
+            _ => {
+                /* Here we land at the line after a TryMeElse(0),
+                 * which happens iff a single clause belongs to the
+                 * indexed subsequence. So, end the search by pointing
+                 * to the original derelict TryMeElse.
+                 */
+                return index - 1;
+            }
         }
     }
 }
 
-fn compile_query(
-    terms: Vec<QueryTerm>,
-    queue: VecDeque<TopLevel>,
-) -> Result<(Code, AllocVarDict), ParserError> {
-    // count backtracking inferences.
-    let mut cg = CodeGenerator::<DebrayAllocator>::new(false);
-    let mut code = cg.compile_query(&terms)?;
-
-    compile_appendix(&mut code, &queue, false)?;
-    Ok((code, cg.take_vars()))
-}
-
-fn add_hooks_to_mockup(
-    code_repo: &mut CodeRepo,
-    hook: CompileTimeHook,
-    expansions: (Predicate, VecDeque<TopLevel>),
+fn remove_index_from_subsequence(
+    code: &mut Code,
+    opt_arg_index_key: &OptArgIndexKey,
+    clause_start: usize,
+    retraction_info: &mut RetractionInfo,
 ) {
-    let key = (hook.name(), hook.arity());
-    let preds = code_repo
-        .term_dir
-        .entry(key.clone())
-        .or_insert((Predicate::new(), VecDeque::from(vec![])));
-
-    (preds.0).0.extend((expansions.0).0.into_iter());
-    preds.1.extend(expansions.1.into_iter());
-}
+    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);
 
-fn setup_module_expansions(wam: &mut Machine, module: &Module) {
-    let term_expansions = module.term_expansions.clone();
-    let goal_expansions = module.goal_expansions.clone();
+        let target_indexing_line =
+            to_indexing_line_mut(&mut code[index_loc]).unwrap();
 
-    add_hooks_to_mockup(
-        &mut wam.code_repo,
-        CompileTimeHook::TermExpansion,
-        term_expansions,
-    );
+        let offset = clause_start - index_loc + 1;
 
-    add_hooks_to_mockup(
-        &mut wam.code_repo,
-        CompileTimeHook::GoalExpansion,
-        goal_expansions,
-    );
+        remove_index(opt_arg_index_key, target_indexing_line, offset);
+
+        // TODO: this isn't sufficiently precise. The removed offset could
+        // appear anywhere inside an Internal record.
+        retraction_info.push_record(
+            RetractionRecord::RemovedIndex(
+                index_loc,
+                opt_arg_index_key.clone(),
+                offset,
+            ),
+        );
+    }
 }
 
-pub(super)
-fn compile_into_module(
-    wam: &mut Machine,
-    module_name: ClauseName,
-    src: Stream,
-    name: ClauseName,
-) -> EvalSession {
-    let mut indices = default_index_store!(wam.atom_tbl_of(&name));
-    let module = wam.indices.take_module(module_name.clone()).unwrap();
-
-    indices.code_dir = module.code_dir.clone();
-    indices.op_dir   = module.op_dir.clone();
-    indices.atom_tbl = module.atom_tbl.clone();
-
-    let mut compiler = ListingCompiler::new(
-        &wam.code_repo,
-        true,
-        module.listing_src.clone(),
+fn merge_indexed_subsequences(
+    code: &mut Code,
+    skeleton: &mut PredicateSkeleton,
+    lower_upper_bound: usize,
+    upper_lower_bound: usize,
+    retraction_info: &mut RetractionInfo,
+) -> Option<IndexPtr> {
+    // patch the inner-threaded choice instructions to link the
+    // two sequences, patch lower_bound's outer-threaded choice
+    // instruction to TrustMe (or RetryMeElse), and derelict-ize
+    // target_pos + 1's inner TryMeElse.
+
+    let inner_trust_me_loc =
+        skeleton.clauses[upper_lower_bound - 2].clause_start;
+
+    let inner_try_me_else_loc = find_inner_choice_instr(
+        code,
+        skeleton.clauses[upper_lower_bound].clause_start,
+        skeleton.clauses[upper_lower_bound].opt_arg_index_key
+            .switch_on_term_loc().unwrap(),
     );
 
-    match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
-        Ok(()) => {
-            EvalSession::EntrySuccess
+    match &mut code[inner_try_me_else_loc] {
+        Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+            retraction_info.push_record(
+                RetractionRecord::ModifiedTryMeElse(
+                    skeleton.clauses[upper_lower_bound].clause_start,
+                    *o,
+                ),
+            );
+
+            match *o {
+                0 => {
+                    code[inner_try_me_else_loc] =
+                        Line::Choice(ChoiceInstruction::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));
+                        }
+                        _ => {
+                            code[inner_try_me_else_loc] =
+                                Line::Choice(ChoiceInstruction::RetryMeElse(o));
+                        }
+                    }
+                }
+            }
         }
-        Err(e) => {
-            compiler.drop_expansions(&mut wam.code_repo);
-            EvalSession::from(e)
+        _ => {
         }
     }
-}
 
-fn compile_into_module_impl(
-    wam: &mut Machine,
-    compiler: &mut ListingCompiler,
-    module: Module,
-    src: Stream,
-    mut indices: IndexStore,
-) -> Result<(), SessionError> {
-    setup_module_expansions(wam, &module);
+    thread_choice_instr_at_to(
+        code,
+        inner_trust_me_loc,
+        inner_try_me_else_loc,
+        retraction_info,
+    );
 
-    let module_name = module.module_decl.name.clone();
-    // compiler.module = Some(module); This trips the goal expansion up. Should be possible to 'merge' modules.
-    // A much better strategy!
-    wam.indices.insert_module(module);
+    let mut end_of_upper_lower_bound = None;
 
-    wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
-    wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
+    for index in upper_lower_bound .. skeleton.clauses.len() {
+        if !skeleton.clauses[index].opt_arg_index_key.is_some() {
+            end_of_upper_lower_bound = Some(index);
+            break;
+        }
+    }
 
-    let mut results = compiler.gather_items(
-        wam,
-        &mut parsing_stream(src)?,
-        &mut indices,
-    )?;
+    let outer_threaded_choice_instr_loc =
+        skeleton.clauses[lower_upper_bound].clause_start - 2;
 
-    compiler.adapt_in_situ_code(
-        results.worker_results,
-        wam,
-        &mut indices.code_dir,
-        &mut indices.module_dir,
-        &mut results.in_situ_code,
-        &results.in_situ_code_dir,
-        &results.in_situ_module_dir,
-    )?;
+    match end_of_upper_lower_bound {
+        Some(outer_threaded_clause_index) => {
+            thread_choice_instr_at_to(
+                code,
+                outer_threaded_choice_instr_loc,
+                skeleton.clauses[outer_threaded_clause_index].clause_start,
+                retraction_info,
+            );
+        }
+        None => {
+            match &mut code[outer_threaded_choice_instr_loc] {
+                Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+                    retraction_info.push_record(
+                        RetractionRecord::ModifiedTryMeElse(inner_trust_me_loc, *o),
+                    );
 
-    let mut clause_code_generator = ClauseCodeGenerator::new(
-        results.in_situ_code.len(),
-        module_name.clone()
-    );
+                    *o = 0;
 
-    clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
+                    return Some(IndexPtr::Index(outer_threaded_choice_instr_loc + 1));
+                }
+                _ => {
+                }
+            }
+        }
+    }
 
-    let top_level_term_dir = results.top_level_term_dirs.consolidate();
-    let module = wam.indices.take_module(module_name).unwrap();
+    None
+}
 
-    add_module(
-        wam,
-        module,
-        indices,
-        top_level_term_dir,
+fn delete_from_dynamic_skeleton(
+    compilation_target: CompilationTarget,
+    key: PredicateKey,
+    skeleton: &mut PredicateSkeleton,
+    target_pos: usize,
+    retraction_info: &mut RetractionInfo,
+) -> usize {
+    let clause_clause_loc = skeleton.clause_clause_locs.remove(target_pos);
+    let clause_index_info = skeleton.clauses.remove(target_pos);
+
+    retraction_info.push_record(
+        RetractionRecord::RemovedDynamicSkeletonClause(
+            compilation_target,
+            key,
+            target_pos,
+            clause_index_info,
+            clause_clause_loc,
+        ),
     );
 
-    wam.code_repo.code.extend(results.in_situ_code.into_iter());
-    clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
-
-    Ok(compiler.drop_expansions(&mut wam.code_repo))
+    clause_clause_loc
 }
 
-#[derive(Debug)]
-pub struct GatherResult {
-    dynamic_clause_map: DynamicClauseMap,
-    pub(crate) worker_results: Vec<PredicateCompileQueue>,
-    toplevel_results: Vec<PredicateCompileQueue>,
-    toplevel_indices: IndexStore,
-    addition_results: ExpansionAdditionResult,
-    top_level_terms: Vec<(Term, usize, usize)>,
-    top_level_term_dirs: TermDirQuantum,
-    module_term_dirs: TermDirQuantum,
-    in_situ_code_dir: InSituCodeDir,
-    in_situ_code: Code,
-    in_situ_module_dir: ModuleStubDir,
-}
+fn blunt_leading_choice_instr(
+    code: &mut Code,
+    mut instr_loc: usize,
+    retraction_info: &mut RetractionInfo,
+) -> usize {
+    loop {
+        match &mut code[instr_loc] {
+            Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+                retraction_info.push_record(
+                    RetractionRecord::ModifiedRetryMeElse(instr_loc, *o),
+                );
 
-#[derive(Debug)]
-pub struct ClauseCodeGenerator {
-    len_offset: usize,
-    code: Code,
-    module_name: ClauseName,
-    pi_to_loc: IndexMap<PredicateKey, usize>,
-}
+                code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(*o));
+
+                return instr_loc;
+            }
+            Line::Choice(ChoiceInstruction::TrustMe(offset)) => {
+                retraction_info.push_record(
+                    RetractionRecord::AppendedTrustMe(instr_loc, *offset, false),
+                );
 
-impl ClauseCodeGenerator {
-    #[inline]
-    fn new(len_offset: usize, module_name: ClauseName) -> Self {
-        ClauseCodeGenerator {
-            len_offset,
-            code: vec![],
-            module_name,
-            pi_to_loc: IndexMap::new(),
+                code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0));
+                return instr_loc + 1;
+            }
+            Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+                return instr_loc + 1;
+            }
+            Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
+                instr_loc += *o;
+            }
+            Line::Control(ControlInstruction::RevJmpBy(o)) => {
+                instr_loc -= *o;
+            }
+            _ => {
+                unreachable!()
+            }
         }
     }
+}
 
-    // compiles the latest version of clause/2.
-    fn generate_clause_code(
-        &mut self,
-        dynamic_clause_map: &DynamicClauseMap,
-        wam: &Machine,
-    ) -> Result<(), SessionError> {
-        for ((name, arity), heads_and_tails) in dynamic_clause_map {
-            if heads_and_tails.is_empty() {
-                continue;
-            }
+fn set_switch_var_offset_to_choice_instr_(
+    code: &mut Code,
+    index_loc: usize,
+    offset: usize,
+    retraction_info: &mut RetractionInfo,
+) {
+    let target_indexing_line =
+        to_indexing_line_mut(&mut code[index_loc]).unwrap();
 
-            let predicate = Predicate(
-                heads_and_tails
-                    .iter()
-                    .map(|(head, tail)| {
-                        let clause = Term::Clause(
-                            Cell::default(),
-                            clause_name!("clause"),
-                            vec![Box::new(head.clone()), Box::new(tail.clone())],
-                            None,
-                        );
+    let v =
+        match &mut target_indexing_line[0] {
+            IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
+                *v
+            }
+            _ => {
+                unreachable!();
+            }
+        };
 
-                        PredicateClause::Fact(clause, 0, 0)
-                    })
-                    .collect(),
+    match &code[index_loc + v] {
+        Line::Choice(ChoiceInstruction::TryMeElse(_)) => {
+        }
+        _ => {
+            set_switch_var_offset(
+                code,
+                index_loc,
+                offset,
+                retraction_info,
             );
-
-            let p = self.code.len() + wam.code_repo.code.len() + self.len_offset;
-            let mut cg = CodeGenerator::<DebrayAllocator>::new(false);
-
-            let mut decl_code = compile_relation(
-                &mut cg,
-                &TopLevel::Predicate(predicate),
-            )?;
-
-            compile_appendix(&mut decl_code, &VecDeque::new(), false)?;
-
-            self.pi_to_loc.insert((name.clone(), *arity), p);
-            self.code.extend(decl_code.into_iter());
         }
-
-        Ok(())
     }
+}
 
-    fn add_clause_code(self, wam: &mut Machine, dynamic_code_dir: DynamicClauseMap)
-    {
-        wam.code_repo.code.extend(self.code.into_iter());
+#[inline]
+fn set_switch_var_offset(
+    code: &mut Code,
+    index_loc: usize,
+    offset: usize,
+    retraction_info: &mut RetractionInfo,
+) {
+    let target_indexing_line =
+        to_indexing_line_mut(&mut code[index_loc]).unwrap();
 
-        if self.module_name.as_str() == "user" {
-            for ((name, arity), _) in &dynamic_code_dir {
-                wam.indices.code_dir.entry((name.clone(), *arity))
-                   .or_insert(CodeIndex::dynamic_undefined(clause_name!("user")));
+    let old_v =
+        match &mut target_indexing_line[0] {
+            IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => {
+                mem::replace(v, offset)
             }
-        }
+            _ => {
+                unreachable!()
+            }
+        };
 
-        for ((name, arity), _) in dynamic_code_dir {
-            wam.indices.dynamic_code_dir.insert((name.owning_module(), name, arity),
-                                                DynamicPredicateInfo::default());
-        }
+    retraction_info.push_record(
+        RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v),
+    );
+}
 
-        for ((name, arity), p) in self.pi_to_loc {
-            let entry = wam
-                .indices
-                .dynamic_code_dir
-                .entry((name.owning_module(), name, arity))
-                .or_insert(DynamicPredicateInfo::default());
+fn internalize_choice_instr_at(
+    code: &mut Code,
+    instr_loc: usize,
+    retraction_info: &mut RetractionInfo,
+) {
+    match &mut code[instr_loc] {
+        Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+            retraction_info.push_record(
+                RetractionRecord::ModifiedTryMeElse(instr_loc, 0),
+            );
 
-            entry.clauses_subsection_p = p;
+            code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0));
         }
-    }
-}
+        Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
+            let o = *o;
 
-fn insert_or_refresh_term_dir_quantum(
-    term_dir: &TermDir,
-    key: PredicateKey,
-    term_dirs: &mut TermDirQuantum
-) {
-    match term_dir.get(&key) {
-        Some((ref preds, ref queue)) => {
-            let entry = TermDirQuantumEntry::from(preds, queue);
-            term_dirs.insert_or_refresh(key, entry);
+            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));
+                    }
+                _ => {
+                    code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o));
+                }
+            }
         }
-        None => {
-            let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new());
-            term_dirs.insert_or_refresh(key, entry);
+        _ => {
+            unreachable!();
         }
     }
 }
 
-#[derive(Debug)]
-pub struct ListingCompiler {
-    module: Option<Module>,
-    user_term_dir: TermDir,
-    orig_term_expansion_lens: (usize, usize),
-    orig_goal_expansion_lens: (usize, usize),
-    initialization_goals: (Vec<QueryTerm>, VecDeque<TopLevel>),
-    suppress_warnings: bool,
-    listing_src: ListingSource, // a file? a module?
-}
-
-fn add_toplevel(
-    wam: &mut Machine,
-    indices: IndexStore,
-    term_dir: TermDir,
+fn thread_choice_instr_at_to(
+    code: &mut Code,
+    mut instr_loc: usize,
+    target_loc: usize,
+    retraction_info: &mut RetractionInfo,
 ) {
-    wam.add_batched_code_dir(indices.code_dir);
-    wam.add_batched_ops(indices.op_dir);
-    wam.add_in_situ_module_dir(indices.module_dir);
+    loop {
+        match &mut code[instr_loc] {
+            Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) |
+            Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
+                if target_loc >= instr_loc => {
+                    retraction_info.push_record(
+                        RetractionRecord::ReplacedChoiceOffset(instr_loc, *o),
+                    );
 
-    wam.code_repo.term_dir.extend(term_dir.into_iter());
-}
+                    *o = target_loc - instr_loc;
+                    return;
+                }
+            Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) |
+            Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => {
+                instr_loc += *o;
+            }
+            Line::Control(ControlInstruction::RevJmpBy(ref mut o))
+                if instr_loc >= target_loc => {
+                    retraction_info.push_record(
+                        RetractionRecord::ModifiedRevJmpBy(instr_loc, *o),
+                    );
 
-#[inline]
-fn add_module(
-    wam: &mut Machine,
-    mut module: Module,
-    indices: IndexStore,
-    term_dir: TermDir,
-) {
-    module.code_dir.extend(indices.code_dir);
-    module.op_dir.extend(indices.op_dir);
-    module.term_dir.extend(term_dir);
+                    *o = instr_loc - target_loc;
+                    return;
+                }
+            Line::Choice(ChoiceInstruction::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));
 
-    wam.add_in_situ_module_dir(indices.module_dir);
-    wam.add_module(module);
+                    return;
+                }
+            Line::Choice(ChoiceInstruction::TrustMe(o))
+                if *o > 0 => {
+                    instr_loc += *o;
+                }
+            _ => {
+                unreachable!()
+            }
+        }
+    }
 }
 
-fn add_non_module_code(
-    wam: &mut Machine,
-    dynamic_clause_map: DynamicClauseMap,
-    code: Code,
-    indices: IndexStore,
-    term_dir: TermDir,
-) -> Result<(), SessionError> {
-    wam.check_toplevel_code(&indices)?;
+fn remove_non_leading_clause(
+    code: &mut Code,
+    preceding_choice_instr_loc: usize,
+    non_indexed_choice_instr_loc: usize,
+    retraction_info: &mut RetractionInfo,
+) -> Option<IndexPtr> {
+    match &mut code[non_indexed_choice_instr_loc] {
+        Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => {
+            let o = *o;
+
+            thread_choice_instr_at_to(
+                code,
+                preceding_choice_instr_loc,
+                non_indexed_choice_instr_loc + o,
+                retraction_info,
+            );
 
-    let mut clause_code_generator = ClauseCodeGenerator::new(code.len(), clause_name!("user"));
-    clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
+            None
+        }
+        Line::Choice(ChoiceInstruction::TrustMe(_)) => {
+            match &mut code[preceding_choice_instr_loc] {
+                Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+                    retraction_info.push_record(
+                        RetractionRecord::ModifiedRetryMeElse(
+                            preceding_choice_instr_loc,
+                            *o,
+                        ),
+                    );
 
-    add_toplevel(wam, indices, term_dir);
-    wam.code_repo.code.extend(code);
-    clause_code_generator.add_clause_code(wam, dynamic_clause_map);
+                    code[preceding_choice_instr_loc] =
+                        Line::Choice(ChoiceInstruction::TrustMe(0));
 
-    Ok(())
-}
+                    None
+                }
+                Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+                    retraction_info.push_record(
+                        RetractionRecord::ModifiedTryMeElse(
+                            preceding_choice_instr_loc,
+                            *o,
+                        )
+                    );
 
-pub(super)
-fn load_library(
-    wam: &mut Machine,
-    name: ClauseName,
-    suppress_warnings: bool,
-) -> Result<ClauseName, SessionError> {
-    match LIBRARIES.borrow().get(name.as_str()) {
-        Some(code) => {
-            let listing_src = ListingSource::User;
-
-            load_module(
-                wam,
-                Stream::from(*code),
-                suppress_warnings,
-                &listing_src,
-            )
-        }
-        None => {
-            let err = ExistenceError::ModuleSource(ModuleSource::Library(
-                name.clone()
-            ));
+                    *o = 0;
 
-            Err(SessionError::ExistenceError(err))
+                    Some(IndexPtr::Index(preceding_choice_instr_loc + 1))
+                }
+                _ => {
+                    unreachable!();
+                }
+            }
+        }
+        _ => {
+            unreachable!();
         }
     }
 }
 
-impl ListingCompiler {
-    #[inline]
-    pub fn new(
-        code_repo: &CodeRepo,
-        suppress_warnings: bool,
-        listing_src: ListingSource,
-    ) -> Self {
-        ListingCompiler {
-            module: None,
-            user_term_dir: TermDir::new(),
-            orig_term_expansion_lens: code_repo
-                .term_dir_entry_len((clause_name!("term_expansion"), 2)),
-            orig_goal_expansion_lens: code_repo
-                .term_dir_entry_len((clause_name!("goal_expansion"), 2)),
-               initialization_goals: (vec![], VecDeque::from(vec![])),
-            suppress_warnings,
-            listing_src
-        }
-    }
+fn finalize_retract(
+    key: PredicateKey,
+    compilation_target: CompilationTarget,
+    skeleton: &mut PredicateSkeleton,
+    code_index: CodeIndex,
+    target_pos: usize,
+    index_ptr_opt: Option<IndexPtr>,
+    retraction_info: &mut RetractionInfo,
+) -> usize {
+    let clause_clause_loc =
+        delete_from_dynamic_skeleton(
+            compilation_target.clone(),
+            key.clone(),
+            skeleton,
+            target_pos,
+            retraction_info,
+        );
 
-    /* Replace calls to self with a localized index cell, not
-     * available to the global CodeIndex.  This is done to implement
-     * logical update semantics for dynamic database updates.
-     */
-    fn localize_self_calls(&mut self, key: PredicateKey, code: &mut Code, p: usize, target_p: usize)
-    {
-        let (name, arity) = key;
-
-        let self_idx = CodeIndex::default();
-        set_code_index!(self_idx, IndexPtr::Index(target_p), self.get_module_name());
-
-        walk_code_mut(code, p, |instr|
-            match instr {
-                Line::Control(ControlInstruction::CallClause(ref mut ct, ..)) => {
-                    match ct {
-                        ClauseType::Named(ref ct_name, ct_arity, ref mut idx)
-                            if ct_name == &name && arity == *ct_arity =>
-                        {
-                            *idx = self_idx.clone();
-                        }
-                        ClauseType::Op(ref op_name, ref shared_op_desc, ref mut idx)
-                            if op_name == &name && shared_op_desc.arity() == arity =>
-                        {
-                            *idx = self_idx.clone();
-                        }
-                        _ => {}
-                    }
-                }
-                _ => {}
-            },
+    if let Some(index_ptr) = index_ptr_opt {
+        set_code_index(
+            retraction_info,
+            &compilation_target,
+            key,
+            &code_index,
+            index_ptr,
         );
     }
 
-    fn use_module(
-        &mut self,
-        submodule: ClauseName,
-        code_repo: &mut CodeRepo,
-        flags: MachineFlags,
-        wam_indices: &mut IndexStore,
-        indices: &mut IndexStore,
-    ) -> Result<(), SessionError> {
-        let module_name = self.get_module_name();
+    clause_clause_loc
+}
 
-        if let Some(mut submodule) = wam_indices.take_module(submodule) {
-            unwind_protect!(
-                indices.use_module(code_repo, flags, &submodule),
-                wam_indices.insert_module(submodule)
-            );
+fn remove_leading_unindexed_clause(
+    code: &mut Code,
+    non_indexed_choice_instr_loc: usize,
+    retraction_info: &mut RetractionInfo,
+) -> Option<IndexPtr> {
+    match &mut code[non_indexed_choice_instr_loc] {
+        Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+            if *o > 0 {
+                retraction_info.push_record(
+                    RetractionRecord::ModifiedTryMeElse(
+                        non_indexed_choice_instr_loc,
+                        *o,
+                    )
+                );
 
-            if let Some(ref mut module) = &mut self.module {
-                module.remove_module(module_name, &submodule);
-                unwind_protect!(
-                    module.use_module(code_repo, flags, &submodule),
-                    wam_indices.insert_module(submodule)
+                let o = mem::replace(o, 0);
+
+                let index_ptr = blunt_leading_choice_instr(
+                    code,
+                    non_indexed_choice_instr_loc + o,
+                    retraction_info,
                 );
+
+                Some(IndexPtr::Index(index_ptr))
             } else {
-                submodule.inserted_expansions = true;
-                wam_indices.remove_module(clause_name!("user"), &submodule);
+                Some(IndexPtr::DynamicUndefined)
             }
-
-            Ok(wam_indices.insert_module(submodule))
-        } else {
-            let err = ExistenceError::ModuleSource(ModuleSource::File(
-                module_name,
-            ));
-
-            Err(SessionError::ExistenceError(err))
+        }
+        _ => {
+            unreachable!();
         }
     }
+}
 
-    fn use_qualified_module(
-        &mut self,
-        submodule: ClauseName,
-        code_repo: &mut CodeRepo,
-        flags: MachineFlags,
-        exports: &Vec<ModuleExport>,
-        wam_indices: &mut IndexStore,
-        indices: &mut IndexStore,
-    ) -> Result<(), SessionError> {
-        let module_name = self.get_module_name();
+fn prepend_compiled_clause(
+    code: &mut Code,
+    compilation_target: CompilationTarget,
+    key: PredicateKey,
+    mut clause_code: Code,
+    skeleton: &mut PredicateSkeleton,
+    retraction_info: &mut RetractionInfo,
+) -> usize {
+    let clause_loc = code.len();
+    let mut prepend_queue = sdeq![];
+
+    let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num();
+    let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num();
+
+    if skeleton.clauses[0].opt_arg_index_key.switch_on_term_loc().is_some() {
+        match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() {
+            Some(index_loc) if target_arg_num == head_arg_num => {
+                prepend_queue.extend(clause_code.drain(3 ..));
+
+                skeleton.clauses[0].opt_arg_index_key += index_loc - 1;
+                skeleton.clauses[0].clause_start = clause_loc + 2;
+
+                retraction_info.push_record(
+                    RetractionRecord::AddedIndex(
+                        skeleton.clauses[0].opt_arg_index_key.clone(),
+                        skeleton.clauses[0].clause_start,
+                    ),
+                );
 
-        if let Some(mut submodule) = wam_indices.take_module(submodule) {
-            unwind_protect!(
-                indices.use_qualified_module(code_repo, flags, &submodule, exports),
-                wam_indices.insert_module(submodule)
-            );
+                let outer_thread_choice_loc = skeleton.clauses[1].clause_start - 2;
 
-            if let &mut Some(ref mut module) = &mut self.module {
-                module.remove_module(module_name, &submodule);
-                unwind_protect!(
-                    module.use_qualified_module(code_repo, flags, &submodule, exports),
-                    wam_indices.insert_module(submodule)
+                retraction_info.push_record(
+                    RetractionRecord::SkeletonClauseStartReplaced(
+                        compilation_target,
+                        key.clone(),
+                        1,
+                        skeleton.clauses[1].clause_start,
+                    ),
                 );
-            } else {
-                submodule.inserted_expansions = true;
-                wam_indices.remove_module(clause_name!("user"), &submodule);
-            }
 
-            Ok(wam_indices.insert_module(submodule))
-        } else {
-            let err = ExistenceError::ModuleSource(ModuleSource::File(
-                module_name
-            ));
+                skeleton.clauses[1].clause_start =
+                    find_inner_choice_instr(
+                        code,
+                        skeleton.clauses[1].clause_start,
+                        index_loc,
+                    );
 
-            Err(SessionError::ExistenceError(err))
-        }
-    }
+                let inner_thread_rev_offset =
+                    3 + prepend_queue.len() + clause_loc - skeleton.clauses[1].clause_start;
 
-    #[inline]
-    fn get_module_name(&self) -> ClauseName {
-        self.module
-            .as_ref()
-            .map(|module| module.module_decl.name.clone())
-            .unwrap_or(ClauseName::BuiltIn("user"))
-    }
+                prepend_queue.push_back(
+                    Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)),
+                );
 
-    fn generate_init_goal_code(
-           &mut self,
-    ) -> Result<Code, SessionError> {
-           let query_terms = mem::replace(&mut self.initialization_goals.0, vec![]);
-           let queue = mem::replace(&mut self.initialization_goals.1, VecDeque::new());
+                prepend_queue.push_front(
+                    Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())),
+                );
 
-           compile_query(query_terms, queue)
-               .map(|(code, _)| code)
-               .map_err(SessionError::from)
-    }
+                // prepend_queue is now:
+                //      | TryMeElse N_2
+                //      | (clause_code)
+                // +N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1)
 
-    fn set_code_index(
-        &mut self,
-        wam: &Machine,
-        key: PredicateKey,
-        in_situ_code: &mut Code,
-        code_dir: &mut CodeDir,
-        in_situ_code_dir: &InSituCodeDir,
-        decl: PredicateCompileQueue,
-    ) -> Result<(), SessionError> {
-        let p = wam.code_repo.code.len();
+                prepend_queue.push_front(
+                    Line::Control(ControlInstruction::RevJmpBy(
+                        1 + clause_loc - index_loc
+                    )),
+                );
 
-        let idx = code_dir
-            .entry(key.clone())
-            .or_insert(CodeIndex::default());
+                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) {
+                        Some(next_subseq_offset) => {
+                            // skeleton.clauses[1] has a non-stub TryMeElse.
 
-        Ok(match in_situ_code_dir.get(&key) {
-            Some(in_situ_p) => {
-                set_code_index!(idx, IndexPtr::Index(p + *in_situ_p), self.get_module_name());
-                self.localize_self_calls(key, in_situ_code, *in_situ_p, p + *in_situ_p);
-            }
-            None => {
-                let (decl, queue) = decl;
+                            let outer_thread_rev_offset =
+                                prepend_queue.len() + 1 + clause_loc - outer_thread_choice_loc -
+                                next_subseq_offset;
 
-                let mut cg = CodeGenerator::<DebrayAllocator>::new(false);
-                let mut decl_code = cg.compile_predicate(&decl.0)?;
+                            prepend_queue.push_back(
+                                Line::Control(ControlInstruction::RevJmpBy(outer_thread_rev_offset))
+                            );
 
-                compile_appendix(&mut decl_code, &queue, false)?;
+                            prepend_queue.len()
+                        }
+                        None => {
+                            // This case occurs when the clauses of
+                            // the host predicate, up to and including
+                            // the prepending of this clause, are
+                            // indexed.
+
+                            // The outer TryMeElse / RevJmpBy pushed
+                            // in this case are stub instructions
+                            // awaiting the addition of unindexed
+                            // clauses.
+
+                            prepend_queue.push_back(
+                                Line::Control(ControlInstruction::RevJmpBy(0)),
+                            );
+
+                            0
+                        }
+                    };
+
+                prepend_queue.push_front(
+                    Line::Choice(ChoiceInstruction::TryMeElse(outer_thread_choice_offset)),
+                );
+
+                // prepend_queue is now:
+                //     | TryMeElse N_3
+                //     | RevJmpBy (SwitchOnTerm at index_loc)
+                //     | TryMeElse N_2
+                //     | (clause_code)
+                // 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();
+
+                merge_clause_index(
+                    target_indexing_line,
+                    &mut skeleton.clauses,
+                    clause_loc + 2, // == skeleton.clauses[0].clause_start
+                    AppendOrPrepend::Prepend,
+                );
+
+                set_switch_var_offset(
+                    code,
+                    index_loc,
+                    clause_loc - index_loc + 2,
+                    retraction_info,
+                );
 
-                let in_situ_p = in_situ_code.len();
+                internalize_choice_instr_at(code, skeleton.clauses[1].clause_start, retraction_info);
 
-                in_situ_code.extend(decl_code.into_iter());
+                code.extend(prepend_queue.into_iter());
 
-                set_code_index!(idx, IndexPtr::Index(p + in_situ_p), self.get_module_name());
-                self.localize_self_calls(key, in_situ_code, in_situ_p, p + in_situ_p);
+                clause_loc + (outer_thread_choice_offset == 0) as usize
             }
-        })
-    }
+            _ => {
+                prepend_queue.extend(clause_code.drain(1 ..));
 
-    fn adapt_in_situ_code(
-        &mut self,
-        decls: Vec<PredicateCompileQueue>,
-        wam: &Machine,
-        code_dir: &mut CodeDir,
-        module_dir: &mut ModuleDir,
-        in_situ_code: &mut Code,
-        in_situ_code_dir: &InSituCodeDir,
-        in_situ_module_dir: &ModuleStubDir,
-    ) -> Result<(), SessionError> {
-        for decl in decls {
-            let key = decl.0
-                .predicate_indicator()
-                .ok_or(SessionError::NamelessEntry)?;
-
-            let (name, _arity) = key.clone();
-            let module_name = name.owning_module();
-
-            match in_situ_module_dir.get(&module_name) {
-                Some(ref module_stub) if name.has_table(&module_stub.atom_tbl) => {
-                    let module =
-                        module_dir.entry(module_name.clone())
-                                  .or_insert_with(|| {
-                                      let module_decl = ModuleDecl {
-                                          name: module_name.clone(),
-                                          exports: vec![]
-                                      };
-
-                                      Module::new(
-                                          module_decl,
-                                          module_stub.atom_tbl.clone(),
-                                          self.listing_src.clone(),
-                                      )
-                                  });
-
-                    self.set_code_index(
-                        wam,
-                        key,
-                        in_situ_code,
-                        &mut module.code_dir,
-                        &module_stub.in_situ_code_dir,
-                        decl,
-                    )?;
-                }
-                _ => {
-                    self.set_code_index(
-                        wam,
-                        key,
-                        in_situ_code,
-                        code_dir,
-                        in_situ_code_dir,
-                        decl,
-                    )?;
+                skeleton.clauses[0].opt_arg_index_key += clause_loc;
+                skeleton.clauses[0].clause_start = clause_loc + 2;
+
+                let old_clause_start = skeleton.clauses[1].clause_start;
+
+                let inner_thread_rev_offset =
+                    2 + prepend_queue.len() + clause_loc - old_clause_start;
+
+                // this is a stub for chaining inner-threaded choice
+                // instructions.
+                prepend_queue.push_back(
+                    Line::Control(ControlInstruction::RevJmpBy(0))
+                );
+
+                let prepend_queue_len = prepend_queue.len();
+
+                match &mut prepend_queue[1] {
+                    Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
+                        if *o == 0 => {
+                            *o = prepend_queue_len - 2;
+                        }
+                    _ => {
+                        unreachable!();
+                    }
                 }
-            }
-        }
 
-        Ok(())
-    }
+                prepend_queue.push_back(
+                    Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)),
+                );
 
-    fn add_term_dir_terms(
-        &mut self,
-        hook: CompileTimeHook,
-        code_repo: &mut CodeRepo,
-        key: PredicateKey,
-        clause: PredicateClause,
-        queue: VecDeque<TopLevel>,
-    ) -> (usize, usize) {
-        let preds = code_repo
-            .term_dir
-            .entry(key.clone())
-            .or_insert((Predicate::new(), VecDeque::from(vec![])));
-
-        let (mut len, mut queue_len) = ((preds.0).0.len(), preds.1.len());
-
-        if self.module.is_some() && hook.has_module_scope() {
-            let module_preds = self
-                .user_term_dir
-                .entry(key.clone())
-                .or_insert((Predicate::new(), VecDeque::from(vec![])));
-
-            if let Some(ref mut module) = &mut self.module {
-                module.add_expansion_record(hook, clause.clone(), queue.clone());
-                module.add_local_expansion(hook, clause.clone(), queue.clone());
+                prepend_queue.push_front(
+                    Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())),
+                );
+
+                // prepend_queue is now:
+                //      | TryMeElse(N_2)
+                //      | SwitchOnTerm 2, ...
+                //      | TryMeElse(0)
+                //      | (clause_code)
+                // +N_2 | RevJmpBy (RetryMeElse(M_1))
+
+                internalize_choice_instr_at(code, old_clause_start, retraction_info);
+
+                code.extend(prepend_queue.into_iter());
+
+                clause_loc // + (outer_thread_choice_offset == 0 as usize)
             }
+        }
+    } else {
+        match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() {
+            Some(_) => {
+                prepend_queue.extend(clause_code.drain(1 ..));
 
-            (module_preds.0).0.push(clause);
-            module_preds.1.extend(queue.into_iter());
+                let old_clause_start = skeleton.clauses[1].clause_start - 2;
 
-            (preds.0).0.extend((module_preds.0).0.iter().cloned());
-            preds.1.extend(module_preds.1.iter().cloned());
-        } else {
-            let module_preds = self
-                .user_term_dir
-                .entry(key.clone())
-                .or_insert((Predicate::new(), VecDeque::from(vec![])));
+                let inner_thread_rev_offset =
+                    1 + prepend_queue.len() + clause_loc - old_clause_start;
 
-            len += 1;
-            queue_len += queue.len();
+                prepend_queue.push_back(
+                    Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)),
+                );
 
-            (preds.0).0.push(clause);
-            preds.1.extend(queue.into_iter());
+                prepend_queue.push_front(
+                    Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())),
+                );
 
-            (preds.0).0.extend((module_preds.0).0.iter().cloned());
-            preds.1.extend(module_preds.1.iter().cloned());
-        }
+                // prepend_queue is now:
+                //      | TryMeElse(N_2)
+                //      | (clause_code)
+                // +N_2 | RevJmpBy (RetryMeElse(M_1))
 
-        (len, queue_len)
-    }
+                internalize_choice_instr_at(code, old_clause_start, retraction_info);
 
-    fn submit_op(
-        &mut self,
-        wam: &Machine,
-        indices: &mut IndexStore,
-        op_decl: &OpDecl,
-    ) -> Result<(), SessionError> {
-        let spec = get_desc(
-            op_decl.name(),
-            composite_op!(
-                self.module.is_some(),
-                &wam.indices.op_dir,
-                &mut indices.op_dir
-            ),
-        );
+                code.extend(prepend_queue.into_iter());
 
-        op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
-    }
+                // skeleton.clauses[0].opt_arg_index_key += clause_loc;
+                skeleton.clauses[0].clause_start = clause_loc;
 
-    fn process_decl(
-        &mut self,
-        decl: Declaration,
-        wam: &mut Machine,
-        indices: &mut IndexStore,
-        flags: MachineFlags,
-        non_counted_bt_preds: &mut IndexSet<PredicateKey>,
-    ) -> Result<(), SessionError> {
-        match decl {
-            Declaration::Dynamic(..) => {
-                Ok(())
-            }
-            Declaration::EndOfFile => {
-                Ok(())
+                clause_loc // + (outer_thread_choice_offset == 0 as usize)
             }
-            Declaration::Hook(hook, clause, queue) => {
-                let key = (hook.name(), hook.arity());
-                let (len, queue_len) =
-                    self.add_term_dir_terms(hook, &mut wam.code_repo, key.clone(), clause, queue);
+            None => {
+                prepend_queue.extend(clause_code.drain(1 ..));
 
-                let result = wam
-                    .code_repo
-                    .compile_hook(hook)
-                    .map_err(SessionError::from);
+                let old_clause_start = skeleton.clauses[1].clause_start;
 
-                wam.code_repo.truncate_terms(key, len, queue_len);
+                let inner_thread_rev_offset =
+                    1 + prepend_queue.len() + clause_loc - old_clause_start;
 
-                result
-            }
-            Declaration::Module(module_decl) => {
-                if self.module.is_none() {
-                    let module_name = module_decl.name.clone();
-                    let atom_tbl = TabledData::new(module_name.to_rc());
-
-                    for export in module_decl.exports.iter() {
-                        if let ModuleExport::OpDecl(ref op_decl) = export {
-                            self.submit_op(wam, indices, op_decl)?;
-                        }
-                    }
+                prepend_queue.push_back(
+                    Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)),
+                );
 
-                    let listing_src = self.listing_src.clone();
+                prepend_queue.push_front(
+                    Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())),
+                );
 
-                    Ok(self.module = Some(Module::new(module_decl, atom_tbl, listing_src)))
-                } else {
-                    Err(SessionError::from(ParserError::InvalidModuleDecl))
-                }
-            }
-               Declaration::ModuleInitialization(query_terms, queue) => {
-                       self.initialization_goals.0.extend(query_terms.into_iter());
-                       self.initialization_goals.1.extend(queue.into_iter());
-
-                       Ok(())
-               }
-            Declaration::MultiFile(..) => {
-                Ok(())
-            }
-            Declaration::NonCountedBacktracking(name, arity) => {
-                non_counted_bt_preds.insert((name, arity));
-                Ok(())
-            }
-            Declaration::Op(op_decl) => {
-                self.submit_op(wam, indices, &op_decl)
-            }
-            Declaration::SetPrologFlag(dbl_quotes) => {
-                wam.machine_st.flags.double_quotes = dbl_quotes;
-                Ok(())
-            }
-            Declaration::UseModule(ModuleSource::Library(name)) => {
-                let name = if !wam.indices.modules.contains_key(&name) {
-                    load_library(wam, name, true)?
-                } else {
-                    name
-                };
+                // prepend_queue is now:
+                //      | TryMeElse(N_2)
+                //      | (clause_code)
+                // +N_2 | RevJmpBy (RetryMeElse(M_1))
 
-                self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices)
-            }
-            Declaration::UseModule(ModuleSource::File(filename)) => {
-                let mut path_buf = self.listing_src.path();
-                path_buf.push(filename.as_str());
+                internalize_choice_instr_at(code, old_clause_start, retraction_info);
 
-                let name = load_module_from_file(wam, path_buf, true)?;
-                self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices)
-            }
-            Declaration::UseQualifiedModule(ModuleSource::Library(name), exports) => {
-                let name = if !wam.indices.modules.contains_key(&name) {
-                    load_library(wam, name, true)?
-                } else {
-                    name
-                };
-
-                self.use_qualified_module(
-                    name,
-                    &mut wam.code_repo,
-                    flags,
-                    &exports,
-                    &mut wam.indices,
-                    indices
-                )
-            }
-            Declaration::UseQualifiedModule(ModuleSource::File(filename), exports) => {
-                let mut path_buf = self.listing_src.path();
-                path_buf.push(filename.as_str());
-
-                let name = load_module_from_file(wam, path_buf, true)?;
-
-                self.use_qualified_module(
-                    name,
-                    &mut wam.code_repo,
-                    flags,
-                    &exports,
-                    &mut wam.indices,
-                    indices,
-                )
+                code.extend(prepend_queue.into_iter());
+
+                // skeleton.clauses[0].opt_arg_index_key += clause_loc;
+                skeleton.clauses[0].clause_start = clause_loc;
+
+                clause_loc // + (outer_thread_choice_offset == 0 as usize)
             }
         }
     }
+}
 
-    fn setup_multifile_decl(
-        &self,
-        indicator: MultiFileIndicator,
-        worker: &mut TopLevelBatchWorker,
-    ) -> Result<(), SessionError> {
-        match indicator {
-            MultiFileIndicator::LocalScoped(name, arity) => {
-                let term_dir  = &worker.term_stream.wam.code_repo.term_dir;
-                let key       = (name, arity);
-                let term_dirs = &mut worker.term_dirs;
+fn append_compiled_clause(
+    code: &mut Code,
+    mut clause_code: Code,
+    skeleton: &mut PredicateSkeleton,
+    retraction_info: &mut RetractionInfo,
+) -> Option<usize> {
+    let clause_loc = code.len();
+    let target_pos = skeleton.clauses.len() - 1;
+    let lower_bound = lower_bound_of_target_clause(skeleton, target_pos);
+
+    code.push(Line::Choice(ChoiceInstruction::TrustMe(0)));
+    skeleton.clauses[target_pos].clause_start = clause_loc;
+
+    let mut code_ptr_opt = None;
+
+    let lower_bound_arg_num = skeleton.clauses[lower_bound].opt_arg_index_key.arg_num();
+    let target_arg_num = skeleton.clauses[target_pos].opt_arg_index_key.arg_num();
+
+    let threaded_choice_instr_loc =
+        match skeleton.clauses[lower_bound].opt_arg_index_key.switch_on_term_loc() {
+            Some(index_loc) if lower_bound_arg_num == target_arg_num => {
+                code.extend(clause_code.drain(3 ..)); // skip the indexing code
+
+                // set skeleton[target_pos].opt_arg_index_key to
+                // index_loc. its original value is always 1.
+                skeleton.clauses[target_pos].opt_arg_index_key += index_loc - 1;
+
+                retraction_info.push_record(
+                    RetractionRecord::AddedIndex(
+                        skeleton.clauses[target_pos].opt_arg_index_key.clone(),
+                        skeleton.clauses[target_pos].clause_start,
+                    ),
+                );
+
+                let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+
+                merge_clause_index(
+                    target_indexing_line,
+                    &mut skeleton.clauses[lower_bound ..],
+                    clause_loc,
+                    AppendOrPrepend::Append,
+                );
+
+                if lower_bound + 1 == target_pos {
+                    set_switch_var_offset(code, index_loc, 1, retraction_info);
+                }
 
-                insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
+                skeleton.clauses[target_pos - 1].clause_start
             }
-            MultiFileIndicator::ModuleScoped((module_name, key)) => {
-                match worker.term_stream.wam.indices.modules.get(&module_name) {
-                    Some(ref module) => {
-                        let term_dir  = &module.term_dir;
-                        let term_dirs = worker.intra_module_term_dirs
-                            .entry(module_name)
-                            .or_insert(TermDirQuantum::new());
-
-                        insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
+            _ => {
+                skeleton.clauses[target_pos].opt_arg_index_key += clause_loc;
+                code.extend(clause_code.drain(1 ..));
+
+                match skeleton.clauses[lower_bound].opt_arg_index_key.switch_on_term_loc() {
+                    Some(_) => {
+                        if lower_bound == 0 {
+                            code_ptr_opt = Some(skeleton.clauses[lower_bound].clause_start - 2);
+                        }
+
+                        skeleton.clauses[lower_bound].clause_start - 2
                     }
-                    None => {
-                        let err = ExistenceError::ModuleSource(ModuleSource::File(
-                            module_name,
-                        ));
+                    _ => {
+                        if lower_bound == 0 {
+                            code_ptr_opt = Some(skeleton.clauses[lower_bound].clause_start);
+                        }
 
-                        return Err(SessionError::ExistenceError(err));
+                        skeleton.clauses[lower_bound].clause_start
                     }
                 }
             }
         };
 
-        Ok(())
+    thread_choice_instr_at_to(code, threaded_choice_instr_loc, clause_loc, retraction_info);
+
+    code_ptr_opt
+}
+
+#[inline]
+fn mergeable_indexed_subsequences(
+    lower_bound: usize,
+    target_pos: usize,
+    skeleton: &PredicateSkeleton,
+) -> bool {
+    let lower_bound_arg_num = skeleton.clauses[lower_bound].opt_arg_index_key.arg_num();
+
+    if target_pos + 1 < skeleton.clauses.len() {
+        let succ_arg_num   = skeleton.clauses[target_pos + 1].opt_arg_index_key.arg_num();
+        let target_arg_num = skeleton.clauses[target_pos].opt_arg_index_key.arg_num();
+
+        return target_arg_num != succ_arg_num && lower_bound_arg_num == succ_arg_num;
     }
 
-    fn process_and_commit_decl(
+    false
+}
+
+impl<'a> LoadState<'a> {
+    fn compile(
         &mut self,
-        decl: Declaration,
-        worker: &mut TopLevelBatchWorker,
-        indices: &mut IndexStore,
-        flags: MachineFlags,
-    ) -> Result<(), SessionError> {
-        let mut update_expansion_lengths = false;
-
-        match &decl {
-            &Declaration::Dynamic(ref name, arity) => {
-                worker
-                    .dynamic_clause_map
-                    .entry((name.clone(), arity))
-                    .or_insert(vec![]);
-
-                       indices.code_dir
-                           .entry((name.clone(), arity))
-                           .or_insert(CodeIndex::dynamic_undefined(self.get_module_name()));
-            }
-            &Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker
-                .term_stream
-                .incr_expansion_lens(hook.user_scope(), 1, queue.len()),
-            &Declaration::Hook(hook, _, ref queue) if !hook.has_module_scope() => {
-                worker.term_stream.incr_expansion_lens(hook, 1, queue.len())
+        key: PredicateKey,
+        predicates: &Vec<PredicateClause>,
+        queue: &VecDeque<TopLevel>,
+        settings: CodeGenSettings,
+    ) -> Result<IndexPtr, SessionError> {
+        let code_index = self.get_or_insert_code_index(key.clone());
+        let code_len = self.wam.code_repo.code.len();
+        let mut code_ptr = code_len;
+
+        let mut cg = CodeGenerator::<DebrayAllocator>::new(
+            self.wam.machine_st.atom_tbl.clone(),
+            settings,
+        );
+
+        let mut code = cg.compile_predicate(predicates)?;
+
+        compile_appendix(
+            &mut code,
+            queue,
+            cg.jmp_by_locs,
+            settings.non_counted_bt,
+            self.wam.machine_st.atom_tbl.clone(),
+        )?;
+
+        if settings.is_extensible {
+            for clause_index_info in cg.skeleton.clauses.iter_mut() {
+                clause_index_info.clause_start += code_len;
+                clause_index_info.opt_arg_index_key += code_len;
             }
-            &Declaration::MultiFile(ref indicator) => {
-                self.setup_multifile_decl(indicator.clone(), worker)?;
+
+            match &mut code[0] {
+                Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+                    code_ptr += 1;
+                }
+                _ => {
+                }
             }
-            &Declaration::UseModule(_) | &Declaration::UseQualifiedModule(..) => {
-                update_expansion_lengths = true
+
+            match self.wam.indices.get_predicate_skeleton(
+                &self.compilation_target,
+                &key,
+            ) {
+                Some(skeleton) => {
+                    self.retraction_info.push_record(
+                        RetractionRecord::SkeletonClauseTruncateBack(
+                            self.compilation_target.clone(),
+                            key.clone(),
+                            skeleton.clauses.len(),
+                        ),
+                    );
+
+                    skeleton.clauses.extend(cg.skeleton.clauses.into_iter());
+                }
+                None => {
+                    self.add_extensible_predicate(key.clone(), cg.skeleton);
+                }
             }
-            _ => {}
-        };
+        }
 
-        let result = self.process_decl(
-            decl,
-            &mut worker.term_stream.wam,
-            indices,
-            flags,
-            &mut worker.non_counted_bt_preds,
+        set_code_index(
+            &mut self.retraction_info,
+            &self.compilation_target,
+            key,
+            &code_index,
+            IndexPtr::Index(code_ptr),
         );
 
-        if update_expansion_lengths {
-            worker.term_stream.update_expansion_lens();
-        }
+        self.wam.code_repo.code.extend(code.into_iter());
+        Ok(code_index.get())
+    }
 
-        result
+    fn record_incremental_compile(&mut self, key: PredicateKey, append_or_prepend: AppendOrPrepend)
+    {
+        self.retraction_info.push_record(
+            match &self.compilation_target {
+                CompilationTarget::User => {
+                    match append_or_prepend {
+                        AppendOrPrepend::Append => {
+                            RetractionRecord::AppendedUserExtensiblePredicate(
+                                key,
+                            )
+                        }
+                        AppendOrPrepend::Prepend => {
+                            RetractionRecord::PrependedUserExtensiblePredicate(
+                                key,
+                            )
+                        }
+                    }
+                }
+                CompilationTarget::Module(ref module_name) => {
+                    match append_or_prepend {
+                        AppendOrPrepend::Append => {
+                            RetractionRecord::AppendedModuleExtensiblePredicate(
+                                module_name.clone(), key,
+                            )
+                        }
+                        AppendOrPrepend::Prepend => {
+                            RetractionRecord::PrependedModuleExtensiblePredicate(
+                                module_name.clone(), key,
+                            )
+                        }
+                    }
+                }
+            }
+        );
     }
 
-    pub(crate)
-    fn gather_items(
+    pub(super)
+    fn incremental_compile_clause(
         &mut self,
-        wam: &mut Machine,
-        src: &mut ParsingStream<Stream>,
-        indices: &mut IndexStore,
-    ) -> Result<GatherResult, SessionError> {
-        let flags = wam.machine_flags();
-        let atom_tbl = indices.atom_tbl.clone();
-        let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags, wam);
-
-        let mut toplevel_results = vec![];
-        let mut toplevel_indices = default_index_store!(atom_tbl.clone());
+        key: PredicateKey,
+        clause: PredicateClause,
+        queue: VecDeque<TopLevel>,
+        non_counted_bt: bool,
+        append_or_prepend: AppendOrPrepend,
+    ) -> Result<IndexPtr, SessionError> {
+        self.record_incremental_compile(key.clone(), append_or_prepend);
+
+        let skeleton =
+            match self.wam.indices.get_predicate_skeleton(
+                &self.compilation_target,
+                &key,
+            ) {
+                Some(skeleton) if !skeleton.clauses.is_empty() => {
+                    skeleton
+                }
+                _ => {
+                    // true because this predicate is extensible.
+                    let settings = CodeGenSettings::new(true, non_counted_bt);
+                    return self.compile(key, &vec![clause], &queue, settings);
+                }
+            };
 
-        let mut top_level_term_dirs = TermDirQuantum::new();
+        let settings = CodeGenSettings::new(true, non_counted_bt);
+        let atom_tbl = self.wam.machine_st.atom_tbl.clone();
 
-        while let Some(decl) = worker.consume(indices)? {
-            if decl.is_module_decl() {
-                toplevel_indices.copy_and_swap(indices);
-                mem::swap(&mut worker.results, &mut toplevel_results);
-                worker.in_module = true;
+        let StandaloneCompileResult { clause_code, mut standalone_skeleton } =
+            compile_standalone_clause(clause, queue, settings, atom_tbl)?;
 
-                self.process_and_commit_decl(decl, &mut worker, indices, flags)?;
+        match append_or_prepend {
+            AppendOrPrepend::Append => {
+                skeleton.clauses.push_back(standalone_skeleton.clauses.pop_back().unwrap());
 
-                if let Some(ref module) = &self.module {
-                    worker.term_stream.set_atom_tbl(module.atom_tbl.clone());
+                self.retraction_info.push_record(
+                    RetractionRecord::SkeletonClausePopBack(
+                        self.compilation_target.clone(),
+                        key.clone(),
+                    ),
+                );
 
-                    top_level_term_dirs = mem::replace(
-                        &mut worker.term_dirs,
-                        TermDirQuantum::new(),
+                let result =
+                    append_compiled_clause(
+                        &mut self.wam.code_repo.code,
+                        clause_code,
+                        skeleton,
+                        &mut self.retraction_info,
                     );
-                }
-            } else if decl.is_end_of_file() {
-                break;
-            } else {
-                self.process_and_commit_decl(decl, &mut worker, indices, flags)?;
-            }
-        }
 
-        let addition_results = worker.term_stream.rollback_expansion_code()?;
+                let code_index = self.get_or_insert_code_index(key.clone());
 
-        let module_term_dirs = if self.module.is_some() {
-            worker.term_dirs
-        } else {
-            top_level_term_dirs = worker.term_dirs;
-            TermDirQuantum::new()
-        };
+                if let Some(new_code_index) = result {
+                    set_code_index(
+                        &mut self.retraction_info,
+                        &self.compilation_target,
+                        key,
+                        &code_index,
+                        IndexPtr::Index(new_code_index),
+                    );
+                }
 
-        Ok(GatherResult {
-            worker_results: worker.results,
-            dynamic_clause_map: worker.dynamic_clause_map,
-            toplevel_results,
-            toplevel_indices,
-            addition_results,
-            top_level_terms: worker.term_stream.top_level_terms(),
-            top_level_term_dirs,
-            module_term_dirs,
-            in_situ_code_dir: worker.term_stream.wam.indices.take_in_situ_code_dir(),
-            in_situ_code: worker.term_stream.wam.code_repo.take_in_situ_code(),
-            in_situ_module_dir: worker.term_stream.wam.indices.take_in_situ_module_dir(),
-        })
-    }
+                Ok(code_index.get())
+            }
+            AppendOrPrepend::Prepend => {
+                skeleton.clauses.push_front(standalone_skeleton.clauses.pop_back().unwrap());
+
+                self.retraction_info.push_record(
+                    RetractionRecord::SkeletonClausePopFront(
+                        self.compilation_target.clone(),
+                        key.clone(),
+                    ),
+                );
 
-    fn drop_expansions(&self, code_repo: &mut CodeRepo) {
-        let (te_len, te_queue_len) = self.orig_term_expansion_lens;
-        let (ge_len, ge_queue_len) = self.orig_goal_expansion_lens;
+                let threaded_choice_instr_loc =
+                    prepend_compiled_clause(
+                        &mut self.wam.code_repo.code,
+                        self.compilation_target.clone(),
+                        key.clone(),
+                        clause_code,
+                        skeleton,
+                        &mut self.retraction_info,
+                    );
 
-        code_repo.truncate_terms((clause_name!("term_expansion"), 2), te_len, te_queue_len);
-        code_repo.truncate_terms((clause_name!("goal_expansion"), 2), ge_len, ge_queue_len);
+                let code_index = self.get_or_insert_code_index(key.clone());
 
-        discard_result!(code_repo.compile_hook(CompileTimeHook::UserGoalExpansion));
-        discard_result!(code_repo.compile_hook(CompileTimeHook::UserTermExpansion));
-    }
+                set_code_index(
+                    &mut self.retraction_info,
+                    &self.compilation_target,
+                    key,
+                    &code_index,
+                    IndexPtr::Index(threaded_choice_instr_loc),
+                );
 
-    fn print_error(&self, e: &SessionError) {
-        if let &SessionError::ParserError(ref e) = e {
-            if let Some((line_num, _col_num)) = e.line_and_col_num() {
-                println!("{}:{}: {}", self.listing_src.name(), line_num, e.as_str());
+                Ok(IndexPtr::Index(threaded_choice_instr_loc))
             }
         }
     }
-}
 
-fn compile_work_impl(
-    compiler: &mut ListingCompiler,
-    wam: &mut Machine,
-    mut indices: IndexStore,
-    mut results: GatherResult,
-) -> Result<(), SessionError> {
-    if let Some(ref mut module) = &mut compiler.module {
-        // compile the module-level goal and term expansions and store
-        // their locations to the module's code_dir.
-        let mut decls = module.take_local_expansions();
+    pub(super)
+    fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
+        let code_index = self.get_or_insert_code_index(key.clone());
+
+        let skeleton =
+            match self.wam.indices.get_predicate_skeleton(
+                &self.compilation_target,
+                &key,
+            ) {
+                Some(skeleton) => {
+                    skeleton
+                }
+                None => {
+                    unreachable!();
+                }
+            };
+
+        let code = &mut self.wam.code_repo.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.
+            match skeleton.clauses[target_pos].opt_arg_index_key.switch_on_term_loc() {
+                Some(index_loc) => {
+                    let inner_clause_start = find_inner_choice_instr(
+                        code,
+                        skeleton.clauses[target_pos].clause_start,
+                        index_loc,
+                    );
 
-        if !decls.is_empty() {
-            append_trivial_goal(&clause_name!("term_expansion"), &mut decls[0].0);
-            append_trivial_goal(&clause_name!("goal_expansion"), &mut decls[1].0);
+                    remove_index_from_subsequence(
+                        code,
+                        &skeleton.clauses[target_pos].opt_arg_index_key,
+                        inner_clause_start,
+                        &mut self.retraction_info,
+                    );
 
-            results.worker_results.extend(decls.into_iter());
+                    match derelictize_try_me_else(
+                        code,
+                        inner_clause_start,
+                        &mut self.retraction_info,
+                    ) {
+                        Some(offset) => {
+                            let instr_loc = find_inner_choice_instr(
+                                code,
+                                inner_clause_start + offset,
+                                index_loc,
+                            );
+
+                            let clause_loc = blunt_leading_choice_instr(
+                                code,
+                                instr_loc,
+                                &mut self.retraction_info,
+                            );
+
+                            set_switch_var_offset(
+                                code,
+                                index_loc,
+                                clause_loc - index_loc,
+                                &mut self.retraction_info,
+                            );
+
+                            self.retraction_info.push_record(
+                                RetractionRecord::SkeletonClauseStartReplaced(
+                                    self.compilation_target.clone(),
+                                    key.clone(),
+                                    target_pos + 1,
+                                    skeleton.clauses[target_pos + 1].clause_start,
+                                ),
+                            );
+
+                            skeleton.clauses[target_pos + 1].clause_start =
+                                skeleton.clauses[target_pos].clause_start;
+
+                            return delete_from_dynamic_skeleton(
+                                self.compilation_target.clone(),
+                                key,
+                                skeleton,
+                                target_pos,
+                                &mut self.retraction_info,
+                            );
+                        }
+                        None => {
+                            let index_ptr_opt =
+                                if target_pos > 0 {
+                                    let preceding_choice_instr_loc =
+                                        skeleton.clauses[target_pos - 1].clause_start;
+
+                                    remove_non_leading_clause(
+                                        code,
+                                        preceding_choice_instr_loc,
+                                        skeleton.clauses[target_pos].clause_start - 2,
+                                        &mut self.retraction_info,
+                                    )
+                                } else {
+                                    remove_leading_unindexed_clause(
+                                        code,
+                                        skeleton.clauses[target_pos].clause_start - 2,
+                                        &mut self.retraction_info,
+                                    )
+                                };
+
+                            return finalize_retract(
+                                key,
+                                self.compilation_target.clone(),
+                                skeleton,
+                                code_index,
+                                target_pos,
+                                index_ptr_opt,
+                                &mut self.retraction_info,
+                            );
+                        }
+                    }
+                }
+                None => {
+                }
+            }
         }
-    }
-
-    let top_level_term_dir = results.top_level_term_dirs.consolidate();
-    let module_term_dir = results.module_term_dirs.consolidate();
-
-    let mut code = results.in_situ_code;
-
-    let in_situ_code_dir = results.in_situ_code_dir;
-    let in_situ_module_dir = results.in_situ_module_dir;
 
-    compiler.adapt_in_situ_code(
-        results.worker_results,
-        wam,
-        &mut indices.code_dir,
-        &mut indices.module_dir,
-        &mut code,
-        &in_situ_code_dir,
-        &in_situ_module_dir,
-    )?;
+        let index_ptr_opt =
+            match skeleton.clauses[lower_bound].opt_arg_index_key.switch_on_term_loc() {
+                Some(target_indexing_loc)
+                    if mergeable_indexed_subsequences(lower_bound, target_pos, skeleton) =>
+                {
+                    let result;
+
+                    match skeleton.clauses[target_pos + 1].opt_arg_index_key.switch_on_term_loc() {
+                        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
+                                )),
+                            );
+
+                            match target_indexing_line {
+                                Line::IndexingCode(indexing_code) => {
+                                    self.retraction_info.push_record(
+                                        RetractionRecord::ReplacedIndexingLine(
+                                            target_indexing_loc,
+                                            indexing_code,
+                                        ),
+                                    );
+                                }
+                                _ => {
+                                }
+                            }
+
+                            set_switch_var_offset(
+                                code,
+                                later_indexing_loc,
+                                target_indexing_loc - later_indexing_loc + 1,
+                                &mut self.retraction_info,
+                            );
+
+                            result = merge_indexed_subsequences(
+                                code,
+                                skeleton,
+                                lower_bound,
+                                target_pos + 1,
+                                &mut self.retraction_info,
+                            );
+
+                            merge_indices(
+                                code,
+                                later_indexing_loc,
+                                0 .. target_pos - lower_bound,
+                                &mut skeleton.clauses[lower_bound ..],
+                                &mut self.retraction_info,
+                            );
+                        }
+                        _ => {
+                            set_switch_var_offset_to_choice_instr_(
+                                code,
+                                target_indexing_loc,
+                                1,
+                                &mut self.retraction_info,
+                            );
+
+                            result = merge_indexed_subsequences(
+                                code,
+                                skeleton,
+                                lower_bound,
+                                target_pos + 1,
+                                &mut self.retraction_info,
+                            );
+
+                            merge_indices(
+                                code,
+                                target_indexing_loc,
+                                target_pos + 1 - lower_bound .. skeleton.clauses.len() - lower_bound,
+                                &mut skeleton.clauses[lower_bound ..],
+                                &mut self.retraction_info,
+                            );
+                        }
+                    };
 
-    compiler.adapt_in_situ_code(
-        results.toplevel_results,
-        wam,
-        &mut results.toplevel_indices.code_dir,
-        &mut indices.module_dir,
-        &mut code,
-        &in_situ_code_dir,
-        &in_situ_module_dir,
-    )?;
+                    result
+                }
+                _ => {
+                    if target_pos > 0 {
+                        remove_index_from_subsequence(
+                            code,
+                            &skeleton.clauses[target_pos].opt_arg_index_key,
+                            skeleton.clauses[target_pos].clause_start,
+                            &mut self.retraction_info,
+                        );
 
-    if let Some(ref mut module) = &mut compiler.module {
-        if !module.is_impromptu_module {
-            module.user_term_expansions = results.addition_results.take_term_expansions();
-            module.user_goal_expansions = results.addition_results.take_goal_expansions();
-        }
+                        match skeleton.clauses[target_pos].opt_arg_index_key.switch_on_term_loc() {
+                            Some(index_loc) => {
+                                let 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.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,
+                                        );
+                                    }
+                                    _ => {
+                                    }
+                                }
+
+                                None
+                            }
+                            None => {
+                                let preceding_choice_instr_loc =
+                                    if skeleton.clauses[lower_bound].opt_arg_index_key.is_some() {
+                                        skeleton.clauses[lower_bound].clause_start - 2
+                                    } else {
+                                        skeleton.clauses[lower_bound].clause_start
+                                    };
+
+                                remove_non_leading_clause(
+                                    code,
+                                    preceding_choice_instr_loc,
+                                    skeleton.clauses[target_pos].clause_start,
+                                    &mut self.retraction_info,
+                                )
+                            }
+                        }
+                    } else {
+                        remove_leading_unindexed_clause(
+                            code,
+                            skeleton.clauses[target_pos].clause_start,
+                            &mut self.retraction_info,
+                        )
+                    }
+                }
+            };
+
+        finalize_retract(
+            key,
+            self.compilation_target.clone(),
+            skeleton,
+            code_index,
+            target_pos,
+            index_ptr_opt,
+            &mut self.retraction_info,
+        )
     }
+}
 
-    wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion)?;
-    wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion)?;
-
-    if let Some(mut module) = compiler.module.take() {
-        if module.is_impromptu_module {
-            module.module_decl.exports = indices.code_dir.keys().cloned()
-                .filter(|(name, _)| name.owning_module().as_str() != "builtins")
-                .map(ModuleExport::PredicateKey)
-                .collect();
-
-            module.module_decl.exports.extend(
-                indices.op_dir.iter()
-                    .map(|((name, _), OpDirValue (shared_op_desc, _))|
-                        ModuleExport::OpDecl(OpDecl(
-                            shared_op_desc.prec(),
-                            shared_op_desc.assoc(),
-                            name.clone(),
-                        ))
+impl<'a, TS: TermStream> Loader<'a, TS> {
+    pub(super)
+    fn compile_clause_clauses<ClauseIter: Iterator<Item=(Term, Term)>>(
+        &mut self,
+        key: PredicateKey,
+        clause_clauses: ClauseIter,
+        append_or_prepend: AppendOrPrepend,
+    ) -> Result<(), SessionError> {
+        let clause_predicates =
+            clause_clauses.map(|(head, body)| {
+                PredicateClause::Fact(
+                    Term::Clause(
+                        Cell::default(),
+                        clause_name!("$clause"),
+                        vec![Box::new(head), Box::new(body)],
+                        None,
                     )
-            );
-        }
+                )
+            });
 
-        let mut clause_code_generator =
-            ClauseCodeGenerator::new(code.len(), module.module_decl.name.clone());
+        let compilation_target = mem::replace(
+            &mut self.load_state.compilation_target,
+            CompilationTarget::Module(clause_name!("builtins")),
+        );
 
-        wam.check_toplevel_code(&results.toplevel_indices)?;
-        clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
+        let mut clause_clause_locs = sdeq![];
 
-        if let Some(ref module) = wam.indices.modules.swap_remove(&module.module_decl.name) {
-            wam.indices.remove_module(clause_name!("user"), module);
-        }
+        for clause_predicate in clause_predicates {
+            clause_clause_locs.push_back(self.load_state.wam.code_repo.code.len());
 
-        if module.is_impromptu_module {
-            add_module(wam, module, indices, module_term_dir);
+            let result = self.load_state.incremental_compile_clause(
+                (clause_name!("$clause"), 2),
+                clause_predicate,
+                VecDeque::new(),
+                false, // non_counted_bt is false.
+                append_or_prepend,
+            );
 
-            let module = wam.indices.take_module(compiler.listing_src.name()).unwrap();
+            if let Err(e) = result {
+                self.load_state.compilation_target = compilation_target;
+                return Err(e);
+            }
+        }
 
-            wam.indices.use_module(&mut wam.code_repo, wam.machine_st.flags, &module)?;
-            wam.indices.insert_module(module);
-        } else {
-            add_module(wam, module, indices, module_term_dir);
+        match self.load_state.wam.indices.get_predicate_skeleton(
+            &self.load_state.compilation_target,
+            &(clause_name!("$clause"), 2),
+        ) {
+            Some(skeleton) if append_or_prepend.is_append() => {
+                skeleton.clause_clause_locs.extend_from_slice(&clause_clause_locs[0 ..]);
+            }
+            Some(skeleton) => {
+                for loc in clause_clause_locs.iter() {
+                    skeleton.clause_clause_locs.push_front(*loc);
+                }
+            }
+            None => {
+                unreachable!();
+            }
         }
 
-        add_toplevel(wam, results.toplevel_indices, top_level_term_dir);
-        wam.code_repo.code.extend(code.into_iter());
+        match self.load_state.wam.indices.get_predicate_skeleton(
+            &compilation_target,
+            &key,
+        ) {
+            Some(skeleton) if append_or_prepend.is_append() => {
+                self.load_state.retraction_info.push_record(
+                    RetractionRecord::SkeletonClauseClausesTruncateBack(
+                        compilation_target.clone(),
+                        key.clone(),
+                        skeleton.clause_clause_locs.len(),
+                    ),
+                );
 
-        clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
-    } else {
-        add_non_module_code(
-            wam,
-            results.dynamic_clause_map,
-            code,
-            indices,
-            top_level_term_dir,
-        )?;
-    }
+                skeleton.clause_clause_locs.append(
+                    &mut clause_clause_locs
+                );
+            }
+            Some(skeleton) => {
+                self.load_state.retraction_info.push_record(
+                    RetractionRecord::SkeletonClauseClausesTruncateFront(
+                        compilation_target.clone(),
+                        key.clone(),
+                        skeleton.clause_clause_locs.len(),
+                    ),
+                );
 
-    let init_goal_code = compiler.generate_init_goal_code()?;
+                for loc in clause_clause_locs.iter() {
+                    skeleton.clause_clause_locs.push_front(*loc);
+                }
 
-    if init_goal_code.len() > 0 {
-           if !wam.run_init_code(init_goal_code) {
-            println!("Warning: initialization goal for {} failed",
-                     compiler.listing_src.name());
+                self.load_state.increment_clause_assert_margin(
+                    clause_clause_locs.len()
+                );
+            }
+            None => {
+                unreachable!();
+            }
         }
-    }
 
-    if !compiler.suppress_warnings {
-        issue_singleton_warnings(
-            compiler.listing_src.name(),
-            results.top_level_terms,
-        );
+        self.load_state.compilation_target = compilation_target;
+        Ok(())
     }
 
-    Ok(())
-}
-
-fn compile_work(
-    compiler: &mut ListingCompiler,
-    wam: &mut Machine,
-    src: Stream,
-    mut indices: IndexStore,
-) -> EvalSession {
-    let mut stream = try_eval_session!(parsing_stream(src));
-    let src = &mut stream;
-    let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
-
-    try_eval_session!(compile_work_impl(compiler, wam, indices, results));
-
-    EvalSession::EntrySuccess
-}
-
-/* This is a truncated version of compile_user_module, used for
-compiling code composing special forms, ie. the code that calls
-M:verify_attributes on attributed variables. */
-pub fn compile_special_form(
-    wam: &mut Machine,
-    src: Stream,
-    listing_src: ListingSource,
-) -> Result<usize, SessionError> {
-    let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
-    setup_indices(wam, clause_name!("builtins"), &mut indices)?;
-
-    let mut src = parsing_stream(src)?;
-    let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src);
-    let mut results = compiler.gather_items(wam, &mut src, &mut indices)?;
-
-    compiler.adapt_in_situ_code(
-        results.worker_results,
-        wam,
-        &mut indices.code_dir,
-        &mut indices.module_dir,
-        &mut results.in_situ_code,
-        &results.in_situ_code_dir,
-        &results.in_situ_module_dir,
-    )?;
-
-    let p = wam.code_repo.code.len();
-    let top_level_term_dir = results.top_level_term_dirs.consolidate();
-
-    add_toplevel(wam, indices, top_level_term_dir);
+    pub(super)
+    fn compile_and_submit(&mut self) -> Result<(), SessionError> {
+        let queue = self.preprocessor.parse_queue(&mut self.load_state)?;
 
-    wam.code_repo.code.extend(results.in_situ_code.into_iter());
+        let key = self.predicates
+            .first()
+            .and_then(|cl| {
+                let arity = cl.arity();
+                cl.name().map(|name| (name, arity))
+            })
+            .ok_or(SessionError::NamelessEntry)?;
 
-    Ok(p)
-}
+        let (is_dynamic, is_extensible) = self.load_state.wam.indices
+            .get_predicate_skeleton(&self.load_state.compilation_target, &key)
+            .map(|skeleton| (skeleton.is_dynamic, true))
+            .unwrap_or((false, false));
 
-#[inline]
-pub fn compile_listing(
-    wam: &mut Machine,
-    src: Stream,
-    indices: IndexStore,
-    suppress_warnings: bool,
-    listing_src: ListingSource,
-) -> EvalSession {
-    let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings, listing_src);
+        let non_counted_bt = self.non_counted_bt_preds.contains(&key);
+        let settings = CodeGenSettings::new(is_extensible, non_counted_bt);
 
-    match compile_work(&mut compiler, wam, src, indices) {
-        EvalSession::Error(e) => {
-            compiler.drop_expansions(&mut wam.code_repo);
-            compiler.print_error(&e);
+        self.load_state.compile(key.clone(), &self.predicates, &queue, settings)?;
 
-            EvalSession::Error(e)
+        if is_dynamic {
+            let iter = mem::replace(&mut self.clause_clauses, vec![]).into_iter();
+            self.compile_clause_clauses(key, iter, AppendOrPrepend::Append)?;
         }
-        result => result,
-    }
-}
-
-pub(super) fn setup_indices(
-    wam: &mut Machine,
-    module: ClauseName,
-    indices: &mut IndexStore,
-) -> Result<(), SessionError> {
-    if let Some(module) = wam.indices.take_module(module.clone()) {
-        let flags = wam.machine_flags();
-        let result = indices.use_module(&mut wam.code_repo, flags, &module);
-
-        wam.indices.insert_module(module);
-        result
-    } else {
-        let err = ExistenceError::ModuleSource(ModuleSource::Library(
-            module
-        ));
 
-        Err(SessionError::ExistenceError(err))
+        Ok(self.predicates.clear())
     }
 }
-
-pub fn compile_user_module(
-    wam: &mut Machine,
-    src: Stream,
-    suppress_warnings: bool,
-    listing_src: ListingSource,
-) -> EvalSession {
-    let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
-    try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices));
-    compile_listing(wam, src, indices, suppress_warnings, listing_src)
-}
diff --git a/src/machine/dynamic_database.rs b/src/machine/dynamic_database.rs
deleted file mode 100644 (file)
index 6fc01b4..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-use crate::prolog_parser::ast::*;
-
-use crate::heap_print::*;
-use crate::machine::*;
-use crate::machine::compile::*;
-use crate::machine::machine_errors::*;
-use crate::machine::streams::*;
-
-use std::convert::TryFrom;
-
-impl Machine {
-    pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
-        match name {
-            &ClauseName::User(ref rc) => rc.table.clone(),
-            _ => self.indices.atom_tbl(),
-        }
-    }
-
-    fn compile_into_machine(
-        &mut self,
-        src: Stream,
-        name: ClauseName,
-        arity: usize,
-    ) -> EvalSession {
-        match name.owning_module().as_str() {
-            "user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
-                Some(idx) => {
-                    let module = idx.0.borrow().1.clone();
-
-                    match module.as_str() {
-                        "user" => compile_user_module(self, src, true, ListingSource::User),
-                        _ => compile_into_module(self, module, src, name)
-                    }
-                }
-                None => compile_user_module(self, src, true, ListingSource::User),
-            },
-            _ => compile_into_module(self, name.owning_module(), src, name),
-        }
-    }
-
-    fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey {
-        let name = self.machine_st[name].clone();
-        let arity = self.machine_st[arity].clone();
-
-        let name = match self.machine_st.store(self.machine_st.deref(name)) {
-            Addr::Con(h) =>
-                if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] {
-                    name.clone()
-                } else {
-                    unreachable!()
-                },
-            _ => unreachable!(),
-        };
-
-        let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
-            Addr::Con(h) => {
-                match &self.machine_st.heap[h] {
-                    HeapCellValue::Integer(ref arity) => {
-                        arity.to_usize().unwrap()
-                    }
-                    HeapCellValue::Addr(Addr::Fixnum(arity)) => {
-                        usize::try_from(*arity).unwrap()
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                }
-            }
-            Addr::Fixnum(arity) => {
-                usize::try_from(arity).unwrap()
-            }
-            Addr::Usize(n) => {
-                n
-            }
-            _ => {
-                unreachable!()
-            }
-        };
-
-        (name, arity)
-    }
-
-    fn print_new_dynamic_clause(
-        &self,
-        addrs: VecDeque<Addr>,
-        name: ClauseName,
-        arity: usize,
-    ) -> String {
-        let mut output = PrinterOutputter::new();
-        output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
-
-        for addr in addrs {
-            let mut printer = HCPrinter::new(&self.machine_st, &self.indices.op_dir, output);
-            printer.quoted = true;
-
-            output = printer.print(addr);
-            output.append(". ");
-        }
-
-        output.result()
-    }
-
-    fn make_undefined(&mut self, name: ClauseName, arity: usize) {
-        let module_name = name.owning_module();
-
-        match self.indices.modules.get(&module_name) {
-            Some(ref module) => {
-                if let Some(idx) = module.code_dir.get(&(name.clone(), arity)) {
-                    set_code_index!(idx, IndexPtr::DynamicUndefined, module_name);
-                }
-            }
-            None => {
-            }
-        }
-
-        if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
-            set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
-        }
-    }
-
-    fn make_undefined_in_module(&mut self, module_name: ClauseName, name: ClauseName, arity: usize) {
-        if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
-            if idx.module_name() == module_name {
-                set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
-            }
-        }
-    }
-
-    fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType) {
-        let (name, arity) = self.get_predicate_key(name, arity);
-
-        self.make_undefined(name.clone(), arity);
-
-        self.indices.remove_code_index((name.clone(), arity));
-        self.indices.remove_clause_subsection(name.owning_module(), name, arity);
-    }
-
-    fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) {
-        let (name, arity) = self.get_predicate_key(name, arity);
-        let module_addr = self.machine_st[module].clone();
-
-        let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
-            Addr::Con(h) =>
-                if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
-                    match self.indices.modules.get_mut(module) {
-                        Some(ref mut module) => {
-                            module.code_dir.remove(&(name.clone(), arity));
-                            module.module_decl.name.clone()
-                        }
-                        _ => {
-                            self.machine_st.fail = true;
-                            return;
-                        }
-                    }
-                } else {
-                    unreachable!()
-                },
-            _ => unreachable!(),
-        };
-
-        self.make_undefined_in_module(module_name.clone(), name.clone(), arity);
-
-        self.indices.remove_code_index((name.clone(), arity));
-        self.indices.remove_clause_subsection(module_name, name, arity);
-    }
-
-    fn handle_eval_result_from_dynamic_compile(
-        &mut self,
-        pred_str: String,
-        name: ClauseName,
-        arity: usize,
-        src: ClauseName,
-    ) {
-        let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
-
-        let result = self.compile_into_machine(
-            Stream::from(pred_str),
-            name,
-            arity,
-        );
-
-        self.machine_st = machine_st;
-
-        if let EvalSession::Error(err) = result {
-            let h = self.machine_st.heap.h();
-            let stub = MachineError::functor_stub(src, 1);
-            let err = MachineError::session_error(h, err);
-            let err = self.machine_st.error_form(err, stub);
-
-            self.machine_st.throw_exception(err);
-        }
-    }
-
-    fn recompile_dynamic_predicate_impl(
-        &mut self,
-        place: DynamicAssertPlace,
-        name: ClauseName,
-        arity: usize,
-    ) {
-        let stub = MachineError::functor_stub(place.predicate_name(), 1);
-        let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) {
-            Ok(addrs) => {
-                let mut addrs = VecDeque::from(addrs);
-                let added_clause = self.machine_st[temp_v!(1)].clone();
-
-                place.push_to_queue(&mut addrs, added_clause);
-                self.print_new_dynamic_clause(addrs, name.clone(), arity)
-            }
-            Err(err) => {
-                return self.machine_st.throw_exception(err);
-            }
-        };
-
-        self.handle_eval_result_from_dynamic_compile(
-            pred_str,
-            name,
-            arity,
-            place.predicate_name(),
-        );
-    }
-
-    fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
-        let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
-            Addr::Con(h) =>
-                if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
-                    match self.indices.modules.get(module) {
-                        Some(ref module) => module.atom_tbl.clone(),
-                        None => {
-                            self.machine_st.fail = true;
-                            return false;
-                        }
-                    }
-                } else {
-                    self.machine_st.fail = true;
-                    return false;
-                },
-            _ => unreachable!(),
-        };
-
-        if let &mut ClauseName::User(ref mut rc) = name {
-            rc.table = atom_tbl;
-        }
-
-        true
-    }
-
-    fn recompile_dynamic_predicate_in_module(&mut self, place: DynamicAssertPlace) {
-        let (mut name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
-        let module_addr = self.machine_st[temp_v!(5)].clone();
-
-        if self.set_module_atom_tbl(module_addr, &mut name) {
-            self.recompile_dynamic_predicate_impl(place, name, arity);
-        }
-    }
-
-    fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace) {
-        let (name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
-        self.recompile_dynamic_predicate_impl(place, name, arity);
-    }
-
-    fn retract_from_dynamic_predicate_in_module(&mut self) {
-        let index = self.machine_st[temp_v!(3)].clone();
-        let index = match self.machine_st.store(self.machine_st.deref(index)) {
-            Addr::Con(h) =>
-                match &self.machine_st.heap[h] {
-                    HeapCellValue::Integer(ref arity) => {
-                        arity.to_usize().unwrap()
-                    }
-                    HeapCellValue::Addr(Addr::Fixnum(arity)) => {
-                        usize::try_from(*arity).unwrap()
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                }
-            Addr::Fixnum(arity) => {
-                usize::try_from(arity).unwrap()
-            }
-            _ => {
-                unreachable!()
-            }
-        };
-
-        let (mut name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
-        let module_addr = self.machine_st[temp_v!(5)].clone();
-
-        if self.set_module_atom_tbl(module_addr, &mut name) {
-            let stub = MachineError::functor_stub(clause_name!("retract"), 1);
-            let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
-                Ok(addrs) => {
-                    let mut addrs = VecDeque::from(addrs);
-                    addrs.remove(index);
-
-                    if addrs.is_empty() {
-                        self.make_undefined(name.clone(), arity);
-                    }
-
-                    self.print_new_dynamic_clause(addrs, name.clone(), arity)
-                }
-                Err(err) => {
-                    return self.machine_st.throw_exception(err);
-                }
-            };
-
-            self.handle_eval_result_from_dynamic_compile(
-                pred_str,
-                name,
-                arity,
-                clause_name!("retract"),
-            );
-        }
-    }
-
-    fn retract_from_dynamic_predicate(&mut self) {
-        let index = self.machine_st[temp_v!(3)].clone();
-        let index = match self.machine_st.store(self.machine_st.deref(index)) {
-            Addr::Con(h) => {
-                match &self.machine_st.heap[h] {
-                    HeapCellValue::Integer(ref arity) => {
-                        arity.to_usize().unwrap()
-                    }
-                    HeapCellValue::Addr(Addr::Fixnum(arity)) => {
-                        usize::try_from(*arity).unwrap()
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                }
-            }
-            Addr::Usize(n) => {
-                n
-            }
-            Addr::Fixnum(n) => {
-                usize::try_from(n).unwrap()
-            }
-            _ => {
-                unreachable!()
-            }
-        };
-
-        let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
-
-        let stub = MachineError::functor_stub(clause_name!("retract"), 1);
-        let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
-            Ok(addrs) => {
-                let mut addrs = VecDeque::from(addrs);
-                addrs.remove(index);
-
-                if addrs.is_empty() {
-                    self.make_undefined(name.clone(), arity);
-                }
-
-                self.print_new_dynamic_clause(addrs, name.clone(), arity)
-            }
-            Err(err) => {
-                return self.machine_st.throw_exception(err);
-            }
-        };
-
-        self.handle_eval_result_from_dynamic_compile(
-            pred_str,
-            name,
-            arity,
-            clause_name!("retract"),
-        );
-    }
-
-    pub(super) fn dynamic_transaction(
-        &mut self,
-        trans_type: DynamicTransactionType,
-        p: LocalCodePtr,
-    ) {
-        match trans_type {
-            DynamicTransactionType::Abolish => {
-                self.abolish_dynamic_clause(temp_v!(1), temp_v!(2))
-            }
-            DynamicTransactionType::Assert(place) => {
-                self.recompile_dynamic_predicate(place)
-            }
-            DynamicTransactionType::ModuleAbolish => {
-                self.abolish_dynamic_clause_in_module(temp_v!(1), temp_v!(2), temp_v!(3))
-            }
-            DynamicTransactionType::ModuleAssert(place) => {
-                self.recompile_dynamic_predicate_in_module(place)
-            }
-            DynamicTransactionType::ModuleRetract => {
-                self.retract_from_dynamic_predicate_in_module()
-            }
-            DynamicTransactionType::Retract => {
-                self.retract_from_dynamic_predicate()
-            }
-        }
-
-        self.machine_st.p = CodePtr::Local(p);
-    }
-}
index 8f741f660a34c804d8cdbfe468529716f3f5d974..612742c98601bd95e1568ddf447f5cf67def3c6c 100644 (file)
@@ -168,6 +168,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
             &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())
             }
@@ -295,6 +298,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
             val @ HeapCellValue::Rational(_) => {
                 Addr::Con(self.push(val))
             }
+            val @ HeapCellValue::LoadStatePayload(_) => {
+                Addr::LoadStatePayload(self.push(val))
+            }
             val @ HeapCellValue::NamedStr(..) => {
                 Addr::Str(self.push(val))
             }
@@ -371,15 +377,6 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
         }
     }
 
-    #[inline]
-    pub(crate)
-    fn take(&mut self) -> Self {
-        HeapTemplate {
-            buf: self.buf.take(),
-            _marker: PhantomData,
-        }
-    }
-
     #[inline]
     pub(crate)
     fn truncate(&mut self, h: usize) {
@@ -479,9 +476,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
                             ("dir_entry", 1) => {
                                 extract_integer(s+1).map(LocalCodePtr::DirEntry)
                             }
-                            ("in_situ_dir_entry", 1) => {
-                                extract_integer(s+1).map(LocalCodePtr::InSituDirEntry)
-                            }
+                            /*
                             ("top_level", 2) => {
                                 if let Some(chunk_num) = extract_integer(s+1) {
                                     if let Some(p) = extract_integer(s+2) {
@@ -491,13 +486,10 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
 
                                 None
                             }
-                            ("user_goal_expansion", 1) => {
-                                extract_integer(s+1).map(LocalCodePtr::UserGoalExpansion)
-                            }
-                            ("user_term_expansion", 1) => {
-                                extract_integer(s+1).map(LocalCodePtr::UserTermExpansion)
+                            */
+                            _ => {
+                                None
                             }
-                            _ => None
                         }
                     }
                     _ => unreachable!()
@@ -508,8 +500,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
     }
 
     #[inline]
-    pub
-    fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
+    pub 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])
diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs
new file mode 100644 (file)
index 0000000..1d5526a
--- /dev/null
@@ -0,0 +1,918 @@
+use crate::machine::*;
+use crate::machine::machine_indices::*;
+use crate::machine::term_stream::*;
+
+use indexmap::IndexSet;
+
+use crate::ref_thread_local::RefThreadLocal;
+
+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,
+}
+
+pub(super)
+fn set_code_index(
+    retraction_info: &mut RetractionInfo,
+    compilation_target: &CompilationTarget,
+    key: PredicateKey,
+    code_index: &CodeIndex,
+    code_ptr: IndexPtr,
+) {
+    let record =
+        match compilation_target {
+            CompilationTarget::User => {
+                if IndexPtr::Undefined == code_index.get() {
+                    code_index.set(code_ptr);
+                    RetractionRecord::AddedUserPredicate(key)
+                } else {
+                    // TODO: emit warning about overwriting previous record
+                    let replaced = code_index.replace(code_ptr);
+                    RetractionRecord::ReplacedUserPredicate(key, replaced)
+                }
+            }
+            CompilationTarget::Module(ref module_name) => {
+                if IndexPtr::Undefined == code_index.get() {
+                    code_index.set(code_ptr);
+                    RetractionRecord::AddedModulePredicate(module_name.clone(), key)
+                } else {
+                    // TODO: emit warning about overwriting previous record
+                    let replaced = code_index.replace(code_ptr);
+                    RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, replaced)
+                }
+            }
+        };
+
+    retraction_info.push_record(record);
+}
+
+fn add_op_decl_as_module_export(
+    module_op_dir: &mut OpDir,
+    compilation_target: &CompilationTarget,
+    retraction_info: &mut RetractionInfo,
+    wam_op_dir: &mut OpDir,
+    module_op_exports: &mut ModuleOpExports,
+    op_decl: &OpDecl,
+) {
+    /*
+    insert the operator at top-level so it can
+    inform the parser. it will be retracted
+    from the user-level op_dir when the load
+    succeeds.
+    */
+
+    match op_decl.insert_into_op_dir(wam_op_dir) {
+        Some((prec, spec)) => {
+            retraction_info.push_record(
+                RetractionRecord::ReplacedUserOp(op_decl.clone(), prec, spec)
+            );
+
+            module_op_exports.push((op_decl.clone(), Some((prec, spec))));
+        }
+        None => {
+            retraction_info.push_record(
+                RetractionRecord::AddedUserOp(op_decl.clone())
+            );
+
+            module_op_exports.push((op_decl.clone(), None));
+        }
+    }
+
+    add_op_decl(retraction_info, compilation_target, module_op_dir, op_decl);
+}
+
+pub(super)
+fn add_op_decl(
+    retraction_info: &mut RetractionInfo,
+    compilation_target: &CompilationTarget,
+    op_dir: &mut OpDir,
+    op_decl: &OpDecl,
+) {
+    match op_decl.insert_into_op_dir(op_dir) {
+        Some((prec, spec)) => {
+            match &compilation_target {
+                CompilationTarget::User => {
+                    retraction_info.push_record(
+                        RetractionRecord::ReplacedUserOp(op_decl.clone(), prec, spec),
+                    );
+                }
+                CompilationTarget::Module(ref module_name) => {
+                    retraction_info.push_record(
+                        RetractionRecord::ReplacedModuleOp(
+                            module_name.clone(), op_decl.clone(), prec, spec,
+                        ),
+                    );
+                }
+            }
+        }
+        None => {
+            match &compilation_target {
+                CompilationTarget::User => {
+                    retraction_info.push_record(
+                        RetractionRecord::AddedUserOp(op_decl.clone()),
+                    );
+                }
+                CompilationTarget::Module(ref module_name) => {
+                    retraction_info.push_record(
+                        RetractionRecord::AddedModuleOp(module_name.clone(), op_decl.clone()),
+                    );
+                }
+            }
+        }
+    }
+}
+
+pub(super)
+fn import_module_exports(
+    retraction_info: &mut RetractionInfo,
+    compilation_target: &CompilationTarget,
+    imported_module: &Module,
+    code_dir: &mut CodeDir,
+    op_dir: &mut OpDir,
+    meta_predicates: &mut MetaPredicateDir,
+) {
+    for export in imported_module.module_decl.exports.iter() {
+        match export {
+            ModuleExport::PredicateKey((ref name, arity)) => {
+                let key = (name.clone(), *arity);
+
+                if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
+                    meta_predicates.insert(key.clone(), meta_specs.clone());
+                }
+
+                if let Some(src_code_index) = imported_module.code_dir.get(&key) {
+                    let target_code_index = code_dir
+                        .entry(key.clone())
+                        .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                        .clone();
+
+                    set_code_index(
+                        retraction_info,
+                        compilation_target,
+                        key,
+                        &target_code_index,
+                        src_code_index.get(),
+                    );
+                } else {
+                    unreachable!()
+                }
+            }
+            ModuleExport::OpDecl(ref op_decl) => {
+                add_op_decl(
+                    retraction_info,
+                    compilation_target,
+                    op_dir,
+                    op_decl,
+                );
+            }
+        }
+    }
+}
+
+fn import_module_exports_into_module(
+    retraction_info: &mut RetractionInfo,
+    compilation_target: &CompilationTarget,
+    imported_module: &Module,
+    code_dir: &mut CodeDir,
+    op_dir: &mut OpDir,
+    meta_predicates: &mut MetaPredicateDir,
+    wam_op_dir: &mut OpDir,
+    module_op_exports: &mut ModuleOpExports
+) {
+    for export in imported_module.module_decl.exports.iter() {
+        match export {
+            ModuleExport::PredicateKey((ref name, arity)) => {
+                let key = (name.clone(), *arity);
+
+                if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
+                    meta_predicates.insert(key.clone(), meta_specs.clone());
+                }
+
+                if let Some(src_code_index) = imported_module.code_dir.get(&key) {
+                    let target_code_index = code_dir
+                        .entry(key.clone())
+                        .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                        .clone();
+
+                    set_code_index(
+                        retraction_info,
+                        compilation_target,
+                        key,
+                        &target_code_index,
+                        src_code_index.get(),
+                    );
+                } else {
+                    unreachable!()
+                }
+            }
+            ModuleExport::OpDecl(ref op_decl) => {
+                add_op_decl_as_module_export(
+                    op_dir,
+                    compilation_target,
+                    retraction_info,
+                    wam_op_dir,
+                    module_op_exports,
+                    op_decl,
+                );
+            }
+        }
+    }
+}
+
+
+fn import_qualified_module_exports(
+    retraction_info: &mut RetractionInfo,
+    compilation_target: &CompilationTarget,
+    imported_module: &Module,
+    exports: &IndexSet<ModuleExport>,
+    code_dir: &mut CodeDir,
+    op_dir: &mut OpDir,
+) {
+    for export in imported_module.module_decl.exports.iter() {
+        if !exports.contains(export) {
+            continue;
+        }
+
+        match export {
+            ModuleExport::PredicateKey((ref name, arity)) => {
+                let key = (name.clone(), *arity);
+
+                if let Some(src_code_index) = imported_module.code_dir.get(&key) {
+                    let target_code_index = code_dir
+                        .entry(key.clone())
+                        .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                        .clone();
+
+                    set_code_index(
+                        retraction_info,
+                        compilation_target,
+                        key,
+                        &target_code_index,
+                        src_code_index.get(),
+                    );
+                } else {
+                    unreachable!()
+                }
+            }
+            ModuleExport::OpDecl(ref op_decl) => {
+                add_op_decl(
+                    retraction_info,
+                    compilation_target,
+                    op_dir,
+                    op_decl,
+                );
+            }
+        }
+    }
+}
+
+fn import_qualified_module_exports_into_module(
+    retraction_info: &mut RetractionInfo,
+    compilation_target: &CompilationTarget,
+    imported_module: &Module,
+    exports: &IndexSet<ModuleExport>,
+    code_dir: &mut CodeDir,
+    op_dir: &mut OpDir,
+    wam_op_dir: &mut OpDir,
+    module_op_exports: &mut ModuleOpExports,
+) {
+    for export in imported_module.module_decl.exports.iter() {
+        if !exports.contains(export) {
+            continue;
+        }
+
+        match export {
+            ModuleExport::PredicateKey((ref name, arity)) => {
+                let key = (name.clone(), *arity);
+
+                if let Some(src_code_index) = imported_module.code_dir.get(&key) {
+                    let target_code_index = code_dir
+                        .entry(key.clone())
+                        .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                        .clone();
+
+                    set_code_index(
+                        retraction_info,
+                        compilation_target,
+                        key,
+                        &target_code_index,
+                        src_code_index.get(),
+                    );
+                } else {
+                    unreachable!()
+                }
+            }
+            ModuleExport::OpDecl(ref op_decl) => {
+                add_op_decl_as_module_export(
+                    op_dir,
+                    compilation_target,
+                    retraction_info,
+                    wam_op_dir,
+                    module_op_exports,
+                    op_decl,
+                );
+            }
+        }
+    }
+}
+
+impl<'a> LoadState<'a> {
+    #[inline]
+    pub(super)
+    fn increment_clause_assert_margin(&mut self, incr: usize) {
+        match &self.compilation_target {
+            CompilationTarget::User => {
+            }
+            CompilationTarget::Module(ref module_name) => {
+                self.retraction_info.push_record(
+                    RetractionRecord::IncreasedClauseAssertMargin(
+                        module_name.clone(),
+                        incr,
+                    ),
+                );
+
+                self.wam.indices.modules.get_mut(module_name)
+                    .map(|module| module.clause_assert_margin += incr);
+            }
+        }
+    }
+
+    #[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);
+
+            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);
+            }
+        }
+    }
+
+    fn get_or_insert_local_code_index(
+        &mut self,
+        module_name: ClauseName,
+        key: PredicateKey,
+    ) -> CodeIndex {
+        match self.wam.indices.modules.get_mut(&module_name) {
+            Some(ref mut module) => {
+                module.code_dir
+                    .entry(key)
+                    .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                    .clone()
+            }
+            None => {
+                let mut module = Module::new(
+                    ModuleDecl { name: module_name.clone(), exports: vec![] },
+                    ListingSource::DynamicallyGenerated,
+                );
+
+                let code_index = module.code_dir
+                    .entry(key)
+                    .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                    .clone();
+
+                self.retraction_info.push_record(
+                    RetractionRecord::AddedModule(module_name.clone()),
+                );
+
+                self.wam.indices.modules.insert(module_name, module);
+                code_index
+            }
+        }
+    }
+
+    pub(super)
+    fn get_or_insert_code_index(&mut self, key: PredicateKey) -> CodeIndex {
+        match self.compilation_target.clone() {
+            CompilationTarget::User => {
+                self.wam.indices.code_dir
+                    .entry(key)
+                    .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                    .clone()
+            }
+            CompilationTarget::Module(module_name) => {
+                self.get_or_insert_local_code_index(module_name, key)
+            }
+        }
+    }
+
+    pub(super)
+    fn get_or_insert_qualified_code_index(
+        &mut self,
+        module_name: ClauseName,
+        key: PredicateKey,
+    ) -> CodeIndex {
+        if module_name.as_str() == "user" {
+            return self.wam.indices.code_dir
+                .entry(key)
+                .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
+                .clone();
+        } else {
+            self.get_or_insert_local_code_index(module_name, key)
+        }
+    }
+
+    #[inline]
+    pub(super)
+    fn add_extensible_predicate(&mut self, key: PredicateKey, skeleton: PredicateSkeleton) {
+        match &self.compilation_target {
+            CompilationTarget::User => {
+                self.wam.indices.extensible_predicates.insert(key.clone(), skeleton);
+
+                self.retraction_info.push_record(
+                    RetractionRecord::AddedUserExtensiblePredicate(key),
+                );
+            }
+            CompilationTarget::Module(ref module_name) => {
+                if let Some(module) = self.wam.indices.modules.get_mut(module_name) {
+                    module.extensible_predicates.insert(key.clone(), skeleton);
+
+                    self.retraction_info.push_record(
+                        RetractionRecord::AddedModuleExtensiblePredicate(module_name.clone(), key),
+                    );
+                } else {
+                    unreachable!()
+                }
+            }
+        }
+    }
+
+    pub(super)
+    fn add_op_decl(&mut self, op_decl: &OpDecl) {
+        match &self.compilation_target {
+            CompilationTarget::User => {
+                add_op_decl(
+                    &mut self.retraction_info,
+                    &self.compilation_target,
+                    &mut self.wam.indices.op_dir,
+                    op_decl,
+                );
+            }
+            CompilationTarget::Module(ref module_name) => {
+                match self.wam.indices.modules.get_mut(module_name) {
+                    Some(ref mut module) => {
+                        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,
+                            op_decl,
+                        );
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
+            }
+        }
+    }
+
+    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));
+                ClauseType::Named(name, arity, idx)
+            }
+            ClauseType::Op(name, fixity, _) => {
+                let idx = self.get_or_insert_code_index((name.clone(), arity));
+                ClauseType::Op(name, fixity, idx)
+            }
+            ct => {
+                ct
+            }
+        }
+    }
+
+    pub(super)
+    fn get_qualified_clause_type(
+        &mut self,
+        module_name: ClauseName,
+        name: ClauseName,
+        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);
+                let idx = self.get_or_insert_qualified_code_index(module_name, key);
+
+                ClauseType::Op(name, fixity, idx)
+            }
+            ct => {
+                ct
+            }
+        }
+    }
+
+    #[inline]
+    pub(super)
+    fn module_name(&self) -> ClauseName {
+        match self.compilation_target {
+            CompilationTarget::User => {
+                clause_name!("user")
+            }
+            CompilationTarget::Module(ref module_name) => {
+                module_name.clone()
+            }
+        }
+    }
+
+    pub(super)
+    fn add_meta_predicate_record(
+        &mut self,
+        module_name: ClauseName,
+        name: ClauseName,
+        meta_specs: Vec<MetaSpec>,
+    ) {
+        let arity = meta_specs.len();
+        let key = (name, arity);
+
+        match module_name.as_str() {
+            "user" => {
+                match self.wam.indices.meta_predicates.insert(key.clone(), meta_specs) {
+                    Some(old_meta_specs) => {
+                        self.retraction_info.push_record(
+                            RetractionRecord::ReplacedMetaPredicate(
+                                module_name.clone(), key.0, old_meta_specs,
+                            ),
+                        );
+                    }
+                    None => {
+                        self.retraction_info.push_record(
+                            RetractionRecord::AddedMetaPredicate(
+                                module_name.clone(), key,
+                            )
+                        );
+                    }
+                }
+            }
+            _ => {
+                match self.wam.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(
+                                    RetractionRecord::ReplacedMetaPredicate(
+                                        module_name.clone(), key.0, old_meta_specs,
+                                    ),
+                                );
+                            }
+                            None => {
+                                self.retraction_info.push_record(
+                                    RetractionRecord::AddedMetaPredicate(
+                                        module_name.clone(), key,
+                                    )
+                                );
+                            }
+                        }
+                    }
+                    None => {
+                        let module_decl = ModuleDecl {
+                            name: module_name.clone(),
+                            exports: vec![],
+                        };
+
+                        let listing_src = ListingSource::DynamicallyGenerated;
+                        let mut module = Module::new(module_decl, listing_src);
+
+                        module.meta_predicates.insert(key.clone(), meta_specs);
+
+                        self.retraction_info.push_record(
+                            RetractionRecord::AddedMetaPredicate(
+                                module_name.clone(), key,
+                            )
+                        );
+
+                        self.retraction_info.push_record(
+                            RetractionRecord::AddedModule(module_name.clone()),
+                        );
+
+                        self.wam.indices.modules.insert(module_name, module);
+                    }
+                }
+            }
+        }
+    }
+
+    fn import_builtins_in_module(
+        &mut self,
+        code_dir: &mut CodeDir,
+        op_dir: &mut OpDir,
+        meta_predicates: &mut MetaPredicateDir,
+    ) {
+        if let Some(builtins) = self.wam.indices.modules.get(&clause_name!("builtins")) {
+            import_module_exports(
+                &mut self.retraction_info,
+                &self.compilation_target,
+                builtins,
+                code_dir,
+                op_dir,
+                meta_predicates,
+            );
+        }
+    }
+
+    pub(crate)
+    fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) {
+        let module_name = module_decl.name.clone();
+
+        let mut module =
+            match self.wam.indices.modules.remove(&module_name) {
+                Some(mut module) => {
+                    let old_module_decl = mem::replace(&mut module.module_decl, module_decl);
+
+                    self.retraction_info.push_record(
+                        RetractionRecord::ReplacedModule(
+                            old_module_decl, listing_src.clone(),
+                        ),
+                    );
+
+                    module.listing_src = listing_src;
+                    module
+                }
+                None => {
+                    self.retraction_info.push_record(
+                        RetractionRecord::AddedModule(module_name.clone()),
+                    );
+
+                    Module::new(module_decl, listing_src)
+                }
+            };
+
+        self.import_builtins_in_module(
+            &mut module.code_dir,
+            &mut module.op_dir,
+            &mut module.meta_predicates,
+        );
+
+        for export in &module.module_decl.exports {
+            if let ModuleExport::OpDecl(ref op_decl) = export {
+                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,
+                    op_decl,
+                );
+            }
+        }
+
+        if let Some(load_context) = self.wam.load_contexts.last_mut() {
+            load_context.module = module_name.clone();
+        }
+
+        self.wam.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 {
+                CompilationTarget::User => {
+                    import_module_exports(
+                        &mut self.retraction_info,
+                        &self.compilation_target,
+                        &module,
+                        &mut self.wam.indices.code_dir,
+                        &mut self.wam.indices.op_dir,
+                        &mut self.wam.indices.meta_predicates,
+                    );
+                }
+                CompilationTarget::Module(ref defining_module_name) => {
+                    match self.wam.indices.modules.get_mut(defining_module_name) {
+                        Some(ref mut target_module) => {
+                            import_module_exports_into_module(
+                                &mut self.retraction_info,
+                                &self.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,
+                            );
+                        }
+                        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);
+                            return Err(SessionError::ModuleCannotImportSelf(module_name));
+                        }
+                    }
+                }
+            }
+
+            self.wam.indices.modules.insert(module_name, module);
+            Ok(())
+        } else {
+            Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
+        }
+    }
+
+    fn import_qualified_module(
+        &mut self,
+        module_name: ClauseName,
+        exports: IndexSet<ModuleExport>,
+    ) -> Result<(), SessionError> {
+        if let Some(module) = self.wam.indices.modules.remove(&module_name) {
+            match &self.compilation_target {
+                CompilationTarget::User => {
+                    import_qualified_module_exports(
+                        &mut self.retraction_info,
+                        &self.compilation_target,
+                        &module,
+                        &exports,
+                        &mut self.wam.indices.code_dir,
+                        &mut self.wam.indices.op_dir,
+                    );
+                }
+                CompilationTarget::Module(ref defining_module_name) => {
+                    match self.wam.indices.modules.get_mut(defining_module_name) {
+                        Some(ref mut target_module) => {
+                            import_qualified_module_exports_into_module(
+                                &mut self.retraction_info,
+                                &self.compilation_target,
+                                &module,
+                                &exports,
+                                &mut target_module.code_dir,
+                                &mut target_module.op_dir,
+                                &mut self.wam.indices.op_dir,
+                                &mut self.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);
+                            return Err(SessionError::ModuleCannotImportSelf(module_name));
+                        }
+                    }
+                }
+            }
+
+            self.wam.indices.modules.insert(module_name, module);
+            Ok(())
+        } else {
+            Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
+        }
+    }
+
+    pub(crate)
+    fn use_module(&mut self, module_src: ModuleSource) -> Result<(), SessionError> {
+        let (stream, listing_src) =
+            match module_src {
+                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),
+                     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 ListingSource::DynamicallyGenerated = &module.listing_src {
+                                    (Stream::from(*code), ListingSource::User)
+                                } else {
+                                    return self.import_module(library);
+                                }
+                            } else {
+                                (Stream::from(*code), ListingSource::User)
+                            }
+                        }
+                        None => {
+                            return self.import_module(library);
+                        }
+                    }
+                }
+            };
+
+        let compilation_target = {
+            let stream = &mut parsing_stream(stream)?;
+
+            let ts = BootstrappingTermStream::from_prolog_stream(
+                stream,
+                self.wam.machine_st.atom_tbl.clone(),
+                self.wam.machine_st.flags,
+                listing_src,
+            );
+
+            let subloader = Loader::new(ts, self.wam);
+            subloader.load()?
+        };
+
+        match compilation_target {
+            CompilationTarget::User => {
+                // nothing to do.
+                Ok(())
+            }
+            CompilationTarget::Module(module_name) => {
+                self.import_module(module_name)
+            }
+        }
+    }
+
+    pub(crate)
+    fn use_qualified_module(
+        &mut self,
+        module_src: ModuleSource,
+        exports: IndexSet<ModuleExport>,
+    ) -> Result<(), SessionError> {
+        let (stream, listing_src) =
+            match module_src {
+                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),
+                     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) {
+                                return self.import_qualified_module(library, exports);
+                            } else {
+                                (Stream::from(*code), ListingSource::User)
+                            }
+                        }
+                        None => {
+                            return self.import_qualified_module(library, exports);
+                        }
+                    }
+                }
+            };
+
+        let compilation_target = {
+            let stream = &mut parsing_stream(stream)?;
+
+            let ts = BootstrappingTermStream::from_prolog_stream(
+                stream,
+                self.wam.machine_st.atom_tbl.clone(),
+                self.wam.machine_st.flags,
+                listing_src,
+            );
+
+            let subloader = Loader::new(ts, self.wam);
+            subloader.load()?
+        };
+
+        match compilation_target {
+            CompilationTarget::User => {
+                // nothing to do.
+                Ok(())
+            }
+            CompilationTarget::Module(module_name) => {
+                self.import_qualified_module(module_name, exports)
+            }
+        }
+    }
+
+    #[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
new file mode 100644 (file)
index 0000000..a670489
--- /dev/null
@@ -0,0 +1,1708 @@
+use prolog_parser::ast::*;
+
+use crate::forms::*;
+use crate::indexing::*;
+use crate::machine::*;
+use crate::machine::load_state::*;
+use crate::machine::machine_indices::*;
+use crate::machine::preprocessor::*;
+
+use indexmap::IndexSet;
+
+use std::cell::Cell;
+use std::convert::TryFrom;
+use std::rc::Rc;
+
+/*
+ * The loader compiles Prolog terms read from a TermStream instance,
+ * which may be incremental or monolithic. The monolithic term stream
+ * reads from a file. It's used only to bootstrap Scryer at
+ * start-up. Once Scryer is bootstrapped, all compilation and loading
+ * work is divided between loader.pl and loader.rs.
+ *
+ * loader.pl does a few high-level things more easily handled from
+ * Prolog that are not supported (or needed) during bootstrapping:
+ * term and goal expansion, loading modules from different streams,
+ * verifying certain kinds of declarations, perhaps (in the future?)
+ * compiling inline disjunctions.
+ *
+ * Since the loader can operate incrementally, it uses an intermittent
+ * structure to rebuild the loader between
+ * invocations. TopLevelBatchWorker needs access to a &'a mut Machine
+ * for as long as it lives, and we can't have copies of &'a mut
+ * Machine distributed among multiple owners.
+ *
+ * When loading a module, we modify the records of the WAM with the
+ * location of new predicates, with new meta-predicate information,
+ * new term and goal expansions, new dynamic clauses, etc. Should the
+ * loader fail later, all changes must be rolled back, restoring the
+ * WAM to its prior state. Retraction records describe individual changes
+ * made by the loader, and they may be used later.
+ */
+
+#[derive(Debug)]
+pub(crate) enum RetractionRecord {
+    AddedMetaPredicate(ClauseName, PredicateKey),
+    ReplacedMetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>),
+    AddedModule(ClauseName),
+    ReplacedModule(ModuleDecl, ListingSource),
+    AddedModuleDynamicPredicate(ClauseName, PredicateKey),
+    AddedModuleExtensiblePredicate(ClauseName, PredicateKey),
+    AppendedModuleExtensiblePredicate(ClauseName, PredicateKey),
+    PrependedModuleExtensiblePredicate(ClauseName, PredicateKey),
+    AddedModuleOp(ClauseName, OpDecl),
+    ReplacedModuleOp(ClauseName, OpDecl, usize, Specifier),
+    AddedModulePredicate(ClauseName, PredicateKey),
+    ReplacedModulePredicate(ClauseName, PredicateKey, IndexPtr),
+    AddedUserDynamicPredicate(PredicateKey),
+    AddedUserOp(OpDecl),
+    ReplacedUserOp(OpDecl, usize, Specifier),
+    AddedUserExtensiblePredicate(PredicateKey),
+    AppendedUserExtensiblePredicate(PredicateKey),
+    PrependedUserExtensiblePredicate(PredicateKey),
+    AddedUserPredicate(PredicateKey),
+    ReplacedUserPredicate(PredicateKey, IndexPtr),
+    AddedIndex(OptArgIndexKey, usize), //, Vec<usize>),
+    RemovedIndex(usize, OptArgIndexKey, usize),
+    ReplacedChoiceOffset(usize, usize),
+    AppendedTrustMe(usize, usize, bool),
+    ReplacedSwitchOnTermVarIndex(usize, usize),
+    ModifiedTryMeElse(usize, usize),
+    ModifiedRetryMeElse(usize, usize),
+    ModifiedRevJmpBy(usize, usize),
+    IncreasedClauseAssertMargin(ClauseName, usize),
+    SkeletonClauseClausesTruncateBack(CompilationTarget, PredicateKey, usize),
+    SkeletonClauseClausesTruncateFront(CompilationTarget, PredicateKey, usize),
+    SkeletonClausePopBack(CompilationTarget, PredicateKey),
+    SkeletonClausePopFront(CompilationTarget, PredicateKey),
+    SkeletonClauseTruncateBack(CompilationTarget, PredicateKey, usize),
+    SkeletonClauseStartReplaced(CompilationTarget, PredicateKey, usize, usize),
+    RemovedDynamicSkeletonClause(CompilationTarget, PredicateKey, usize, ClauseIndexInfo, usize),
+    ReplacedIndexingLine(usize, Vec<IndexingLine>),
+}
+
+/*
+ * Retractions to be performed on rollback are represented by
+ * individual records, and the original extent of the code vector of
+ * the IndexStore, of which there are several (one per module).  The
+ * "extent" of a code vector is its length prior to an attempted
+ * module load. The only code vector of the WAM's IndexStore, "code",
+ * is shared by all modules, including the default "user" module.
+ */
+
+pub(super) struct RetractionInfo {
+    orig_code_extent: usize,
+    records: Vec<RetractionRecord>,
+}
+
+impl RetractionInfo {
+    #[inline]
+    pub(super)
+    fn new(orig_code_extent: usize) -> Self {
+        Self {
+            orig_code_extent,
+            records: vec![], //BTreeMap::new(),
+        }
+    }
+
+    #[inline]
+    pub(crate)
+    fn push_record(&mut self, record: RetractionRecord) {
+        self.records.push(record);
+    }
+
+    #[inline]
+    pub(crate)
+    fn reset(&mut self, code_len: usize) -> Self {
+        let orig_code_extent = self.orig_code_extent;
+        self.orig_code_extent = code_len;
+
+        Self {
+            orig_code_extent,
+            records: mem::replace(&mut self.records, vec![]), //BTreeMap::new()),
+        }
+    }
+}
+
+impl<'a> Drop for LoadState<'a> {
+    fn drop(&mut self) {
+        while let Some(record) = self.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 self.wam.indices.modules.get_mut(&target_module_name) {
+                                Some(ref mut module) => {
+                                    module.meta_predicates.remove(&key);
+                                }
+                                _ => {
+                                    unreachable!()
+                                }
+                            }
+                        }
+                    }
+                }
+                RetractionRecord::ReplacedMetaPredicate(target_module_name, name, meta_specs) => {
+                    match target_module_name.as_str() {
+                        "user" => {
+                            self.wam.indices.meta_predicates.insert(
+                                (name, meta_specs.len()),
+                                meta_specs,
+                            );
+                        }
+                        _ => {
+                            match self.wam.indices.modules.get_mut(&target_module_name) {
+                                Some(ref mut module) => {
+                                    module.meta_predicates.insert(
+                                        (name, meta_specs.len()),
+                                        meta_specs,
+                                    );
+                                }
+                                _ => {
+                                    unreachable!()
+                                }
+                            }
+                        }
+                    }
+                }
+                RetractionRecord::AddedModule(module_name) => {
+                    self.wam.indices.modules.remove(&module_name);
+                }
+                RetractionRecord::ReplacedModule(module_decl, listing_src) => {
+                    match self.wam.indices.modules.get_mut(&module_decl.name) {
+                        Some(ref mut module) => {
+                            module.module_decl = module_decl;
+                            module.listing_src = listing_src;
+                        }
+                        _ => {
+                            unreachable!()
+                        }
+                    }
+                }
+                RetractionRecord::AddedModuleDynamicPredicate(module_name, key) => {
+                    match self.wam.indices.modules.get_mut(&module_name) {
+                        Some(ref mut module) => {
+                            module.extensible_predicates.get_mut(&key)
+                                  .map(|skeleton| {
+                                      skeleton.is_dynamic = false;
+                                  });
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::AddedModuleExtensiblePredicate(module_name, key) => {
+                    self.wam.indices.remove_predicate_skeleton(
+                        &CompilationTarget::Module(module_name),
+                        &key,
+                    );
+                }
+                RetractionRecord::AppendedModuleExtensiblePredicate(module_name, key) => {
+                    self.wam.indices.get_predicate_skeleton(
+                        &CompilationTarget::Module(module_name),
+                        &key,
+                    ).map(|skeleton| {
+                        skeleton.clauses.pop_back();
+                    });
+                }
+                RetractionRecord::PrependedModuleExtensiblePredicate(module_name, key) => {
+                    self.wam.indices.get_predicate_skeleton(
+                        &CompilationTarget::Module(module_name),
+                        &key,
+                    ).map(|skeleton| {
+                        skeleton.clauses.pop_front();
+                    });
+                }
+                RetractionRecord::AddedModuleOp(module_name, mut op_decl) => {
+                    match self.wam.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) {
+                        Some(ref mut module) => {
+                            op_decl.prec = prec;
+                            op_decl.spec = spec;
+                            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) {
+                        Some(ref mut module) => {
+                            module.code_dir.remove(&key);
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::ReplacedModulePredicate(module_name, key, old_code_idx) => {
+                    match self.wam.indices.modules.get_mut(&module_name) {
+                        Some(ref mut module) => {
+                            module.code_dir
+                                .get_mut(&key)
+                                .map(|code_idx| code_idx.replace(old_code_idx));
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::AddedUserDynamicPredicate(key) => {
+                    self.wam.indices.extensible_predicates.get_mut(&key)
+                        .map(|skeleton| {
+                            skeleton.is_dynamic = false;
+                        });
+                }
+                RetractionRecord::AddedUserExtensiblePredicate(key) => {
+                    self.wam.indices.remove_predicate_skeleton(
+                        &CompilationTarget::User,
+                        &key,
+                    );
+                }
+                RetractionRecord::AppendedUserExtensiblePredicate(key) => {
+                    self.wam.indices.get_predicate_skeleton(
+                        &CompilationTarget::User,
+                        &key,
+                    ).map(|skeleton| {
+                        skeleton.clauses.pop_back();
+                    });
+                }
+                RetractionRecord::PrependedUserExtensiblePredicate(key) => {
+                    self.wam.indices.get_predicate_skeleton(
+                        &CompilationTarget::User,
+                        &key,
+                    ).map(|skeleton| {
+                        skeleton.clauses.pop_front();
+                    });
+                }
+                RetractionRecord::AddedUserOp(mut op_decl) => {
+                    op_decl.remove(&mut self.wam.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::AddedUserPredicate(key) => {
+                    self.wam.indices.code_dir.remove(&key);
+                }
+                RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => {
+                    self.wam.indices.code_dir
+                        .get_mut(&key)
+                        .map(|code_idx| code_idx.replace(old_code_idx));
+                }
+                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
+                                }
+                                _ => {
+                                    unreachable!()
+                                }
+                            };
+
+                        match index_key {
+                            OptArgIndexKey::Constant(_, index_loc, constant, overlapping_constants) => {
+                                remove_constant_indices(
+                                    &constant,
+                                    &overlapping_constants,
+                                    indexing_code,
+                                    clause_loc - index_loc, // WAS: &inner_index_locs,
+                                );
+                            }
+                            OptArgIndexKey::Structure(_, index_loc, name, arity) => {
+                                remove_structure_index(
+                                    &name,
+                                    arity,
+                                    indexing_code,
+                                    clause_loc - index_loc, // WAS: &inner_index_locs,
+                                );
+                            }
+                            OptArgIndexKey::List(_, index_loc) => {
+                                remove_list_index(
+                                    indexing_code,
+                                    clause_loc - index_loc, // WAS: &inner_index_locs,
+                                );
+                            }
+                            OptArgIndexKey::None => {
+                                unreachable!();
+                            }
+                        }
+                    }
+                }
+                RetractionRecord::RemovedIndex(_index_loc, _index_key, _clause_loc) => {
+                    // TODO: this needs to be fixed! RemovedIndex doesn't provide
+                    // enough information to restore the index. Correct that, then
+                    // 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)) => {
+                            *o = offset;
+                        }
+                        _ => {
+                            unreachable!();
+                        }
+                    }
+                }
+                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!();
+                        }
+                    }
+                }
+                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] {
+                                IndexingLine::Indexing(
+                                    IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)
+                                ) => {
+                                    *v = old_v;
+                                }
+                                _ => {
+                                }
+                            }
+                        }
+                        _ => {
+                        }
+                    }
+                }
+                RetractionRecord::ModifiedTryMeElse(instr_loc, o) => {
+                    self.wam.code_repo.code[instr_loc] =
+                        Line::Choice(ChoiceInstruction::TryMeElse(o));
+                }
+                RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => {
+                    self.wam.code_repo.code[instr_loc] =
+                        Line::Choice(ChoiceInstruction::RetryMeElse(o));
+                }
+                RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => {
+                    self.wam.code_repo.code[instr_loc] =
+                        Line::Control(ControlInstruction::RevJmpBy(o));
+                }
+                RetractionRecord::IncreasedClauseAssertMargin(module_name, incr) => {
+                    if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
+                        module.clause_assert_margin -= incr;
+                    }
+                }
+                RetractionRecord::SkeletonClauseClausesTruncateFront(compilation_target, key, len) => {
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &key,
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clause_clause_locs.truncate_front(len);
+                        }
+                        None => {
+                        }
+                    }
+
+                    let compilation_target =
+                        match compilation_target {
+                            CompilationTarget::User => {
+                                CompilationTarget::Module(clause_name!("builtins"))
+                            }
+                            _ => {
+                                compilation_target
+                            }
+                        };
+
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &(clause_name!("$clause"), 2),
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clause_clause_locs.truncate_front(len);
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::SkeletonClauseClausesTruncateBack(compilation_target, key, len) => {
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &key,
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clause_clause_locs.truncate_back(len);
+                        }
+                        None => {
+                        }
+                    }
+
+                    let compilation_target =
+                        match compilation_target {
+                            CompilationTarget::User => {
+                                CompilationTarget::Module(clause_name!("builtins"))
+                            }
+                            _ => {
+                                compilation_target
+                            }
+                        };
+
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &(clause_name!("$clause"), 2),
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clause_clause_locs.truncate_back(len);
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::SkeletonClausePopBack(compilation_target, key) => {
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &key,
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clauses.pop_back();
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::SkeletonClausePopFront(compilation_target, key) => {
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &key,
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clauses.pop_front();
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => {
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &key,
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clauses.truncate_back(len);
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::SkeletonClauseStartReplaced(
+                    compilation_target,
+                    key,
+                    target_pos,
+                    clause_start,
+                ) => {
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &key,
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clauses[target_pos].clause_start = clause_start;
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::RemovedDynamicSkeletonClause(
+                    compilation_target,
+                    key,
+                    target_pos,
+                    clause_index_info,
+                    clause_clause_loc,
+                ) => {
+                    match self.wam.indices.get_predicate_skeleton(
+                        &compilation_target,
+                        &key,
+                    ) {
+                        Some(skeleton) => {
+                            skeleton.clause_clause_locs.insert(target_pos, clause_clause_loc);
+                            skeleton.clauses.insert(target_pos, clause_index_info);
+                        }
+                        None => {
+                        }
+                    }
+                }
+                RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => {
+                    self.wam.code_repo.code[index_loc] = Line::IndexingCode(indexing_code);
+                }
+            }
+        }
+        // TODO: necessary? unnecessary?
+        // self.wam.code_repo.code.truncate(self.retraction_info.orig_code_extent);
+    }
+}
+
+#[derive(Debug, Clone)]
+pub 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)
+    }
+}
+
+pub(crate) struct Loader<'a, TermStream> {
+    pub(super) load_state: LoadState<'a>,
+    pub(super) predicates: Vec<PredicateClause>,
+    pub(super) clause_clauses: Vec<(Term, Term)>,
+    term_stream: TermStream,
+    pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
+    pub(super) preprocessor: Preprocessor,
+}
+
+impl<'a, TS: TermStream> Loader<'a, TS> {
+    #[inline]
+    pub(super)
+    fn new(term_stream: TS, wam: &'a mut Machine) -> Self {
+        let flags = wam.machine_st.flags;
+        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(),
+            preprocessor: Preprocessor::new(flags),
+            predicates: vec![],
+            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 tl = self.preprocessor.try_term_to_tl(
+                &mut self.load_state,
+                term,
+                CutContext::BlocksCuts,
+            )?;
+
+            match tl {
+                TopLevel::Fact(fact) =>
+                    self.predicates.push(PredicateClause::Fact(fact)),
+                TopLevel::Rule(rule) =>
+                    self.predicates.push(PredicateClause::Rule(rule)),
+                TopLevel::Predicate(pred) =>
+                    self.predicates.extend(pred),
+                TopLevel::Declaration(decl) =>
+                    return Ok(Some(decl)),
+                TopLevel::Query(_) =>
+                    return Err(SessionError::QueryCannotBeDefinedAsFact),
+            }
+        }
+
+        Ok(None)
+    }
+
+    pub(super)
+    fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> {
+        match decl {
+            Declaration::Dynamic(name, arity) => {
+                self.add_dynamic_predicate(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.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,
+        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 export_list = setup_module_export_list(export_list, atom_tbl)?;
+
+        Ok(export_list.into_iter().collect())
+    }
+
+    fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
+        match term {
+            Term::Clause(_, turnstile, mut terms, _)
+                if turnstile.as_str() == ":-" && terms.len() == 2 => {
+                    let body = *terms.pop().unwrap();
+                    let head = *terms.pop().unwrap();
+
+                    self.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));
+            }
+            _ => {
+                return Err(CompilationError::InadmissibleFact);
+            }
+        }
+
+        Ok(())
+    }
+
+    fn add_dynamic_predicate(&mut self, name: ClauseName, arity: usize) {
+        let key = (name, arity);
+
+        match &self.load_state.compilation_target {
+            CompilationTarget::User => {
+                match self.load_state.wam.indices.extensible_predicates.get_mut(&key) {
+                    Some(ref mut skeleton) => {
+                        if !skeleton.is_dynamic {
+                            skeleton.is_dynamic = true;
+
+                            self.load_state.retraction_info.push_record(
+                                RetractionRecord::AddedUserDynamicPredicate(key.clone())
+                            );
+                        }
+                    }
+                    None => {
+                        self.load_state.wam.indices.extensible_predicates.insert(
+                            key.clone(),
+                            PredicateSkeleton::new().set_dynamic(true),
+                        );
+
+                        self.load_state.retraction_info.push_record(
+                            RetractionRecord::AddedUserExtensiblePredicate(key.clone())
+                        );
+                    }
+                }
+            }
+            CompilationTarget::Module(ref module_name) => {
+                match self.load_state.wam.indices.modules.get_mut(module_name) {
+                    Some(ref mut module) => {
+                        match module.extensible_predicates.get_mut(&key) {
+                            Some(ref mut skeleton) => {
+                                if !skeleton.is_dynamic {
+                                    skeleton.is_dynamic = true;
+
+                                    self.load_state.retraction_info.push_record(
+                                        RetractionRecord::AddedModuleDynamicPredicate(
+                                            module_name.clone(),
+                                            key.clone(),
+                                        ),
+                                    );
+                                }
+                            }
+                            None => {
+                                module.extensible_predicates.insert(
+                                    key.clone(),
+                                    PredicateSkeleton::new().set_dynamic(true),
+                                );
+
+                                self.load_state.retraction_info.push_record(
+                                    RetractionRecord::AddedModuleExtensiblePredicate(
+                                        module_name.clone(),
+                                        key.clone(),
+                                    ),
+                                );
+                            }
+                        }
+                    }
+                    None => {
+                        unreachable!();
+                    }
+                }
+            }
+        }
+
+        let code_index = self.load_state.get_or_insert_code_index(key.clone());
+
+        set_code_index(
+            &mut self.load_state.retraction_info,
+            &self.load_state.compilation_target,
+            key,
+            &code_index,
+            IndexPtr::DynamicUndefined,
+        );
+    }
+}
+
+impl Machine {
+    pub(crate)
+    fn use_module(&mut self) {
+        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!()
+                            }
+                        }
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
+            );
+
+        let (mut loader, evacuable_h) = 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)?;
+            } else {
+                loader.load_state.use_qualified_module(module_src, export_list)?;
+            }
+
+            LiveTermStream::evacuate(loader)
+        };
+
+        let result = use_module();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+
+    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)]
+            ))
+        );
+
+        if let Some(module) = self.indices.modules.get(&library) {
+            if let ListingSource::DynamicallyGenerated = module.listing_src {
+                self.machine_st.fail = true;
+                return;
+            }
+
+            let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2));
+
+            let import_module = || {
+                loader.load_state.import_module(library)?;
+                LiveTermStream::evacuate(loader)
+            };
+
+            let result = import_module();
+            self.restore_load_state_payload(result, evacuable_h);
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    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)]
+            ))
+        );
+
+        // 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 declare_module = || {
+            // let export_list = export_list?;
+            let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?;
+
+            let module_decl = ModuleDecl {
+                name: module_name,
+                exports: exports.into_iter().collect(),
+            };
+
+            loader.load_decl(Declaration::Module(module_decl))?;
+            LiveTermStream::evacuate(loader)
+        };
+
+        let result = declare_module();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+
+    pub(crate)
+    fn add_dynamic_predicate(&mut self) {
+        let predicate_name = atom_from!(
+            self.machine_st,
+            self.machine_st.store(self.machine_st.deref(
+                self.machine_st[temp_v!(1)]
+            ))
+        );
+
+        let arity =
+            self.machine_st.store(self.machine_st.deref(self.machine_st[temp_v!(2)]));
+
+        let arity =
+            match Number::try_from((arity, &self.machine_st.heap)) {
+                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()),
+                _ =>
+                    Err(SessionError::from(CompilationError::InvalidRuleHead))
+            };
+
+        let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3));
+
+        let add_dynamic_predicate = || {
+            loader.add_dynamic_predicate(predicate_name, arity?);
+            LiveTermStream::evacuate(loader)
+        };
+
+        let result = add_dynamic_predicate();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+
+    pub(crate)
+    fn add_term_expansion_clause(&mut self) {
+        let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2));
+
+        let add_clause = || {
+            let term = loader.read_term_from_heap(temp_v!(1))?;
+
+            loader.incremental_compile_clause(
+                (clause_name!("$term_expansion"), 2),
+                term,
+                CompilationTarget::User,
+                false,
+                AppendOrPrepend::Append,
+            )?;
+
+            LiveTermStream::evacuate(loader)
+        };
+
+        let result = add_clause();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+
+    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)]
+            ))
+        );
+
+        let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3));
+
+        let compilation_target =
+            match target_module_name.as_str() {
+                "user" => CompilationTarget::User,
+                _ => CompilationTarget::Module(target_module_name),
+            };
+
+        let add_clause = || {
+            let term = loader.read_term_from_heap(temp_v!(2))?;
+
+            loader.incremental_compile_clause(
+                (clause_name!("goal_expansion"), 2),
+                term,
+                compilation_target,
+                false, // backtracking inferences are counted by call_with_inference_limit.
+                AppendOrPrepend::Append,
+            )?;
+
+            LiveTermStream::evacuate(loader)
+        };
+
+        let result = add_clause();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+
+    pub(crate)
+    fn loader_from_heap_evacuable(&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!()
+                }
+            };
+
+        match load_state_payload {
+            HeapCellValue::LoadStatePayload(payload) => {
+                (Loader::from_load_state_payload(self, payload), evacuable_h)
+            }
+            _ => {
+                unreachable!()
+            }
+        }
+    }
+
+    #[inline]
+    pub(crate)
+    fn push_load_state_payload(&mut self) {
+        let payload = LoadStatePayload::new(self);
+        let addr = Addr::LoadStatePayload(
+            self.machine_st.heap.push(HeapCellValue::LoadStatePayload(payload))
+        );
+
+        self.machine_st.bind(self.machine_st[temp_v!(1)].as_var().unwrap(), addr);
+    }
+
+    #[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!()
+                }
+            };
+
+        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.
+            }
+        }
+    }
+
+    #[inline]
+    pub(crate)
+    fn pop_load_context(&mut self) {
+        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,
+                    "$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)]
+                ))
+            );
+
+        self.load_contexts.push(LoadContext::new(path.as_str(), stream));
+    }
+
+    pub(crate)
+    fn restore_load_state_payload(
+        &mut self,
+        result: Result<LoadStatePayload, SessionError>,
+        evacuable_h: usize,
+    ) {
+        match result {
+            Ok(payload) => {
+                self.machine_st.heap[evacuable_h] = HeapCellValue::LoadStatePayload(
+                    payload
+                );
+            }
+            Err(e) => {
+                self.throw_session_error(e, (clause_name!("load"), 1));
+            }
+        }
+    }
+
+    pub(crate)
+    fn clause_to_evacuable(&mut self) {
+        let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2));
+
+        let enqueue_term = || {
+            let term = loader.read_term_from_heap(temp_v!(1))?;
+
+            if let Some(predicate_name) = ClauseInfo::name(&term) {
+                let arity = ClauseInfo::arity(&term);
+
+                let is_dynamic =
+                    loader.load_state.wam.indices.get_predicate_skeleton(
+                        &loader.load_state.compilation_target,
+                        &(predicate_name, arity),
+                    ).map(|skeleton| skeleton.is_dynamic)
+                     .unwrap_or(false);
+
+                if is_dynamic {
+                    loader.add_clause_clause(term.clone())?;
+                }
+            }
+
+            loader.enqueue_term(term);
+            loader.load()
+        };
+
+        let result = enqueue_term();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+
+    pub(crate)
+    fn conclude_load(&mut self) {
+        let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1));
+
+        let compile_final_terms = || {
+            if !loader.predicates.is_empty() {
+                loader.compile_and_submit()?;
+            }
+
+            loader.load_state.remove_module_op_exports();
+            LiveTermStream::evacuate(loader)
+        };
+
+        let result = compile_final_terms();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+
+    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))
+            );
+
+            self.machine_st.unify(path_addr, self.machine_st[temp_v!(1)]);
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    pub(crate)
+    fn load_context_file(&mut self) {
+        if let Some(load_context) = self.load_contexts.last() {
+            if let Some(file_name) = load_context.path.file_name() {
+                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_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)]);
+                return;
+            }
+        }
+
+        self.machine_st.fail = true;
+    }
+
+    pub(crate)
+    fn load_context_directory(&mut self) {
+        if let Some(load_context) = self.load_contexts.last() {
+            if let Some(directory) = load_context.path.ancestors().next() {
+                let directory_str = directory.to_str().unwrap();
+                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)]);
+                return;
+            }
+        }
+
+        self.machine_st.fail = true;
+    }
+
+    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)]);
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    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(stream_addr, self.machine_st[temp_v!(1)]);
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    pub(crate)
+    fn compile_user_assert(&mut self, append_or_prepend: AppendOrPrepend) {
+        let key =
+            self.machine_st.read_predicate_key(
+                self.machine_st[temp_v!(3)],
+                self.machine_st[temp_v!(4)],
+            );
+
+        let compile_user_assert = || {
+            let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
+
+            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),
+                );
+
+            loader.incremental_compile_clause(
+                key.clone(),
+                asserted_clause,
+                CompilationTarget::User,
+                false,
+                append_or_prepend,
+            )?;
+
+            // if a new predicate was just created, make it dynamic.
+            loader.load_state.wam.indices.get_predicate_skeleton(
+                &loader.load_state.compilation_target,
+                &key,
+            ).map(|skeleton| skeleton.is_dynamic = true);
+
+            loader.compile_clause_clauses(key, std::iter::once((head, body)), append_or_prepend)?;
+
+            LiveTermStream::evacuate(loader)
+        };
+
+        match compile_user_assert() {
+            Ok(_) => {
+            }
+            Err(e) => {
+                let error_pi =
+                    match append_or_prepend {
+                        AppendOrPrepend::Append  => (clause_name!("assertz"), 1),
+                        AppendOrPrepend::Prepend => (clause_name!("asserta"), 1),
+                    };
+
+                self.throw_session_error(e, error_pi);
+            }
+        }
+    }
+
+    pub(crate)
+    fn retract_user_clause(&mut self) {
+        let key =
+            self.machine_st.read_predicate_key(
+                self.machine_st[temp_v!(1)],
+                self.machine_st[temp_v!(2)],
+            );
+
+        let target_pos =
+            self.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)) {
+                Ok(Number::Integer(n)) =>
+                    n.to_usize().unwrap(),
+                Ok(Number::Fixnum(n)) =>
+                    usize::try_from(n).unwrap(),
+                _ =>
+                    unreachable!()
+            };
+
+        let retract_user_clause = || {
+            let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
+            let clause_clause_loc = loader.load_state.retract_clause(key, target_pos);
+
+            let clause_assert_margin =
+                loader.load_state.wam.indices.modules.get(&clause_name!("builtins"))
+                      .map(|builtins| builtins.clause_assert_margin)
+                      .unwrap();
+
+            let target_pos =
+                match loader.load_state.wam.indices.get_predicate_skeleton(
+                    &CompilationTarget::Module(clause_name!("builtins")),
+                    &(clause_name!("$clause"), 2),
+                ) {
+                    Some(skeleton) => {
+                        let search_result =
+                            skeleton.clause_clause_locs[0 .. clause_assert_margin]
+                                    .binary_search_by(|loc| clause_clause_loc.cmp(&loc));
+
+                        let result =
+                            search_result.unwrap_or_else(|_| {
+                                skeleton.clause_clause_locs[clause_assert_margin ..]
+                                    .binary_search_by(|loc| loc.cmp(&clause_clause_loc))
+                                    .unwrap() + clause_assert_margin
+                            });
+
+                        if result < clause_assert_margin {
+                            loader.load_state.wam.indices.modules.get_mut(&clause_name!("builtins"))
+                                  .map(|builtins| builtins.clause_assert_margin -= 1);
+                        }
+
+                        result
+                    }
+                    None => {
+                        unreachable!();
+                    }
+                };
+
+
+            let compilation_target = mem::replace(
+                &mut loader.load_state.compilation_target,
+                CompilationTarget::Module(clause_name!("builtins")),
+            );
+
+            loader.load_state.retract_clause((clause_name!("$clause"), 2), target_pos);
+            loader.load_state.compilation_target = compilation_target;
+
+            LiveTermStream::evacuate(loader)
+        };
+
+        match retract_user_clause() {
+            Ok(_) => {
+            }
+            Err(e) => {
+                self.throw_session_error(e, (clause_name!("retract"), 1));
+            }
+        }
+    }
+
+    pub(crate)
+    fn meta_predicate_property(&mut self) {
+        let (predicate_name, arity) =
+            self.machine_st.read_predicate_key(
+                self.machine_st[temp_v!(1)],
+                self.machine_st[temp_v!(2)],
+            );
+
+        let compilation_target =
+            if let Some(load_context) = self.load_contexts.last() {
+                CompilationTarget::Module(load_context.module.clone())
+            } else {
+                CompilationTarget::User
+            };
+
+        match self.indices.get_meta_predicate_spec(predicate_name, arity, &compilation_target) {
+            Some(meta_specs) => {
+                let op_spec = fetch_op_spec(clause_name!(":"), 2, &self.indices.op_dir);
+
+                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),
+                            MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
+                                HeapCellValue::Addr(Addr::Usize(*arg_num))
+                            }
+                            MetaSpec::RequiresExpansion => {
+                                HeapCellValue::Atom(clause_name!(":"), op_spec.clone())
+                            }
+                        }
+                    }),
+                );
+
+                let heap_loc = self.machine_st.heap.push(
+                    HeapCellValue::NamedStr(1, clause_name!("meta_predicate"), None),
+                );
+
+                self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(list_loc)));
+                self.machine_st.unify(Addr::HeapCell(heap_loc), self.machine_st[temp_v!(3)]);
+            }
+            None => {
+                self.machine_st.fail = true;
+            }
+        }
+    }
+
+    pub(crate)
+    fn compile_pending_predicates(&mut self) {
+        let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1));
+
+        let compile_pending_predicates = || {
+            if !loader.predicates.is_empty() {
+                loader.compile_and_submit()?;
+            }
+
+            LiveTermStream::evacuate(loader)
+        };
+
+        let result = compile_pending_predicates();
+        self.restore_load_state_payload(result, evacuable_h);
+    }
+}
+
+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),
+                ),
+            preprocessor:
+                mem::replace(
+                    &mut self.preprocessor,
+                    Preprocessor::new(self.load_state.wam.machine_st.flags),
+                ),
+            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:
+                mem::replace(
+                    &mut self.predicates,
+                    vec![],
+                ),
+            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: LoadStatePayload) -> Self {
+        Loader {
+            term_stream:
+                mem::replace(
+                    &mut payload.term_stream,
+                    LiveTermStream::new(ListingSource::User),
+                ),
+            preprocessor:
+                mem::replace(
+                    &mut payload.preprocessor,
+                    Preprocessor::new(MachineFlags::default()),
+                ),
+            non_counted_bt_preds:
+                mem::replace(
+                    &mut payload.non_counted_bt_preds,
+                    IndexSet::new(),
+                ),
+            clause_clauses:
+                mem::replace(
+                    &mut payload.clause_clauses,
+                    vec![],
+                ),
+            predicates:
+                mem::replace(
+                    &mut payload.predicates,
+                    vec![],
+                ),
+            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,
+            },
+        }
+    }
+
+    fn incremental_compile_clause(
+        &mut self,
+        key: PredicateKey,
+        term: Term,
+        compilation_target: CompilationTarget,
+        non_counted_bt: bool,
+        append_or_prepend: AppendOrPrepend,
+    ) -> Result<(), SessionError> {
+        let mut preprocessor = Preprocessor::new(self.load_state.wam.machine_st.flags);
+
+        let tl = preprocessor.try_term_to_tl(
+            &mut self.load_state,
+            term,
+            CutContext::BlocksCuts,
+        )?;
+
+        let queue = preprocessor.parse_queue(&mut self.load_state)?;
+
+        let clause =
+            match tl {
+                TopLevel::Fact(fact) => {
+                    PredicateClause::Fact(fact)
+                }
+                TopLevel::Rule(rule) => {
+                    PredicateClause::Rule(rule)
+                }
+                _ => {
+                    unreachable!()
+                }
+            };
+
+        let compilation_target =
+            mem::replace(&mut self.load_state.compilation_target, compilation_target);
+
+        let result = self.load_state.incremental_compile_clause(
+            key,
+            clause,
+            queue,
+            non_counted_bt,
+            append_or_prepend,
+        );
+
+        self.load_state.compilation_target = compilation_target;
+        result?;
+
+        Ok(())
+    }
+
+    #[inline]
+    fn enqueue_term(&mut self, term: Term) {
+        self.term_stream.term_queue.push_back(term);
+    }
+}
+
+#[inline]
+pub(super)
+fn load_module(
+    code_dir: &mut CodeDir,
+    op_dir: &mut OpDir,
+    meta_predicate_dir: &mut MetaPredicateDir,
+    module: &Module,
+) {
+    import_module_exports(
+        &mut RetractionInfo::new(0),
+        &CompilationTarget::User,
+        module,
+        code_dir,
+        op_dir,
+        meta_predicate_dir,
+    );
+}
index 1dcc1db8bf63444fffd2aafeb00b86af14f65477..dcea844868fba50262a68403a1a2f917cf7febd9 100644 (file)
@@ -1,6 +1,6 @@
 use crate::prolog_parser::ast::*;
 
-use crate::forms::{ModuleSource, Number, PredicateKey};
+use crate::forms::{ModuleSource, Number}; //, PredicateKey};
 use crate::machine::heap::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
@@ -355,24 +355,11 @@ impl MachineError {
         }
     }
 
-    pub(super)
-    fn uninstantiation_error(culprit: Addr) -> Self {
-        let stub = functor!(
-            "uninstantiation_error",
-            [addr(culprit)]
-        );
-
-        MachineError {
-            stub,
-            location: None,
-            from: ErrorProvenance::Received,
-        }
-    }
-
     pub(super)
     fn session_error(h: usize, err: SessionError) -> Self {
         match err {
-            SessionError::CannotOverwriteBuiltIn(pred_str) |
+            // SessionError::CannotOverwriteBuiltIn(pred_str) |
+            /*
             SessionError::CannotOverwriteImport(pred_str) => {
                 Self::permission_error(
                     h,
@@ -381,12 +368,14 @@ impl MachineError {
                     functor!(clause_name(pred_str)),
                 )
             }
+            */
             SessionError::ExistenceError(err) => {
                 Self::existence_error(h, err)
             }
-            SessionError::InvalidFileName(filename) => {
-                Self::existence_error(h, ExistenceError::Module(filename))
-            }
+            // SessionError::InvalidFileName(filename) => {
+            //     Self::existence_error(h, ExistenceError::Module(filename))
+            // }
+            /*
             SessionError::ModuleDoesNotContainExport(..) => {
                 Self::permission_error(
                     h,
@@ -395,6 +384,15 @@ impl MachineError {
                     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,
@@ -411,7 +409,7 @@ impl MachineError {
                     functor!(clause_name(op)),
                 )
             }
-            SessionError::ParserError(err) => {
+            SessionError::CompilationError(err) => {
                 Self::syntax_error(h, err)
             }
             SessionError::QueryCannotBeDefinedAsFact => {
@@ -426,13 +424,15 @@ impl MachineError {
     }
 
     pub(super)
-    fn syntax_error(h: usize, err: ParserError) -> Self {
-        if let ParserError::Arithmetic(err) = err {
+    fn syntax_error<E: Into<CompilationError>>(h: usize, err: E) -> Self {
+        let err = err.into();
+
+        if let CompilationError::Arithmetic(err) = err {
             return Self::arithmetic_error(h, err);
         }
 
         let location = err.line_and_col_num();
-        let stub = functor!(err.as_str());
+        let stub = err.as_functor(h);
 
         let stub = functor!(
             "syntax_error",
@@ -475,9 +475,103 @@ impl MachineError {
     }
 }
 
+#[derive(Debug)]
+pub enum CompilationError {
+    Arithmetic(ArithmeticError),
+    ParserError(ParserError),
+    // BadPendingByte,
+    CannotParseCyclicTerm,
+    // ExpandedTermsListNotAList,
+    ExpectedRel,
+    // ExpectedTopLevelTerm,
+    InadmissibleFact,
+    InadmissibleQueryTerm,
+    InconsistentEntry,
+    // InvalidDoubleQuotesDecl,
+    // InvalidHook,
+    InvalidMetaPredicateDecl,
+    InvalidModuleDecl,
+    InvalidModuleExport,
+    InvalidRuleHead,
+    InvalidUseModuleDecl,
+    InvalidModuleResolution(ClauseName),
+    UnreadableTerm,
+}
+
+impl From<ArithmeticError> for CompilationError {
+    #[inline]
+    fn from(err: ArithmeticError) -> CompilationError {
+        CompilationError::Arithmetic(err)
+    }
+}
+
+impl From<ParserError> for CompilationError {
+    #[inline]
+    fn from(err: ParserError) -> CompilationError {
+        CompilationError::ParserError(err)
+    }
+}
+
+impl CompilationError {
+    pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
+        match self {
+            &CompilationError::ParserError(ref err) =>
+                err.line_and_col_num(),
+            _ =>
+                None
+        }
+    }
+
+    pub fn as_functor(&self, _h: usize) -> MachineStub {
+        match self {
+            &CompilationError::Arithmetic(..) =>
+                functor!("arithmetic_error"),
+            // &CompilationError::BadPendingByte =>
+            //     functor!("bad_pending_byte"),
+            &CompilationError::CannotParseCyclicTerm =>
+                functor!("cannot_parse_cyclic_term"),
+            // &CompilationError::ExpandedTermsListNotAList =>
+            //     functor!("expanded_terms_list_is_not_a_list"),
+            &CompilationError::ExpectedRel =>
+                functor!("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"),
+            // &CompilationError::InvalidDoubleQuotesDecl =>
+            //     functor!("invalid_double_quotes_declaration"),
+            // &CompilationError::InvalidHook =>
+            //     functor!("invalid_hook"),
+            &CompilationError::InvalidMetaPredicateDecl =>
+                functor!("invalid_meta_predicate_decl"),
+            &CompilationError::InvalidModuleDecl =>
+                functor!("invalid_module_declaration"),
+            &CompilationError::InvalidModuleExport =>
+                functor!("invalid_module_export"),
+            &CompilationError::InvalidModuleResolution(ref module_name) =>
+                functor!(
+                    "no_such_module",
+                    [clause_name(module_name.clone())]
+                ),
+            &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"),
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy)]
 pub enum Permission {
-    Access,
+    // Access,
     Create,
     InputStream,
     Modify,
@@ -490,7 +584,7 @@ impl Permission {
     #[inline]
     pub fn as_str(self) -> &'static str {
         match self {
-            Permission::Access => "access",
+            // Permission::Access => "access",
             Permission::Create => "create",
             Permission::InputStream => "input",
             Permission::Modify => "modify",
@@ -807,37 +901,55 @@ pub enum ExistenceError {
 
 #[derive(Debug)]
 pub enum SessionError {
-    CannotOverwriteBuiltIn(ClauseName),
-    CannotOverwriteImport(ClauseName),
+    CompilationError(CompilationError),
+    // CannotOverwriteBuiltIn(ClauseName),
+    // CannotOverwriteImport(ClauseName),
     ExistenceError(ExistenceError),
-    InvalidFileName(ClauseName),
-    ModuleDoesNotContainExport(ClauseName, PredicateKey),
+    // InvalidFileName(ClauseName),
+    // ModuleDoesNotContainExport(ClauseName, PredicateKey),
+    ModuleCannotImportSelf(ClauseName),
     NamelessEntry,
     OpIsInfixAndPostFix(ClauseName),
     QueryCannotBeDefinedAsFact,
-    ParserError(ParserError),
 }
 
 #[derive(Debug)]
 pub enum EvalSession {
-    EntrySuccess,
+    // EntrySuccess,
     Error(SessionError),
 }
 
 impl From<SessionError> for EvalSession {
+    #[inline]
     fn from(err: SessionError) -> Self {
         EvalSession::Error(err)
     }
 }
 
+impl From<std::io::Error> for SessionError {
+    #[inline]
+    fn from(err: std::io::Error) -> SessionError {
+        SessionError::from(ParserError::from(err))
+    }
+}
+
 impl From<ParserError> for SessionError {
+    #[inline]
     fn from(err: ParserError) -> Self {
-        SessionError::ParserError(err)
+        SessionError::CompilationError(CompilationError::from(err))
+    }
+}
+
+impl From<CompilationError> for SessionError {
+    #[inline]
+    fn from(err: CompilationError) -> Self {
+        SessionError::CompilationError(err)
     }
 }
 
 impl From<ParserError> for EvalSession {
+    #[inline]
     fn from(err: ParserError) -> Self {
-        EvalSession::from(SessionError::ParserError(err))
+        EvalSession::from(SessionError::from(err))
     }
 }
index 13fb6ae7c330e3e3c309798857596bf9a87168a4..14489b767fbd58be7299153f3ea7ab0a1522cb15 100644 (file)
@@ -1,9 +1,9 @@
 use crate::prolog_parser::ast::*;
-use crate::prolog_parser::tabled_rc::*;
 
 use crate::clause_types::*;
 use crate::fixtures::*;
 use crate::forms::*;
+use crate::machine::CompilationTarget;
 use crate::machine::code_repo::CodeRepo;
 use crate::machine::Ball;
 use crate::machine::heap::*;
@@ -11,20 +11,21 @@ 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::instructions::*;
 use crate::ordered_float::OrderedFloat;
 use crate::rug::{Integer, Rational};
 
 use crate::indexmap::IndexMap;
 
-use std::cell::RefCell;
+use std::cell::Cell;
 use std::cmp::Ordering;
-use std::collections::{BTreeMap, BTreeSet, VecDeque};
+use std::collections::{BTreeMap, BTreeSet};
 use std::convert::TryFrom;
 use std::fmt;
-use std::mem;
+// use std::mem;
 use std::net::TcpListener;
-use std::ops::{Add, AddAssign, Sub, SubAssign};
+use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
 use std::rc::Rc;
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -64,6 +65,7 @@ pub enum Addr {
     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),
@@ -231,7 +233,7 @@ impl Addr {
                     Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
                         Some(TermOrderCategory::Compound)
                     }
-                    Addr::CutPoint(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
+                    Addr::CutPoint(_) | Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
                         None
                     }
                 }
@@ -369,6 +371,7 @@ pub enum HeapCellValue {
     Atom(ClauseName, Option<SharedOpDesc>),
     DBRef(DBRef),
     Integer(Rc<Integer>),
+    LoadStatePayload(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.
@@ -387,6 +390,9 @@ impl HeapCellValue {
             HeapCellValue::Rational(..) => {
                 Addr::Con(focus)
             }
+            HeapCellValue::LoadStatePayload(_) => {
+                Addr::LoadStatePayload(focus)
+            }
             HeapCellValue::NamedStr(_, _, _) => {
                 Addr::Str(focus)
             }
@@ -417,6 +423,9 @@ impl HeapCellValue {
             &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())
             }
@@ -443,50 +452,42 @@ impl From<Addr> for HeapCellValue {
     }
 }
 
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub enum IndexPtr {
     DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
-    Undefined,
-    InSituDirEntry(usize),
     Index(usize),
-    UserGoalExpansion,
-    UserTermExpansion
+    Undefined,
 }
 
 #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
-pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>);
+pub struct CodeIndex(pub Rc<Cell<IndexPtr>>);
 
-impl CodeIndex {
-    #[inline]
-    pub fn new(ptr: IndexPtr, module_name: ClauseName) -> Self {
-        CodeIndex(Rc::new(RefCell::new(( ptr, module_name ))))
-    }
+impl Deref for CodeIndex {
+    type Target = Cell<IndexPtr>;
 
     #[inline]
-    pub fn is_undefined(&self) -> bool {
-        let index_ptr = &self.0.borrow().0;
-
-        match index_ptr {
-            &IndexPtr::Undefined | &IndexPtr::DynamicUndefined => true,
-            _ => false
-        }
+    fn deref(&self) -> &Self::Target {
+        self.0.deref()
     }
+}
 
+impl CodeIndex {
     #[inline]
-    pub fn dynamic_undefined(module_name: ClauseName) -> Self {
-        CodeIndex(Rc::new(RefCell::new((
-            IndexPtr::DynamicUndefined,
-            module_name
-        ))))
+    pub(super)
+    fn new(ptr: IndexPtr) -> Self {
+        CodeIndex(Rc::new(Cell::new(ptr)))
     }
 
     #[inline]
-    pub fn module_name(&self) -> ClauseName {
-        self.0.borrow().1.clone()
+    pub fn is_undefined(&self) -> bool {
+        match self.0.get() {
+            IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true,
+            _ => false
+        }
     }
 
     pub fn local(&self) -> Option<usize> {
-        match self.0.borrow().0 {
+        match self.0.get() {
             IndexPtr::Index(i) => Some(i),
             _ => None,
         }
@@ -495,60 +496,34 @@ impl CodeIndex {
 
 impl Default for CodeIndex {
     fn default() -> Self {
-        CodeIndex(Rc::new(RefCell::new((
-            IndexPtr::Undefined,
-            clause_name!(""),
-        ))))
-    }
-}
-
-impl From<(usize, ClauseName)> for CodeIndex {
-    fn from(value: (usize, ClauseName)) -> Self {
-        CodeIndex(Rc::new(RefCell::new((IndexPtr::Index(value.0), value.1))))
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum DynamicAssertPlace {
-    Back,
-    Front,
-}
-
-impl DynamicAssertPlace {
-    #[inline]
-    pub fn predicate_name(self) -> ClauseName {
-        match self {
-            DynamicAssertPlace::Back => clause_name!("assertz"),
-            DynamicAssertPlace::Front => clause_name!("asserta"),
-        }
-    }
-
-    #[inline]
-    pub fn push_to_queue(self, addrs: &mut VecDeque<Addr>, new_addr: Addr) {
-        match self {
-            DynamicAssertPlace::Back => addrs.push_back(new_addr),
-            DynamicAssertPlace::Front => addrs.push_front(new_addr),
-        }
+        CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined)))
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum DynamicTransactionType {
-    Abolish,
-    Assert(DynamicAssertPlace),
-    ModuleAbolish,
-    ModuleAssert(DynamicAssertPlace),
-    ModuleRetract,
-    Retract, // dynamic index of the clause to remove.
-}
-
 #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
 pub enum REPLCodePtr {
-    CompileBatch,
+    AddDynamicPredicate,
+    AddGoalExpansionClause,
+    AddTermExpansionClause,
+    ClauseToEvacuable,
+    ConcludeLoad,
+    DeclareModule,
+    LoadCompiledLibrary,
+    LoadContextSource,
+    LoadContextFile,
+    LoadContextDirectory,
+    LoadContextModule,
+    LoadContextStream,
+    PopLoadContext,
+    PopLoadStatePayload,
+    PushLoadContext,
+    PushLoadStatePayload,
     UseModule,
-    UseQualifiedModule,
-    UseModuleFromFile,
-    UseQualifiedModuleFromFile
+    MetaPredicateProperty,
+    CompilePendingPredicates,
+    UserAsserta,
+    UserAssertz,
+    UserRetract,
 }
 
 #[derive(Debug, Clone, PartialEq)]
@@ -556,7 +531,7 @@ pub 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.
+    // 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.
 }
@@ -568,18 +543,26 @@ impl CodePtr {
           | &CodePtr::CallN(_, ref local, _)
           | &CodePtr::Local(ref local) => local.clone(),
             &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
-            &CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p,
+            &CodePtr::REPL(_, p) => p // | &CodePtr::DynamicTransaction(_, p) => p,
+        }
+    }
+
+    #[inline]
+    pub fn is_halt(&self) -> bool {
+        if let CodePtr::Local(LocalCodePtr::Halt) = self {
+            true
+        } else {
+            false
         }
     }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum LocalCodePtr {
-    DirEntry(usize), // offset.
-    InSituDirEntry(usize),
-    TopLevel(usize, usize), // chunk_num, offset.
-    UserGoalExpansion(usize),
-    UserTermExpansion(usize),
+    DirEntry(usize), // offset
+    Halt,
+    IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
+    // TopLevel(usize, usize), // chunk_num, offset
 }
 
 impl LocalCodePtr {
@@ -591,6 +574,16 @@ impl LocalCodePtr {
         }
     }
 
+    #[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)) {
@@ -621,28 +614,21 @@ impl LocalCodePtr {
                     [integer(*p)]
                 ));
             }
-            LocalCodePtr::InSituDirEntry(p) => {
-                heap.append(functor!(
-                    "in_situ_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::UserGoalExpansion(p) => {
+            */
+            LocalCodePtr::IndexingBuf(p, o, i) => {
                 heap.append(functor!(
-                    "user_goal_expansion",
-                    [integer(*p)]
-                ));
-            }
-            LocalCodePtr::UserTermExpansion(p) => {
-                heap.append(functor!(
-                    "user_term_expansion",
-                    [integer(*p)]
+                    "indexed_buf",
+                    [integer(*p), integer(*o), integer(*i)]
                 ));
             }
         }
@@ -651,6 +637,7 @@ impl LocalCodePtr {
     }
 }
 
+/*
 impl PartialOrd<CodePtr> for CodePtr {
     fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
         match (self, other) {
@@ -667,11 +654,8 @@ impl PartialOrd<CodePtr> for CodePtr {
 impl PartialOrd<LocalCodePtr> for LocalCodePtr {
     fn partial_cmp(&self, other: &LocalCodePtr) -> Option<Ordering> {
         match (self, other) {
-            (&LocalCodePtr::InSituDirEntry(p1), &LocalCodePtr::InSituDirEntry(ref p2))
-         | (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2))
-          | (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2))
-          | (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2))
-          | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
+               (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2)) |
+            (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
                 p1.partial_cmp(p2)
             }
             (_, &LocalCodePtr::TopLevel(_, _)) => {
@@ -683,29 +667,34 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
         }
     }
 }
+*/
 
 impl Default for CodePtr {
+    #[inline]
     fn default() -> Self {
         CodePtr::Local(LocalCodePtr::default())
     }
 }
 
 impl Default for LocalCodePtr {
+    #[inline]
     fn default() -> Self {
-        LocalCodePtr::TopLevel(0, 0)
+        LocalCodePtr::DirEntry(0)
     }
 }
 
 impl Add<usize> for LocalCodePtr {
     type Output = LocalCodePtr;
 
+    #[inline]
     fn add(self, rhs: usize) -> Self::Output {
         match self {
-            LocalCodePtr::InSituDirEntry(p) => LocalCodePtr::InSituDirEntry(p + rhs),
-            LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs),
-            LocalCodePtr::TopLevel(cn, p) => LocalCodePtr::TopLevel(cn, p + rhs),
-            LocalCodePtr::UserTermExpansion(p) => LocalCodePtr::UserTermExpansion(p + rhs),
-            LocalCodePtr::UserGoalExpansion(p) => LocalCodePtr::UserGoalExpansion(p + rhs),
+            LocalCodePtr::DirEntry(p) =>
+                LocalCodePtr::DirEntry(p + rhs),
+            LocalCodePtr::Halt =>
+                unreachable!(),
+            LocalCodePtr::IndexingBuf(p, o, i) =>
+                LocalCodePtr::IndexingBuf(p, o, i + rhs),
         }
     }
 }
@@ -713,30 +702,40 @@ impl Add<usize> for LocalCodePtr {
 impl Sub<usize> for LocalCodePtr {
     type Output = Option<LocalCodePtr>;
 
+    #[inline]
     fn sub(self, rhs: usize) -> Self::Output {
         match self {
-            LocalCodePtr::InSituDirEntry(p) =>
-                p.checked_sub(rhs).map(LocalCodePtr::InSituDirEntry),
             LocalCodePtr::DirEntry(p) =>
                 p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
-            LocalCodePtr::TopLevel(cn, p) =>
-                p.checked_sub(rhs).map(|r| LocalCodePtr::TopLevel(cn, r)),
-            LocalCodePtr::UserTermExpansion(p) =>
-                p.checked_sub(rhs).map(LocalCodePtr::UserTermExpansion),
-            LocalCodePtr::UserGoalExpansion(p) =>
-                p.checked_sub(rhs).map(LocalCodePtr::UserGoalExpansion),
+            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::InSituDirEntry(ref mut p)
-          | &mut LocalCodePtr::UserGoalExpansion(ref mut p)
-          | &mut LocalCodePtr::UserTermExpansion(ref mut p)
-          | &mut LocalCodePtr::DirEntry(ref mut p)
-          | &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs,
+            &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!(),
         }
     }
 }
@@ -746,10 +745,14 @@ impl Add<usize> for 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),
+            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)
             }
@@ -767,186 +770,206 @@ impl AddAssign<usize> for CodePtr {
     }
 }
 
-pub type HeapVarDict = IndexMap<Rc<Var>, Addr>;
-pub type AllocVarDict = IndexMap<Rc<Var>, VarData>;
-
-#[derive(Debug, Clone)]
-pub struct DynamicPredicateInfo {
-    pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value.
-}
-
-impl Default for DynamicPredicateInfo {
-    fn default() -> Self {
-        DynamicPredicateInfo {
-            clauses_subsection_p: 0,
+impl SubAssign<usize> for CodePtr {
+    #[inline]
+    fn sub_assign(&mut self, rhs: usize) {
+        match self {
+            CodePtr::Local(ref mut local) => *local -= rhs,
+            _ => unreachable!(),
         }
     }
 }
 
-pub type InSituCodeDir = IndexMap<PredicateKey, usize>;
 
-// key type: module name, predicate indicator.
-pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>;
+pub type HeapVarDict = IndexMap<Rc<Var>, Addr>;
+pub type AllocVarDict = IndexMap<Rc<Var>, VarData>;
 
+pub type InSituCodeDir = IndexMap<PredicateKey, usize>;
 pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
 
 #[derive(Debug)]
 pub(crate) struct ModuleStub {
-    pub(crate) atom_tbl: TabledData<Atom>,
     pub(crate) in_situ_code_dir: InSituCodeDir,
 }
 
-impl ModuleStub {
-    pub(crate) fn new(atom_tbl: TabledData<Atom>) -> Self {
-        ModuleStub {
-            atom_tbl,
-            in_situ_code_dir: InSituCodeDir::new(),
-        }
-    }
-}
-
-pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
+// pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
 pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
 pub(crate) type StreamDir = BTreeSet<Stream>;
 
+pub type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>;
+
+pub type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton>;
+
 #[derive(Debug)]
 pub struct IndexStore {
-    pub(super) atom_tbl: TabledData<Atom>,
     pub(super) code_dir: CodeDir,
-    pub(super) dynamic_code_dir: DynamicCodeDir,
+    pub(super) extensible_predicates: ExtensiblePredicates,
     pub(super) global_variables: GlobalVarDir,
-    pub(super) in_situ_code_dir: InSituCodeDir,
-    pub(super) in_situ_module_dir: ModuleStubDir,
-    pub(super) module_dir: ModuleDir,
+    pub(super) meta_predicates: MetaPredicateDir,
     pub(super) modules: ModuleDir,
     pub(super) op_dir: OpDir,
     pub(super) streams: StreamDir,
     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 fn predicate_exists(
+    pub fn get_predicate_skeleton(
+        &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
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn remove_predicate_skeleton(
+        &mut self,
+        compilation_target: &CompilationTarget,
+        key: &PredicateKey,
+    ) {
+        match (key.0.as_str(), key.1) {
+            ("term_expansion", 2) => {
+                self.extensible_predicates.remove(key);
+            },
+            _ => {
+                match compilation_target {
+                    CompilationTarget::User => {
+                        self.extensible_predicates.remove(key);
+                    }
+                    CompilationTarget::Module(ref module_name) => {
+                        if let Some(module) = self.modules.get_mut(module_name) {
+                            module.extensible_predicates.remove(key);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn get_predicate_code_index(
         &self,
         name: ClauseName,
-        module: ClauseName,
         arity: usize,
+        module: ClauseName,
         op_spec: Option<SharedOpDesc>,
-    ) -> bool {
-        match self.modules.get(&module) {
-            Some(module) => match ClauseType::from(name, arity, op_spec) {
-                ClauseType::Named(name, arity, _) => module.code_dir.contains_key(&(name, arity)),
+    ) -> 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, ..) => {
-                    module.code_dir.contains_key(&(name, spec.arity()))
+                    self.code_dir.get(&(name, spec.arity())).cloned()
                 }
-                _ => true,
-            },
-            None => match ClauseType::from(name, arity, op_spec) {
-                ClauseType::Named(name, arity, _) => self.code_dir.contains_key(&(name, arity)),
-                ClauseType::Op(name, spec, ..) => self.code_dir.contains_key(&(name, spec.arity())),
-                _ => true,
-            },
+                _ => {
+                    None
+                }
+            }
+        } else {
+            self.modules.get(&module).and_then(|module| {
+                match ClauseType::from(name, arity, op_spec) {
+                    ClauseType::Named(name, arity, _) => {
+                        module.code_dir.get(&(name, arity)).cloned()
+                    }
+                    ClauseType::Op(name, spec, ..) => {
+                        module.code_dir.get(&(name, spec.arity())).cloned()
+                    }
+                    _ => {
+                        None
+                    }
+                }
+            })
         }
     }
 
-    pub fn add_term_and_goal_expansion_indices(&mut self) {
-        self.code_dir.insert((clause_name!("term_expansion"), 2),
-                             CodeIndex(Rc::new(RefCell::new(
-                                 (IndexPtr::UserTermExpansion,
-                                  clause_name!("user"))
-                             ))));
-        self.code_dir.insert((clause_name!("goal_expansion"), 2),
-                             CodeIndex(Rc::new(RefCell::new(
-                                 (IndexPtr::UserGoalExpansion,
-                                  clause_name!("user"))
-                             ))));
-    }
-
-    #[inline]
-    pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
-        self.dynamic_code_dir.swap_remove(&(module, name, arity));
-    }
-
-    #[inline]
-    pub fn get_clause_subsection(
+    pub fn get_meta_predicate_spec(
         &self,
-        module: ClauseName,
         name: ClauseName,
         arity: usize,
-    ) -> Option<DynamicPredicateInfo> {
-        self.dynamic_code_dir.get(&(module, name, arity)).cloned()
-    }
-
-    #[inline]
-    pub(crate) fn take_in_situ_module_dir(&mut self) -> ModuleStubDir {
-        mem::replace(&mut self.in_situ_module_dir, ModuleStubDir::new())
-    }
-
-    #[inline]
-    pub fn take_in_situ_code_dir(&mut self) -> InSituCodeDir {
-        mem::replace(&mut self.in_situ_code_dir, InSituCodeDir::new())
-    }
-
-    #[inline]
-    pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
-        self.modules.swap_remove(&name)
-    }
-
-    #[inline]
-    pub fn insert_module(&mut self, module: Module) {
-        self.modules.insert(module.module_decl.name.clone(), module);
-    }
-
-    #[inline]
-    pub(super) fn new() -> Self {
-        IndexStore {
-            atom_tbl: TabledData::new(Rc::new("user".to_string())),
-            code_dir: CodeDir::new(),
-            module_dir: ModuleDir::new(),
-            dynamic_code_dir: DynamicCodeDir::new(),
-            global_variables: GlobalVarDir::new(),
-            in_situ_code_dir: InSituCodeDir::new(),
-            in_situ_module_dir: ModuleStubDir::new(),
-            op_dir: default_op_dir(),
-            modules: ModuleDir::new(),
-            stream_aliases: StreamAliasDir::new(),
-            streams: StreamDir::new(),
+        compilation_target: &CompilationTarget,
+    ) -> Option<&Vec<MetaSpec>> {
+        match compilation_target {
+            CompilationTarget::User => {
+                self.meta_predicates.get(&(name, arity))
+            }
+            CompilationTarget::Module(ref module_name) => {
+                match self.modules.get(module_name) {
+                    Some(ref module) => {
+                        module.meta_predicates.get(&(name.clone(), arity))
+                              .or_else(|| {
+                                  self.meta_predicates.get(&(name, arity))
+                              })
+                    }
+                    None => {
+                        self.meta_predicates.get(&(name, arity))
+                    }
+                }
+            }
         }
     }
 
-    #[inline]
-    pub(super) fn copy_and_swap(&mut self, other: &mut IndexStore) {
-        self.code_dir = other.code_dir.clone();
-        self.op_dir = other.op_dir.clone();
-
-        mem::swap(&mut self.code_dir, &mut other.code_dir);
-        mem::swap(&mut self.op_dir, &mut other.op_dir);
-        mem::swap(&mut self.modules, &mut other.modules);
+    pub fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool {
+        match module_name.as_str() {
+            "user" => {
+                self.extensible_predicates.get(&key)
+                    .map(|skeleton| skeleton.is_dynamic)
+                    .unwrap_or(false)
+            }
+            _ => {
+                match self.modules.get(&module_name) {
+                    Some(ref module) => {
+                        module.extensible_predicates.get(&key)
+                              .map(|skeleton| skeleton.is_dynamic)
+                              .unwrap_or(false)
+                    }
+                    None => {
+                        false
+                    }
+                }
+            }
+        }
     }
 
     #[inline]
-    fn get_internal(
-        &self,
-        name: ClauseName,
-        arity: usize,
-        in_mod: ClauseName,
-    ) -> Option<CodeIndex> {
-        self.modules
-            .get(&in_mod)
-            .and_then(|ref module| module.code_dir.get(&(name, arity)))
-            .cloned()
+    pub(super) fn new() -> Self {
+        IndexStore::default()
     }
 
-    pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
+    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_internal(r_w_h, 0, iso_ext.clone())
+            .get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None)
             .and_then(|item| item.local());
         let r_wo_h = self
-            .get_internal(r_wo_h, 1, iso_ext)
+            .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 {
@@ -960,129 +983,6 @@ impl IndexStore {
 }
 
 pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
-pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>;
-
-#[derive(Debug)]
-pub struct TermDirQuantumEntry {
-    pub old_terms: (Predicate, VecDeque<TopLevel>),
-    pub new_terms: (Predicate, VecDeque<TopLevel>),
-    pub is_fresh: bool,
-}
-
-impl TermDirQuantumEntry {
-    #[inline]
-    pub fn new() -> Self {
-        TermDirQuantumEntry {
-            old_terms: (Predicate::new(), VecDeque::new()),
-            new_terms: (Predicate::new(), VecDeque::new()),
-            is_fresh: false,
-        }
-    }
-
-    pub fn from(preds: &Predicate, queue: &VecDeque<TopLevel>) -> Self
-    {
-        let mut entry = TermDirQuantumEntry::new();
-        entry.is_fresh = false;
-
-        (entry.old_terms.0).0.extend(preds.0.iter().cloned());
-        entry.old_terms.1.extend(queue.iter().cloned());
-
-        entry
-    }
-}
-
-#[derive(Debug)]
-pub struct TermDirQuantum(IndexMap<PredicateKey, TermDirQuantumEntry>);
-
-impl TermDirQuantum {
-    #[inline]
-    pub fn new() -> Self {
-        TermDirQuantum(IndexMap::new())
-    }
-
-    #[inline]
-    pub fn insert_or_refresh(&mut self, key: PredicateKey, mut entry: TermDirQuantumEntry) {
-        if let Some(prev_entry) = self.get_mut(&key) {
-            prev_entry.is_fresh = true;
-        } else {
-            entry.is_fresh = true;
-            self.0.insert(key, entry);
-        }
-    }
-
-    #[inline]
-    pub fn insert(&mut self, key: PredicateKey, entry: TermDirQuantumEntry) {
-        self.0.insert(key, entry);
-    }
-
-    #[inline]
-    pub fn get_mut(&mut self, key: &PredicateKey) -> Option<&mut TermDirQuantumEntry> {
-        self.0.get_mut(key)
-    }
-
-    pub fn consolidate(self) -> TermDir {
-        let mut term_dir = TermDir::new();
-
-        for (key, entry) in self.0 {
-            let (preds, queue) =
-                term_dir.entry(key).or_insert((Predicate::new(), VecDeque::new()));
-
-            preds.0.extend((entry.new_terms.0).0.into_iter());
-            queue.extend(entry.new_terms.1.into_iter());
-        }
-
-        term_dir
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
-pub enum CompileTimeHook {
-    GoalExpansion,
-    TermExpansion,
-    UserGoalExpansion,
-    UserTermExpansion,
-}
-
-impl CompileTimeHook {
-    pub fn name(self) -> ClauseName {
-        match self {
-            CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
-                clause_name!("goal_expansion")
-            }
-            CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
-                clause_name!("term_expansion")
-            }
-        }
-    }
-
-    #[inline]
-    pub fn arity(self) -> usize {
-        match self {
-            CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => 2,
-            CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => 2,
-        }
-    }
-
-    #[inline]
-    pub fn user_scope(self) -> Self {
-        match self {
-            CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
-                CompileTimeHook::UserGoalExpansion
-            }
-            CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
-                CompileTimeHook::UserTermExpansion
-            }
-        }
-    }
-
-    #[inline]
-    pub fn has_module_scope(self) -> bool {
-        match self {
-            CompileTimeHook::UserTermExpansion | CompileTimeHook::UserGoalExpansion => false,
-            _ => true,
-        }
-    }
-}
 
 pub enum RefOrOwned<'a, T: 'a> {
     Borrowed(&'a T),
@@ -1094,7 +994,8 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> {
         match self {
             &RefOrOwned::Borrowed(ref borrowed) =>
                 write!(f, "Borrowed({:?})", borrowed),
-            &RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned),
+            &RefOrOwned::Owned(ref owned) =>
+                write!(f, "Owned({:?})", owned),
         }
     }
 }
@@ -1107,9 +1008,7 @@ impl<'a, T> RefOrOwned<'a, T> {
         }
     }
 
-    pub fn to_owned(self) -> T
-    where
-        T: Clone,
+    pub fn to_owned(self) -> T where T: Clone
     {
         match self {
             RefOrOwned::Borrowed(item) => item.clone(),
index e8799566a99097ac774a79ae35a82ecda4e61e71..ab04a532b3ca1a4b0a7ce762cd5718b724c4de22 100644 (file)
@@ -9,14 +9,14 @@ use crate::machine::copier::*;
 use crate::machine::heap::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
-use crate::machine::modules::*;
+use crate::machine::partial_string::HeapPStrIter;
 use crate::machine::stack::*;
 use crate::machine::streams::*;
 use crate::rug::Integer;
 
 use crate::downcast::Any;
 
-use crate::indexmap::{IndexMap, IndexSet};
+use crate::indexmap::IndexMap;
 
 use std::cmp::Ordering;
 use std::convert::TryFrom;
@@ -25,292 +25,6 @@ use std::io::Write;
 use std::mem;
 use std::ops::{Index, IndexMut};
 
-#[derive(Debug)]
-pub(crate) struct HeapPStrIter<'a> {
-    focus: Addr,
-    machine_st: &'a MachineState,
-    seen: IndexSet<Addr>,
-}
-
-impl<'a> HeapPStrIter<'a> {
-    #[inline]
-    fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
-        HeapPStrIter {
-            focus,
-            machine_st,
-            seen: IndexSet::new(),
-        }
-    }
-
-    #[inline]
-    pub(crate)
-    fn focus(&self) -> Addr {
-        self.machine_st.store(self.machine_st.deref(self.focus))
-    }
-
-    #[inline]
-    pub(crate)
-    fn to_string(&mut self) -> String {
-        let mut buf = String::new();
-
-        while let Some(iteratee) = self.next() {
-            match iteratee {
-                PStrIteratee::Char(c) => {
-                    buf.push(c);
-                }
-                PStrIteratee::PStrSegment(h, n) => {
-                    match &self.machine_st.heap[h] {
-                        HeapCellValue::PartialString(ref pstr, _) => {
-                            buf += pstr.as_str_from(n);
-                        }
-                        _ => {
-                            unreachable!()
-                        }
-                    }
-                }
-            }
-        }
-
-        buf
-    }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum PStrIteratee {
-    Char(char),
-    PStrSegment(usize, usize),
-}
-
-impl<'a> Iterator for HeapPStrIter<'a> {
-    type Item = PStrIteratee;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let addr = self.machine_st.store(self.machine_st.deref(self.focus));
-
-        if !self.seen.contains(&addr) {
-            self.seen.insert(addr);
-        } else {
-            return None;
-        }
-
-        match addr {
-            Addr::PStrLocation(h, n) => {
-                if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
-                    self.focus = if has_tail {
-                        Addr::HeapCell(h + 1)
-                    } else {
-                        Addr::EmptyList
-                    };
-
-                    return Some(PStrIteratee::PStrSegment(h, n));
-                } else {
-                    unreachable!()
-                }
-            }
-            Addr::Lis(l) => {
-                let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
-
-                let opt_c = match addr {
-                    Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
-                        if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
-                            if atom.is_char() {
-                                Some(atom.as_str().chars().next().unwrap())
-                            } else {
-                                None
-                            }
-                        } else {
-                            unreachable!()
-                        }
-                    }
-                    Addr::Char(c) => {
-                        Some(c)
-                    }
-                    _ => {
-                        None
-                    }
-                };
-
-                if let Some(c) = opt_c {
-                    self.focus = Addr::HeapCell(l + 1);
-                    return Some(PStrIteratee::Char(c));
-                } else {
-                    return None;
-                }
-            }
-            Addr::EmptyList => {
-                self.focus = Addr::EmptyList;
-                return None;
-            }
-            _ => {
-                return None;
-            }
-        }
-    }
-}
-
-#[inline]
-pub(super)
-fn compare_pstr_prefixes<'a>(
-    i1: &mut HeapPStrIter<'a>,
-    i2: &mut HeapPStrIter<'a>,
-) -> Option<Ordering> {
-    let mut r1 = i1.next();
-    let mut r2 = i2.next();
-
-    loop {
-        if let Some(r1i) = r1 {
-            if let Some(r2i) = r2 {
-                match (r1i, r2i) {
-                    (PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => {
-                        if c1 != c2 {
-                            return c1.partial_cmp(&c2);
-                        }
-                    }
-                    (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()));
-
-                                    continue;
-                                }
-                            } else {
-                                r2 = i2.next();
-                                continue;
-                            }
-                        } else {
-                            unreachable!()
-                        }
-                    }
-                    (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()));
-
-                                    continue;
-                                }
-                            } else {
-                                r1 = i1.next();
-                                continue;
-                            }
-                        } else {
-                            unreachable!()
-                        }
-                    }
-                    (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();
-
-                                    continue;
-                                } else if str2.starts_with(str1) {
-                                    r1 = i1.next();
-                                    r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len()));
-
-                                    continue;
-                                } else {
-                                    return str1.partial_cmp(str2);
-                                }
-                            }
-                            _ => {
-                                unreachable!()
-                            }
-                        }
-                    }
-                }
-
-                r1 = i1.next();
-                r2 = i2.next();
-
-                continue;
-            }
-        }
-
-        return match (i1.focus(), i2.focus()) {
-            (Addr::EmptyList, Addr::EmptyList) => {
-                Some(Ordering::Equal)
-            }
-            (Addr::EmptyList, _) => {
-                Some(Ordering::Less)
-            }
-            (_, Addr::EmptyList) => {
-                Some(Ordering::Greater)
-            }
-            _ => {
-                None
-            }
-        };
-    }
-}
-
-#[inline]
-pub(super)
-fn compare_pstr_to_string<'a>(
-    heap_pstr_iter: &mut HeapPStrIter<'a>,
-    s: &String,
-) -> Option<usize> {
-    let mut s_offset = 0;
-
-    while let Some(iteratee) = heap_pstr_iter.next() {
-        match iteratee {
-            PStrIteratee::Char(c1) => {
-                if let Some(c2) = s[s_offset ..].chars().next() {
-                    if c1 != c2 {
-                        return None;
-                    } else {
-                        s_offset += c1.len_utf8();
-                    }
-                } else {
-                    return 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);
-
-                        if s[s_offset ..].starts_with(t) {
-                            s_offset += t.len();
-                        } else if t.starts_with(&s[s_offset ..]) {
-                            heap_pstr_iter.focus =
-                                Addr::PStrLocation(h, n + s[s_offset ..].len());
-
-                            s_offset += s[s_offset ..].len();
-                            return Some(s_offset);
-                        } else {
-                            return None;
-                        }
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                }
-            }
-        }
-
-        if s[s_offset ..].is_empty() {
-            return Some(s_offset);
-        }
-    }
-
-    Some(s_offset)
-}
-
 #[derive(Debug)]
 pub struct Ball {
     pub(super) boundary: usize,
@@ -332,17 +46,6 @@ impl Ball {
         self.stub.clear();
     }
 
-    pub(super)
-    fn take(&mut self) -> Ball {
-        let boundary = self.boundary;
-        self.boundary = 0;
-
-        Ball {
-            boundary,
-            stub: self.stub.take(),
-        }
-    }
-
     pub(super)
     fn copy_and_align(&self, h: usize) -> Heap {
         let diff = self.boundary as i64 - h as i64;
@@ -586,6 +289,7 @@ impl Default for HeapPtr {
 
 #[derive(Debug)]
 pub struct MachineState {
+    pub(crate) atom_tbl: TabledData<Atom>,
     pub(super) s: HeapPtr,
     pub(super) p: CodePtr,
     pub(super) b: usize,
@@ -640,7 +344,7 @@ impl MachineState {
         loop {
             match self.read(
                 stream.clone(),
-                indices.atom_tbl.clone(),
+                self.atom_tbl.clone(),
                 &indices.op_dir,
             ) {
                 Ok(term_write_result) => {
@@ -654,7 +358,7 @@ impl MachineState {
                     let mut list_of_var_eqs = vec![];
 
                     for (var, binding) in term_write_result.var_dict.into_iter() {
-                        let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
+                        let var_atom = clause_name!(var.to_string(), self.atom_tbl);
 
                         let h = self.heap.h();
                         let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
@@ -854,6 +558,15 @@ impl MachineState {
         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> {
@@ -895,6 +608,24 @@ impl MachineState {
         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);
@@ -914,58 +645,35 @@ impl MachineState {
     fn module_lookup(
         &mut self,
         indices: &IndexStore,
+        call_policy: &mut Box<dyn CallPolicy>,
         key: PredicateKey,
         module_name: ClauseName,
-        last_call: bool,
+        _last_call: bool,
+        current_input_stream: &mut Stream,
+        current_output_stream: &mut Stream,
     ) -> CallResult {
-        let (name, arity) = key;
-
-        if let Some(ref idx) = indices.get_code_index((name.clone(), arity), module_name.clone()) {
-            match idx.0.borrow().0 {
-                IndexPtr::Index(compiled_tl_index) => {
-                    if last_call {
-                        self.execute_at_index(arity, dir_entry!(compiled_tl_index));
-                    } else {
-                        self.call_at_index(arity, dir_entry!(compiled_tl_index));
-                    }
-
-                    return Ok(());
-                }
-                IndexPtr::DynamicUndefined => {
-                    self.fail = true;
-                    return Ok(());
-                }
-                IndexPtr::UserTermExpansion => {
-                    if last_call {
-                        self.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
-                    } else {
-                        self.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
-                    }
-
-                    return Ok(());
-                }
-                IndexPtr::UserGoalExpansion => {
-                    if last_call {
-                        self.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
-                    } else {
-                        self.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
-                    }
-
-                    return Ok(());
-                }
-                IndexPtr::InSituDirEntry(p) => {
-                    if last_call {
-                        self.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p));
-                    } else {
-                        self.call_at_index(arity, LocalCodePtr::InSituDirEntry(p));
-                    }
-
-                    return Ok(());
-                }
-                _ => {}
-            }
+        if module_name.as_str() == "user" {
+            return call_policy.call_clause_type(
+                self,
+                key,
+                &indices.code_dir,
+                &indices.op_dir,
+                current_input_stream,
+                current_output_stream,
+            );
+        } else if let Some(module) = indices.modules.get(&module_name) {
+            return call_policy.call_clause_type(
+                self,
+                key,
+                &module.code_dir,
+                &module.op_dir,
+                current_input_stream,
+                current_output_stream,
+            );
         }
 
+        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);
@@ -974,49 +682,6 @@ impl MachineState {
     }
 }
 
-fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<LocalCodePtr>
-{
-    match indices.in_situ_code_dir.get(&(name.clone(), arity)) {
-        Some(p) => Some(LocalCodePtr::InSituDirEntry(*p)),
-        None =>
-            match indices.code_dir.get(&(name, arity)) {
-                Some(ref idx) => {
-                    if let IndexPtr::Index(p) = idx.0.borrow().0 {
-                        Some(LocalCodePtr::DirEntry(p))
-                    } else {
-                        None
-                    }
-                }
-                _ => None,
-            },
-    }
-}
-
-fn try_in_situ(
-    machine_st: &mut MachineState,
-    name: ClauseName,
-    arity: usize,
-    indices: &IndexStore,
-    last_call: bool,
-) -> CallResult {
-    if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
-        if last_call {
-            machine_st.execute_at_index(arity, p);
-        } else {
-            machine_st.call_at_index(arity, p);
-        }
-
-        machine_st.p = CodePtr::Local(p);
-        Ok(())
-    } else {
-        let stub = MachineError::functor_stub(name.clone(), arity);
-        let h = machine_st.heap.h();
-        let key = ExistenceError::Procedure(name, arity);
-
-        Err(machine_st.error_form(MachineError::existence_error(h, key), stub))
-    }
-}
-
 pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
 
 pub(crate) trait CallPolicy: Any + fmt::Debug {
@@ -1090,7 +755,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         machine_st.attr_var_init.backtrack(attr_var_init_queue_b, attr_var_init_bindings_b);
 
         machine_st.hb = machine_st.heap.h();
-        machine_st.p += offset;
+        machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
 
         Ok(())
     }
@@ -1130,7 +795,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         machine_st.stack.truncate(b);
 
         machine_st.hb = machine_st.heap.h();
-        machine_st.p += offset;
+        machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
 
         Ok(())
     }
@@ -1180,13 +845,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         machine_st: &mut MachineState,
         name: ClauseName,
         arity: usize,
-        idx: CodeIndex,
-        indices: &mut IndexStore,
+        idx: &CodeIndex,
     ) -> CallResult {
         if machine_st.last_call {
-            self.try_execute(machine_st, name, arity, idx, indices)
+            self.try_execute(machine_st, name, arity, idx)
         } else {
-            self.try_call(machine_st, name, arity, idx, indices)
+            self.try_call(machine_st, name, arity, idx)
         }
     }
 
@@ -1195,27 +859,18 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         machine_st: &mut MachineState,
         name: ClauseName,
         arity: usize,
-        idx: CodeIndex,
-        indices: &IndexStore,
+        idx: &CodeIndex,
     ) -> CallResult {
-        match idx.0.borrow().0 {
+        match idx.get() {
             IndexPtr::DynamicUndefined => {
                 machine_st.fail = true;
+                return Ok(());
             }
             IndexPtr::Undefined => {
-                return try_in_situ(machine_st, name, arity, indices, false);
+                return Err(machine_st.throw_undefined_error(name, arity));
             }
             IndexPtr::Index(compiled_tl_index) => {
-                machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index))
-            }
-            IndexPtr::UserTermExpansion => {
-                machine_st.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
-            }
-            IndexPtr::UserGoalExpansion => {
-                machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
-            }
-            IndexPtr::InSituDirEntry(p) => {
-                machine_st.call_at_index(arity, LocalCodePtr::InSituDirEntry(p));
+                machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index));
             }
         }
 
@@ -1227,25 +882,18 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         machine_st: &mut MachineState,
         name: ClauseName,
         arity: usize,
-        idx: CodeIndex,
-        indices: &IndexStore,
+        idx: &CodeIndex,
     ) -> CallResult {
-        match idx.0.borrow().0 {
-            IndexPtr::DynamicUndefined =>
-                machine_st.fail = true,
-            IndexPtr::Undefined =>
-                return try_in_situ(machine_st, name, arity, indices, true),
-            IndexPtr::Index(compiled_tl_index) => {
-                machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
-            }
-            IndexPtr::UserTermExpansion => {
-                machine_st.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
+        match idx.get() {
+            IndexPtr::DynamicUndefined => {
+                machine_st.fail = true;
+                return Ok(());
             }
-            IndexPtr::UserGoalExpansion => {
-                machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
+            IndexPtr::Undefined => {
+                return Err(machine_st.throw_undefined_error(name, arity));
             }
-            IndexPtr::InSituDirEntry(p) => {
-                machine_st.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p));
+            IndexPtr::Index(compiled_tl_index) => {
+                machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
             }
         }
 
@@ -1256,7 +904,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         &mut self,
         machine_st: &mut MachineState,
         ct: &BuiltInClauseType,
-        indices: &mut IndexStore,
+        _code_dir: &CodeDir,
+        op_dir: &OpDir,
         current_input_stream: &mut Stream,
         current_output_stream: &mut Stream,
     ) -> CallResult {
@@ -1305,15 +954,15 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
 
                 let atom = match machine_st.compare_term_test(&a2, &a3) {
                     Some(Ordering::Greater) => {
-                        let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir);
+                        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, &indices.op_dir);
+                        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, &indices.op_dir);
+                        let spec = fetch_atom_op_spec(clause_name!("<"), None, op_dir);
                         HeapCellValue::Atom(clause_name!("<"), spec)
                     }
                 };
@@ -1338,8 +987,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
             &BuiltInClauseType::Read => {
                 match machine_st.read(
                     current_input_stream.clone(),
-                    indices.atom_tbl.clone(),
-                    &indices.op_dir,
+                    machine_st.atom_tbl.clone(),
+                    op_dir,
                 ) {
                     Ok(offset) => {
                         let addr = machine_st[temp_v!(1)];
@@ -1347,16 +996,18 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
                     }
                     Err(ParserError::UnexpectedEOF) => {
                         let addr = machine_st[temp_v!(1)];
-                        let eof = clause_name!("end_of_file".to_string(),
-                            indices.atom_tbl);
+                        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(addr, atom);
                     }
                     Err(e) => {
                         let h = machine_st.heap.h();
                         let stub = MachineError::functor_stub(clause_name!("read"), 1);
+
                         let err = MachineError::syntax_error(h, e);
                         let err = machine_st.error_form(err, stub);
 
@@ -1382,7 +1033,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
                 return_from_clause!(machine_st.last_call, machine_st)
             }
             &BuiltInClauseType::Functor => {
-                machine_st.try_functor(&indices)?;
+                machine_st.try_functor(op_dir)?;
                 return_from_clause!(machine_st.last_call, machine_st)
             }
             &BuiltInClauseType::NotEq => {
@@ -1453,24 +1104,66 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         }
     }
 
-    fn compile_hook(
+    fn call_clause_type(
         &mut self,
         machine_st: &mut MachineState,
-        hook: &CompileTimeHook,
+        key: PredicateKey,
+        code_dir: &CodeDir,
+        op_dir: &OpDir,
+        current_input_stream: &mut Stream,
+        current_output_stream: &mut Stream,
     ) -> CallResult {
-        machine_st.cp = LocalCodePtr::TopLevel(0, 0);
+        let (name, arity) = key;
 
-        machine_st.num_of_args = hook.arity();
-        machine_st.b0 = machine_st.b;
+        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,
+                    current_input_stream,
+                    current_output_stream,
+                )?;
+            }
+            ClauseType::CallN => {
+                machine_st.handle_internal_call_n(arity);
+
+                if machine_st.fail {
+                    return Ok(());
+                }
 
-        machine_st.p = match hook {
-            CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
-                CodePtr::Local(LocalCodePtr::UserTermExpansion(0))
+                machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
             }
-            CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
-                CodePtr::Local(LocalCodePtr::UserGoalExpansion(0))
+            ClauseType::Inlined(inlined) => {
+                machine_st.execute_inlined(&inlined);
+
+                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,
+                ));
+            }
+        }
 
         Ok(())
     }
@@ -1479,57 +1172,20 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
         &mut self,
         machine_st: &mut MachineState,
         arity: usize,
-        indices: &mut IndexStore,
+        code_dir: &CodeDir,
+        op_dir: &OpDir,
         current_input_stream: &mut Stream,
         current_output_stream: &mut Stream,
     ) -> CallResult {
-        if let Some((name, arity)) = machine_st.setup_call_n(arity) {
-            match ClauseType::from(name.clone(), arity, None) {
-                ClauseType::BuiltIn(built_in) => {
-                    machine_st.setup_built_in_call(built_in.clone());
-                    self.call_builtin(
-                        machine_st,
-                        &built_in,
-                        indices,
-                        current_input_stream,
-                        current_output_stream,
-                    )?;
-                }
-                ClauseType::CallN => {
-                    machine_st.handle_internal_call_n(arity);
-
-                    if machine_st.fail {
-                        return Ok(());
-                    }
-
-                    machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
-                }
-                ClauseType::Inlined(inlined) => {
-                    machine_st.execute_inlined(&inlined);
-
-                    if machine_st.last_call {
-                        machine_st.p = CodePtr::Local(machine_st.cp);
-                    }
-                }
-                ClauseType::Op(..) | ClauseType::Named(..) => {
-                    let module = name.owning_module();
-
-                    if let Some(idx) = indices.get_code_index((name.clone(), arity), module) {
-                        self.context_call(machine_st, name, arity, idx, indices)?;
-                    } else {
-                        try_in_situ(machine_st, name, arity, indices, machine_st.last_call)?;
-                    }
-                }
-                ClauseType::Hook(_) | 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,
-                    ));
-                }
-            };
+        if let Some(key) = machine_st.setup_call_n(arity) {
+            self.call_clause_type(
+                machine_st,
+                key,
+                code_dir,
+                op_dir,
+                current_input_stream,
+                current_output_stream,
+            )?;
         }
 
         Ok(())
@@ -1542,11 +1198,9 @@ impl CallPolicy for CWILCallPolicy {
         machine_st: &mut MachineState,
         name: ClauseName,
         arity: usize,
-        idx: CodeIndex,
-        indices: &mut IndexStore,
+        idx: &CodeIndex,
     ) -> CallResult {
-        self.prev_policy
-            .context_call(machine_st, name, arity, idx, indices)?;
+        self.prev_policy.context_call(machine_st, name, arity, idx)?;//, indices)?;
         self.increment(machine_st)
     }
 
@@ -1574,14 +1228,16 @@ impl CallPolicy for CWILCallPolicy {
         &mut self,
         machine_st: &mut MachineState,
         ct: &BuiltInClauseType,
-        indices: &mut IndexStore,
+        code_dir: &CodeDir,
+        op_dir: &OpDir,
         current_input_stream: &mut Stream,
         current_output_stream: &mut Stream,
     ) -> CallResult {
         self.prev_policy.call_builtin(
             machine_st,
             ct,
-            indices,
+            code_dir,
+            op_dir,
             current_input_stream,
             current_output_stream
         )?;
@@ -1593,14 +1249,16 @@ impl CallPolicy for CWILCallPolicy {
         &mut self,
         machine_st: &mut MachineState,
         arity: usize,
-        indices: &mut IndexStore,
+        code_dir: &CodeDir,
+        op_dir: &OpDir,
         current_input_stream: &mut Stream,
         current_output_stream: &mut Stream,
     ) -> CallResult {
         self.prev_policy.call_n(
             machine_st,
             arity,
-            indices,
+            code_dir,
+            op_dir,
             current_input_stream,
             current_output_stream,
         )?;
index 5de0714011dd7f2eec4a81ef9a8e1238db2ef27a..a387970e0c0060f9502836d20295d771b20f9f1a 100644 (file)
@@ -4,6 +4,7 @@ use crate::prolog_parser::tabled_rc::*;
 use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
+use crate::indexing::*;
 use crate::instructions::*;
 use crate::machine::INTERRUPT;
 use crate::machine::attributed_variables::*;
@@ -13,6 +14,7 @@ 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::stack::*;
 use crate::machine::streams::*;
 use crate::ordered_float::*;
@@ -24,22 +26,11 @@ use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::rc::Rc;
 
-macro_rules! try_or_fail {
-    ($s:ident, $e:expr) => {{
-        match $e {
-            Ok(val) => val,
-            Err(msg) => {
-                $s.throw_exception(msg);
-                return;
-            }
-        }
-    }};
-}
-
 impl MachineState {
     pub(crate)
     fn new() -> Self {
         MachineState {
+            atom_tbl: TabledData::new(Rc::new("".to_owned())),
             s: HeapPtr::default(),
             p: CodePtr::default(),
             b: 0,
@@ -67,36 +58,6 @@ impl MachineState {
         }
     }
 
-    pub(crate)
-    fn with_small_heap() -> Self {
-        MachineState {
-            s: HeapPtr::default(),
-            p: CodePtr::default(),
-            b: 0,
-            b0: 0,
-            e: 0,
-            num_of_args: 0,
-            cp: LocalCodePtr::default(),
-            attr_var_init: AttrVarInitializer::new(0, 0),
-            fail: false,
-            heap: Heap::new(),
-            mode: MachineMode::Write,
-            stack: Stack::new(),
-            registers: vec![Addr::HeapCell(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(); 0],
-            last_call: false,
-            heap_locs: HeapVarDict::new(),
-            flags: MachineFlags::default(),
-            at_end_of_expansion: false
-        }
-    }
-
     #[inline]
     pub fn machine_flags(&self) -> MachineFlags {
         self.flags
@@ -1390,85 +1351,130 @@ impl MachineState {
     }
 
     pub(super)
-    fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) {
-        match instr {
-            &IndexingInstruction::SwitchOnTerm(arg, v, c, l, s) => {
-                let addr = self[temp_v!(arg)];
-                let addr = self.store(self.deref(addr));
+    fn execute_indexing_instr(
+        &mut self,
+        indexing_lines: &Vec<IndexingLine>,
+        call_policy: &mut Box<dyn CallPolicy>,
+    ) {
+        let mut index = 0;
+        let addr =
+            match &indexing_lines[0] {
+                &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
+                    self.store(self.deref(self[temp_v!(arg)]))
+                }
+                _ => {
+                    unreachable!()
+                }
+            };
 
-                let offset = match addr {
-                    Addr::Stream(_) | Addr::TcpListener(_) => {
-                        0
-                    }
-                    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
-                    }
-                };
+        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(..) => {
+                            IndexingCodePtr::External(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 {
-                    0 => self.fail = true,
-                    o => self.p += o,
-                };
-            }
-            &IndexingInstruction::SwitchOnConstant(arg, _, ref hm) => {
-                let addr = self[temp_v!(arg)];
-                let addr = self.store(self.deref(addr));
+                    match offset {
+                        IndexingCodePtr::Fail => {
+                            self.fail = true;
+                            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
+                            }
+                        };
 
-                let offset =
-                    match addr.as_constant_index(&self) {
-                        Some(c) => {
-                            match hm.get(&c) {
-                                Some(offset) => *offset,
-                                _ => 0,
+                    match offset {
+                        IndexingCodePtr::Fail => {
+                            self.fail = true;
+                            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
+                                }
+                            } else {
+                                IndexingCodePtr::Fail
                             }
                         }
-                        None => {
-                            0
+                        _ => {
+                            IndexingCodePtr::Fail
                         }
                     };
 
-                match offset {
-                    0 => self.fail = true,
-                    o => self.p += o,
-                };
-            }
-            &IndexingInstruction::SwitchOnStructure(arg, _, ref hm) => {
-                let a1 = self.registers[arg];
-                let addr = self.store(self.deref(a1));
-
-                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,
-                                _ => 0,
-                            }
-                        } else {
-                            0
+                    match offset {
+                        IndexingCodePtr::Fail => {
+                            self.fail = true;
+                            break;
+                        }
+                        IndexingCodePtr::External(o) => {
+                            self.p += o;
+                            break;
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            index += o;
                         }
                     }
-                    _ => {
-                        0
+                }
+                &IndexingLine::IndexedChoice(ref instrs) => {
+                    if let LocalCodePtr::DirEntry(p) = self.p.local() {
+                        self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
+                    } else {
+                        unreachable!()
                     }
-                };
 
-                match offset {
-                    0 => self.fail = true,
-                    o => self.p += o,
-                };
+                    self.execute_indexed_choice_instr(instrs.first().unwrap(), call_policy);
+                    break;
+                }
             }
         };
     }
@@ -1679,23 +1685,38 @@ impl MachineState {
         Some((name, arity + narity - 1))
     }
 
-    pub(super) fn unwind_stack(&mut self) {
+    pub(super)
+    fn unwind_stack(&mut self) {
         self.b = self.block;
         self.fail = true;
     }
 
-    pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool {
+    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 is_composite = |addr: &Addr| {
+            match *addr {
+                Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => {
+                    true
+                }
+                _ => {
+                    false
+                }
+            }
+        };
+
         loop {
             if let Some(addr) = iter.stack().last() {
-                if !seen.contains(addr) {
-                    seen.insert(*addr);
-                } else {
-                    fail = true;
-                    break;
+                if is_composite(addr) {
+                    if !seen.contains(addr) {
+                        seen.insert(*addr);
+                    } else {
+                        fail = true;
+                        break;
+                    }
                 }
             }
 
@@ -2513,7 +2534,7 @@ impl MachineState {
     }
 
     pub(super)
-    fn try_functor(&mut self, indices: &IndexStore) -> CallResult {
+    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)]));
 
@@ -2531,7 +2552,7 @@ impl MachineState {
                         name.clone(),
                         arity,
                         spec,
-                        &indices.op_dir,
+                        &op_dir,
                     );
 
                     self.try_functor_compound_case(name, arity, spec)
@@ -2545,7 +2566,7 @@ impl MachineState {
                     clause_name!("."),
                     2,
                     None,
-                    &indices.op_dir,
+                    &op_dir,
                 );
 
                 self.try_functor_compound_case(clause_name!("."), 2, spec)
@@ -2620,7 +2641,7 @@ impl MachineState {
                                 name,
                                 arity as usize,
                                 spec,
-                                &indices.op_dir,
+                                &op_dir,
                                 a1.as_var().unwrap(),
                             );
                         } else {
@@ -2637,10 +2658,10 @@ impl MachineState {
                     }
                     Addr::Char(c) => {
                         self.try_functor_fabricate_struct(
-                            clause_name!(c.to_string(), indices.atom_tbl),
+                            clause_name!(c.to_string(), self.atom_tbl),
                             arity as usize,
                             None,
-                            &indices.op_dir,
+                            &op_dir,
                             a1.as_var().unwrap(),
                         );
                     }
@@ -3156,16 +3177,23 @@ impl MachineState {
                 call_policy.call_builtin(
                     self,
                     ct,
-                    indices,
+                    &indices.code_dir,
+                    &indices.op_dir,
                     current_input_stream,
                     current_output_stream,
                 )
             ),
             &ClauseType::CallN => try_or_fail!(
                 self,
-                call_policy.call_n(self, arity, indices, current_input_stream, current_output_stream)
+                call_policy.call_n(
+                    self,
+                    arity,
+                    &indices.code_dir,
+                    &indices.op_dir,
+                    current_input_stream,
+                    current_output_stream,
+                )
             ),
-            &ClauseType::Hook(ref hook) => try_or_fail!(self, call_policy.compile_hook(self, hook)),
             &ClauseType::Inlined(ref ct) => {
                 self.execute_inlined(ct);
 
@@ -3176,7 +3204,7 @@ impl MachineState {
             &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.clone(), indices)
+                    call_policy.context_call(self, name.clone(), arity, idx)
                 )
             }
             &ClauseType::System(ref ct) => try_or_fail!(
@@ -3234,6 +3262,9 @@ impl MachineState {
                 self.b0 = self.b;
                 self.p += offset;
             }
+            &ControlInstruction::RevJmpBy(offset) => {
+                self.p -= offset;
+            }
             &ControlInstruction::Proceed => {
                 self.p = CodePtr::Local(self.cp);
             }
@@ -3272,7 +3303,7 @@ impl MachineState {
                 }
 
                 self.hb = self.heap.h();
-                self.p += offset;
+                self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset));
             }
             &IndexedChoiceInstruction::Retry(l) => {
                 try_or_fail!(self, call_policy.retry(self, l));
@@ -3283,7 +3314,8 @@ impl MachineState {
         };
     }
 
-    pub(super) fn execute_choice_instr(
+    pub(super)
+    fn execute_choice_instr(
         &mut self,
         instr: &ChoiceInstruction,
         call_policy: &mut Box<dyn CallPolicy>,
@@ -3320,14 +3352,14 @@ impl MachineState {
                 let mut call_policy = DefaultCallPolicy {};
                 try_or_fail!(self, call_policy.retry_me_else(self, offset))
             }
-            &ChoiceInstruction::DefaultTrustMe => {
+            &ChoiceInstruction::DefaultTrustMe(_) => {
                 let mut call_policy = DefaultCallPolicy {};
                 try_or_fail!(self, call_policy.trust_me(self))
             }
             &ChoiceInstruction::RetryMeElse(offset) => {
                 try_or_fail!(self, call_policy.retry_me_else(self, offset))
             }
-            &ChoiceInstruction::TrustMe => {
+            &ChoiceInstruction::TrustMe(_) => {
                 try_or_fail!(self, call_policy.trust_me(self))
             }
         }
@@ -3374,30 +3406,4 @@ impl MachineState {
             }
         }
     }
-
-    pub fn reset(&mut self) {
-        self.stack.drop_in_place();
-
-        self.hb = 0;
-        self.e = 0;
-        self.b = 0;
-        self.b0 = 0;
-        self.s = HeapPtr::default();
-        self.tr = 0;
-        self.p = CodePtr::default();
-        self.cp = LocalCodePtr::default();
-        self.attr_var_init.reset();
-        self.num_of_args = 0;
-
-        self.fail = false;
-        self.trail.clear();
-        self.heap.clear();
-        self.mode = MachineMode::Write;
-        self.registers = vec![Addr::HeapCell(0); MAX_ARITY + 1]; // self.registers[0] is never used.
-        self.block = 0;
-
-        self.ball.reset();
-        self.heap_locs.clear();
-        self.lifted_heap.clear();
-    }
 }
index daaf4e813ae2454b5b816415d33907c98476f073..f8d661a21e2d04deb2403bc834f1311ef8886516 100644 (file)
@@ -3,28 +3,29 @@ use crate::prolog_parser::tabled_rc::*;
 
 use crate::clause_types::*;
 use crate::forms::*;
-use crate::heap_print::*;
 use crate::instructions::*;
 use crate::machine::heap::*;
+use crate::machine::loader::*;
+use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream};
 use crate::read::*;
 
 mod attributed_variables;
 pub(super) mod code_repo;
 pub mod code_walker;
-pub mod compile;
+mod compile;
 mod copier;
-mod dynamic_database;
 pub mod heap;
+mod load_state;
+mod loader;
 pub mod machine_errors;
 pub mod machine_indices;
 pub(super) mod machine_state;
-pub mod modules;
 pub mod partial_string;
+mod preprocessor;
 mod raw_block;
 mod stack;
 pub(crate) mod streams;
-pub(super) mod term_expansion;
-pub mod toplevel;
+mod term_stream;
 
 #[macro_use]
 mod arithmetic_ops;
@@ -32,25 +33,21 @@ mod arithmetic_ops;
 mod machine_state_impl;
 mod system_calls;
 
-use crate::machine::attributed_variables::*;
-use crate::machine::code_repo::*;
+//use crate::machine::attributed_variables::*;
 use crate::machine::compile::*;
+use crate::machine::code_repo::*;
+// use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
-use crate::machine::modules::*;
 use crate::machine::streams::*;
-use crate::machine::toplevel::*;
 
 use crate::indexmap::IndexMap;
 
-use std::collections::VecDeque;
-use std::convert::TryFrom;
+//use std::convert::TryFrom;
 use std::fs::File;
 use std::mem;
-use std::ops::Index;
 use std::path::PathBuf;
-use std::rc::Rc;
 use std::sync::atomic::AtomicBool;
 
 #[derive(Debug)]
@@ -81,142 +78,47 @@ impl Default for MachinePolicies {
 }
 
 #[derive(Debug)]
-pub struct Machine {
-    pub(super) machine_st: MachineState,
-    pub(super) inner_heap: Heap,
-    pub(super) policies: MachinePolicies,
-    pub(super) indices: IndexStore,
-    pub(super) code_repo: CodeRepo,
-    pub(super) toplevel_idx: usize,
-    pub(super) current_input_stream: Stream,
-    pub(super) current_output_stream: Stream,
+pub(super) struct LoadContext {
+    pub(super) path: PathBuf,
+    pub(super) stream: Stream,
+    pub(super) module: ClauseName,
 }
 
-impl Index<LocalCodePtr> for CodeRepo {
-    type Output = Line;
-
-    fn index(&self, ptr: LocalCodePtr) -> &Self::Output {
-        match ptr {
-            LocalCodePtr::InSituDirEntry(p) => &self.in_situ_code[p],
-            LocalCodePtr::TopLevel(_, p) => &self.cached_query[p],
-            LocalCodePtr::DirEntry(p) => &self.code[p],
-            LocalCodePtr::UserGoalExpansion(p) => &self.goal_expanders[p],
-            LocalCodePtr::UserTermExpansion(p) => &self.term_expanders[p],
+impl LoadContext {
+    #[inline]
+    fn new(path: &str, stream: Stream) -> Self {
+        LoadContext {
+            path: PathBuf::from(path),
+            stream,
+            module: clause_name!("user"),
         }
     }
 }
 
-impl Index<LocalCodePtr> for Machine {
-    type Output = Line;
-
-    fn index(&self, ptr: LocalCodePtr) -> &Self::Output {
-        &self.code_repo[ptr]
-    }
+#[derive(Debug)]
+pub struct Machine {
+    pub(super) machine_st: MachineState,
+    pub(super) inner_heap: Heap,
+    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) load_contexts: Vec<LoadContext>,
 }
 
-impl SubModuleUser for IndexStore {
-    fn atom_tbl(&self) -> TabledData<Atom> {
-        self.atom_tbl.clone()
-    }
-
-    fn op_dir(&mut self) -> &mut OpDir {
-        &mut self.op_dir
-    }
-
-    fn get_code_index(&self, key: PredicateKey, module_name: ClauseName) -> Option<CodeIndex> {
-        match module_name.as_str() {
-            "user" => {
-                self.code_dir.get(&key).cloned()
-            }
-            _ => {
-                match self.in_situ_module_dir.get(&module_name) {
-                    Some(ref module_stub) => {
-                        match module_stub.in_situ_code_dir.get(&key) {
-                            Some(p) => {
-                                return Some(CodeIndex::new(
-                                    IndexPtr::InSituDirEntry(*p),
-                                    module_name.clone()
-                                ));
-                            }
-                            None => {
-                            }
-                        }
-                    }
-                    None => {
-                    }
-                };
-
-                self.modules
-                    .get(&module_name)
-                    .and_then(|ref module| {
-                        module.code_dir.get(&key).cloned()
-                    })
-            }
-        }
-    }
-
-    fn remove_code_index(&mut self, key: PredicateKey) {
-        self.code_dir.remove(&key);
-    }
-
-    fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
-        if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) {
-            if !code_idx.is_undefined() {
-                match (name.as_str(), arity) {
-                    ("term_expansion", 2) => {
-                    }
-                    ("goal_expansion", 2) => {
-                    }
-                    _ => {
-                        println!("Warning: overwriting {}/{}", &name, arity);
-                    }
-                }
-            }
-
-            let (p, module_name) = idx.0.borrow().clone();
-            set_code_index!(code_idx, p, module_name);
-            return;
-        }
-
-        self.code_dir.insert((name.clone(), arity), idx.clone());
-    }
+#[inline]
+fn current_dir() -> std::path::PathBuf {
+    let mut path_buf = std::path::PathBuf::from(file!());
 
-    fn use_qualified_module(
-        &mut self,
-        code_repo: &mut CodeRepo,
-        _: MachineFlags,
-        submodule: &Module,
-        exports: &Vec<ModuleExport>,
-    ) -> Result<(), SessionError> {
-        use_qualified_module(self, submodule, exports)?;
-        submodule
-            .dump_expansions(code_repo)
-            .map_err(SessionError::from)
-    }
-
-    fn use_module(
-        &mut self,
-        code_repo: &mut CodeRepo,
-        _: MachineFlags,
-        submodule: &Module,
-    ) -> Result<(), SessionError> {
-        use_module(self, submodule)?;
-
-        if !submodule.inserted_expansions {
-            submodule
-                .dump_expansions(code_repo)
-                .map_err(SessionError::from)
-        } else {
-            Ok(())
-        }
-    }
+    path_buf.pop();
+    path_buf
 }
 
 include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
 
-static TOPLEVEL: &str = include_str!("../toplevel.pl");
-
 impl Machine {
+    /*
     fn compile_special_forms(&mut self)
     {
         let verify_attrs_src = ListingSource::User;
@@ -250,36 +152,6 @@ impl Machine {
         }
     }
 
-    fn compile_top_level(&mut self) -> Result<(), SessionError>
-    {
-        self.toplevel_idx = self.code_repo.code.len();
-
-        let top_lvl_src = ListingSource::User;
-
-        compile_user_module(
-            self,
-            Stream::from(TOPLEVEL),
-            true,
-            top_lvl_src,
-        );
-
-        if let Some(module) = self.indices.take_module(clause_name!("$toplevel")) {
-            self.indices.use_module(
-                &mut self.code_repo,
-                self.machine_st.flags,
-                &module,
-            )?;
-
-            Ok(self.indices.insert_module(module))
-        } else {
-            let err = ExistenceError::ModuleSource(ModuleSource::File(
-                clause_name!("$toplevel"),
-            ));
-
-            Err(SessionError::ExistenceError(err))
-        }
-    }
-
     fn compile_scryerrc(&mut self) {
         let mut path = match dirs_next::home_dir() {
             Some(path) => path,
@@ -302,10 +174,10 @@ impl Machine {
                 path.to_path_buf(),
             );
 
-            compile_user_module(self, file_src, true, rc_src);
+            compile_user_module(self, file_src, rc_src);
         }
     }
-
+*/
     #[cfg(test)]
     pub fn reset(&mut self) {
         self.current_input_stream = readline::input_stream();
@@ -313,17 +185,94 @@ impl Machine {
         self.machine_st.reset();
     }
 
-    pub fn run_init_code(&mut self, code: Code) -> bool {
-           let old_machine_st = self.sink_to_snapshot();
-           self.machine_st.reset();
+    fn run_module_predicate(&mut self, module_name: ClauseName, 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));
+
+                return self.run_query();
+            }
+        }
+
+        unreachable!();
+    }
+
+    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,
+            ))
+        );
+
+        self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2));
+    }
+
+    fn load_top_level(&mut self) {
+        let mut path_buf = current_dir();
+        path_buf.push("toplevel.pl");
 
-           self.code_repo.cached_query = code;
-           self.run_query();
+        let path = path_buf.to_str().unwrap().to_string();
 
-        let result = self.machine_st.fail;
-           self.absorb_snapshot(old_machine_st);
+        self.load_file(path, Stream::from(include_str!("../toplevel.pl")));
 
-        !result
+        if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) {
+            load_module(
+                &mut self.indices.code_dir,
+                &mut self.indices.op_dir,
+                &mut self.indices.meta_predicates,
+                toplevel,
+            );
+        } else {
+            unreachable!()
+        }
+    }
+
+    fn load_special_forms(&mut self) {
+        let mut path_buf = current_dir();
+        path_buf.push("machine/attributed_variables.pl");
+
+        bootstrapping_compile(
+            Stream::from(include_str!("attributed_variables.pl")),
+            self,
+            ListingSource::from_file_and_path(
+                clause_name!("attributed_variables"),
+                path_buf,
+            ),
+        ).unwrap();
+
+        let mut path_buf = current_dir();
+        path_buf.push("machine/project_attributes.pl");
+
+        bootstrapping_compile(
+            Stream::from(include_str!("project_attributes.pl")),
+            self,
+            ListingSource::from_file_and_path(
+                clause_name!("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)) {
+                self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap();
+            }
+        }
+
+        if let Some(module) = self.indices.modules.get(&clause_name!("$project_atts")) {
+            if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) {
+                self.machine_st.attr_var_init.project_attrs_loc = code_index.local().unwrap();
+            }
+        }
     }
 
     pub fn run_top_level(&mut self) {
@@ -336,15 +285,16 @@ impl Machine {
         }
 
         let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter()));
+
         self.machine_st[temp_v!(1)] = list_addr;
 
-        loop {
-            self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
-            self.run_query();
-        }
+        // WAS:
+        // self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1));
+
+        self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("repl"), 0));
     }
 
-    pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self
+    pub fn new(user_input: Stream, user_output: Stream) -> Self
     {
         use crate::ref_thread_local::RefThreadLocal;
 
@@ -354,193 +304,107 @@ impl Machine {
             policies: MachinePolicies::new(),
             indices: IndexStore::new(),
             code_repo: CodeRepo::new(),
-            toplevel_idx: 0,
-            current_input_stream,
-            current_output_stream,
+            user_input,
+            user_output,
+            load_contexts: vec![],
         };
 
-        let atom_tbl = wam.indices.atom_tbl.clone();
+        let mut lib_path = current_dir();
 
-        wam.indices.add_term_and_goal_expansion_indices();
+        lib_path.pop();
+        lib_path.push("lib");
 
-        compile_listing(
+        bootstrapping_compile(
+            Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]),
             &mut wam,
-            Stream::from(LIBRARIES.borrow()["builtins"]),
-            default_index_store!(atom_tbl.clone()),
-            true,
-            ListingSource::User,
-        );
+            ListingSource::from_file_and_path(
+                clause_name!("ops_and_meta_predicates.pl"),
+                lib_path.clone(),
+            ),
+        ).unwrap();
 
-        wam.compile_special_forms();
-
-        compile_user_module(
-            &mut wam,
-            Stream::from(LIBRARIES.borrow()["error"]),
-            true,
-            ListingSource::User,
-        );
-
-        compile_user_module(
-            &mut wam,
-            Stream::from(LIBRARIES.borrow()["pairs"]),
-            true,
-            ListingSource::User,
-        );
-
-        compile_user_module(
+        bootstrapping_compile(
+            Stream::from(LIBRARIES.borrow()["builtins"]),
             &mut wam,
-            Stream::from(LIBRARIES.borrow()["lists"]),
-            true,
-            ListingSource::User,
-        );
+            ListingSource::from_file_and_path(
+                clause_name!("builtins.pl"),
+                lib_path.clone(),
+            ),
+        ).unwrap();
+
+        if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) {
+            load_module(
+                &mut wam.indices.code_dir,
+                &mut wam.indices.op_dir,
+                &mut wam.indices.meta_predicates,
+                builtins,
+            );
+        } else {
+            unreachable!()
+        }
 
-        compile_user_module(
-            &mut wam,
-            Stream::from(LIBRARIES.borrow()["iso_ext"]),
-            true,
-            ListingSource::User,
-        );
+        lib_path.pop(); // remove the "lib" at the end
 
-        compile_user_module(
+        bootstrapping_compile(
+            Stream::from(include_str!("../term_and_goal_expansion.pl")),
             &mut wam,
-            Stream::from(LIBRARIES.borrow()["si"]),
-            true,
-            ListingSource::User,
-        );
-
-        compile_user_module(
+            ListingSource::from_file_and_path(
+                clause_name!("term_and_goal_expansion.pl"),
+                lib_path.clone(),
+            ),
+        ).unwrap();
+
+        bootstrapping_compile(
+            Stream::from(include_str!("../loader.pl")),
             &mut wam,
-            Stream::from(LIBRARIES.borrow()["charsio"]),
-            true,
-            ListingSource::User,
-        );
-
-        if wam.compile_top_level().is_err() {
-            panic!("Loading '$toplevel' module failed");
+            ListingSource::from_file_and_path(
+                clause_name!("loader.pl"),
+                lib_path.clone(),
+            ),
+        ).unwrap();
+
+        if let Some(loader) = wam.indices.modules.get(&clause_name!("loader")) {
+            load_module(
+                &mut wam.indices.code_dir,
+                &mut wam.indices.op_dir,
+                &mut wam.indices.meta_predicates,
+                loader,
+            );
+        } else {
+            unreachable!()
         }
 
-        wam.compile_scryerrc();
+        wam.load_special_forms();
+        wam.load_top_level();
         wam.configure_streams();
 
         wam
     }
 
     pub fn configure_streams(&mut self) {
-        self.current_input_stream.options.alias = Some(clause_name!("user_input"));
+        self.user_input.options.alias = Some(clause_name!("user_input"));
 
         self.indices.stream_aliases.insert(
             clause_name!("user_input"),
-            self.current_input_stream.clone(),
+            self.user_input.clone(),
         );
 
         self.indices.streams.insert(
-            self.current_input_stream.clone()
+            self.user_input.clone()
         );
 
-        self.current_output_stream.options.alias = Some(clause_name!("user_output"));
+        self.user_output.options.alias = Some(clause_name!("user_output"));
 
         self.indices.stream_aliases.insert(
             clause_name!("user_output"),
-            self.current_output_stream.clone(),
+            self.user_output.clone(),
         );
 
         self.indices.streams.insert(
-            self.current_output_stream.clone()
+            self.user_output.clone()
         );
     }
 
-    #[inline]
-    pub fn machine_flags(&self) -> MachineFlags {
-        self.machine_st.flags
-    }
-
-    pub fn check_toplevel_code(&self, indices: &IndexStore) -> Result<(), SessionError> {
-        for (key, idx) in &indices.code_dir {
-            match ClauseType::from(key.0.clone(), key.1, None) {
-                ClauseType::Named(..) | ClauseType::Op(..) => {}
-                _ => {
-                    // ensure we don't try to overwrite the name/arity of a builtin.
-                    let err_str = format!("{}/{}", key.0, key.1);
-                    let err_str = clause_name!(err_str, self.indices.atom_tbl());
-
-                    return Err(SessionError::CannotOverwriteBuiltIn(err_str));
-                }
-            };
-
-            if let Some(ref existing_idx) = self.indices.code_dir.get(&key) {
-                // ensure we don't try to overwrite an existing predicate from a different module.
-                if !existing_idx.is_undefined() && !idx.is_undefined() {
-                    // allow the overwriting of user-level predicates by all other predicates.
-                    if existing_idx.module_name().as_str() == "user" {
-                        continue;
-                    }
-
-                    if existing_idx.module_name() != idx.module_name() {
-                        let err_str = format!(
-                            "{}/{} from module {}",
-                            key.0,
-                            key.1,
-                            existing_idx.module_name().as_str()
-                        );
-                        let err_str = clause_name!(err_str, self.indices.atom_tbl());
-
-                        return Err(SessionError::CannotOverwriteImport(err_str));
-                    }
-                }
-            }
-        }
-
-        Ok(())
-    }
-
-    pub(crate) fn add_batched_code_dir(&mut self, code_dir: CodeDir) {
-        // error detection has finished, so update the master index of keys.
-        for (key, idx) in code_dir {
-            if let Some(ref master_idx) = self.indices.code_dir.get(&key) {
-                // ensure we don't double borrow if master_idx == idx.
-                // we don't need to modify anything in that case.
-                if !Rc::ptr_eq(&master_idx.0, &idx.0) {
-                    set_code_index!(master_idx, idx.0.borrow().0, idx.module_name());
-                }
-
-                continue;
-            }
-
-            self.indices.code_dir.insert(key, idx);
-        }
-    }
-
-    #[inline]
-    pub(crate) fn add_batched_ops(&mut self, op_dir: OpDir) {
-        self.indices.op_dir.extend(op_dir.into_iter());
-    }
-
-    pub(crate) fn add_in_situ_module_dir(&mut self, module_dir: ModuleDir) {
-        for (module_name, module_skeleton) in module_dir {
-            match self.indices.modules.get_mut(&module_name) {
-                Some(ref mut module) => {
-                    for (key, idx) in module_skeleton.code_dir {
-                        if let Some(existing_idx) = module.code_dir.get(&key) {
-                            set_code_index!(existing_idx, idx.0.borrow().0, module_name.clone());
-                        } else {
-                            module.code_dir.insert(key, idx);
-                        }
-                    }
-                }
-                None => {
-                    self.add_module(module_skeleton);
-                }
-            }
-        }
-    }
-
-    #[inline]
-    pub fn add_module(&mut self, module: Module) {
-        self.indices
-            .modules
-            .insert(module.module_decl.name.clone(), module);
-    }
-
     fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
         let h = self.machine_st.heap.h();
 
@@ -552,307 +416,118 @@ impl Machine {
         return;
     }
 
-    fn extract_module_export_list(&mut self) -> Result<Vec<ModuleExport>, ParserError>
-    {
-           let mut export_list = self.machine_st[temp_v!(2)].clone();
-           let mut exports = vec![];
-
-           while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) {
-               match &self.machine_st.heap[l] {
-                       &HeapCellValue::Addr(Addr::Str(s)) => {
-                    match &self.machine_st.heap[s] {
-                        HeapCellValue::NamedStr(arity, ref name, _)
-                            if *arity == 2 && name.as_str() == "/" => {
-                                       let name = match &self.machine_st.heap[s+1] {
-                                               &HeapCellValue::Atom(ref name, _) =>
-                                                   name.clone(),
-                                               _ =>
-                                                   unreachable!()
-                                       };
-
-                                       let arity = match &self.machine_st.heap[s+2] {
-                                               &HeapCellValue::Integer(ref arity) =>
-                                                   arity.to_usize().unwrap(),
-                                    &HeapCellValue::Addr(Addr::Fixnum(n)) =>
-                                        usize::try_from(n).unwrap(),
-                                               _ =>
-                                                   unreachable!()
-                                       };
-
-                                       exports.push(ModuleExport::PredicateKey((name, arity)));
-                            }
-                        HeapCellValue::NamedStr(arity, ref name, _)
-                            if *arity == 3 && name.as_str() == "op" => {
-                                let name = match &self.machine_st.heap[s+3] {
-                                               &HeapCellValue::Atom(ref name, _) =>
-                                                   name.clone(),
-                                               _ =>
-                                                   unreachable!()
-                                       };
-
-                                let spec = match &self.machine_st.heap[s+2] {
-                                               &HeapCellValue::Atom(ref name, _) =>
-                                                   name.clone(),
-                                               _ =>
-                                                   unreachable!()
-                                       };
-
-                                       let prec = match &self.machine_st.heap[s+1] {
-                                               &HeapCellValue::Integer(ref arity) =>
-                                                   arity.to_usize().unwrap(),
-                                    &HeapCellValue::Addr(Addr::Fixnum(n)) =>
-                                        usize::try_from(n).unwrap(),
-                                               _ =>
-                                                   unreachable!()
-                                       };
-
-                                exports.push(ModuleExport::OpDecl(to_op_decl(
-                                    prec,
-                                    spec.as_str(),
-                                    name,
-                                )?));
-                            }
-                        _ => unreachable!()
-                    }
-                       }
-                       _ => unreachable!()
-               }
-
-               export_list = self.machine_st.heap[l+1].as_addr(l+1);
-           }
-
-           Ok(exports)
-    }
-
-    fn use_module<ToSource>(&mut self, to_src: ToSource)
-       where ToSource: Fn(ClauseName) -> ModuleSource
-    {
-           // the term expander will overwrite the cached query, so save it here.
-           let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
-
-           let module_spec = self.machine_st[temp_v!(1)].clone();
-           let name = {
-            let addr = self.machine_st.store(self.machine_st.deref(module_spec));
-
-            match self.machine_st.heap.index_addr(&addr).as_ref() {
-                HeapCellValue::Atom(name, _) =>
-                    name.clone(),
-                HeapCellValue::Addr(Addr::Char(c)) =>
-                    clause_name!(c.to_string(), self.indices.atom_tbl),
-                HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => {
-                    let mut heap_pstr_iter =
-                        self.machine_st.heap_pstr_iter(*addr);
-                    clause_name!(
-                        heap_pstr_iter.to_string(),
-                        self.indices.atom_tbl
-                    )
-                }
-                _ => unreachable!(),
+    fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
+        match code_ptr {
+            REPLCodePtr::AddDynamicPredicate => {
+                self.add_dynamic_predicate();
             }
-           };
-
-           let load_result = match to_src(name) {
-               ModuleSource::Library(name) =>
-                if let Some(module) = self.indices.take_module(name.clone()) {
-                    self.indices.remove_module(clause_name!("user"), &module);
-                    self.indices.modules.insert(name.clone(), module);
-
-                           Ok(name)
-                       } else {
-                           load_library(self, name, false)
-                       },
-               ModuleSource::File(name) =>
-                load_module_from_file(self, PathBuf::from(name.as_str()), false)
-           };
-
-           let result = load_result.and_then(|name| {
-            let module = self.indices.take_module(name.clone()).unwrap();
-
-            if !module.is_impromptu_module {
-                self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?;
+            REPLCodePtr::AddGoalExpansionClause => {
+                self.add_goal_expansion_clause();
             }
-
-            Ok(self.indices.insert_module(module))
-        });
-
-           self.code_repo.cached_query = cached_query;
-
-           if let Err(e) = result {
-               self.throw_session_error(e, (clause_name!("use_module"), 1));
-           }
-    }
-
-    fn use_qualified_module<ToSource>(&mut self, to_src: ToSource)
-       where ToSource: Fn(ClauseName) -> ModuleSource
-    {
-           // the term expander will overwrite the cached query, so save it here.
-           let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
-
-           let module_spec = self.machine_st[temp_v!(1)].clone();
-           let name = {
-            let addr = self.machine_st.store(self.machine_st.deref(module_spec));
-
-            match self.machine_st.heap.index_addr(&addr).as_ref() {
-                HeapCellValue::Atom(name, _) =>
-                    name.clone(),
-                HeapCellValue::Addr(Addr::Char(c)) =>
-                    clause_name!(c.to_string(), self.indices.atom_tbl),
-                   _ =>
-                    unreachable!(),
+            REPLCodePtr::AddTermExpansionClause => {
+                self.add_term_expansion_clause();
             }
-           };
-
-           let exports = match self.extract_module_export_list() {
-            Ok(exports) => exports,
-            Err(e) => {
-                self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2));
-                return;
+            REPLCodePtr::ClauseToEvacuable => {
+                self.clause_to_evacuable();
             }
-        };
-
-           let load_result = match to_src(name) {
-               ModuleSource::Library(name) =>
-                if let Some(module) = self.indices.take_module(name.clone()) {
-                    self.indices.remove_module(clause_name!("user"), &module);
-                    self.indices.modules.insert(name.clone(), module);
-
-                           Ok(name)
-                       } else {
-                           load_library(self, name, false)
-                       },
-               ModuleSource::File(name) =>
-                load_module_from_file(self, PathBuf::from(name.as_str()), false)
-           };
-
-           let result = load_result.and_then(|name| {
-               let module = self.indices.take_module(name.clone()).unwrap();
-
-            if !module.is_impromptu_module {
-                   self.indices.use_qualified_module(&mut self.code_repo,
-                                                                     self.machine_st.flags,
-                                                                     &module,
-                                                                     &exports)?;
+            REPLCodePtr::ConcludeLoad => {
+                self.conclude_load();
             }
-
-               Ok(self.indices.insert_module(module))
-        });
-
-           self.code_repo.cached_query = cached_query;
-
-           if let Err(e) = result {
-               self.throw_session_error(e, (clause_name!("use_module"), 2));
-           }
-    }
-
-    fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
-        match code_ptr {
-            REPLCodePtr::CompileBatch => {
-                let user_src = ListingSource::User;
-
-                let src = readline::input_stream();
-                readline::set_prompt(false);
-
-                if let EvalSession::Error(e) = compile_user_module(self, src, false, user_src) {
-                    self.throw_session_error(e, (clause_name!("repl"), 0));
-                }
+            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::CompilePendingPredicates => {
+                self.compile_pending_predicates();
+            }
+            REPLCodePtr::UserAssertz => {
+                self.compile_user_assert(AppendOrPrepend::Append);
+            }
+            REPLCodePtr::UserAsserta => {
+                self.compile_user_assert(AppendOrPrepend::Prepend);
+            }
+            REPLCodePtr::UserRetract => {
+                self.retract_user_clause();
             }
-               REPLCodePtr::UseModule =>
-                       self.use_module(ModuleSource::Library),
-               REPLCodePtr::UseModuleFromFile =>
-                       self.use_module(ModuleSource::File),
-               REPLCodePtr::UseQualifiedModule =>
-                       self.use_qualified_module(ModuleSource::Library),
-               REPLCodePtr::UseQualifiedModuleFromFile =>
-                       self.use_qualified_module(ModuleSource::File)
         }
 
         self.machine_st.p = CodePtr::Local(p);
     }
 
-    fn sink_to_snapshot(&mut self) -> MachineState {
-        let mut snapshot = MachineState::with_small_heap();
-
-        snapshot.hb = self.machine_st.hb;
-        snapshot.e = self.machine_st.e;
-        snapshot.b = self.machine_st.b;
-        snapshot.b0 = self.machine_st.b0;
-        snapshot.s = self.machine_st.s.clone();
-        snapshot.tr = self.machine_st.tr;
-        snapshot.num_of_args = self.machine_st.num_of_args;
-
-        snapshot.fail = self.machine_st.fail;
-        snapshot.trail = mem::replace(&mut self.machine_st.trail, vec![]);
-        snapshot.heap = self.machine_st.heap.take();
-        snapshot.mode = self.machine_st.mode;
-        snapshot.stack = self.machine_st.stack.take();
-        snapshot.registers = mem::replace(&mut self.machine_st.registers, vec![]);
-        snapshot.block = self.machine_st.block;
-
-        snapshot.ball = self.machine_st.ball.take();
-        snapshot.lifted_heap = self.machine_st.lifted_heap.take();
-
-        snapshot
-    }
-
-    fn absorb_snapshot(&mut self, mut snapshot: MachineState) {
-        self.machine_st.hb = snapshot.hb;
-        self.machine_st.e = snapshot.e;
-        self.machine_st.b = snapshot.b;
-        self.machine_st.b0 = snapshot.b0;
-        self.machine_st.s = snapshot.s;
-        self.machine_st.tr = snapshot.tr;
-        self.machine_st.num_of_args = snapshot.num_of_args;
-
-        self.machine_st.fail = snapshot.fail;
-        self.machine_st.trail = mem::replace(&mut snapshot.trail, vec![]);
-
-        self.inner_heap = self.machine_st.heap.take();
-        self.inner_heap.truncate(0);
-
-        self.machine_st.heap = snapshot.heap.take();
-        self.machine_st.mode = snapshot.mode;
-        self.machine_st.stack = snapshot.stack;
-        self.machine_st.registers = mem::replace(&mut snapshot.registers, vec![]);
-        self.machine_st.block = snapshot.block;
-
-        self.machine_st.ball = snapshot.ball.take();
-        self.machine_st.lifted_heap = snapshot.lifted_heap.take();
-    }
-
-    pub(super) fn run_query(&mut self) {
-           self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
-        let end_ptr = CodePtr::Local(self.machine_st.cp);
-
-        while self.machine_st.p < end_ptr {
+    pub(super)
+    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.current_input_stream,
-                &mut self.current_output_stream,
+                &mut self.user_input,
+                &mut self.user_output,
             );
 
             match self.machine_st.p {
-                CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {
-                }
                 CodePtr::REPL(code_ptr, p) => {
-                    self.handle_toplevel_command(code_ptr, p)
+                    self.handle_toplevel_command(code_ptr, p);
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    }
                 }
-                CodePtr::DynamicTransaction(trans_type, p) => {
+                /*
+                CodePtr::DynamicTransaction(_trans_type, _p) => {
                     // self.code_repo.cached_query is about to be overwritten by the term expander,
                     // so hold onto it locally and restore it after the compiler has finished.
                     self.machine_st.fail = false;
+                    /*
                     let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
 
-                    self.dynamic_transaction(trans_type, p);
+                    // self.dynamic_transaction(trans_type, p);
                     self.code_repo.cached_query = cached_query;
 
                     if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p {
                         break;
                     }
+                    */
+                }
+                */
+                _ => {
+                    break;
                 }
-                _ =>
-                    break
             };
         }
     }
@@ -865,8 +540,8 @@ impl MachineState {
         indices: &mut IndexStore,
         policies: &mut MachinePolicies,
         code_repo: &CodeRepo,
-        current_input_stream: &mut Stream,
-        current_output_stream: &mut Stream,
+        user_input: &mut Stream,
+        user_output: &mut Stream,
     ) {
         match instr {
             &Line::Arithmetic(ref arith_instr) => {
@@ -884,8 +559,8 @@ impl MachineState {
                     code_repo,
                     &mut policies.call_policy,
                     &mut policies.cut_policy,
-                    current_input_stream,
-                    current_output_stream,
+                    user_input,
+                    user_output,
                     control_instr,
                 )
             }
@@ -893,8 +568,8 @@ impl MachineState {
                 self.execute_fact_instr(&fact_instr);
                 self.p += 1;
             }
-            &Line::Indexing(ref indexing_instr) => {
-                self.execute_indexing_instr(&indexing_instr)
+            &Line::IndexingCode(ref indexing_lines) => {
+                self.execute_indexing_instr(indexing_lines, &mut policies.call_policy)
             }
             &Line::IndexedChoice(ref choice_instr) => {
                 self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
@@ -911,8 +586,8 @@ impl MachineState {
         indices: &mut IndexStore,
         policies: &mut MachinePolicies,
         code_repo: &CodeRepo,
-        current_input_stream: &mut Stream,
-        current_output_stream: &mut Stream,
+        user_input: &mut Stream,
+        user_output: &mut Stream,
     ) {
         let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
             Some(instr) => instr,
@@ -924,40 +599,40 @@ impl MachineState {
             indices,
             policies,
             code_repo,
-            current_input_stream,
-            current_output_stream,
+            user_input,
+            user_output,
         );
     }
 
     fn backtrack(&mut self) {
-        if self.b > 0 {
-            let b = self.b;
+        // if self.b > 0 {
+        let b = self.b;
 
-            self.b0 = self.stack.index_or_frame(b).prelude.b0;
-            self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp);
+        self.b0 = self.stack.index_or_frame(b).prelude.b0;
+        self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp);
 
-            if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p {
-                self.fail = p == 0;
-            } else {
-                self.fail = false;
-            }
+        /*
+        if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p {
+            self.fail = p == 0;
         } else {
+        */
+        self.fail = false;
+        // }
+        /*} else {
             self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0));
-        }
+        }*/
     }
 
     fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool {
         match self.p {
-            CodePtr::Local(LocalCodePtr::DirEntry(p)) if p < code_repo.code.len() => {}
-            CodePtr::Local(LocalCodePtr::UserTermExpansion(p))
-                if p < code_repo.term_expanders.len() => {}
-            CodePtr::Local(LocalCodePtr::UserTermExpansion(_)) => self.fail = true,
-            CodePtr::Local(LocalCodePtr::UserGoalExpansion(p))
-                if p < code_repo.goal_expanders.len() => {}
-            CodePtr::Local(LocalCodePtr::UserGoalExpansion(_)) => self.fail = true,
-            CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) if p < code_repo.in_situ_code.len() => {
+            CodePtr::Local(LocalCodePtr::DirEntry(p)) |
+            CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..))
+                if p < code_repo.code.len() => {
+                }
+            CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => {
+                return false;
             }
-            CodePtr::Local(_) | CodePtr::REPL(..) => return false,
+            /*
             CodePtr::DynamicTransaction(..) => {
                 // prevent use of dynamic transactions from
                 // succeeding in expansions. self.fail will be toggled
@@ -965,7 +640,9 @@ impl MachineState {
                 self.fail = true;
                 return false;
             }
-            _ => {}
+            */
+            _ => {
+            }
         }
 
         true
@@ -977,8 +654,8 @@ impl MachineState {
         indices: &mut IndexStore,
         policies: &mut MachinePolicies,
         code_repo: &mut CodeRepo,
-        current_input_stream: &mut Stream,
-        current_output_stream: &mut Stream,
+        user_input: &mut Stream,
+        user_output: &mut Stream,
     ) -> bool {
         loop {
             let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
@@ -999,8 +676,8 @@ impl MachineState {
                 indices,
                 policies,
                 code_repo,
-                current_input_stream,
-                current_output_stream,
+                user_input,
+                user_output,
             );
 
             if self.fail {
@@ -1025,16 +702,16 @@ impl MachineState {
         indices: &mut IndexStore,
         policies: &mut MachinePolicies,
         code_repo: &mut CodeRepo,
-        current_input_stream: &mut Stream,
-        current_output_stream: &mut Stream,
+        user_input: &mut Stream,
+        user_output: &mut Stream,
     ) {
         loop {
             self.execute_instr(
                 indices,
                 policies,
                 code_repo,
-                current_input_stream,
-                current_output_stream,
+                user_input,
+                user_output,
             );
 
             if self.fail {
@@ -1055,8 +732,8 @@ impl MachineState {
                         indices,
                         policies,
                         code_repo,
-                        current_input_stream,
-                        current_output_stream,
+                        user_input,
+                        user_output,
                     ) {
                         if self.fail {
                             break;
diff --git a/src/machine/modules.rs b/src/machine/modules.rs
deleted file mode 100644 (file)
index 4257603..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-use crate::prolog_parser::ast::*;
-use crate::prolog_parser::tabled_rc::*;
-
-use crate::forms::*;
-use crate::machine::code_repo::*;
-use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::*;
-
-use std::collections::VecDeque;
-use std::mem;
-
-// Module's and related types are defined in forms.
-impl Module {
-    pub fn new(
-        module_decl: ModuleDecl,
-        atom_tbl: TabledData<Atom>,
-        listing_src: ListingSource,
-    ) -> Self
-    {
-        Module {
-            atom_tbl,
-            module_decl,
-            term_dir: TermDir::new(),
-            user_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
-            user_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
-            term_expansions: (Predicate::new(), VecDeque::from(vec![])),
-            goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
-            local_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
-            local_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
-            code_dir: CodeDir::new(),
-            op_dir: default_op_dir(),
-            inserted_expansions: false,
-            is_impromptu_module: false,
-            listing_src,
-        }
-    }
-
-    pub fn dump_expansions(
-        &self,
-        code_repo: &mut CodeRepo,
-    ) -> Result<(), ParserError> {
-        {
-            let te = code_repo
-                .term_dir
-                .entry((clause_name!("term_expansion"), 2))
-                .or_insert((Predicate::new(), VecDeque::from(vec![])));
-
-            (te.0)
-                .0
-                .extend((self.user_term_expansions.0).0.iter().cloned());
-
-            te.1.extend(self.user_term_expansions.1.iter().cloned());
-        }
-
-        {
-            let ge = code_repo
-                .term_dir
-                .entry((clause_name!("goal_expansion"), 2))
-                .or_insert((Predicate::new(), VecDeque::from(vec![])));
-
-            (ge.0)
-                .0
-                .extend((self.user_goal_expansions.0).0.iter().cloned());
-
-            ge.1.extend(self.user_goal_expansions.1.iter().cloned());
-        }
-
-        code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
-        code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
-
-        Ok(())
-    }
-
-    pub fn add_expansion_record(
-        &mut self,
-        hook: CompileTimeHook,
-        clause: PredicateClause,
-        queue: VecDeque<TopLevel>,
-    ) {
-        match hook {
-            CompileTimeHook::TermExpansion | CompileTimeHook::UserTermExpansion => {
-                (self.term_expansions.0).0.push(clause);
-                self.term_expansions.1.extend(queue.into_iter());
-            }
-            CompileTimeHook::GoalExpansion | CompileTimeHook::UserGoalExpansion => {
-                (self.goal_expansions.0).0.push(clause);
-                self.goal_expansions.1.extend(queue.into_iter());
-            }
-        }
-    }
-
-    pub fn add_local_expansion(
-        &mut self,
-        hook: CompileTimeHook,
-        clause: PredicateClause,
-        queue: VecDeque<TopLevel>,
-    ) {
-        match hook {
-            CompileTimeHook::TermExpansion => {
-                (self.local_term_expansions.0).0.push(clause);
-                self.local_term_expansions.1.extend(queue.into_iter());
-            }
-            CompileTimeHook::GoalExpansion => {
-                (self.local_goal_expansions.0).0.push(clause);
-                self.local_goal_expansions.1.extend(queue.into_iter());
-            }
-            _ => {}
-        }
-    }
-
-    pub fn take_local_expansions(&mut self) -> Vec<(Predicate, VecDeque<TopLevel>)>
-    {
-        let term_expansions =
-            mem::replace(&mut self.local_term_expansions, (Predicate::new(), VecDeque::new()));
-        let goal_expansions =
-            mem::replace(&mut self.local_goal_expansions, (Predicate::new(), VecDeque::new()));
-
-        vec![term_expansions, goal_expansions]
-    }
-}
-
-pub trait SubModuleUser {
-    fn atom_tbl(&self) -> TabledData<Atom>;
-    fn op_dir(&mut self) -> &mut OpDir;
-    fn remove_code_index(&mut self, _: PredicateKey);
-    fn get_code_index(&self, _: PredicateKey, _: ClauseName) -> Option<CodeIndex>;
-
-    fn insert_dir_entry(&mut self, _: ClauseName, _: usize, _: CodeIndex);
-
-    fn get_op_module_name(&mut self, name: ClauseName, fixity: Fixity) -> Option<ClauseName> {
-        self.op_dir()
-            .get(&(name, fixity))
-            .map(|op_val| op_val.owning_module())
-    }
-
-    fn remove_module(&mut self, mod_name: ClauseName, module: &Module) {
-        for export in module.module_decl.exports.iter().cloned() {
-            match export {
-                ModuleExport::PredicateKey((name, arity)) => {
-                    let name = name.defrock_brackets();
-
-                    match self.get_code_index((name.clone(), arity), mod_name.clone()) {
-                        Some(CodeIndex(ref code_idx)) => {
-                            if &code_idx.borrow().1 != &module.module_decl.name {
-                                continue;
-                            }
-
-                            self.remove_code_index((name.clone(), arity));
-
-                            // remove or respecify ops.
-                            if arity == 2 {
-                                if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::In) {
-                                    if mod_name == module.module_decl.name {
-                                        self.op_dir().remove(&(name.clone(), Fixity::In));
-                                    }
-                                }
-                            } else if arity == 1 {
-                                if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Pre) {
-                                    if mod_name == module.module_decl.name {
-                                        self.op_dir().remove(&(name.clone(), Fixity::Pre));
-                                    }
-                                }
-
-                                if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
-                                {
-                                    if mod_name == module.module_decl.name {
-                                        self.op_dir().remove(&(name.clone(), Fixity::Post));
-                                    }
-                                }
-                            }
-                        }
-                        _ => {}
-                    };
-                },
-                ModuleExport::OpDecl(op_decl) => {
-                    let op_dir = self.op_dir();
-                    op_dir.remove(&(op_decl.name(), op_decl.fixity()));
-                }
-            }
-        }
-    }
-
-    // returns true on successful import.
-    fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
-        let name = name.defrock_brackets();
-
-        if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
-            let name = name.with_table(submodule.atom_tbl.clone());
-            let atom_tbl = self.atom_tbl();
-
-            atom_tbl.borrow_mut().insert(name.to_rc());
-
-            self.insert_dir_entry(name, arity, code_data.clone());
-            true
-        } else {
-            submodule.is_impromptu_module
-        }
-    }
-
-    fn use_qualified_module(
-        &mut self,
-        _: &mut CodeRepo,
-        _: MachineFlags,
-        _: &Module,
-        _: &Vec<ModuleExport>,
-    ) -> Result<(), SessionError>;
-
-    fn use_module(
-        &mut self,
-        _: &mut CodeRepo,
-        _: MachineFlags,
-        _: &Module
-    ) -> Result<(), SessionError>;
-}
-
-pub fn use_qualified_module<User>(
-    user: &mut User,
-    submodule: &Module,
-    exports: &Vec<ModuleExport>,
-) -> Result<(), SessionError>
-where
-    User: SubModuleUser,
-{
-    for export in exports.iter().cloned() {
-        match export {
-            ModuleExport::PredicateKey((name, arity)) => {
-                if !submodule
-                    .module_decl
-                    .exports
-                    .contains(&ModuleExport::PredicateKey((name.clone(), arity)))
-                {
-                    continue;
-                }
-
-                if !user.import_decl(name.clone(), arity, submodule) {
-                    let submodule_name = submodule.module_decl.name.clone();
-
-                    return Err(SessionError::ModuleDoesNotContainExport(
-                        submodule_name,
-                        (name, arity)
-                    ));
-                }
-            },
-            ModuleExport::OpDecl(op_decl) => {
-                if !submodule
-                    .module_decl
-                    .exports
-                    .contains(&ModuleExport::OpDecl(op_decl.clone()))
-                {
-                    continue;
-                }
-
-                let op_dir = user.op_dir();
-                let prec = op_decl.0;
-
-                op_decl.insert_into_op_dir(
-                    submodule.module_decl.name.clone(),
-                    op_dir,
-                    prec,
-                );
-            }
-        }
-    }
-
-    Ok(())
-}
-
-pub fn use_module<User: SubModuleUser>(
-    user: &mut User,
-    submodule: &Module,
-) -> Result<(), SessionError> {
-    for export in submodule.module_decl.exports.iter().cloned() {
-        match export {
-            ModuleExport::PredicateKey((name, arity)) => {
-                if !user.import_decl(name.clone(), arity, submodule) {
-                    let submodule_name = submodule.module_decl.name.clone();
-
-                    return Err(SessionError::ModuleDoesNotContainExport(
-                        submodule_name,
-                        (name, arity)
-                    ));
-                }
-            }
-            ModuleExport::OpDecl(op_decl) => {
-                let op_dir = user.op_dir();
-                let prec = op_decl.0;
-
-                op_decl.insert_into_op_dir(
-                    submodule.module_decl.name.clone(),
-                    op_dir,
-                    prec,
-                );
-            }
-        }
-    }
-
-    Ok(())
-}
-
-impl SubModuleUser for Module {
-    fn atom_tbl(&self) -> TabledData<Atom> {
-        self.atom_tbl.clone()
-    }
-
-    fn op_dir(&mut self) -> &mut OpDir {
-        &mut self.op_dir
-    }
-
-    fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option<CodeIndex> {
-        self.code_dir.get(&key).cloned()
-    }
-
-    fn remove_code_index(&mut self, key: PredicateKey) {
-        self.code_dir.remove(&key);
-    }
-
-    fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
-        self.code_dir.insert((name, arity), idx);
-    }
-
-    fn use_qualified_module(
-        &mut self,
-        _: &mut CodeRepo,
-        _: MachineFlags,
-        submodule: &Module,
-        exports: &Vec<ModuleExport>,
-    ) -> Result<(), SessionError> {
-        use_qualified_module(self, submodule, exports)?;
-
-        (self.user_term_expansions.0)
-            .0
-            .extend((submodule.term_expansions.0).0.iter().cloned());
-        self.user_term_expansions
-            .1
-            .extend(submodule.term_expansions.1.iter().cloned());
-
-        (self.user_goal_expansions.0)
-            .0
-            .extend((submodule.goal_expansions.0).0.iter().cloned());
-        self.user_goal_expansions
-            .1
-            .extend(submodule.goal_expansions.1.iter().cloned());
-
-        Ok(())
-    }
-
-    fn use_module(
-        &mut self,
-        _: &mut CodeRepo,
-        _: MachineFlags,
-        submodule: &Module,
-    ) -> Result<(), SessionError> {
-        use_module(self, submodule)?;
-
-        (self.user_term_expansions.0)
-            .0
-            .extend((submodule.term_expansions.0).0.iter().cloned());
-        self.user_term_expansions
-            .1
-            .extend(submodule.term_expansions.1.iter().cloned());
-
-        (self.user_goal_expansions.0)
-            .0
-            .extend((submodule.goal_expansions.0).0.iter().cloned());
-        self.user_goal_expansions
-            .1
-            .extend(submodule.goal_expansions.1.iter().cloned());
-
-        Ok(())
-    }
-}
index 1413b37cca32fc1d12b760fde4985e931a38ba22..7d865d4975e3d522e34447819329e2a908a110ad 100644 (file)
@@ -1,12 +1,18 @@
+use crate::machine::*;
+use crate::machine::machine_indices::*;
+
 use core::marker::PhantomData;
 
 use std::alloc;
+use std::cmp::Ordering;
 use std::mem;
 use std::ptr;
 use std::ops::RangeFrom;
 use std::slice;
 use std::str;
 
+use indexmap::IndexSet;
+
 #[derive(Debug)]
 pub struct PartialString {
     buf: *const u8,
@@ -200,3 +206,290 @@ impl PartialString {
         }
     }
 }
+
+#[derive(Debug)]
+pub(crate) struct HeapPStrIter<'a> {
+    focus: Addr,
+    machine_st: &'a MachineState,
+    seen: IndexSet<Addr>,
+}
+
+impl<'a> HeapPStrIter<'a> {
+    #[inline]
+    pub(super)
+    fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
+        HeapPStrIter {
+            focus,
+            machine_st,
+            seen: IndexSet::new(),
+        }
+    }
+
+    #[inline]
+    pub(crate)
+    fn focus(&self) -> Addr {
+        self.machine_st.store(self.machine_st.deref(self.focus))
+    }
+
+    #[inline]
+    pub(crate)
+    fn to_string(&mut self) -> String {
+        let mut buf = String::new();
+
+        while let Some(iteratee) = self.next() {
+            match iteratee {
+                PStrIteratee::Char(c) => {
+                    buf.push(c);
+                }
+                PStrIteratee::PStrSegment(h, n) => {
+                    match &self.machine_st.heap[h] {
+                        HeapCellValue::PartialString(ref pstr, _) => {
+                            buf += pstr.as_str_from(n);
+                        }
+                        _ => {
+                            unreachable!()
+                        }
+                    }
+                }
+            }
+        }
+
+        buf
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum PStrIteratee {
+    Char(char),
+    PStrSegment(usize, usize),
+}
+
+impl<'a> Iterator for HeapPStrIter<'a> {
+    type Item = PStrIteratee;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let addr = self.machine_st.store(self.machine_st.deref(self.focus));
+
+        if !self.seen.contains(&addr) {
+            self.seen.insert(addr);
+        } else {
+            return None;
+        }
+
+        match addr {
+            Addr::PStrLocation(h, n) => {
+                if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
+                    self.focus = if has_tail {
+                        Addr::HeapCell(h + 1)
+                    } else {
+                        Addr::EmptyList
+                    };
+
+                    return Some(PStrIteratee::PStrSegment(h, n));
+                } else {
+                    unreachable!()
+                }
+            }
+            Addr::Lis(l) => {
+                let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
+
+                let opt_c = match addr {
+                    Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
+                        if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
+                            if atom.is_char() {
+                                Some(atom.as_str().chars().next().unwrap())
+                            } else {
+                                None
+                            }
+                        } else {
+                            unreachable!()
+                        }
+                    }
+                    Addr::Char(c) => {
+                        Some(c)
+                    }
+                    _ => {
+                        None
+                    }
+                };
+
+                if let Some(c) = opt_c {
+                    self.focus = Addr::HeapCell(l + 1);
+                    return Some(PStrIteratee::Char(c));
+                } else {
+                    return None;
+                }
+            }
+            Addr::EmptyList => {
+                self.focus = Addr::EmptyList;
+                return None;
+            }
+            _ => {
+                return None;
+            }
+        }
+    }
+}
+
+#[inline]
+pub(super)
+fn compare_pstr_prefixes<'a>(
+    i1: &mut HeapPStrIter<'a>,
+    i2: &mut HeapPStrIter<'a>,
+) -> Option<Ordering> {
+    let mut r1 = i1.next();
+    let mut r2 = i2.next();
+
+    loop {
+        if let Some(r1i) = r1 {
+            if let Some(r2i) = r2 {
+                match (r1i, r2i) {
+                    (PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => {
+                        if c1 != c2 {
+                            return c1.partial_cmp(&c2);
+                        }
+                    }
+                    (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()));
+
+                                    continue;
+                                }
+                            } else {
+                                r2 = i2.next();
+                                continue;
+                            }
+                        } else {
+                            unreachable!()
+                        }
+                    }
+                    (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()));
+
+                                    continue;
+                                }
+                            } else {
+                                r1 = i1.next();
+                                continue;
+                            }
+                        } else {
+                            unreachable!()
+                        }
+                    }
+                    (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();
+
+                                    continue;
+                                } else if str2.starts_with(str1) {
+                                    r1 = i1.next();
+                                    r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len()));
+
+                                    continue;
+                                } else {
+                                    return str1.partial_cmp(str2);
+                                }
+                            }
+                            _ => {
+                                unreachable!()
+                            }
+                        }
+                    }
+                }
+
+                r1 = i1.next();
+                r2 = i2.next();
+
+                continue;
+            }
+        }
+
+        return match (i1.focus(), i2.focus()) {
+            (Addr::EmptyList, Addr::EmptyList) => {
+                Some(Ordering::Equal)
+            }
+            (Addr::EmptyList, _) => {
+                Some(Ordering::Less)
+            }
+            (_, Addr::EmptyList) => {
+                Some(Ordering::Greater)
+            }
+            _ => {
+                None
+            }
+        };
+    }
+}
+
+#[inline]
+pub(super)
+fn compare_pstr_to_string<'a>(
+    heap_pstr_iter: &mut HeapPStrIter<'a>,
+    s: &String,
+) -> Option<usize> {
+    let mut s_offset = 0;
+
+    while let Some(iteratee) = heap_pstr_iter.next() {
+        match iteratee {
+            PStrIteratee::Char(c1) => {
+                if let Some(c2) = s[s_offset ..].chars().next() {
+                    if c1 != c2 {
+                        return None;
+                    } else {
+                        s_offset += c1.len_utf8();
+                    }
+                } else {
+                    return 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);
+
+                        if s[s_offset ..].starts_with(t) {
+                            s_offset += t.len();
+                        } else if t.starts_with(&s[s_offset ..]) {
+                            heap_pstr_iter.focus =
+                                Addr::PStrLocation(h, n + s[s_offset ..].len());
+
+                            s_offset += s[s_offset ..].len();
+                            return Some(s_offset);
+                        } else {
+                            return None;
+                        }
+                    }
+                    _ => {
+                        unreachable!()
+                    }
+                }
+            }
+        }
+
+        if s[s_offset ..].is_empty() {
+            return Some(s_offset);
+        }
+    }
+
+    Some(s_offset)
+}
diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs
new file mode 100644 (file)
index 0000000..7054796
--- /dev/null
@@ -0,0 +1,987 @@
+use crate::prolog_parser::ast::*;
+use crate::prolog_parser::tabled_rc::*;
+
+use crate::forms::*;
+use crate::iterators::*;
+use crate::machine::*;
+use crate::machine::load_state::*;
+use crate::machine::machine_errors::*;
+
+use crate::indexmap::IndexSet;
+
+use std::cell::Cell;
+use std::collections::VecDeque;
+use std::convert::TryFrom;
+use std::rc::Rc;
+
+/*
+ *  The preprocessor fabricates if-then-else ( .. -> ... ; ...)
+ *  clauses into nameless standalone predicates, which it queues for
+ *  later preprocessing and compilation. Fabricated predicates inherit
+ *  explicit "cut variables" from the handwritten predicate
+ *  surrounding their source if-then-else. They must be specially
+ *  handled.
+ */
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) enum CutContext {
+    BlocksCuts,
+    HasCutVariable,
+}
+
+pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> 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
+}
+
+pub fn to_op_decl(prec: usize, spec: &str, name: ClauseName) -> 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)),
+        _ => Err(CompilationError::InconsistentEntry),
+    }
+}
+
+fn setup_op_decl(
+    mut terms: Vec<Box<Term>>,
+    atom_tbl: TabledData<Atom>,
+) -> 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),
+        _ => 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),
+        _ => return Err(CompilationError::InconsistentEntry),
+    };
+
+    let prec = match *terms.pop().unwrap() {
+        Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
+            Ok(n) if n <= 1200 => n,
+            _ => return Err(CompilationError::InconsistentEntry),
+        },
+        _ => return Err(CompilationError::InconsistentEntry),
+    };
+
+    to_op_decl(prec, spec.as_str(), 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 =>
+        {
+            let arity = *terms.pop().unwrap();
+            let name  = *terms.pop().unwrap();
+
+            let arity = arity
+                .to_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 name  = name
+                .to_constant()
+                .and_then(|c| c.to_atom())
+                .ok_or(CompilationError::InvalidModuleExport)?;
+
+            if slash.as_str() == "/" {
+                Ok((name, arity))
+            } else {
+                Ok((name, arity + 2))
+            }
+        }
+        _ => {
+            Err(CompilationError::InvalidModuleExport)
+        }
+    }
+}
+
+/*
+fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, CompilationError>
+{
+    match term {
+        Term::Clause(_, ref name, ref mut terms, Some(_))
+            if name.as_str() == ":" && terms.len() == 2 =>
+        {
+            let mut predicate_indicator = *terms.pop().unwrap();
+            let module_name = *terms.pop().unwrap();
+
+            let module_name = module_name
+                .to_constant()
+                .and_then(|c| c.to_atom())
+                .ok_or(CompilationError::InvalidModuleExport)?;
+
+            let key = setup_predicate_indicator(&mut predicate_indicator)?;
+
+            Ok((module_name, key))
+        }
+        _ => Err(CompilationError::InvalidModuleExport),
+    }
+}
+*/
+
+fn setup_module_export(
+    mut term: Term,
+    atom_tbl: TabledData<Atom>,
+) -> 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" {
+                    Ok(ModuleExport::OpDecl(setup_op_decl(
+                        terms,
+                        atom_tbl
+                    )?))
+                } else {
+                    Err(CompilationError::InvalidModuleDecl)
+                }
+            } else {
+                Err(CompilationError::InvalidModuleDecl)
+            }
+        })
+}
+
+pub(super)
+fn setup_module_export_list(
+    mut export_list: Term,
+    atom_tbl: TabledData<Atom>,
+) -> 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())?;
+
+        exports.push(module_export);
+        export_list = *t2;
+    }
+
+    if export_list.to_constant() != Some(Constant::EmptyList) {
+        Err(CompilationError::InvalidModuleDecl)
+    } else {
+        Ok(exports)
+    }
+}
+
+fn setup_module_decl(
+    mut terms: Vec<Box<Term>>,
+    atom_tbl: TabledData<Atom>,
+) -> Result<ModuleDecl, CompilationError> {
+    let export_list = *terms.pop().unwrap();
+    let name = terms
+        .pop()
+        .unwrap()
+        .to_constant()
+        .and_then(|c| c.to_atom())
+        .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 =>
+        {
+            terms
+                .pop()
+                .unwrap()
+                .to_constant()
+                .and_then(|c| c.to_atom())
+                .map(|c| ModuleSource::Library(c))
+                .ok_or(CompilationError::InvalidUseModuleDecl)
+        }
+        Term::Constant(_, Constant::Atom(ref name, _)) =>
+            Ok(ModuleSource::File(name.clone())),
+        _ => 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>,
+) -> 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 =>
+        {
+            terms
+                .pop()
+                .unwrap()
+                .to_constant()
+                .and_then(|c| c.to_atom())
+                .map(|c| ModuleSource::Library(c))
+                .ok_or(CompilationError::InvalidUseModuleDecl)
+        }
+        Term::Constant(_, Constant::Atom(ref name, _)) => {
+            Ok(ModuleSource::File(name.clone()))
+        }
+        _ => {
+            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())?);
+        export_list = *t2;
+    }
+
+    if export_list.to_constant() != Some(Constant::EmptyList) {
+        Err(CompilationError::InvalidModuleDecl)
+    } else {
+        Ok((module_src, exports))
+    }
+}
+
+/*
+ * setup_meta_predicate tries to extract meta-predicate information
+ * from an appropriately formed declaration
+ *
+ * :- meta_predicate maplist(:, ?, ?).
+ *
+ * indicating that, for each QueryTerm call to maplist/3, the first
+ * argument is to be expanded with the call resolution ((:)/2)
+ * operator, the first argument of which is the name of the host
+ * module, as an atom. For example,
+ *
+ * p(X) :- maplist(X, [a,b,c], Result).
+ *
+ * If p/2 is defined in a module named "mod", the call is expanded to
+ *
+ * maplist(mod:X, [a,b,c], Result).
+ *
+ * before the predicate is compiled to WAM instructions.
+ *
+ * If the term bound to X -- the predicate to be called -- is
+ * qualified with (:)/2 already, the innermost qualifier is used for
+ * call resolution.
+ *
+ * The three arguments returned by a successful call are the module name,
+ * predicate name, and the list of meta-specs, one for each predicate argument.
+ *
+ * The module name might be used to specify intra-module meta-predicates whose
+ * module is not yet defined. There are several examples of this
+ * contained in src/lib/ops_and_meta_predicates.pl, which is loaded before
+ * src/lib/builtins.pl.
+ *
+ * Meta-specs have three forms:
+ *
+ * (:)  (the argument should be expanded with (:)/2 as described above)
+ * +    (mode declarations under the mode syntax, which currently have no effect)
+ * -
+ * ?
+ */
+fn setup_meta_predicate<'a>(
+    mut terms: Vec<Box<Term>>,
+    load_state: &LoadState<'a>,
+) -> Result<(ClauseName, ClauseName, Vec<MetaSpec>), CompilationError>
+{
+    fn get_name_and_meta_specs(
+        name: ClauseName,
+        terms: &mut [Box<Term>],
+    ) -> Result<(ClauseName, 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::RequiresExpansion,
+                            "+" => MetaSpec::Plus,
+                            "-" => MetaSpec::Minus,
+                            "?" => MetaSpec::Either,
+                            _   => return Err(CompilationError::InvalidMetaPredicateDecl),
+                        };
+
+                    meta_specs.push(meta_spec);
+                }
+                Term::Constant(_, Constant::Fixnum(n)) => {
+                    match usize::try_from(*n) {
+                        Ok(n) if n <= MAX_ARITY => {
+                            meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
+                        }
+                        _ => {
+                            return Err(CompilationError::InvalidMetaPredicateDecl);
+                        }
+                    }
+                }
+                _ => {
+                    return Err(CompilationError::InvalidMetaPredicateDecl);
+                }
+            }
+        }
+
+        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 module_name {
+                    Term::Constant(_, Constant::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)
+                            }
+                        }
+                    }
+                    _ => {
+                        Err(CompilationError::InvalidMetaPredicateDecl)
+                    }
+                }
+            }
+        Term::Clause(_, name, mut terms, _) => {
+            let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
+            Ok((load_state.module_name(), name, meta_specs))
+        }
+        _ => {
+            Err(CompilationError::InvalidMetaPredicateDecl)
+        }
+    }
+}
+
+fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationError>
+{
+    let mut clauses = vec![];
+
+    while let Some(tl) = tls.pop_front() {
+        match tl {
+            TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => {
+                return Ok(tl);
+            }
+            TopLevel::Declaration(_) if clauses.is_empty() => {
+                return Ok(tl);
+            }
+            TopLevel::Query(_) => {
+                return Err(CompilationError::InconsistentEntry);
+            }
+            TopLevel::Fact(fact) => {
+                let clause = PredicateClause::Fact(fact);
+                clauses.push(clause);
+            }
+            TopLevel::Rule(rule) => {
+                let clause = PredicateClause::Rule(rule);
+                clauses.push(clause);
+            }
+            TopLevel::Predicate(predicate) => {
+                clauses.extend(predicate.into_iter())
+            }
+            _ => {
+                tls.push_front(tl);
+                break;
+            }
+        }
+    }
+
+    if clauses.is_empty() {
+        Err(CompilationError::InconsistentEntry)
+    } else {
+        Ok(TopLevel::Predicate(clauses))
+    }
+}
+
+fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
+    for term in terms.iter_mut() {
+        match term {
+            &mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => {
+                *var = name.clone()
+            }
+            _ => {}
+        }
+    }
+}
+
+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,
+        _ => false,
+    };
+
+    if cut_var_found {
+        *term = Term::Var(Cell::default(), rc_atom!("!"));
+        true
+    } else {
+        false
+    }
+}
+
+fn mark_cut_variables(terms: &mut Vec<Term>) -> bool {
+    let mut found_cut_var = false;
+
+    for item in terms.iter_mut() {
+        found_cut_var = mark_cut_variable(item) || found_cut_var;
+    }
+
+    found_cut_var
+}
+
+// terms is a list of goals composing one clause in a (;) functor. it
+// checks that the first (and only) of these clauses is a ->. if so,
+// it expands its terms using a blocked_!.
+fn check_for_internal_if_then(terms: &mut Vec<Term>) {
+    if terms.len() != 1 {
+        return;
+    }
+
+    if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() {
+        if name.as_str() != "->" || 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(), ","));
+
+        conq_terms.push_front(Term::Constant(
+            Cell::default(),
+            Constant::Atom(clause_name!("blocked_!"), None))
+        );
+
+        while let Some(term) = pre_cut_terms.pop_back() {
+            conq_terms.push_front(term);
+        }
+
+        let tail_term = conq_terms.pop_back().unwrap();
+
+        terms.push(fold_by_str(
+            conq_terms.into_iter(),
+            tail_term,
+            clause_name!(","),
+        ));
+    }
+}
+
+fn setup_declaration<'a>(
+    load_state: &LoadState<'a>,
+    mut terms: Vec<Box<Term>>,
+) -> Result<Declaration, CompilationError> {
+    let term = *terms.pop().unwrap();
+    let atom_tbl = load_state.wam.machine_st.atom_tbl.clone();
+
+    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())?;
+                           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())?;
+                    Ok(Declaration::NonCountedBacktracking(name, arity))
+                }
+                ("use_module", 1) => {
+                    Ok(Declaration::UseModule(setup_use_module_decl(terms)?))
+                }
+                ("use_module", 2) => {
+                    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)?;
+                    Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
+                }
+                _ => {
+                    Err(CompilationError::InconsistentEntry)
+                }
+            },
+        _ => {
+            Err(CompilationError::InconsistentEntry)
+        }
+    }
+}
+
+#[inline]
+fn clause_to_query_term<'a>(
+    load_state: &mut LoadState<'a>,
+    name: ClauseName,
+    terms: Vec<Box<Term>>,
+    fixity: Option<SharedOpDesc>,
+) -> QueryTerm {
+    let ct = load_state.get_clause_type(name, terms.len(), fixity);
+    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>,
+) -> QueryTerm {
+    let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity);
+    QueryTerm::Clause(Cell::default(), ct, terms, false)
+}
+
+#[derive(Debug)]
+pub(crate) struct Preprocessor {
+    flags: MachineFlags,
+    queue: VecDeque<VecDeque<Term>>,
+}
+
+impl Preprocessor {
+    pub(super)
+    fn new(flags: MachineFlags) -> Self {
+        Preprocessor {
+            flags,
+            queue: VecDeque::new(),
+        }
+    }
+
+    fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
+        match term {
+            Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
+                Ok(term)
+            }
+            _ => {
+                Err(CompilationError::InadmissibleFact)
+            }
+        }
+    }
+
+    fn compute_head(&self, term: &Term) -> Vec<Term> {
+        let mut vars = IndexSet::new();
+
+        for term in post_order_iter(term) {
+            if let TermRef::Var(_, _, v) = term {
+                vars.insert(v.clone());
+            }
+        }
+
+        vars.insert(rc_atom!("!"));
+        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!(":-");
+
+        Term::Clause(Cell::default(), turnstile, rule, None)
+    }
+
+    // the terms form the body of the rule. We create a head, by
+    // gathering variables from the body of terms and recording them
+    // in the head clause.
+    fn fabricate_rule(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
+        // collect the vars of body_term into a head, return the num_vars
+        // (the arity) as well.
+        let vars = self.compute_head(&body_term);
+        let rule = self.fabricate_rule_body(&vars, body_term);
+
+        (vars, VecDeque::from(vec![rule]))
+    }
+
+    fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
+        let vars = self.compute_head(&body_term);
+        let results = unfold_by_str(body_term, ";")
+            .into_iter()
+            .map(|term| {
+                let mut subterms = unfold_by_str(term, ",");
+                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!(","));
+
+                self.fabricate_rule_body(&vars, clause)
+            })
+            .collect();
+
+        (vars, results)
+    }
+
+    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!("!");
+
+        prec_seq.push(Term::Constant(Cell::default(), cut_sym));
+
+        mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!"));
+
+        let mut conq_seq = unfold_by_str(conq, ",");
+
+        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 body_term = Term::Clause(
+            Cell::default(),
+            comma_sym.clone(),
+            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>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+        term: Term,
+    ) -> Result<QueryTerm, CompilationError> {
+        match term {
+            Term::Constant(_, Constant::Atom(name, fixity)) => {
+                if name.as_str() == "!" || name.as_str() == "blocked_!" {
+                    Ok(QueryTerm::BlockedCut)
+                } else {
+                    Ok(clause_to_query_term(load_state, name, vec![], fixity))
+                }
+            }
+            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);
+
+                        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();
+
+                        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(
+                            Cell::default(),
+                            Constant::Atom(clause_name!("$fail"), None)
+                        )));
+
+                        let conq = Term::Constant(
+                            Cell::default(),
+                            Constant::Atom(clause_name!("true"), None)
+                        );
+
+                        let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
+                        let terms = vec![Box::new(prec), Box::new(conq)];
+
+                        let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
+                        let (stub, clauses) = self.fabricate_disjunct(term);
+
+                        debug_assert!(clauses.len() > 0);
+                        self.queue.push_back(clauses);
+
+                        Ok(QueryTerm::Jump(stub))
+                    }
+                    ("$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();
+
+                        match (module_name, predicate_name) {
+                            (Term::Constant(_, Constant::Atom(module_name, _)),
+                             Term::Constant(_, Constant::Atom(predicate_name, fixity))) => {
+                                Ok(qualified_clause_to_query_term(
+                                    load_state,
+                                    module_name,
+                                    predicate_name,
+                                    vec![],
+                                    fixity,
+                                ))
+                            }
+                            (Term::Constant(_, Constant::Atom(module_name, _)),
+                             Term::Clause(_, name, terms, fixity)) => {
+                                Ok(qualified_clause_to_query_term(
+                                    load_state,
+                                    module_name,
+                                    name,
+                                    terms,
+                                    fixity,
+                                ))
+                            }
+                            (module_name, predicate_name) => {
+                                terms.push(Box::new(module_name));
+                                terms.push(Box::new(predicate_name));
+
+                                Ok(clause_to_query_term(load_state, name, terms, fixity))
+                            }
+                        }
+                    }
+                    _ => {
+                        Ok(clause_to_query_term(load_state, name, terms, fixity))
+                    }
+                }
+            }
+            Term::Var(..) => {
+                Ok(QueryTerm::Clause(
+                    Cell::default(),
+                    ClauseType::CallN,
+                    vec![Box::new(term)],
+                    false,
+                ))
+            }
+            _ => {
+                Err(CompilationError::InadmissibleQueryTerm)
+            }
+        }
+    }
+
+    fn pre_query_term<'a>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+        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())
+                        .map(|mut query_term| {
+                            query_term.set_default_caller();
+                            query_term
+                        })
+                } else {
+                    self.to_query_term(load_state, Term::Clause(r, name, subterms, fixity))
+                }
+            }
+            _ => {
+                self.to_query_term(load_state, term)
+            }
+        }
+    }
+
+    fn setup_query<'a>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+        terms: Vec<Box<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;
+
+            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, ",");
+
+                    while let Some(subterm) = subterms.pop() {
+                        work_queue.push_front(Box::new(subterm));
+                    }
+
+                    continue;
+                } else {
+                    term = Term::Clause(cell, name, terms, op_spec);
+                }
+            }
+
+            if let CutContext::HasCutVariable = cut_context {
+                mark_cut_variable(&mut term);
+            }
+
+            query_terms.push(self.pre_query_term(load_state, term)?);
+        }
+
+        Ok(query_terms)
+    }
+
+    fn setup_rule<'a>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+        mut terms: Vec<Box<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 clauses = query_terms.drain(1 ..).collect();
+        let qt = query_terms.pop().unwrap();
+
+        match *terms.pop().unwrap() {
+            Term::Clause(_, name, terms, _) => {
+                Ok(Rule {
+                    head: (name, terms, qt),
+                    clauses,
+                })
+            }
+            Term::Constant(_, Constant::Atom(name, _)) => {
+                Ok(Rule {
+                    head: (name, vec![], qt),
+                    clauses,
+                })
+            }
+            _ => {
+                Err(CompilationError::InvalidRuleHead)
+            }
+        }
+    }
+
+    fn try_term_to_query<'a>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+        terms: Vec<Box<Term>>,
+        cut_context: CutContext,
+    ) -> Result<TopLevel, CompilationError> {
+        Ok(TopLevel::Query(self.setup_query(load_state, terms, cut_context)?))
+    }
+
+    pub(super)
+    fn try_term_to_tl<'a>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+        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 {
+                    Ok(TopLevel::Rule(self.setup_rule(
+                        load_state,
+                        terms,
+                        cut_context,
+                    )?))
+                } else if name.as_str() == ":-" && terms.len() == 1 {
+                    Ok(TopLevel::Declaration(setup_declaration(load_state, terms)?))
+                } else {
+                    let term = Term::Clause(r, name, terms, fixity);
+                    Ok(TopLevel::Fact(self.setup_fact(term)?))
+                }
+            }
+            term => {
+                Ok(TopLevel::Fact(self.setup_fact(term)?))
+            }
+        }
+    }
+
+    fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+        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)?);
+        }
+
+        Ok(results)
+    }
+
+    pub(super)
+    fn parse_queue<'a>(
+        &mut self,
+        load_state: &mut LoadState<'a>,
+    ) -> 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,
+                    terms,
+                    CutContext::HasCutVariable,
+                )?
+            )?;
+
+            queue.push_back(clauses);
+        }
+
+        Ok(queue)
+    }
+}
index 0d7a82d0e8fbe58f21d83428fa0029b5d12e000d..cee4f1ce56cf794ed4d32d03b6231f059e58dd69 100644 (file)
@@ -1,11 +1,11 @@
 :- module('$project_atts', [copy_term/3]).
 
-'$attribute_goals_driver'(QueryVars, AttrVars) :-
-    gather_modules(AttrVars, Modules0, _),
+driver(QueryVars, AttrVars) :-
+    gather_attr_modules(AttrVars, Modules0),
     sort(Modules0, Modules),
     call_project_attributes(Modules, QueryVars, AttrVars),
-    call_attribute_goals(Modules, call_query_var_goals, QueryVars),
-    call_attribute_goals(Modules, call_attr_var_goals, AttrVars).
+    call_attribute_goals(Modules, '$project_atts':call_query_var_goals, QueryVars),
+    call_attribute_goals(Modules, '$project_atts':call_attr_var_goals, AttrVars).
 
 enqueue_goals(Goals0) :-
     nonvar(Goals0),
@@ -36,7 +36,7 @@ call_project_attributes([Module|Modules], QueryVars, AttrVars) :-
     call_project_attributes(Modules, QueryVars, AttrVars).
 
 call_attribute_goals([], _, _).
-call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
+call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
     call(GoalCaller, AttrVars, Module, Goals),
     enqueue_goals(Goals),
     call_attribute_goals(Modules, GoalCaller, AttrVars).
@@ -51,13 +51,13 @@ call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
 
 call_query_var_goals([], _, []).
 call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
-    (  catch((  Module:attribute_goals(AttrVar, Goals, RGoals0)
-            ,  atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
-            ),
-            E,
-            (  '$print_attribute_goals_exception'(Module, E),
-               atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
-            ))
+    (  catch((  Module:attribute_goals(AttrVar, Goals, RGoals0),
+                   atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
+                ),
+                E,
+                (  '$project_atts':'$print_attribute_goals_exception'(Module, E),
+                       atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
+                ))
     -> true
     ;  atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
     ),
@@ -66,25 +66,14 @@ call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
 call_attr_var_goals([], _, []).
 call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
     (  catch(Module:attribute_goals(AttrVar, Goals, RGoals),
-            E,
-            '$print_attribute_goals_exception'(Module, E)
-            )
+                E,
+                '$project_atts':'$print_attribute_goals_exception'(Module, E)
+               )
     -> true
     ;  true
     ),
     call_attr_var_goals(AttrVars, Module, RGoals).
 
-gather_modules([], [], _).
-gather_modules([AttrVar|AttrVars], Modules, Modules0) :-
-    '$get_attr_list'(AttrVar, Attrs),
-    gather_modules_for_attrs(Attrs, Modules, Modules0),
-    gather_modules(AttrVars, Modules0, _).
-
-gather_modules_for_attrs(Attrs, Modules, Modules) :-
-    var(Attrs), !.
-gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :-
-    '$module_of'(Module, Attr),
-    gather_modules_for_attrs(Attrs, Modules, Modules0).
 
 module_prefixed_goals([], _, Gs, Gs).
 module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :-
@@ -100,11 +89,25 @@ call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars
     module_prefixed_goals(Goals0, Module, Goals, Gs),
     call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
 
+
+gather_attr_modules([], []).
+gather_attr_modules([AttrVar|AttrVars], Modules) :-
+    '$get_attr_list'(AttrVar, Attrs),
+    copy_attribute_modules(Attrs, Modules, Modules0),
+    gather_attr_modules(AttrVars, Modules0).
+
+copy_attribute_modules(Attrs, Ls, Ls) :-
+    var(Attrs), !.
+copy_attribute_modules([Module:_|Attrs], [Module|Modules0], Modules1) :-
+    copy_attribute_modules(Attrs, Modules0, Modules1).
+
+
 copy_term(Source, Dest, Goals) :-
-    '$term_attributed_variables'(Source, Vars),
-    gather_modules(Vars, Modules0, _),
+    '$term_attributed_variables'(Source, AttrVars),
+    gather_attr_modules(AttrVars, Modules0),
     sort(Modules0, Modules),
-    call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0),
+    call_attribute_goals_with_module_prefix(Modules, '$project_atts':call_query_var_goals,
+                                            AttrVars, Goals0),
     sort(Goals0, Goals1),
     !,
     '$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]).
index 4bd3802b85fb96a0e79fec43ffcdb6aab455f0a2..ab7d48e2af36eccece12ac0a989dc2526d9873c6 100644 (file)
@@ -246,10 +246,6 @@ impl Stack {
         }
     }
 
-    pub fn take(&mut self) -> Self {
-        Stack { buf: self.buf.take(), _marker: PhantomData }
-    }
-
     #[inline]
     pub fn truncate(&mut self, b: usize) {
         if b == 0 {
index 1375cb65f8ecbf0c8297456820be525ab8b5354a..644e6ee7250be19b472167fdbfd3a036842afd92 100644 (file)
@@ -179,10 +179,10 @@ impl Drop for StreamInstance {
     fn drop(&mut self) {
         match self {
             StreamInstance::TcpStream(_, ref mut tcp_stream) => {
-                discard_result!(tcp_stream.shutdown(Shutdown::Both));
+                tcp_stream.shutdown(Shutdown::Both).unwrap();
             }
             StreamInstance::TlsStream(_, ref mut tls_stream) => {
-                discard_result!(tls_stream.shutdown());
+                tls_stream.shutdown().unwrap();
             }
             _ => {
             }
index da31e966c82719dd1f433dbca9e2e354680f686c..0623df76cb0e00eff1a667d8b453cebbb3c163ab 100644 (file)
@@ -6,14 +6,16 @@ use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_print::*;
 use crate::instructions::*;
+use crate::machine;
 use crate::machine::code_repo::CodeRepo;
 use crate::machine::copier::*;
 use crate::machine::code_walker::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
+use crate::machine::preprocessor::to_op_decl;
 use crate::machine::streams::*;
-use crate::machine::toplevel::to_op_decl;
+
 use crate::ordered_float::OrderedFloat;
 use crate::read::readline;
 use crate::rug::Integer;
@@ -402,9 +404,7 @@ impl MachineState {
             }
         }
 
-        let mode =
-            atom_from!(self, indices, self.store(self.deref(self[temp_v!(2)])));
-
+        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) =
@@ -560,7 +560,7 @@ impl MachineState {
                         let spec = get_clause_spec(
                             name.clone(),
                             *arity,
-                            composite_op!(&indices.op_dir),
+                            &CompositeOpDir::new(&indices.op_dir, None),
                         );
 
                         let addr = self.heap.to_unifiable(HeapCellValue::DBRef(
@@ -681,11 +681,11 @@ impl MachineState {
 
         let mut parser = Parser::new(
             &mut stream,
-            indices.atom_tbl.clone(),
+            self.atom_tbl.clone(),
             self.machine_flags(),
         );
 
-        match parser.read_term(composite_op!(&indices.op_dir)) {
+        match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) {
             Err(err) => {
                 let h = self.heap.h();
                 let err = MachineError::syntax_error(h, err);
@@ -792,6 +792,7 @@ impl MachineState {
         current_output_stream: &mut Stream,
     ) -> CallResult {
         match ct {
+            /*
             &SystemClauseType::AbolishClause => {
                 let p = self.cp;
                 let trans_type = DynamicTransactionType::Abolish;
@@ -806,6 +807,7 @@ impl MachineState {
                 self.p = CodePtr::DynamicTransaction(trans_type, p);
                 return Ok(());
             }
+            */
             &SystemClauseType::BindFromRegister => {
                 let reg = self.store(self.deref(self[temp_v!(2)]));
                 let n =
@@ -833,6 +835,7 @@ impl MachineState {
 
                 self.fail = true;
             }
+            /*
             &SystemClauseType::AssertDynamicPredicateToFront => {
                 let p = self.cp;
                 let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front);
@@ -841,19 +844,21 @@ impl MachineState {
                 return Ok(());
             }
             &SystemClauseType::AssertDynamicPredicateToBack => {
-                let p = self.cp;
-                let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Back);
+                // let p = self.cp;
+                // let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Back);
 
-                self.p = CodePtr::DynamicTransaction(trans_type, p);
+                // self.p = CodePtr::DynamicTransaction(trans_type, p);
+                self.p = CodePtr::REPL(REPLCodePtr::UserAssertz, self.cp);
                 return Ok(());
             }
+            */
             &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, indices.atom_tbl), None)
+                                    HeapCellValue::Atom(clause_name!(host, self.atom_tbl), None)
                                 );
 
                                 self.unify(self[temp_v!(1)], hostname);
@@ -1016,6 +1021,7 @@ impl MachineState {
                                    return Err(err);
                             }
                         };
+
                     let chars = self.heap.put_complete_string(current);
                     self.unify(self[temp_v!(1)], chars);
 
@@ -1092,11 +1098,13 @@ impl MachineState {
                     return Ok(());
                 }
             }
+            /*
             &SystemClauseType::AtEndOfExpansion => {
                 if self.cp == LocalCodePtr::TopLevel(0, 0) {
                     self.at_end_of_expansion = true;
                 }
             }
+            */
             &SystemClauseType::AtomChars => {
                 let a1 = self[temp_v!(1)];
 
@@ -1139,7 +1147,7 @@ impl MachineState {
                                 if &string == "[]" {
                                     self.unify(addr, Addr::EmptyList);
                                 } else {
-                                    let chars = clause_name!(string, indices.atom_tbl);
+                                    let chars = clause_name!(string, self.atom_tbl);
                                     let atom  = self.heap.to_unifiable(
                                         HeapCellValue::Atom(chars, None)
                                     );
@@ -1254,7 +1262,7 @@ impl MachineState {
                                 }
 
                                 let string = self.heap.to_unifiable(
-                                    HeapCellValue::Atom(clause_name!(chars, indices.atom_tbl), None)
+                                    HeapCellValue::Atom(clause_name!(chars, self.atom_tbl), None)
                                 );
 
                                 self.bind(addr.as_var().unwrap(), string);
@@ -1281,7 +1289,7 @@ impl MachineState {
                         clause_name!("[]")
                     }
                     Addr::Char(c) => {
-                        clause_name!(c.to_string(), indices.atom_tbl)
+                        clause_name!(c.to_string(), self.atom_tbl)
                     }
                     _ => {
                         unreachable!()
@@ -1858,6 +1866,7 @@ impl MachineState {
                     }
                 }
             }
+            /*
             &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
                 let p = self.cp;
                 let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front);
@@ -1872,6 +1881,7 @@ impl MachineState {
                 self.p = CodePtr::DynamicTransaction(trans_type, p);
                 return Ok(());
             }
+            */
             &SystemClauseType::LiftedHeapLength => {
                 let a1 = self[temp_v!(1)];
                 let lh_len = Addr::Usize(self.lifted_heap.h());
@@ -2854,6 +2864,7 @@ impl MachineState {
 
                 self.unify(Addr::Char(c), a1);
             }
+/*
             &SystemClauseType::GetModuleClause => {
                 let module = self[temp_v!(3)];
                 let head = self[temp_v!(1)];
@@ -2944,20 +2955,24 @@ impl MachineState {
                     _ => unreachable!(),
                 };
             }
+*/
             &SystemClauseType::HeadIsDynamic => {
-                let head = self[temp_v!(1)];
+                let module_name = atom_from!(
+                    self,
+                    self.store(self.deref(
+                        self[temp_v!(1)]
+                    ))
+                );
 
-                self.fail = !match self.store(self.deref(head)) {
+                self.fail = !match self.store(self.deref(self[temp_v!(2)])) {
                     Addr::Str(s) => match &self.heap[s] {
-                        &HeapCellValue::NamedStr(arity, ref name, ..) => indices
-                            .get_clause_subsection(name.owning_module(), name.clone(), arity)
-                            .is_some(),
+                        &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.get_clause_subsection(name.owning_module(), name.clone(), 0)
-                                   .is_some()
+                           if let HeapCellValue::Atom(name, _) = &self.heap[h] {
+                            indices.is_dynamic_predicate(module_name, (name.clone(), 0))
                         } else {
                             unreachable!()
                         }
@@ -3111,21 +3126,27 @@ impl MachineState {
 
                             return self.module_lookup(
                                 indices,
+                                call_policy,
                                 (name, arity + narity),
                                 module_name,
                                 true,
+                                current_input_stream,
+                                current_output_stream,
                             );
                         } else {
                             unreachable!()
                         }
                     }
                     Addr::Con(h) if self.heap.atom_at(h) => {
-                       if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
+                           if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
                             return self.module_lookup(
                                 indices,
+                                call_policy,
                                 (name.clone(), narity),
                                 module_name,
                                 true,
+                                current_input_stream,
+                                current_output_stream,
                             );
                         } else {
                             unreachable!()
@@ -3160,6 +3181,7 @@ impl MachineState {
                     }
                 }
             }
+            /*
             &SystemClauseType::ExpandGoal => {
                 self.p = CodePtr::Local(LocalCodePtr::UserGoalExpansion(0));
                 return Ok(());
@@ -3168,6 +3190,7 @@ impl MachineState {
                 self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0));
                 return Ok(());
             }
+            */
             &SystemClauseType::GetNextDBRef => {
                 let a1 = self[temp_v!(1)];
 
@@ -3185,7 +3208,7 @@ impl MachineState {
                             let spec = get_clause_spec(
                                 name.clone(),
                                 *arity,
-                                composite_op!(&indices.op_dir),
+                                &CompositeOpDir::new(&indices.op_dir, None),
                             );
 
                             let db_ref = DBRef::NamedPred(name.clone(), *arity, spec);
@@ -3429,7 +3452,7 @@ impl MachineState {
 
                 let op = match self.store(self.deref(op)) {
                     Addr::Char(c) =>
-                        clause_name!(c.to_string(), indices.atom_tbl),
+                        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()
@@ -3440,16 +3463,18 @@ impl MachineState {
                         unreachable!(),
                 };
 
-                let module = op.owning_module();
-
                 let result = to_op_decl(priority, specifier.as_str(), op)
                     .map_err(SessionError::from)
-                    .and_then(|op_decl| {
-                        if op_decl.0 == 0 {
+                    .and_then(|mut op_decl| {
+                        if op_decl.prec == 0 {
                             Ok(op_decl.remove(&mut indices.op_dir))
                         } else {
-                            let spec = get_desc(op_decl.name(), composite_op!(&indices.op_dir));
-                            op_decl.submit(module, spec, &mut indices.op_dir)
+                            let spec = get_op_desc(
+                                op_decl.name.clone(),
+                                &CompositeOpDir::new(&indices.op_dir, None),
+                            );
+
+                            op_decl.submit(spec, &mut indices.op_dir)
                         }
                     });
 
@@ -3493,10 +3518,10 @@ impl MachineState {
                                     let mut heap_pstr_iter =
                                         self.heap_pstr_iter(Addr::PStrLocation(h, n));
 
-                                    let file_spec = 
+                                    let file_spec =
                                         clause_name!(
                                             heap_pstr_iter.to_string(),
-                                            indices.atom_tbl.clone()
+                                            self.atom_tbl
                                         );
 
                                     self.stream_from_file_spec(file_spec, indices, &options)?
@@ -3901,65 +3926,18 @@ impl MachineState {
                     }
                 };
             }
-            &SystemClauseType::ModuleOf => {
-                let module = self.store(self.deref(self[temp_v!(2)]));
-
-                match module {
-                    Addr::Con(h) if self.heap.atom_at(h) => {
-                       if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
-                            let module = self.heap.to_unifiable(
-                                HeapCellValue::Atom(
-                                    name.owning_module(),
-                                    None
-                                ),
-                            );
-
-                            let target = self[temp_v!(1)];
-
-                            self.unify(target, module);
-                        } else {
-                            unreachable!()
-                        }
-                    }
-                    Addr::Str(s) => match self.heap.clone(s) {
-                        HeapCellValue::NamedStr(_, name, ..) => {
-                            let module = self.heap.to_unifiable(
-                                HeapCellValue::Atom(
-                                    name.owning_module(),
-                                    None
-                                ),
-                            );
-
-                            let target = self[temp_v!(1)];
-
-                            self.unify(target, module);
-                        }
-                        HeapCellValue::Addr(addr) if addr.is_ref() => {
-                            let err = MachineError::uninstantiation_error(addr);
-                            let stub = MachineError::functor_stub(
-                                clause_name!("$module_of"),
-                                2,
-                            );
-
-                            return Err(self.error_form(err, stub));
-                        }
-                        _ => {
-                            unreachable!()
-                        }
-                    },
-                    _ => {
-                        self.fail = true;
-                    }
-                };
-            }
             &SystemClauseType::NoSuchPredicate => {
-                let head = self[temp_v!(1)];
+                let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)])));
 
-                self.fail = match self.store(self.deref(head)) {
+                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) => {
-                            let module = name.owning_module();
-                            indices.predicate_exists(name.clone(), module, arity, spec.clone())
+                            indices.get_predicate_code_index(
+                                name.clone(),
+                                arity,
+                                module_name,
+                                spec.clone(),
+                            ).is_some()
                         }
                         _ => {
                             unreachable!()
@@ -3967,14 +3945,14 @@ impl MachineState {
                     },
                     Addr::Con(h) if self.heap.atom_at(h) => {
                            if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] {
-                            let module = name.owning_module();
                             let spec = fetch_atom_op_spec(
                                 name.clone(),
                                 spec.clone(),
                                 &indices.op_dir,
                             );
 
-                            indices.predicate_exists(name.clone(), module, 0, spec)
+                            indices.get_predicate_code_index(name.clone(), 0, module_name, spec)
+                                   .is_some()
                         } else {
                             unreachable!()
                         }
@@ -4116,6 +4094,7 @@ impl MachineState {
             &SystemClauseType::REPL(repl_code_ptr) => {
                 return self.repl_redirect(repl_code_ptr);
             }
+            /*
             &SystemClauseType::ModuleRetractClause => {
                 let p = self.cp;
                 let trans_type = DynamicTransactionType::ModuleRetract;
@@ -4130,6 +4109,7 @@ impl MachineState {
                 self.p = CodePtr::DynamicTransaction(trans_type, p);
                 return Ok(());
             }
+            */
             &SystemClauseType::ReturnFromVerifyAttr => {
                 let e = self.e;
                 let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
@@ -4326,6 +4306,7 @@ impl MachineState {
 
                 self.unify(a1, a2);
             }
+/*
             &SystemClauseType::GetClause => {
                 let head = self[temp_v!(1)];
 
@@ -4343,14 +4324,14 @@ impl MachineState {
                         }
                     },
                     Addr::Con(h) if self.heap.atom_at(h) => {
-                       if let &HeapCellValue::Atom(ref name, _) = &self.heap[h] {
+                           if let &HeapCellValue::Atom(ref name, _) = &self.heap[h] {
                             indices.get_clause_subsection(
                                 name.owning_module(),
                                 name.clone(),
                                 0,
                             )
                         } else {
-                            unreachable!()
+                unreachable!()
                         }
                     }
                     _ => {
@@ -4372,6 +4353,7 @@ impl MachineState {
                     }
                 }
             }
+*/
             &SystemClauseType::GetCutPoint => {
                 let a1 = self[temp_v!(1)];
                 let a2 = Addr::CutPoint(self.b0);
@@ -4524,7 +4506,7 @@ impl MachineState {
                     let term_write_result =
                         match self.read(
                             Stream::from(chars),
-                            indices.atom_tbl.clone(),
+                            self.atom_tbl.clone(),
                             &indices.op_dir,
                         ) {
                             Ok(term_write_result) => {
@@ -4595,10 +4577,11 @@ impl MachineState {
                 let mut rand = RANDOM_STATE.borrow_mut();
                 rand.seed(&seed);
             }
-            &SystemClauseType::SkipMaxList =>
+            &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)]));
 
@@ -4695,11 +4678,10 @@ impl MachineState {
                 let stream =
                     match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) {
                         Ok(tcp_stream) => {
-                            let socket_addr = clause_name!(socket_addr, indices.atom_tbl.clone());
+                            let socket_addr = clause_name!(socket_addr, self.atom_tbl);
 
-
-                            let mut stream =
-                              { let tls = match self.store(self.deref(self[temp_v!(8)])) {
+                            let mut stream = {
+                                let tls = match self.store(self.deref(self[temp_v!(8)])) {
                                     Addr::Con(h) if self.heap.atom_at(h) => {
                                         if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
                                             atom.as_str()
@@ -4711,6 +4693,7 @@ impl MachineState {
                                         unreachable!()
                                     }
                                 };
+
                                 match tls {
                                   "false" => { Stream::from_tcp_stream(socket_addr, tcp_stream) }
                                   "true" => { let connector = TlsConnector::new().unwrap();
@@ -4724,6 +4707,7 @@ impl MachineState {
                                    _ => { unreachable!() }
                                 }
                               };
+
                             stream.options = options;
 
                             if let Some(ref alias) = &stream.options.alias {
@@ -4877,7 +4861,7 @@ impl MachineState {
                                 match tcp_listener.accept().ok() {
                                     Some((tcp_stream, socket_addr)) => {
                                         let client =
-                                            clause_name!(format!("{}", socket_addr), indices.atom_tbl);
+                                            clause_name!(format!("{}", socket_addr), self.atom_tbl);
 
                                         let mut tcp_stream =
                                             Stream::from_tcp_stream(client.clone(), tcp_stream);
@@ -5226,8 +5210,13 @@ impl MachineState {
                 self.fail = self.structural_eq_test();
             }
             &SystemClauseType::WAMInstructions => {
-                let name  = self[temp_v!(1)];
-                let arity = self[temp_v!(2)];
+                let module_name = atom_from!(
+                    self,
+                    self.store(self.deref(self[temp_v!(1)]))
+                );
+
+                let name  = self[temp_v!(2)];
+                let arity = self[temp_v!(3)];
 
                 let name = match self.store(self.deref(name)) {
                     Addr::Con(h) if self.heap.atom_at(h) => {
@@ -5257,51 +5246,84 @@ impl MachineState {
                         }
                     };
 
-                let first_idx = match indices
-                    .code_dir
-                    .get(&(name.clone(), arity.to_usize().unwrap()))
-                {
-                    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();
+                let key = (name.clone(), arity.to_usize().unwrap());
 
-                        let err = MachineError::existence_error(
-                            h,
-                            ExistenceError::Procedure(name, arity),
-                        );
+                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();
 
-                        let err = self.error_form(err, stub);
+                            let err = MachineError::session_error(
+                                h,
+                                SessionError::from(
+                                    CompilationError::InvalidModuleResolution(
+                                        module_name
+                                    )
+                                ),
+                            );
 
-                        self.throw_exception(err);
-                        return Ok(());
-                    }
+                            let err = self.error_form(err, stub);
+
+                            self.throw_exception(err);
+                            return Ok(());
+                        }
+                    },
                 };
 
+                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();
+
+                            let err = MachineError::existence_error(
+                                h,
+                                ExistenceError::Procedure(name, arity),
+                            );
+
+                            let err = self.error_form(err, stub);
+
+                            self.throw_exception(err);
+                            return Ok(());
+                        }
+                    };
+
                 let mut h = self.heap.h();
                 let mut functors = vec![];
+                let mut functor_list = vec![];
 
                 walk_code(
                     &code_repo.code,
                     first_idx,
                     |instr| {
-                        let section = instr.to_functor(h);
-                        functors.push(Addr::HeapCell(h));
+                        let old_len = functors.len();
+                        instr.enqueue_functors(h, &mut functors);
+                        let new_len = functors.len();
 
-                        h += section.len();
-                        self.heap.extend(section.into_iter());
+                        for index in old_len .. new_len {
+                            functor_list.push(Addr::HeapCell(h));
+                            h += functors[index].len();
+                        }
                     },
                 );
 
-                let listing = Addr::HeapCell(self.heap.to_list(functors.into_iter()));
-                let listing_var = self[temp_v!(3)];
+                for functor in functors {
+                    self.heap.extend(functor.into_iter());
+                }
+
+                let listing = Addr::HeapCell(self.heap.to_list(functor_list.into_iter()));
+                let listing_var = self[temp_v!(4)];
 
                 self.unify(listing, listing_var);
             }
@@ -5831,6 +5853,53 @@ impl MachineState {
                     self.unify(self[temp_v!(2)], cstr);
                 }
             }
+            &SystemClauseType::LoadLibraryAsStream => {
+                let library_name =
+                    atom_from!(
+                        self,
+                        self.store(self.deref(self[temp_v!(1)]))
+                    );
+
+                use crate::LIBRARIES;
+
+                match LIBRARIES.borrow().get(library_name.as_str()) {
+                    Some(library) => {
+                        let var_ref = Ref::HeapCell(self.heap.push(
+                            HeapCellValue::Stream(Stream::from(*library))
+                        ));
+
+                        self.bind(var_ref, self[temp_v!(2)]);
+
+                        let mut path_buf = machine::current_dir();
+
+                        path_buf.push("/lib");
+                        path_buf.push(library_name.as_str());
+
+                        let library_path_str = path_buf.to_str().unwrap();
+                        let library_path =
+                            clause_name!(library_path_str.to_string(), self.atom_tbl);
+
+                        let library_path_ref = Ref::HeapCell(
+                            self.heap.push(HeapCellValue::Atom(library_path, None))
+                        );
+
+                        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),
+                            )
+                        );
+                    }
+                }
+            }
         };
 
         return_from_clause!(self.last_call, self)
@@ -5905,7 +5974,7 @@ impl MachineState {
         } else {
             let mut avec = Vec::new();
             for attr in node.attributes() {
-                let chars = clause_name!(String::from(attr.name()), indices.atom_tbl);
+                let chars = clause_name!(String::from(attr.name()), self.atom_tbl);
                 let name  = self.heap.to_unifiable(
                     HeapCellValue::Atom(chars, None)
                 );
@@ -5926,7 +5995,7 @@ impl MachineState {
             }
             let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter()));
 
-            let chars = clause_name!(String::from(node.tag_name().name()), indices.atom_tbl);
+            let chars = clause_name!(String::from(node.tag_name().name()), self.atom_tbl);
             let tag  = self.heap.to_unifiable(
                 HeapCellValue::Atom(chars, None)
             );
@@ -5955,7 +6024,7 @@ impl MachineState {
             Some(name) => {
                 let mut avec = Vec::new();
                 for attr in node.attrs() {
-                    let chars = clause_name!(String::from(attr.0), indices.atom_tbl);
+                    let chars = clause_name!(String::from(attr.0), self.atom_tbl);
                     let name  = self.heap.to_unifiable(
                         HeapCellValue::Atom(chars, None)
                     );
@@ -5976,7 +6045,7 @@ impl MachineState {
                 }
                 let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter()));
 
-                let chars = clause_name!(String::from(name), indices.atom_tbl);
+                let chars = clause_name!(String::from(name), self.atom_tbl);
                 let tag  = self.heap.to_unifiable(
                     HeapCellValue::Atom(chars, None)
                 );
diff --git a/src/machine/term_expansion.rs b/src/machine/term_expansion.rs
deleted file mode 100644 (file)
index 6ee8f8d..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-use crate::prolog_parser::ast::*;
-use crate::prolog_parser::parser::*;
-
-use crate::machine::machine_indices::HeapCellValue;
-use crate::machine::*;
-use crate::rug::ops::Pow;
-use crate::rug::Integer;
-
-use std::cell::Cell;
-use std::collections::VecDeque;
-use std::iter::Rev;
-use std::vec::IntoIter;
-
-pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> 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
-}
-
-fn extract_from_list(
-    head: Box<Term>,
-    tail: Box<Term>,
-) -> Result<Rev<IntoIter<Term>>, ParserError>
-{
-    let mut terms = vec![*head];
-    let mut tail = *tail;
-
-    while let Term::Cons(_, head, next_tail) = tail {
-        terms.push(*head);
-        tail = *next_tail;
-    }
-
-    if let Term::Constant(_, Constant::EmptyList) = tail {
-        Ok(terms.into_iter().rev())
-    } else {
-        Err(ParserError::ExpectedTopLevelTerm)
-    }
-}
-
-#[derive(Debug)]
-pub struct TermStream<'a> {
-    stack: Vec<Term>,
-    pub(crate) wam: &'a mut Machine,
-    parser: Parser<'a, Stream>,
-    pub(crate) flags: MachineFlags,
-    term_expansion_lens: (usize, usize),
-    goal_expansion_lens: (usize, usize),
-    top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
-}
-
-#[derive(Debug)]
-pub struct ExpansionAdditionResult {
-    term_expansion_additions: (Predicate, VecDeque<TopLevel>),
-    goal_expansion_additions: (Predicate, VecDeque<TopLevel>),
-}
-
-impl ExpansionAdditionResult {
-    pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
-        let tes = mem::replace(&mut self.term_expansion_additions.0, Predicate::new());
-        let teqs = mem::replace(&mut self.term_expansion_additions.1, VecDeque::from(vec![]));
-
-        (tes, teqs)
-    }
-
-    pub fn take_goal_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
-        let ges = mem::replace(&mut self.goal_expansion_additions.0, Predicate::new());
-        let geqs = mem::replace(&mut self.goal_expansion_additions.1, VecDeque::from(vec![]));
-
-        (ges, geqs)
-    }
-}
-
-impl<'a> Drop for TermStream<'a> {
-    fn drop(&mut self) {
-        self.wam.indices.in_situ_code_dir.clear();
-        self.wam.indices.in_situ_module_dir.clear();
-
-        self.wam.code_repo.in_situ_code.clear();
-        discard_result!(self.rollback_expansion_code());
-    }
-}
-
-impl<'a> TermStream<'a> {
-    pub fn new(
-        src: &'a mut ParsingStream<Stream>,
-        atom_tbl: TabledData<Atom>,
-        flags: MachineFlags,
-        wam: &'a mut Machine,
-    ) -> Self {
-        TermStream {
-            stack: Vec::new(),
-            term_expansion_lens: wam
-                .code_repo
-                .term_dir_entry_len((clause_name!("term_expansion"), 2)),
-            goal_expansion_lens: wam
-                .code_repo
-                .term_dir_entry_len((clause_name!("goal_expansion"), 2)),
-            wam,
-            parser: Parser::new(src, atom_tbl, flags),
-            flags,
-            top_level_terms: vec![],
-        }
-    }
-
-    #[inline]
-    pub fn top_level_terms(&mut self) -> Vec<(Term, usize, usize)> {
-        mem::replace(&mut self.top_level_terms, vec![])
-    }
-
-    #[inline]
-    pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
-        match hook {
-            CompileTimeHook::UserTermExpansion => {
-                self.term_expansion_lens.0 += len;
-                self.term_expansion_lens.1 += queue_len;
-            }
-            CompileTimeHook::UserGoalExpansion => {
-                self.goal_expansion_lens.0 += len;
-                self.goal_expansion_lens.1 += queue_len;
-            }
-            _ => {}
-        }
-    }
-
-    #[inline]
-    pub fn line_num(&self) -> usize {
-        self.parser.line_num()
-    }
-
-    #[inline]
-    pub fn col_num(&self) -> usize {
-        self.parser.col_num()
-    }
-
-    #[inline]
-    pub fn update_expansion_lens(&mut self) {
-        let te_key = (clause_name!("term_expansion"), 2);
-        let ge_key = (clause_name!("goal_expansion"), 2);
-
-        let (tes_len, tes_q_len) = self.wam.code_repo.term_dir_entry_len(te_key);
-
-        self.term_expansion_lens.0 = tes_len;
-        self.term_expansion_lens.1 = tes_q_len;
-
-        let (ges_len, ges_q_len) = self.wam.code_repo.term_dir_entry_len(ge_key);
-
-        self.goal_expansion_lens.0 = ges_len;
-        self.goal_expansion_lens.1 = ges_q_len;
-    }
-
-    #[inline]
-    pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
-        self.parser.set_atom_tbl(atom_tbl);
-    }
-
-    #[inline]
-    pub fn eof(&mut self) -> Result<bool, ParserError> {
-           self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
-        Ok(self.stack.is_empty() && self.parser.eof()?)
-    }
-
-    pub fn rollback_expansion_code(&mut self) -> Result<ExpansionAdditionResult, ParserError> {
-        let te_len = self.term_expansion_lens.0;
-        let te_queue_len = self.term_expansion_lens.1;
-
-        let ge_len = self.goal_expansion_lens.0;
-        let ge_queue_len = self.goal_expansion_lens.1;
-
-        let term_expansion_additions = self.wam.code_repo.truncate_terms(
-            (clause_name!("term_expansion"), 2),
-            te_len,
-            te_queue_len,
-        );
-
-        let goal_expansion_additions = self.wam.code_repo.truncate_terms(
-            (clause_name!("goal_expansion"), 2),
-            ge_len,
-            ge_queue_len,
-        );
-
-        self.wam
-            .code_repo
-            .compile_hook(CompileTimeHook::TermExpansion)?;
-        self.wam
-            .code_repo
-            .compile_hook(CompileTimeHook::GoalExpansion)?;
-
-        Ok(ExpansionAdditionResult {
-            term_expansion_additions,
-            goal_expansion_additions,
-        })
-    }
-
-    fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
-        match term {
-            Term::Cons(_, head, tail) => {
-                let iter = extract_from_list(head, tail)?;
-                Ok(self.stack.extend(iter))
-            }
-            Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
-                Ok(self.stack.push(term))
-            }
-            _ => {
-                Err(ParserError::ExpectedTopLevelTerm)
-            }
-        }
-    }
-
-    fn parse_expansion_output(
-        &self,
-        term_string: &str,
-        op_dir: &OpDir,
-    ) -> Result<Term, ParserError> {
-        let mut stream = parsing_stream(term_string.trim().as_bytes())?;
-        let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
-
-        parser.read_term(composite_op!(
-            false,
-            &self.wam.indices.op_dir,
-            op_dir
-        ))
-    }
-
-    pub fn expand_term(&mut self, term: Term, op_dir: &OpDir) -> Result<Term, ParserError> {
-        let mut machine_st = MachineState::new();
-
-        self.stack.push(term);
-
-        while let Some(term) = self.stack.pop() {
-            match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::TermExpansion) {
-                Some(term_string) => {
-                    let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
-                    self.enqueue_term(term)?;
-                }
-                None => {
-                    return Ok(term);
-                }
-            };
-        }
-
-        unreachable!()
-    }
-
-    pub fn read_term(&mut self, op_dir: &OpDir) -> Result<Term, ParserError> {
-        loop {
-            if let Some(term) = self.stack.pop() {
-                return Ok(self.expand_term(term, op_dir)?);
-            }
-
-            self.parser.reset();
-
-            let line_num = self.line_num();
-            let col_num = self.col_num();
-
-            let term = self.parser.read_term(composite_op!(
-                false,
-                &self.wam.indices.op_dir,
-                op_dir
-            ))?;
-
-            // preserve a copy of the original unexpanded term for warning scans,
-            // if that stage is reached.
-            self.top_level_terms.push((term.clone(), line_num, col_num));
-            self.stack.push(term);
-        }
-    }
-
-    pub(super)
-    fn expand_goals(
-        &mut self,
-        machine_st: &mut MachineState,
-        op_dir: &OpDir,
-        mut terms: VecDeque<Term>,
-    ) -> Result<Vec<Term>, ParserError> {
-        let mut results = vec![];
-
-        while let Some(term) = terms.pop_front() {
-            match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::GoalExpansion) {
-                Some(term_string) => {
-                    let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
-
-                    match term {
-                        Term::Cons(_, head, tail) => {
-                            for term in extract_from_list(head, tail)? {
-                                terms.push_front(term);
-                            }
-                        }
-                        term => terms.push_front(term),
-                    };
-                }
-                None => results.push(term),
-            }
-        }
-
-        Ok(results)
-    }
-}
-
-impl MachineState {
-    pub(super)
-    fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
-        let output = PrinterOutputter::new();
-        let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
-        let mut max_var_length = 0;
-
-        for var in self.heap_locs.keys() {
-            max_var_length = std::cmp::max(var.len(), max_var_length);
-        }
-
-        printer.quoted = true;
-        printer.numbervars = true;
-
-        // the purpose of the offset is to avoid clashes with variable
-        // names that might occur after the addresses in the expanded
-        // term are substituted with the variable names in the
-        // pre-expansion term. This formula ensures that all generated
-        // "numbervars"- style variable names will be longer than the
-        // keys of the var_dict, and therefore not equal to any of
-        // them.
-        printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
-        printer.print_strings_as_strs = true;
-        printer.drop_toplevel_spec();
-
-        printer.see_all_locs();
-
-        let mut output = printer.print(addr);
-
-        output.push_char('.');
-        output
-    }
-
-    // reset the machine, but keep the heap contents as they were.
-    // this prevents clashes between underscored variable names in the
-    // same query.
-    fn reset_with_heap_preservation(&mut self) {
-        let heap = self.heap.take();
-        self.reset();
-        self.heap = heap;
-    }
-
-    fn try_expand_term(
-        &mut self,
-        wam: &mut Machine,
-        term: &Term,
-        hook: CompileTimeHook,
-    ) -> Option<String> {
-        let term_write_result = write_term_to_heap(term, self);
-        let h = self.heap.h();
-
-        self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc);
-        self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
-        self[temp_v!(2)] = Addr::HeapCell(h);
-
-        let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
-        wam.code_repo.cached_query = code;
-
-        self.cp = LocalCodePtr::TopLevel(0, 0);
-
-        self.at_end_of_expansion = false;
-        self.flags.double_quotes = DoubleQuotes::Chars;
-
-        self.query_stepper(
-            &mut wam.indices,
-            &mut MachinePolicies::default(),
-            &mut wam.code_repo,
-            &mut readline::input_stream(),
-            &mut Stream::stdout(),
-        );
-
-        if self.fail || self.at_end_of_expansion {
-            self.reset_with_heap_preservation();
-            None
-        } else {
-            let TermWriteResult { var_dict, .. } = term_write_result;
-
-            self.heap_locs = var_dict;
-            let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
-
-            self.reset_with_heap_preservation();
-
-            Some(output.result())
-        }
-    }
-}
diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs
new file mode 100644 (file)
index 0000000..bceec68
--- /dev/null
@@ -0,0 +1,149 @@
+use crate::prolog_parser::ast::*;
+use crate::prolog_parser::parser::*;
+
+use crate::machine::*;
+use crate::machine::machine_errors::CompilationError;
+use crate::machine::preprocessor::*;
+
+use indexmap::IndexSet;
+
+use std::collections::VecDeque;
+use std::fmt;
+
+pub(crate) trait TermStream : Sized {
+    type Evacuable;
+
+    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> {
+    listing_src: ListingSource,
+    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,
+        listing_src: ListingSource,
+    ) -> Self {
+        let parser = Parser::new(stream, atom_tbl, flags);
+        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();
+        self.parser.read_term(op_dir)
+            .map_err(CompilationError::from)
+    }
+
+    #[inline]
+    fn eof(&mut self) -> Result<bool, CompilationError> {
+           self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
+        Ok(self.parser.eof()?)
+    }
+
+    #[inline]
+    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 struct LiveTermStream {
+    pub(super) term_queue: VecDeque<Term>,
+    pub(super) listing_src: ListingSource,
+}
+
+impl LiveTermStream {
+    #[inline]
+    pub(super)
+    fn new(listing_src: ListingSource) -> Self {
+        Self {
+            term_queue: VecDeque::new(),
+            listing_src,
+        }
+    }
+}
+
+pub 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) preprocessor: Preprocessor,
+    pub(super) predicates: Vec<PredicateClause>,
+    pub(super) clause_clauses: Vec<(Term, Term)>,
+}
+
+impl fmt::Debug for LoadStatePayload {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "LoadStatePayload")
+    }
+}
+
+impl LoadStatePayload {
+    pub(super)
+    fn new(wam: &Machine) -> Self {
+        Self {
+            term_stream: LiveTermStream::new(ListingSource::User),
+            compilation_target: CompilationTarget::default(),
+            retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
+            module_op_exports: vec![],
+            non_counted_bt_preds: IndexSet::new(),
+            preprocessor: Preprocessor::new(wam.machine_st.flags),
+            predicates: vec![],
+            clause_clauses: vec![],
+        }
+    }
+}
+
+impl TermStream for LiveTermStream {
+    type Evacuable = LoadStatePayload;
+
+    #[inline]
+    fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
+        Ok(self.term_queue.pop_front().unwrap())
+    }
+
+    #[inline]
+    fn eof(&mut self) -> Result<bool, CompilationError> {
+        return Ok(self.term_queue.is_empty());
+    }
+
+    #[inline]
+    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/machine/toplevel.rs b/src/machine/toplevel.rs
deleted file mode 100644 (file)
index eaa1769..0000000
+++ /dev/null
@@ -1,1352 +0,0 @@
-use crate::prolog_parser::ast::*;
-use crate::prolog_parser::tabled_rc::*;
-
-use crate::forms::*;
-use crate::iterators::*;
-use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::*;
-use crate::machine::term_expansion::*;
-use crate::machine::*;
-
-use crate::indexmap::{IndexMap, IndexSet};
-
-use std::borrow::BorrowMut;
-use std::cell::Cell;
-use std::collections::VecDeque;
-use std::convert::TryFrom;
-use std::fmt;
-use std::mem;
-use std::ops::DerefMut;
-use std::rc::Rc;
-
-enum IndexSource<'a, T> {
-    TermStream,
-    Local(&'a mut T)
-}
-
-impl<'a, T: fmt::Debug> fmt::Debug for IndexSource<'a, T> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            IndexSource::TermStream => write!(fmt, "TermStream"),
-            IndexSource::Local(ref local) => write!(fmt, "Local({:?})", local),
-        }
-    }
-}
-
-fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, OpDir> {
-    match from {
-        IndexSource::TermStream => RefOrOwned::Owned(OpDir::new()),
-        IndexSource::Local(ref indices) => RefOrOwned::Borrowed(&indices.op_dir)
-    }
-}
-
-#[derive(Debug)]
-struct CompositeIndices<'a, 'b, 'c> {
-    term_stream: &'b mut TermStream<'a>,
-    index_src: IndexSource<'c, IndexStore>,
-    static_code_dir: Option<IndexSource<'c, CodeDir>>
-}
-
-impl<'a, 'b, 'c> CompositeIndices<'a, 'b, 'c> {
-    fn new(
-        term_stream: &'b mut TermStream<'a>,
-        index_src: IndexSource<'c, IndexStore>,
-        static_code_dir: Option<IndexSource<'c, CodeDir>>,
-    ) -> Self {
-        CompositeIndices {
-            term_stream,
-            index_src,
-            static_code_dir,
-        }
-    }
-
-    fn atom_tbl(&self) -> TabledData<Atom> {
-        match self.index_src {
-            IndexSource::TermStream => self.term_stream.wam.indices.atom_tbl.clone(),
-            IndexSource::Local(ref indices) => indices.atom_tbl.clone(),
-        }
-    }
-
-    fn local_code_dir(&mut self) -> &mut CodeDir {
-        match self.index_src {
-            IndexSource::TermStream => &mut self.term_stream.wam.indices.code_dir,
-            IndexSource::Local(ref mut indices) => &mut indices.code_dir,
-        }
-    }
-
-    fn static_code_dir(&self) -> Option<&CodeDir> {
-        match self.static_code_dir {
-            Some(IndexSource::TermStream) => Some(&self.term_stream.wam.indices.code_dir),
-            Some(IndexSource::Local(ref code_dir)) => Some(code_dir),
-            None => None
-        }
-    }
-
-    fn get_code_index(&mut self, name: ClauseName, arity: usize) -> CodeIndex {
-        let idx_opt = self.local_code_dir().get(&(name.clone(), arity));
-        let idx_opt = match idx_opt {
-            Some(idx) => Some(idx.clone()),
-            None => match self.static_code_dir() {
-                Some(ref code_dir) => code_dir.get(&(name.clone(), arity)).cloned(),
-                _ => None,
-            }
-        };
-
-        if let Some(idx) = idx_opt {
-            self.local_code_dir().insert((name.clone(), arity), idx.clone());
-            idx
-        } else {
-            let idx = CodeIndex::default();
-            self.local_code_dir().insert((name.clone(), arity), idx.clone());
-            idx
-        }
-    }
-
-    fn get_clause_type(
-        &mut self,
-        name: ClauseName,
-        arity: usize,
-        spec: Option<SharedOpDesc>,
-    ) -> ClauseType {
-        match ClauseType::from(name, arity, spec) {
-            ClauseType::Named(name, arity, _) => {
-                let idx = self.get_code_index(name.clone(), arity);
-                ClauseType::Named(name, arity, idx.clone())
-            }
-            ClauseType::Op(name, spec, _) => {
-                let idx = self.get_code_index(name.clone(), arity);
-                ClauseType::Op(name, spec, idx.clone())
-            }
-            ct => ct,
-        }
-    }
-
-    fn add_in_situ_module_info(&mut self, module_name: ClauseName, term: &mut Term)
-    {
-        let atom_tbl =
-            match self.term_stream.wam.indices.in_situ_module_dir.get(&module_name) {
-                Some(ref module_stub) => module_stub.atom_tbl.clone(),
-                None => {
-                    let atom_tbl = match self.term_stream.wam.indices.modules.get(&module_name) {
-                        Some(ref module) => module.atom_tbl.clone(),
-                        None => TabledData::new(module_name.to_rc()),
-                    };
-
-                    self.term_stream.wam.indices.in_situ_module_dir.insert(
-                        module_name.clone(),
-                        ModuleStub::new(atom_tbl.clone()),
-                    );
-
-                    atom_tbl
-                }
-            };
-
-        if let Some(name) = term.name() {
-            term.set_name(name.with_table(atom_tbl));
-        }
-    }
-}
-
-fn as_compile_time_hook(
-    name: &str,
-    arity: usize,
-    terms: &Vec<Box<Term>>,
-) -> Option<CompileTimeHook> {
-    match (name, arity) {
-        ("term_expansion", 2) => Some(CompileTimeHook::TermExpansion),
-        ("goal_expansion", 2) => Some(CompileTimeHook::GoalExpansion),
-        (":", 2) => {
-            if let &Term::Constant(_, Constant::Atom(ref name, _)) = &terms[0].as_ref() {
-                if name.as_str() == "user" {
-                    if let &Term::Clause(_, ref name, ref terms, _) = &terms[1].as_ref() {
-                        return match name.as_str() {
-                            "term_expansion" if terms.len() == 2 => {
-                                Some(CompileTimeHook::UserTermExpansion)
-                            }
-                            "goal_expansion" if terms.len() == 2 => {
-                                Some(CompileTimeHook::UserGoalExpansion)
-                            }
-                            _ => None,
-                        };
-                    }
-                }
-            }
-
-            None
-        }
-        _ => None,
-    }
-}
-
-#[inline]
-fn is_compile_time_hook(name: &ClauseName, terms: &Vec<Box<Term>>) -> Option<CompileTimeHook> {
-    if name.as_str() == ":-" {
-        if let Some(ref term) = terms.first() {
-            if let &Term::Clause(_, ref name, ref terms, _) = term.as_ref() {
-                return as_compile_time_hook(name.as_str(), terms.len(), terms);
-            }
-        }
-    }
-
-    as_compile_time_hook(name.as_str(), terms.len(), terms)
-}
-
-type CompileTimeHookCompileInfo = (CompileTimeHook, PredicateClause, VecDeque<TopLevel>);
-
-pub fn to_op_decl(prec: usize, spec: &str, name: ClauseName) -> Result<OpDecl, ParserError> {
-    match spec {
-        "xfx" => Ok(OpDecl(prec, XFX, name)),
-        "xfy" => Ok(OpDecl(prec, XFY, name)),
-        "yfx" => Ok(OpDecl(prec, YFX, name)),
-        "fx" => Ok(OpDecl(prec, FX, name)),
-        "fy" => Ok(OpDecl(prec, FY, name)),
-        "xf" => Ok(OpDecl(prec, XF, name)),
-        "yf" => Ok(OpDecl(prec, YF, name)),
-        _ => Err(ParserError::InconsistentEntry),
-    }
-}
-
-fn setup_op_decl(
-    mut terms: Vec<Box<Term>>,
-    atom_tbl: TabledData<Atom>,
-) -> Result<OpDecl, ParserError> {
-    let name = match *terms.pop().unwrap() {
-        Term::Constant(_, Constant::Atom(name, _)) => name,
-        Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl.clone()),
-        _ => return Err(ParserError::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.clone()),
-        _ => return Err(ParserError::InconsistentEntry),
-    };
-
-    let prec = match *terms.pop().unwrap() {
-        Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
-            Ok(n) if n <= 1200 => n,
-            _ => return Err(ParserError::InconsistentEntry),
-        },
-        _ => return Err(ParserError::InconsistentEntry),
-    };
-
-    to_op_decl(prec, spec.as_str(), name)
-}
-
-fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError>
-{
-    match term {
-        Term::Clause(_, ref slash, ref mut terms, Some(_))
-            if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
-        {
-            let arity = *terms.pop().unwrap();
-            let name  = *terms.pop().unwrap();
-
-            let arity = arity
-                .to_constant()
-                .and_then(|c| {
-                    match c {
-                        Constant::Integer(n) => n.to_usize(),
-                        Constant::Fixnum(n) => usize::try_from(n).ok(),
-                        _ => None
-                    }
-                })
-                .ok_or(ParserError::InvalidModuleExport)?;
-
-            let name  = name
-                .to_constant()
-                .and_then(|c| c.to_atom())
-                .ok_or(ParserError::InvalidModuleExport)?;
-
-            if slash.as_str() == "/" {
-                Ok((name, arity))
-            } else {
-                Ok((name, arity + 2))
-            }
-        }
-        _ => Err(ParserError::InvalidModuleExport),
-    }
-}
-
-fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, ParserError>
-{
-    match term {
-        Term::Clause(_, ref name, ref mut terms, Some(_))
-            if name.as_str() == ":" && terms.len() == 2 =>
-        {
-            let mut predicate_indicator = *terms.pop().unwrap();
-            let module_name = *terms.pop().unwrap();
-
-            let module_name = module_name
-                .to_constant()
-                .and_then(|c| c.to_atom())
-                .ok_or(ParserError::InvalidModuleExport)?;
-
-            let key = setup_predicate_indicator(&mut predicate_indicator)?;
-
-            Ok((module_name, key))
-        }
-        _ => Err(ParserError::InvalidModuleExport),
-    }
-}
-
-fn setup_module_export(
-    mut term: Term,
-    atom_tbl: TabledData<Atom>,
-) -> Result<ModuleExport, ParserError> {
-    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" {
-                    Ok(ModuleExport::OpDecl(setup_op_decl(
-                        terms,
-                        atom_tbl
-                    )?))
-                } else {
-                    Err(ParserError::InvalidModuleDecl)
-                }
-            } else {
-                Err(ParserError::InvalidModuleDecl)
-            }
-        })
-}
-
-fn setup_module_decl(
-    mut terms: Vec<Box<Term>>,
-    atom_tbl: TabledData<Atom>,
-) -> Result<ModuleDecl, ParserError> {
-    let mut export_list = *terms.pop().unwrap();
-    let name = terms
-        .pop()
-        .unwrap()
-        .to_constant()
-        .and_then(|c| c.to_atom())
-        .ok_or(ParserError::InvalidModuleDecl)?;
-
-    let mut exports = vec![];
-
-    while let Term::Cons(_, t1, t2) = export_list {
-        let module_export = setup_module_export(*t1, atom_tbl.clone())?;
-
-        exports.push(module_export);
-        export_list = *t2;
-    }
-
-    if export_list.to_constant() != Some(Constant::EmptyList) {
-        Err(ParserError::InvalidModuleDecl)
-    } else {
-        Ok(ModuleDecl { name, exports })
-    }
-}
-
-fn read_library_path(
-    term: Term,
-    atom_tbl: TabledData<Atom>,
-) -> Option<ClauseName> {
-    match term {
-        Term::Constant(_, Constant::Atom(atom, _)) => {
-            Some(atom.defrock_brackets())
-        }
-        _ => {
-            let mut atoms = vec![];
-
-            for term in unfold_by_str(term, "/") {
-                match term {
-                    Term::Constant(_, Constant::Atom(atom, _)) => {
-                        atoms.push(atom.as_str().to_owned());
-                    }
-                    _ => return None,
-                }
-            }
-
-            Some(clause_name!(atoms.join("/"), atom_tbl))
-        }
-    }
-}
-
-fn setup_use_module_decl(mut terms: Vec<Box<Term>>, atom_tbl: TabledData<Atom>) -> Result<ModuleSource, ParserError> {
-    match *terms.pop().unwrap() {
-        Term::Clause(_, ref name, ref mut terms, None)
-            if name.as_str() == "library" && terms.len() == 1 =>
-        {
-            read_library_path(*terms.pop().unwrap(), atom_tbl)
-                .map(|c| ModuleSource::Library(c))
-                .ok_or(ParserError::InvalidUseModuleDecl)
-        }
-        Term::Constant(_, Constant::Atom(ref name, _)) =>
-            Ok(ModuleSource::File(name.clone())),
-        _ => Err(ParserError::InvalidUseModuleDecl),
-    }
-}
-
-fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, ParserError> {
-    let dbl_quotes = *terms.pop().unwrap();
-
-    match terms[0].as_ref() {
-        Term::Constant(_, Constant::Atom(ref name, _))
-            if name.as_str() == "double_quotes" => {
-                match dbl_quotes {
-                    Term::Constant(_, Constant::Atom(name, _)) => {
-                        match name.as_str() {
-                            "atom"  => Ok(DoubleQuotes::Atom),
-                            "chars" => Ok(DoubleQuotes::Chars),
-                            "codes" => Ok(DoubleQuotes::Codes),
-                            _ => Err(ParserError::InvalidDoubleQuotesDecl),
-                        }
-                    }
-                    _ => {
-                        Err(ParserError::InvalidDoubleQuotesDecl)
-                    }
-                }
-            },
-        _ => {
-            Err(ParserError::InvalidDoubleQuotesDecl)
-        }
-    }
-}
-
-type UseModuleExport = (ModuleSource, Vec<ModuleExport>);
-
-fn setup_qualified_import(
-    mut terms: Vec<Box<Term>>,
-    atom_tbl: TabledData<Atom>,
-) -> Result<UseModuleExport, ParserError> {
-    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 =>
-        {
-            read_library_path(*terms.pop().unwrap(), atom_tbl.clone())
-                .map(|c| ModuleSource::Library(c))
-                .ok_or(ParserError::InvalidUseModuleDecl)
-        }
-        Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
-        _ => Err(ParserError::InvalidUseModuleDecl),
-    }?;
-
-    let mut exports = vec![];
-
-    while let Term::Cons(_, t1, t2) = export_list {
-        exports.push(setup_module_export(*t1, atom_tbl.clone())?);
-        export_list = *t2;
-    }
-
-    if export_list.to_constant() != Some(Constant::EmptyList) {
-        Err(ParserError::InvalidModuleDecl)
-    } else {
-        Ok((module_src, exports))
-    }
-}
-
-fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError>
-{
-    let mut clauses: Vec<PredicateClause> = vec![];
-
-    while let Some(tl) = tls.pop_front() {
-        match tl {
-            TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl),
-            TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl),
-            TopLevel::Query(_) => return Err(ParserError::InconsistentEntry),
-            TopLevel::Fact(..) => {
-                if let TopLevel::Fact(fact, line_num, col_num) = tl {
-                    let clause = PredicateClause::Fact(fact, line_num, col_num);
-                    clauses.push(clause);
-                }
-            }
-            TopLevel::Rule(..) => {
-                if let TopLevel::Rule(rule, line_num, col_num) = tl {
-                    let clause = PredicateClause::Rule(rule, line_num, col_num);
-                    clauses.push(clause);
-                }
-            }
-            TopLevel::Predicate(..) => {
-                if let TopLevel::Predicate(predicate) = tl {
-                    clauses.extend(predicate.clauses().into_iter())
-                }
-            }
-            _ => {
-                tls.push_front(tl);
-                break;
-            }
-        }
-    }
-
-    if clauses.is_empty() {
-        Err(ParserError::InconsistentEntry)
-    } else {
-        Ok(TopLevel::Predicate(Predicate(clauses)))
-    }
-}
-
-fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
-    for term in terms.iter_mut() {
-        match term {
-            &mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => {
-                *var = name.clone()
-            }
-            _ => {}
-        }
-    }
-}
-
-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,
-        _ => false,
-    };
-
-    if cut_var_found {
-        *term = Term::Var(Cell::default(), rc_atom!("!"));
-        true
-    } else {
-        false
-    }
-}
-
-fn mark_cut_variables(terms: &mut Vec<Term>) -> bool {
-    let mut found_cut_var = false;
-
-    for item in terms.iter_mut() {
-        found_cut_var = mark_cut_variable(item) || found_cut_var;
-    }
-
-    found_cut_var
-}
-
-// terms is a list of goals composing one clause in a (;) functor. it
-// checks that the first (and only) of these clauses is a ->. if so,
-// it expands its terms using a blocked_!.
-fn check_for_internal_if_then(terms: &mut Vec<Term>) {
-    if terms.len() != 1 {
-        return;
-    }
-
-    if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() {
-        if name.as_str() != "->" || 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(), ","));
-
-        conq_terms.push_front(Term::Constant(
-            Cell::default(),
-            Constant::Atom(clause_name!("blocked_!"), None))
-        );
-
-        while let Some(term) = pre_cut_terms.pop_back() {
-            conq_terms.push_front(term);
-        }
-
-        let tail_term = conq_terms.pop_back().unwrap();
-
-        terms.push(fold_by_str(
-            conq_terms.into_iter(),
-            tail_term,
-            clause_name!(","),
-        ));
-    }
-}
-
-fn flatten_hook(mut term: Term) -> Term {
-    if let Term::Clause(_, ref mut name, ref mut terms, _) = &mut term {
-        match (name.as_str(), terms.len()) {
-            (":-", 2) => {
-                let inner_term = match terms.first_mut().map(|term| term.borrow_mut()) {
-                    Some(&mut Term::Clause(_, ref name, ref mut inner_terms, _)) => {
-                        if name.as_str() == ":" && inner_terms.len() == 2 {
-                            Some(*inner_terms.pop().unwrap())
-                        } else {
-                            None
-                        }
-                    }
-                    _ => None,
-                };
-
-                if let Some(inner_term) = inner_term {
-                    mem::swap(&mut terms[0], &mut Box::new(inner_term));
-                }
-            }
-            (":", 2) => return *terms.pop().unwrap(),
-            _ => {}
-        }
-    }
-
-    term
-}
-
-fn draw_from_term_dir_impl(
-    term_dir: &TermDir,
-    term_dirs: &mut TermDirQuantum,
-    key: &PredicateKey,
-    preds: &mut Vec<PredicateClause>,
-    queue: &mut VecDeque<TopLevel>
-) {
-    if let Some(entry) = term_dirs.get_mut(key) {
-        if entry.is_fresh {
-            entry.is_fresh = false;
-
-            (entry.new_terms.0).0.extend(preds.drain(0 ..));
-            entry.new_terms.1.extend(queue.drain(0 ..));
-
-            *preds = (entry.old_terms.0).0
-                .iter()
-                .cloned()
-                .chain((entry.new_terms.0).0.iter().cloned())
-                .collect();
-
-            *queue = entry.old_terms.1
-                .iter()
-                .cloned()
-                .chain(entry.new_terms.1.iter().cloned())
-                .collect();
-        } else {
-            *entry = TermDirQuantumEntry::new();
-        }
-    } else if term_dir.contains_key(key) {
-        let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new());
-        term_dirs.insert(key.clone(), entry);
-    }
-}
-
-fn draw_from_term_dir(
-    indices: &CompositeIndices,
-    intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
-    top_level_term_dirs: &mut TermDirQuantum,
-    key: &PredicateKey,
-    preds: &mut Vec<PredicateClause>,
-    queue: &mut VecDeque<TopLevel>,
-) {
-    let module = key.0.owning_module();
-
-    // aaarghhh..
-    match indices.term_stream.wam.indices.in_situ_module_dir.get(&module) {
-        // modify module_stub to do this right.
-        Some(ref module_stub) if key.0.has_table(&module_stub.atom_tbl) => {
-            if let Some(ref mut term_dirs) = intra_module_term_dirs.get_mut(&module) {
-                if let Some(ref module) = indices.term_stream.wam.indices.modules.get(&module) {
-                    return draw_from_term_dir_impl(
-                        &module.term_dir,
-                        term_dirs,
-                        key,
-                        preds,
-                        queue,
-                    );
-                }
-            }
-        }
-        _ => {}
-    }
-
-    draw_from_term_dir_impl(
-        &indices.term_stream.wam.code_repo.term_dir,
-        top_level_term_dirs,
-        key,
-        preds,
-        queue,
-    );
-}
-
-fn setup_declaration<'a, 'b, 'c>(
-    indices: &mut CompositeIndices<'a, 'b, 'c>,
-    flags: MachineFlags,
-    mut terms: Vec<Box<Term>>,
-    line_num: usize,
-    col_num: usize,
-) -> Result<Declaration, ParserError> {
-    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())?;
-                           Ok(Declaration::Dynamic(name, arity))
-                       }
-                       ("initialization", 1) => {
-                           let mut rel_worker = RelationWorker::new(flags, line_num, col_num);
-                           let (query_terms, _) = rel_worker.setup_query(indices, terms, false, false)?;
-                           let queue = rel_worker.parse_queue(indices)?;
-
-                           Ok(Declaration::ModuleInitialization(query_terms, queue))
-                       }
-                       ("module", 2) =>
-                           Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)),
-                       ("op", 3) =>
-                           Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)),
-                       ("non_counted_backtracking", 1) => {
-                           let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
-                           Ok(Declaration::NonCountedBacktracking(name, arity))
-                       }
-                ("set_prolog_flag", 2) => {
-                    Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?))
-                }
-                ("multifile", 1) => {
-                    let mut term = *terms.pop().unwrap();
-
-                    match setup_predicate_indicator(&mut term) {
-                        Ok((name, arity)) => {
-                            Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity)))
-                        }
-                        _ => {
-                            setup_scoped_predicate_indicator(&mut term)
-                                .map(|key| {
-                                    Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
-                                })
-                        }
-                    }
-                }
-                       ("use_module", 1) => {
-                           Ok(Declaration::UseModule(setup_use_module_decl(terms, indices.atom_tbl())?))
-                }
-                       ("use_module", 2) => {
-                           let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?;
-                           Ok(Declaration::UseQualifiedModule(name, exports))
-                       }
-                       _ => {
-                           Err(ParserError::InconsistentEntry)
-                }
-               },
-        _ => {
-            Err(ParserError::InconsistentEntry)
-        }
-    }
-}
-
-#[derive(Debug)]
-struct RelationWorker {
-    flags: MachineFlags,
-    dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
-    queue: VecDeque<VecDeque<Term>>,
-    line_num: usize,
-    col_num: usize
-}
-
-impl RelationWorker {
-    fn new(flags: MachineFlags, line_num: usize, col_num: usize) -> Self {
-        RelationWorker {
-            dynamic_clauses: vec![],
-            flags,
-            queue: VecDeque::new(),
-            line_num,
-            col_num
-        }
-    }
-
-    fn setup_fact(&mut self, term: Term, assume_dyn: bool) -> Result<Term, ParserError> {
-        match term {
-            Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
-                let tail =
-                    Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None));
-
-                if assume_dyn {
-                    self.dynamic_clauses.push((term.clone(), tail));
-                }
-
-                Ok(term)
-            }
-            _ => Err(ParserError::InadmissibleFact),
-        }
-    }
-
-    fn compute_head(&self, term: &Term) -> Vec<Term> {
-        let mut vars = IndexSet::new();
-
-        for term in post_order_iter(term) {
-            if let TermRef::Var(_, _, v) = term {
-                vars.insert(v.clone());
-            }
-        }
-
-        vars.insert(rc_atom!("!"));
-        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!(":-");
-
-        Term::Clause(Cell::default(), turnstile, rule, None)
-    }
-
-    // the terms form the body of the rule. We create a head, by
-    // gathering variables from the body of terms and recording them
-    // in the head clause.
-    fn fabricate_rule(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
-        // collect the vars of body_term into a head, return the num_vars
-        // (the arity) as well.
-        let vars = self.compute_head(&body_term);
-        let rule = self.fabricate_rule_body(&vars, body_term);
-
-        (vars, VecDeque::from(vec![rule]))
-    }
-
-    fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
-        let vars = self.compute_head(&body_term);
-        let results = unfold_by_str(body_term, ";")
-            .into_iter()
-            .map(|term| {
-                let mut subterms = unfold_by_str(term, ",");
-                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!(","));
-
-                self.fabricate_rule_body(&vars, clause)
-            })
-            .collect();
-
-        (vars, results)
-    }
-
-    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!("!");
-
-        prec_seq.push(Term::Constant(Cell::default(), cut_sym));
-
-        mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!"));
-
-        let mut conq_seq = unfold_by_str(conq, ",");
-
-        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 body_term = Term::Clause(
-            Cell::default(),
-            comma_sym.clone(),
-            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, 'b, 'c>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        term: Term,
-    ) -> Result<QueryTerm, ParserError> {
-        match term {
-            Term::Constant(_, Constant::Atom(name, fixity)) => {
-                if name.as_str() == "!" || name.as_str() == "blocked_!" {
-                    Ok(QueryTerm::BlockedCut)
-                } else {
-                    let ct = indices.get_clause_type(name, 0, fixity);
-                    Ok(QueryTerm::Clause(Cell::default(), ct, vec![], false))
-                }
-            }
-            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);
-                    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();
-
-                    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(
-                        Cell::default(),
-                        Constant::Atom(clause_name!("$fail"), None)
-                    )));
-
-                    let conq = Term::Constant(
-                        Cell::default(),
-                        Constant::Atom(clause_name!("true"), None)
-                    );
-
-                    let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
-                    let terms = vec![Box::new(prec), Box::new(conq)];
-
-                    let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
-                    let (stub, clauses) = self.fabricate_disjunct(term);
-
-                    debug_assert!(clauses.len() > 0);
-                    self.queue.push_back(clauses);
-                    Ok(QueryTerm::Jump(stub))
-                }
-                ("$get_level", 1) => {
-                    if let Term::Var(_, ref var) = *terms[0] {
-                        Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
-                    } else {
-                        Err(ParserError::InadmissibleQueryTerm)
-                    }
-                }
-                _ => {
-                    let ct = indices.get_clause_type(name, terms.len(), fixity);
-                    Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
-                }
-            }
-            Term::Var(..) => Ok(QueryTerm::Clause(
-                Cell::default(),
-                ClauseType::CallN,
-                vec![Box::new(term)],
-                false,
-            )),
-            _ => Err(ParserError::InadmissibleQueryTerm),
-        }
-    }
-
-    fn pre_query_term<'a, 'b, 'c>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        term: Term,
-    ) -> Result<QueryTerm, ParserError> {
-        match term {
-            Term::Clause(r, name, mut subterms, fixity) => {
-                if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
-                    self.to_query_term(indices, *subterms.pop().unwrap())
-                        .map(|mut query_term| {
-                            query_term.set_default_caller();
-                            query_term
-                        })
-                } else {
-                    self.to_query_term(indices, Term::Clause(r, name, subterms, fixity))
-                }
-            }
-            _ => self.to_query_term(indices, term),
-        }
-    }
-
-    fn setup_query<'a, 'b, 'c>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        terms: Vec<Box<Term>>,
-        blocks_cuts: bool,
-        assume_dyn: bool,
-    ) -> Result<(Vec<QueryTerm>, Term), ParserError> {
-        let mut query_terms = vec![];
-        let mut work_queue = VecDeque::from(terms);
-        let mut machine_st = MachineState::new();
-
-        let mut dynamic_clause_terms = vec![];
-
-        while let Some(term) = work_queue.pop_front() {
-            let term = *term;
-            let op_dir = op_dir(&indices.index_src);
-
-            let mut expanded_terms = indices.term_stream.expand_goals(
-                &mut machine_st,
-                op_dir.as_ref(),
-                VecDeque::from(vec![term])
-            )?;
-
-            while let Some(term) = expanded_terms.pop() {
-                work_queue.push_front(Box::new(term));
-            }
-
-            if let Some(term) = work_queue.pop_front() {
-                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, ",");
-
-                        while let Some(subterm) = subterms.pop() {
-                            work_queue.push_front(Box::new(subterm));
-                        }
-
-                        continue;
-                    } else {
-                        term = Term::Clause(cell, name, terms, op_spec);
-                    }
-                }
-
-                if !blocks_cuts {
-                    mark_cut_variable(&mut term);
-                }
-
-                if assume_dyn {
-                    dynamic_clause_terms.push(term.clone());
-                }
-
-                query_terms.push(self.pre_query_term(indices, term)?);
-            }
-        }
-
-        let dynamic_clause_body =
-            if let Some(term) = dynamic_clause_terms.pop() {
-                fold_by_str(dynamic_clause_terms.into_iter(), term, clause_name!(","))
-            } else {
-                Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None))
-            };
-
-        Ok((query_terms, dynamic_clause_body))
-    }
-
-    fn setup_hook<'a, 'b, 'c>(
-        &mut self,
-        hook: CompileTimeHook,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        term: Term,
-    ) -> Result<CompileTimeHookCompileInfo, ParserError> {
-        match flatten_hook(term) {
-            Term::Clause(r, name, terms, _) => {
-                if name == hook.name() && terms.len() == hook.arity() {
-                    let term = self.setup_fact(Term::Clause(r, name, terms, None), false)?;
-                    Ok((hook, PredicateClause::Fact(term, 0, 0), VecDeque::from(vec![])))
-                } else if name.as_str() == ":-" && terms.len() == 2 {
-                    let rule = self.setup_rule(indices, terms, true, false)?;
-                    let results_queue = self.parse_queue(indices)?;
-
-                    Ok((hook, PredicateClause::Rule(rule, 0, 0), results_queue))
-                } else {
-                    Err(ParserError::InvalidHook)
-                }
-            }
-            _ => Err(ParserError::InvalidHook),
-        }
-    }
-
-    fn setup_rule<'a, 'b, 'c>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        mut terms: Vec<Box<Term>>,
-        blocks_cuts: bool,
-        assume_dyn: bool,
-    ) -> Result<Rule, ParserError> {
-        let dynamic_term_head = *terms.first().cloned().unwrap();
-        let post_head_terms: Vec<_> = terms.drain(1 ..).collect();
-
-        let (mut query_terms, dynamic_term_body) =
-            self.setup_query(indices, post_head_terms, blocks_cuts, assume_dyn)?;
-
-        if assume_dyn {
-            self.dynamic_clauses.push((dynamic_term_head, dynamic_term_body));
-        }
-
-        let clauses = query_terms.drain(1 ..).collect();
-        let qt = query_terms.pop().unwrap();
-
-        match *terms.pop().unwrap() {
-            Term::Clause(_, name, terms, _) => Ok(Rule {
-                head: (name, terms, qt),
-                clauses,
-            }),
-            Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule {
-                head: (name, vec![], qt),
-                clauses,
-            }),
-            _ => Err(ParserError::InvalidRuleHead),
-        }
-    }
-
-    fn try_term_to_query<'a, 'b, 'c>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        terms: Vec<Box<Term>>,
-        blocks_cuts: bool,
-    ) -> Result<TopLevel, ParserError> {
-        let (result, _) = self.setup_query(
-            indices,
-            terms,
-            blocks_cuts,
-            false,
-        )?;
-
-        Ok(TopLevel::Query(result))
-    }
-
-    fn compact_module_scoped_head<'a, 'b, 'c>(
-        &self,
-        term: &mut Term,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-    ) {
-        let inner_term = match term {
-            Term::Clause(_, ref name, ref mut inner_terms, _)
-                if name.as_str() == ":" && inner_terms.len() == 2 => {
-                    let module_name = match inner_terms[0].as_ref() {
-                        &Term::Constant(_, Constant::Atom(ref module, _)) => {
-                            module.clone()
-                        }
-                        _ => {
-                            return;
-                        }
-                    };
-
-                    indices.add_in_situ_module_info(module_name, inner_terms[1].deref_mut());
-                    *inner_terms.pop().unwrap()
-                }
-            _ => {
-                return;
-            }
-        };
-
-        *term = inner_term;
-    }
-
-    fn try_term_to_tl<'a, 'b, 'c>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        term: Term,
-        blocks_cuts: bool,
-    ) -> Result<TopLevel, ParserError> {
-        match term {
-            Term::Clause(r, name, mut terms, fixity) => {
-                if let Some(hook) = is_compile_time_hook(&name, &terms) {
-                    let term = Term::Clause(r, name, terms, fixity);
-                    let (hook, clause, queue) = self.setup_hook(hook, indices, term)?;
-
-                    Ok(TopLevel::Declaration(Declaration::Hook(
-                        hook, clause, queue,
-                    )))
-                } else if name.as_str() == "?-" {
-                    self.try_term_to_query(indices, terms, blocks_cuts)
-                } else if name.as_str() == ":-" && terms.len() == 2 {
-                    self.compact_module_scoped_head(&mut terms[0], indices);
-
-                    Ok(TopLevel::Rule(self.setup_rule(
-                        indices,
-                        terms,
-                        blocks_cuts,
-                        true,
-                    )?, self.line_num, self.col_num))
-                } else if name.as_str() == ":-" && terms.len() == 1 {
-                    Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms,
-                                                               self.line_num, self.col_num)?))
-                } else {
-                    let mut term = Term::Clause(r, name, terms, fixity);
-                    self.compact_module_scoped_head(&mut term, indices);
-
-                    Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
-                }
-            }
-            term => {
-                Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
-            }
-        }
-    }
-
-    fn try_terms_to_tls<'a, 'b, 'c, I>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-        terms: I,
-        blocks_cuts: bool,
-    ) -> Result<VecDeque<TopLevel>, ParserError>
-    where
-        I: IntoIterator<Item = Term>
-    {
-        let mut results = VecDeque::new();
-
-        for term in terms.into_iter() {
-            results.push_back(self.try_term_to_tl(indices, term, blocks_cuts)?);
-        }
-
-        Ok(results)
-    }
-
-    fn parse_queue<'a, 'b, 'c>(
-        &mut self,
-        indices: &mut CompositeIndices<'a, 'b, 'c>,
-    ) -> Result<VecDeque<TopLevel>, ParserError> {
-        let mut queue = VecDeque::new();
-
-        while let Some(terms) = self.queue.pop_front() {
-            let clauses = merge_clauses(&mut self.try_terms_to_tls(indices, terms, false)?)?;
-            queue.push_back(clauses);
-        }
-
-        Ok(queue)
-    }
-
-    fn absorb(&mut self, other: RelationWorker) {
-        self.queue.extend(other.queue.into_iter());
-        self.dynamic_clauses.extend(other.dynamic_clauses.into_iter());
-    }
-}
-
-pub type DynamicClause = Vec<(Term, Term)>;
-
-pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
-
-#[derive(Debug)]
-pub struct TopLevelBatchWorker<'a> {
-    pub(crate) term_stream: TermStream<'a>,
-    rel_worker: RelationWorker,
-    pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
-    pub(crate) dynamic_clause_map: DynamicClauseMap,
-    pub(crate) in_module: bool,
-    pub(crate) term_dirs: TermDirQuantum,
-    pub(crate) intra_module_term_dirs: IndexMap<ClauseName, TermDirQuantum>,
-    pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
-}
-
-impl<'a> TopLevelBatchWorker<'a> {
-    pub fn new(
-        stream: &'a mut ParsingStream<Stream>,
-        atom_tbl: TabledData<Atom>,
-        flags: MachineFlags,
-        wam: &'a mut Machine,
-    ) -> Self {
-        let term_stream = TermStream::new(stream, atom_tbl, flags, wam);
-
-        let line_num = term_stream.line_num();
-        let col_num  = term_stream.col_num();
-
-        TopLevelBatchWorker {
-            term_stream,
-            rel_worker: RelationWorker::new(flags, line_num, col_num),
-            results: vec![],
-            dynamic_clause_map: IndexMap::new(),
-            in_module: false,
-            term_dirs: TermDirQuantum::new(),
-            intra_module_term_dirs: IndexMap::new(),
-            non_counted_bt_preds: IndexSet::new(),
-        }
-    }
-
-    fn try_term_to_tl(
-        &mut self,
-        indices: &mut IndexStore,
-        term: Term,
-    ) -> Result<(TopLevel, RelationWorker), SessionError> {
-        let line_num = self.term_stream.line_num();
-        let col_num  = self.term_stream.col_num();
-
-        let mut new_rel_worker = RelationWorker::new(self.rel_worker.flags, line_num, col_num);
-        let mut indices = CompositeIndices::new(
-            &mut self.term_stream,
-            IndexSource::Local(indices),
-            if self.in_module { None } else { Some(IndexSource::TermStream) }
-        );
-
-        Ok((
-            new_rel_worker.try_term_to_tl(&mut indices, term, true)?,
-            new_rel_worker,
-        ))
-    }
-
-    fn process_result(
-        &mut self,
-        indices: &mut IndexStore,
-        preds: &mut Vec<PredicateClause>,
-    ) -> Result<(), SessionError> {
-        let mut indices = CompositeIndices::new(
-            &mut self.term_stream,
-            IndexSource::Local(indices),
-            if self.in_module { None } else { Some(IndexSource::TermStream) },
-        );
-
-        let key = (preds[0].name().unwrap(), preds[0].arity());
-
-        let mut preds = mem::replace(preds, vec![]);
-        let mut queue = self.rel_worker.parse_queue(&mut indices)?;
-
-        draw_from_term_dir(
-            &indices,
-            &mut self.intra_module_term_dirs,
-            &mut self.term_dirs,
-            &key,
-            &mut preds,
-            &mut queue,
-        );
-
-        let result = (Predicate(preds), queue);
-
-        indices.term_stream.wam.code_repo.add_in_situ_result(
-            &result,
-            &mut indices.term_stream.wam.indices.in_situ_code_dir,
-            &mut indices.term_stream.wam.indices.in_situ_module_dir,
-            &self.non_counted_bt_preds,
-        )?;
-
-        Ok(self.results.push(result))
-    }
-
-    fn take_dynamic_clauses(&mut self) {
-        let (name, arity) = match self.rel_worker.dynamic_clauses.first() {
-            Some((head, _)) => (head.name().unwrap(), head.arity()),
-            None => return,
-        };
-
-        match self.dynamic_clause_map.get_mut(&(name.clone(), arity)) {
-            Some(ref mut entry) => {
-                entry.clear(); // don't treat dynamic predicates as if they're discontiguous.
-                entry.extend(self.rel_worker.dynamic_clauses.drain(0 ..));
-            }
-            _ => {
-                self.rel_worker.dynamic_clauses.clear();
-            }
-        }
-    }
-
-    pub fn consume(
-        &mut self,
-        indices: &mut IndexStore,
-    ) -> Result<Option<Declaration>, SessionError> {
-        let mut preds = vec![];
-
-        while !self.term_stream.eof()? {
-            let term = self.term_stream.read_term(&indices.op_dir)?;
-
-            // if is_consistent is false, preds is non-empty.
-            let term = if !term.is_consistent(&preds) {
-                self.process_result(indices, &mut preds)?;
-                self.take_dynamic_clauses();
-
-                // expand the term after the addition of the previous
-                // predicate.
-                self.term_stream.expand_term(term, &indices.op_dir)?
-            } else {
-                term
-            };
-
-            let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?;
-
-            if tl.is_end_of_file_atom() {
-                tl = TopLevel::Declaration(Declaration::EndOfFile);
-            }
-
-            self.rel_worker.absorb(new_rel_worker);
-
-            match tl {
-                TopLevel::Fact(fact, line_num, col_num) =>
-                    preds.push(PredicateClause::Fact(fact, line_num, col_num)),
-                TopLevel::Rule(rule, line_num, col_num) =>
-                    preds.push(PredicateClause::Rule(rule, line_num, col_num)),
-                TopLevel::Predicate(pred) =>
-                    preds.extend(pred.0),
-                TopLevel::Declaration(decl) =>
-                    return Ok(Some(decl)),
-                TopLevel::Query(_) =>
-                    return Err(SessionError::QueryCannotBeDefinedAsFact),
-            }
-        }
-
-        if !preds.is_empty() {
-            self.process_result(indices, &mut preds)?;
-            self.take_dynamic_clauses();
-        }
-
-        Ok(None)
-    }
-}
index 7de7da2f8795ce8129d8510b09c861f44d74109d..aa0433274f4c3336b6cdca653eb2da6b8afbbb86 100644 (file)
@@ -68,10 +68,18 @@ macro_rules! functor {
     });
     ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
         {
+            use crate::machine::heap::*;
+
             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),
+                      $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
 
-            vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
-                  $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]
+            result.extend(addendum.into_iter());
+            result
         }
     });
     ($name:expr, $fixity:expr) => (
@@ -112,13 +120,28 @@ macro_rules! functor_term {
     (number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
         $e.into()
     );
-    (integer($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
+    (integer($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
         HeapCellValue::Integer(Rc::new(Integer::from($e)))
     );
-    (clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
+    (indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
+        let stub =
+            match $e {
+                IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
+                IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
+                IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
+            };
+
+        let len: usize = $aux_lens.iter().sum();
+        let h = len + $arity + 1 + $addendum.h() + $h;
+
+        $addendum.extend(stub.into_iter());
+
+        HeapCellValue::Addr(Addr::HeapCell(h))
+    });
+    (clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
         HeapCellValue::Atom($e, None)
     );
-    (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
+    (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) => (
@@ -312,14 +335,6 @@ macro_rules! jmp_call {
     };
 }
 
-macro_rules! try_eval_session {
-    ($e:expr) => {
-        match $e {
-            Ok(result) => result,
-            Err(e) => return EvalSession::from(e),
-        }
-    };
-}
 macro_rules! return_from_clause {
     ($lco:expr, $machine_st:expr) => {{
         if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
@@ -342,39 +357,21 @@ macro_rules! dir_entry {
     };
 }
 
-macro_rules! set_code_index {
-    ($idx:expr, $ip:expr, $mod_name:expr) => {{
-        let mut idx = $idx.0.borrow_mut();
-
-        idx.0 = $ip;
-        idx.1 = $mod_name.clone();
-    }};
-}
-
 macro_rules! index_store {
-    ($atom_tbl:expr, $code_dir:expr, $op_dir:expr, $modules:expr) => {
+    ($code_dir:expr, $op_dir:expr, $modules:expr) => {
         IndexStore {
-            atom_tbl: $atom_tbl,
             code_dir: $code_dir,
-            module_dir: ModuleDir::new(),
-            dynamic_code_dir: DynamicCodeDir::new(),
+            extensible_predicates: ExtensiblePredicates::new(),
             global_variables: GlobalVarDir::new(),
-            in_situ_code_dir: InSituCodeDir::new(),
-            in_situ_module_dir: ModuleStubDir::new(),
-            op_dir: $op_dir,
+            meta_predicates: MetaPredicateDir::new(),
             modules: $modules,
-            stream_aliases: StreamAliasDir::new(),
+            op_dir: $op_dir,
             streams: StreamDir::new(),
+            stream_aliases: StreamAliasDir::new(),
         }
     };
 }
 
-macro_rules! default_index_store {
-    ($atom_tbl:expr) => {
-        index_store!($atom_tbl, CodeDir::new(), default_op_dir(), IndexMap::new())
-    };
-}
-
 macro_rules! put_constant {
     ($lvl:expr, $cons:expr, $r:expr) => {
         QueryInstruction::PutConstant($lvl, $cons, $r)
@@ -387,6 +384,7 @@ macro_rules! get_level_and_unify {
     };
 }
 
+/*
 macro_rules! unwind_protect {
     ($e: expr, $protected: expr) => {
         match $e {
@@ -398,7 +396,8 @@ macro_rules! unwind_protect {
         }
     };
 }
-
+*/
+/*
 macro_rules! discard_result {
     ($f: expr) => {
         match $f {
@@ -406,7 +405,7 @@ macro_rules! discard_result {
         }
     };
 }
-
+*/
 macro_rules! ar_reg {
     ($r: expr) => {
         ArithmeticTerm::Reg($r)
@@ -414,7 +413,7 @@ macro_rules! ar_reg {
 }
 
 macro_rules! atom_from {
-    ($self:expr, $indices:expr, $e:expr) => {
+    ($self:expr, $e:expr) => {
         match $e {
             Addr::Con(h) if $self.heap.atom_at(h) => {
                 match &$self.heap[h] {
@@ -427,7 +426,7 @@ macro_rules! atom_from {
                 }
             }
             Addr::Char(c) => {
-                clause_name!(c.to_string(), $indices.atom_tbl.clone())
+                clause_name!(c.to_string(), $self.atom_tbl)
             }
             _ => {
                 unreachable!()
@@ -435,3 +434,15 @@ macro_rules! atom_from {
         }
     }
 }
+
+macro_rules! try_or_fail {
+    ($s:expr, $e:expr) => {{
+        match $e {
+            Ok(val) => val,
+            Err(msg) => {
+                $s.throw_exception(msg);
+                return;
+            }
+        }
+    }};
+}
index 89168bf902bd783a8f61ad1526147149e18c19a1..2495257ea8d5be661b720f25a7c9a09cbe501d79 100644 (file)
@@ -35,6 +35,7 @@ use crate::nix::sys::signal;
 mod macros;
 mod allocator;
 mod arithmetic;
+mod machine;
 mod codegen;
 mod clause_types;
 mod debray_allocator;
@@ -45,7 +46,6 @@ mod heap_print;
 mod indexing;
 mod instructions;
 mod iterators;
-mod machine;
 mod read;
 mod targets;
 mod write;
index 5e972a0863b7c6323b664f19dce43d8b371867ed..f240ab280aa6ae41aabf4130ae16f53e7b1c0348 100644 (file)
@@ -195,7 +195,7 @@ impl MachineState {
 
         let term = {
             let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
-            parser.read_term(composite_op!(op_dir))?
+            parser.read_term(&CompositeOpDir::new(op_dir, None))?
         };
 
         // 'pausing' the stream saves the pending top buffer
diff --git a/src/term_and_goal_expansion.pl b/src/term_and_goal_expansion.pl
new file mode 100644 (file)
index 0000000..c02bbc9
--- /dev/null
@@ -0,0 +1,44 @@
+% Unsure how to handle the printing of exceptions from term & goal expansion.
+
+'$print_message_and_fail'(Error, Culprit) :-
+%    writeq(error(Error, Culprit)),
+%    nl,
+    '$fail'.
+
+term_expansion(Term, ExpandedTerm) :-
+    (  catch(user:'$term_expansion'(Term, ExpandedTerm0),
+             E,
+             user:'$print_message_and_fail'(E, user:term_expansion)) ->
+       (  var(ExpandedTerm0) ->
+          error:instantiation_error(term_expansion/2)
+       ;  ExpandedTerm0 = [_|_] ->
+          term_expansion_list(ExpandedTerm0, ExpandedTerm, [])
+       ;  term_expansion(ExpandedTerm0, ExpandedTerm)
+       )
+    ;  Term = ExpandedTerm
+    ).
+
+
+term_expansion_list([], ExpandedTerms, ExpandedTerms).
+term_expansion_list([Term|Terms], ExpandedTermsHead, ExpandedTermsTail) :-
+    term_expansion(Term, ExpandedTerm0),
+    (  var(ExpandedTerm0) ->
+       error:instantiation_error(term_expansion/2)
+    ;  ExpandedTerm0 = [_|_] ->
+       term_expansion_list(ExpandedTerm0, ExpandedTermsHead, ExpandedTerms0Tail),
+       term_expansion_list(Terms, ExpandedTerms0Tail, ExpandedTermsTail)
+    ;  ExpandedTermsHead = [ExpandedTerm0 | ExpandedTerms0Tail],
+       term_expansion_list(Terms, ExpandedTerms0Tail, ExpandedTermsTail)
+    ).
+
+
+goal_expansion(Goal, Module, ExpandedGoal) :-
+    (  catch(Module:goal_expansion(Goal, ExpandedGoal0),
+             E,
+             user:'$print_message_and_fail'(E, Module:goal_expansion)) ->
+       (  var(ExpandedGoal0) ->
+          error:instantiation_error(goal_expansion/2)
+       ;  goal_expansion(ExpandedGoal0, Module, ExpandedGoal)
+       )
+    ;  Goal = ExpandedGoal
+    ).
index bbada3a23fa2e665b4c7fa8b4d77329bd2941384..9513b671cc0a66ae06bc4bc53fa3c9e593ce6914 100644 (file)
@@ -1,10 +1,18 @@
-:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2,
-                        argv/1]).
+:- module('$toplevel', [argv/1,
+                        copy_term/3,
+                        predicate_property/2,
+                        prolog_load_context/2]).
+
+:- use_module(library(loader)).
 
 :- use_module(library(charsio)).
+:- use_module(library(iso_ext)).
 :- use_module(library(lists)).
 :- use_module(library(si)).
 
+:- use_module(library('$project_atts')).
+:- use_module(library('$atts')).
+
 :- dynamic(argv/1).
 
 '$repl'([_|Args0]) :-
@@ -109,9 +117,6 @@ read_and_match :-
     instruction_match(Term, VarList).
 
 
-% make compile_batch, a system routine, callable.
-compile_batch :- '$compile_batch'.
-
 instruction_match(Term, VarList) :-
     (  var(Term) ->
        throw(error(instantiation_error, repl/0))
@@ -119,38 +124,43 @@ instruction_match(Term, VarList) :-
        !,
        (  atom(Item) ->
              (  Item == user ->
-                catch(compile_batch, E, print_exception_with_check(E))
-             ;  consult(Item)
+                catch(load(user_input), E, print_exception_with_check(E))
+             ;
+             consult(Item)
              )
        ;
-          catch(throw(error(type_error(atom, Item), repl/0)),
+          catch(type_error(atom, Item, repl/0),
                     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)
     ).
 
-:- use_module(library(iso_ext)).
 
-% auxiliary predicates, so that using them in setup_call_cleanup/3 works
-get_b_value(B) :- '$get_b_value'(B).
-clear_attribute_goals :- '$clear_attribute_goals'.
+submit_query_and_print_results_(Term, VarList) :-
+    '$get_b_value'(B),
+    call(Term),
+    write_eqs_and_read_input(B, VarList),
+    !.
+submit_query_and_print_results_(_, _) :-
+    %  clear attribute goal lists, which may be populated by
+    %  copy_term/3 prior to failure.
+    '$clear_attribute_goals',
+    write('false.'),
+    nl.
+
 
 submit_query_and_print_results(Term0, VarList) :-
-    (  expand_goals(Term0, Term) -> true
-    ;  Term0 = Term
-    ),
+    expand_goal(call(Term0), user, Term),
+    !,
     setup_call_cleanup(bb_put('$first_answer', true),
-                       (   get_b_value(B), call(Term), write_eqs_and_read_input(B, VarList),
-                           !
-                       ;   %  clear attribute goal lists, which may be populated by
-                           %  copy_term/3 prior to failure.
-                           clear_attribute_goals, write('false.'), nl
-                       ),
+                       submit_query_and_print_results_(Term, VarList),
                        bb_put('$first_answer', false)).
 
+
 needs_bracketing(Value, Op) :-
     catch((functor(Value, F, _),
               current_op(EqPrec, EqSpec, Op),
@@ -254,12 +264,12 @@ write_eqs_and_read_input(B, VarList) :-
     (  B0 == B ->
        (  Goals == [] ->
              write('true.'), nl
-       ;  thread_goals(Goals, ThreadedGoals, (',')),
+       ;  loader:thread_goals(Goals, ThreadedGoals, (',')),
              write_eq(ThreadedGoals, NewVarList0, 20),
              write('.'),
              nl
        )
-    ;  thread_goals(Goals, ThreadedGoals, (',')),
+    ;  loader:thread_goals(Goals, ThreadedGoals, (',')),
        write_eq(ThreadedGoals, NewVarList0, 20),
        read_input(ThreadedGoals, NewVarList0)
     ).
@@ -353,133 +363,3 @@ print_exception_with_check(E) :-
     % is expected to be printed instead.
     ;  print_exception(E)
     ).
-
-module_export(Source, PI) :-
-    (  nonvar(PI) ->
-       (  PI = Name / Arity ->
-             (  var(Name) -> throw(error(instantiation_error, Source))
-             ;  integer(Arity) ->
-                (  \+ atom(Name) -> throw(error(type_error(atom, Name), Source))
-                ;  Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), Source))
-                ;  true
-                )
-             ;  throw(error(type_error(integer, Arity), Source))
-             )
-       ;  PI = op(Prec, Spec, Name) ->
-             (  integer(Prec) ->
-                (  \+ atom(Name) ->
-                       throw(error(type_error(atom, Name), Source))
-                ;  Prec < 0 ->
-                       throw(error(domain_error(not_less_than_zero, Prec), Source))
-                ;  Prec > 1200 ->
-                       throw(error(domain_error(operator_precision, Prec), Source))
-                ;  memberchk(Spec, [xfy, yfx, xfx, fx, fy, yf, xf])
-                ;  throw(error(domain_error(operator_specification, Spec), Source))
-                )
-             ;  throw(error(type_error(integer, Prec), Source))
-             )
-       ;  throw(error(type_error(module_export, PI), Source))
-       )
-    ;  throw(error(instantiation_error, Source))
-    ).
-
-consult(Item) :-
-    (  atom(Item) -> use_module(Item)
-    ;  throw(error(type_error(atom, Item), consult/1))
-    ).
-
-use_module(Module) :-
-    (  nonvar(Module) ->
-       (  Module = library(Filename) ->
-          write_term_to_chars(Filename, [], FilenameString),
-          '$use_module'(FilenameString)
-       ;  atom(Module) ->
-          '$use_module_from_file'(Module)
-       ;  throw(error(invalid_module_specifier, use_module/1))
-       )
-    ;  throw(error(instantiation_error, use_module/1))
-    ).
-
-use_module(Module, QualifiedExports) :-
-    (  nonvar(Module) ->
-       (  list_si(QualifiedExports) ->
-             maplist('$module_export'(use_module/2), QualifiedExports) ->
-                 (  Module = library(Filename) ->
-                 write_term_to_chars(Filename, [], FilenameString),
-                    '$use_qualified_module'(FilenameString, QualifiedExports)
-                 ;  atom(Module) ->
-                    '$use_qualified_module_from_file'(Module, QualifiedExports)
-                 ;  throw(error(invalid_module_specifier, use_module/2))
-                 )
-       ;  throw(error(type_error(list, QualifiedExports), use_module/2))
-       )
-    ;  throw(error(instantiation_error, use_module/2))
-    ).
-
-
-% expand goals in initialization directives.
-user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
-    nonvar(Term0),
-    Term0 = (:- initialization(Goals)),
-    expand_goals(Goals, ExpandedGoals),
-    Goals \== ExpandedGoals.
-
-module_expand_goal(UnexpandedGoals, ExpandedGoals) :-
-    (  '$module_of'(Module, UnexpandedGoals),
-       '$module_exists'(Module),
-       Module:goal_expansion(UnexpandedGoals, ExpandedGoals),
-       UnexpandedGoals \== ExpandedGoals ->
-       true
-    ;  user:goal_expansion(UnexpandedGoals, ExpandedGoals)
-    ).
-
-expand_goals(UnexpandedGoals, ExpandedGoals) :-
-    nonvar(UnexpandedGoals),
-    var(ExpandedGoals),
-    (  module_expand_goal(UnexpandedGoals, Goals) ->
-       true
-    ;  Goals = UnexpandedGoals
-    ),
-    (  Goals = (Goal0, Goals0) ->
-       (  expand_goals(Goal0, Goal1) ->
-             expand_goals(Goals0, Goals1),
-             thread_goals(Goal1, ExpandedGoals, Goals1, (','))
-       ;  expand_goals(Goals0, Goals1),
-             ExpandedGoals = (Goal0, Goals1)
-       )
-    ;  Goals = (Goals0 -> Goals1) ->
-       expand_goals(Goals0, ExpandedGoals0),
-       expand_goals(Goals1, ExpandedGoals1),
-       ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1)
-    ;  Goals = (Goals0 ; Goals1) ->
-       expand_goals(Goals0, ExpandedGoals0),
-       expand_goals(Goals1, ExpandedGoals1),
-       ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
-    ;  Goals = (\+ Goals0) ->
-       expand_goals(Goals0, Goals1),
-       ExpandedGoals = (\+ Goals1)
-    ;  thread_goals(Goals, ExpandedGoals, (','))
-    ;  Goals = ExpandedGoals
-    ).
-
-thread_goals(Goals0, Goals1, Hole, Functor) :-
-    nonvar(Goals0),
-    (  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, Functor) :-
-    nonvar(Goals0),
-    (  Goals0 = [G | Gs] ->
-       (  Gs = [] ->
-             Goals1 = G
-       ;  Goals1 =.. [Functor, G, Goals2],
-             thread_goals(Gs, Goals2, Functor)
-       )
-    ;  Goals1 = Goals0
-    ).
index cf40509d4022ed680b4843a6e95770ee2f47d7e8..b0dd010acea24119f782d33be58ed966fd9379ff 100644 (file)
@@ -1,5 +1,6 @@
 use crate::clause_types::*;
 use crate::forms::*;
+use crate::indexing::IndexingCodePtr;
 use crate::instructions::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
@@ -10,14 +11,8 @@ 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::InSituDirEntry(p) => write!(f, "LocalCodePtr::InSituDirEntry({})", p),
-            LocalCodePtr::TopLevel(cn, p) => write!(f, "LocalCodePtr::TopLevel({}, {})", cn, p),
-            LocalCodePtr::UserGoalExpansion(p) => {
-                write!(f, "LocalCodePtr::UserGoalExpansion({})", p)
-            }
-            LocalCodePtr::UserTermExpansion(p) => {
-                write!(f, "LocalCodePtr::UserTermExpansion({})", p)
-            }
+            LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
+            LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
         }
     }
 }
@@ -25,16 +20,50 @@ impl fmt::Display for LocalCodePtr {
 impl fmt::Display for REPLCodePtr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            REPLCodePtr::CompileBatch =>
-                write!(f, "REPLCodePtr::CompileBatch"),
+            REPLCodePtr::AddDynamicPredicate =>
+                write!(f, "REPLCodePtr::AddDynamicPredicate"),
+            REPLCodePtr::AddGoalExpansionClause =>
+                write!(f, "REPLCodePtr::AddGoalExpansionClause"),
+            REPLCodePtr::AddTermExpansionClause =>
+                write!(f, "REPLCodePtr::AddTermExpansionClause"),
+            REPLCodePtr::UserAssertz =>
+                write!(f, "REPLCodePtr::UserAssertz"),
+            REPLCodePtr::UserAsserta =>
+                write!(f, "REPLCodePtr::UserAsserta"),
+            REPLCodePtr::UserRetract =>
+                write!(f, "REPLCodePtr::UserRetract"),
+            REPLCodePtr::ClauseToEvacuable =>
+                write!(f, "REPLCodePtr::ClauseToEvacuable"),
+            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::UseQualifiedModule =>
-                       write!(f, "REPLCodePtr::UseQualifiedModule"),
-               REPLCodePtr::UseModuleFromFile =>
-                       write!(f, "REPLCodePtr::UseModuleFromFile"),
-               REPLCodePtr::UseQualifiedModuleFromFile =>
-                       write!(f, "REPLCodePtr::UseQualifiedModuleFromFile")
+            REPLCodePtr::MetaPredicateProperty =>
+                write!(f, "REPLCodePtr::MetaPredicateProperty"),
+            REPLCodePtr::CompilePendingPredicates =>
+                write!(f, "REPLCodePtr::CompilePendingPredicates"),
         }
     }
 }
@@ -45,9 +74,6 @@ impl fmt::Display for IndexPtr {
             &IndexPtr::DynamicUndefined => write!(f, "undefined"),
             &IndexPtr::Undefined => write!(f, "undefined"),
             &IndexPtr::Index(i) => write!(f, "{}", i),
-            &IndexPtr::InSituDirEntry(i) => write!(f, "in_situ({})", i),
-            &IndexPtr::UserTermExpansion => write!(f, "user:term_expansion"),
-            &IndexPtr::UserGoalExpansion => write!(f, "user:goal_expansion"),
         }
     }
 }
@@ -68,17 +94,27 @@ impl fmt::Display for FactInstruction {
             &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::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),
+            &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)
+            }
         }
     }
 }
@@ -141,12 +177,16 @@ impl fmt::Display for CompareTermQT {
 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::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.borrow();
-                write!(f, "{}:{}/{}", idx.1, name, idx.0)
+                let idx = idx.0.get();
+                write!(f, "{}/{}", name, idx)
+            }
+            ref ct => {
+                write!(f, "{}", ct.name())
             }
-            ref ct => write!(f, "{}", ct.name()),
         }
     }
 }
@@ -158,6 +198,7 @@ impl fmt::Display for HeapCellValue {
             &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,
@@ -209,6 +250,7 @@ impl fmt::Display for Addr {
             &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),
@@ -244,6 +286,9 @@ impl fmt::Display for ControlInstruction {
             &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"),
         }
     }
@@ -262,13 +307,33 @@ impl fmt::Display for IndexedChoiceInstruction {
 impl fmt::Display for ChoiceInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            &ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", offset),
+            &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"),
+            &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::External(o) => {
+                write!(f, "IndexingCodePtr::External({})", o)
+            }
+            &IndexingCodePtr::Fail => {
+                write!(f, "IndexingCodePtr::Fail")
+            }
+            &IndexingCodePtr::Internal(o) => {
+                write!(f, "IndexingCodePtr::Internal({})", o)
+            }
         }
     }
 }
@@ -279,11 +344,11 @@ impl fmt::Display for IndexingInstruction {
             &IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => {
                 write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s)
             }
-            &IndexingInstruction::SwitchOnConstant(_, num_cs, _) => {
-                write!(f, "switch_on_constant {}", num_cs)
+            &IndexingInstruction::SwitchOnConstant(ref constants) => {
+                write!(f, "switch_on_constant {}", constants.len())
             }
-            &IndexingInstruction::SwitchOnStructure(_, num_ss, _) => {
-                write!(f, "switch_on_structure {}", num_ss)
+            &IndexingInstruction::SwitchOnStructure(ref structures) => {
+                write!(f, "switch_on_structure {}", structures.len())
             }
         }
     }
@@ -295,36 +360,40 @@ impl fmt::Display for SessionError {
             &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::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::ParserError(ref e) => {
-                write!(f, "syntax_error({})", e.as_str())
+            &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)
+            }
         }
     }
 }
@@ -364,6 +433,23 @@ impl fmt::Display for ModuleSource {
     }
 }
 
+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(())
+            }
+        }
+    }
+}
+
 impl fmt::Display for Line {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -372,7 +458,13 @@ impl fmt::Display for Line {
             &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::Indexing(ref indexing_instr) => write!(f, "{}", indexing_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::Query(ref query_instr) => write!(f, "{}", query_instr),
         }