From a4d15bfb88876ccf1707a8e59535daa6a4436911 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 30 Jan 2021 14:32:47 -0700 Subject: [PATCH] move to a predicate-based module system, move to loader.[rs|pl]-based compilation, add support for incremental clause compilation --- Cargo.lock | 551 +++--- Cargo.toml | 3 +- build.rs | 2 + src/clause_types.rs | 194 +- src/codegen.rs | 278 ++- src/forms.rs | 483 ++--- src/heap_iter.rs | 15 +- src/heap_print.rs | 13 +- src/indexing.rs | 1287 ++++++++++--- src/instructions.rs | 211 ++- src/iterators.rs | 4 +- src/lib/atts.pl | 100 +- src/lib/builtins.pl | 738 +++++--- src/lib/clpb.pl | 4 +- src/lib/dcgs.pl | 10 +- src/lib/diag.pl | 20 +- src/lib/dif.pl | 14 +- src/lib/error.pl | 8 +- src/lib/iso_ext.pl | 11 +- src/lib/lists.pl | 32 +- src/lib/ops_and_meta_predicates.pl | 127 ++ src/lib/pairs.pl | 2 + src/lib/tabling/wrapper.pl | 8 +- src/lib/time.pl | 2 + src/loader.pl | 433 +++++ src/machine/attributed_variables.pl | 15 + src/machine/attributed_variables.rs | 5 +- src/machine/code_repo.rs | 180 +- src/machine/code_walker.rs | 113 +- src/machine/compile.rs | 2641 +++++++++++++++------------ src/machine/dynamic_database.rs | 396 ---- src/machine/heap.rs | 31 +- src/machine/load_state.rs | 918 ++++++++++ src/machine/loader.rs | 1708 +++++++++++++++++ src/machine/machine_errors.rs | 178 +- src/machine/machine_indices.rs | 663 +++---- src/machine/machine_state.rs | 664 ++----- src/machine/machine_state_impl.rs | 318 ++-- src/machine/mod.rs | 961 ++++------ src/machine/modules.rs | 371 ---- src/machine/partial_string.rs | 293 +++ src/machine/preprocessor.rs | 987 ++++++++++ src/machine/project_attributes.pl | 61 +- src/machine/stack.rs | 4 - src/machine/streams.rs | 4 +- src/machine/system_calls.rs | 339 ++-- src/machine/term_expansion.rs | 394 ---- src/machine/term_stream.rs | 149 ++ src/machine/toplevel.rs | 1352 -------------- src/macros.rs | 91 +- src/main.rs | 2 +- src/read.rs | 2 +- src/term_and_goal_expansion.pl | 44 + src/toplevel.pl | 188 +- src/write.rs | 206 ++- 55 files changed, 10364 insertions(+), 7464 deletions(-) create mode 100644 src/lib/ops_and_meta_predicates.pl create mode 100644 src/loader.pl delete mode 100644 src/machine/dynamic_database.rs create mode 100644 src/machine/load_state.rs create mode 100644 src/machine/loader.rs delete mode 100644 src/machine/modules.rs create mode 100644 src/machine/preprocessor.rs delete mode 100644 src/machine/term_expansion.rs create mode 100644 src/machine/term_stream.rs delete mode 100644 src/machine/toplevel.rs create mode 100644 src/term_and_goal_expansion.pl diff --git a/Cargo.lock b/Cargo.lock index 0b2ca779..b9f316ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 6d10a3ae..cf1d85e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/build.rs b/build.rs index a9ec444e..aaa876ab 100644 --- 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, diff --git a/src/clause_types.rs b/src/clause_types.rs index dbaefb69..a0318d8d 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -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 { 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(), diff --git a/src/codegen.rs b/src/codegen.rs index d260cfa0..1f349246 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -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 { - marker: TermMarker, - pub var_count: IndexMap, 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 { + atom_tbl: TabledData, + marker: TermMarker, + pub var_count: IndexMap, usize>, + non_counted_bt: bool, + is_extensible: bool, + pub skeleton: PredicateSkeleton, + pub jmp_by_locs: Vec, + global_jmp_by_locs_offset: usize, +} + impl<'a, TermMarker: Allocator<'a>> CodeGenerator { - pub fn new(non_counted_bt: bool) -> Self { + pub fn new(atom_tbl: TabledData, 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>>(&mut self, iter: Iter) { for term in iter { if let TermRef::Var(_, _, var) = term { @@ -337,16 +379,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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 { 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 { terms: &'a Vec>, 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 { 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 { 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 { &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 { } } - 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 { 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 { + pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result { let iter = ChunkedIterator::from_rule(rule); let conjunct_info = self.collect_var_data(iter); @@ -739,7 +805,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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 { 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 { } } - 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) -> Result { +/* + pub fn compile_query(&mut self, query: &'a Vec) -> Result { 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 { 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 { @@ -925,48 +1002,50 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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 { - let mut code_body = Vec::new(); - let mut code_offsets = CodeOffsets::new(); + ) -> Result { + 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 { }, 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, - ) -> Result { - let mut code = Vec::new(); + ) -> Result { + 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) diff --git a/src/forms.rs b/src/forms.rs index be572bc4..006371eb 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -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; + // vars of predicate, toplevel offset. Vec is always a vector // of vars (we get their adjoining cells this way). pub type JumpStub = Vec; @@ -24,19 +27,24 @@ pub type JumpStub = Vec; #[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), - 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, } -#[derive(Debug, Clone)] -pub struct Predicate(pub Vec); - -impl Predicate { - #[inline] - pub fn new() -> Self { - Predicate(vec![]) - } - - #[inline] - pub fn clauses(self) -> Vec { - 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) -> 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; 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 { 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 { + 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 { 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); +// pub type CompiledResult = (Predicate, VecDeque); #[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), - ModuleInitialization(Vec, VecDeque), // goal + Dynamic(ClauseName, usize), + MetaPredicate(ClauseName, ClauseName, Vec), // module name, name, meta-specs Module(ModuleDecl), - MultiFile(MultiFileIndicator), NonCountedBacktracking(ClauseName, usize), // name, arity Op(OpDecl), - SetPrologFlag(DoubleQuotes), UseModule(ModuleSource), - UseQualifiedModule(ModuleSource, Vec), + UseQualifiedModule(ModuleSource, IndexSet), } -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, 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; -#[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, 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), - pub goal_expansions: (Predicate, VecDeque), - pub user_term_expansions: (Predicate, VecDeque), // term expansions inherited from the user scope. - pub user_goal_expansions: (Predicate, VecDeque), // same for goal_expansions. - pub local_term_expansions: (Predicate, VecDeque), // expansions local to the module. - pub local_goal_expansions: (Predicate, VecDeque), - pub inserted_expansions: bool, // has the module been successfully inserted into toplevel?? + pub meta_predicates: MetaPredicateDir, + pub extensible_predicates: IndexMap, 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), // 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 { + 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 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, + pub clause_clause_locs: SliceDeque, +} + +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, + } + } + */ +} diff --git a/src/heap_iter.rs b/src/heap_iter.rs index a541d12f..44541237 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -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!() diff --git a/src/heap_print.rs b/src/heap_print.rs index 2a51fa91..e4792969 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -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>(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); } diff --git a/src/indexing.rs b/src/indexing.rs index bf5403bf..f2029a31 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,383 +1,1142 @@ 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, - pub constants: IndexMap, - 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, + offset: usize, + append_or_prepend: AppendOrPrepend, +} + +impl<'a> IndexingCodeMergingPtr<'a> { + #[inline] + fn new( + skeleton: &'a mut [ClauseIndexInfo], + indexing_code: &'a mut Vec, + 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, + 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( - indices: IndexMap, - prelude: &mut CodeDeque, - ) -> IndexMap - 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, + 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, + 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, + 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: IndexMap, len: usize) -> IndexMap - 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, + 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, - 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, + 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( + indices: IndexMap>, + prelude: &mut SliceDeque, +) -> IndexMap +{ + 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( + instr_fn: impl Fn(IndexMap) -> IndexingInstruction, + index: IndexMap>, + prelude: &mut SliceDeque, +) -> 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, + prelude: &mut SliceDeque, +) -> 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) -> Vec { + 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, + pub constants: IndexMap>, + pub lists: SliceDeque, + pub structures: IndexMap<(ClauseName, usize), SliceDeque>, + optimal_index: usize, +} + +impl CodeOffsets { + pub fn new(atom_tbl: TabledData, 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 { + 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 { + 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() } } diff --git a/src/instructions.rs b/src/instructions.rs index c3de3469..a913f49e 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -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 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), +} + +impl From for IndexingLine { + #[inline] + fn from(instr: IndexingInstruction) -> Self { + IndexingLine::Indexing(instr) + } +} + +impl From> for IndexingLine { + #[inline] + fn from(instrs: SliceDeque) -> 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), 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) { 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> { + match line { + Line::IndexingCode(ref mut indexing_code) => { + Some(indexing_code) + } + _ => { + None + } + } +} + +#[inline] +pub fn to_indexing_line(line: &Line) -> Option<&Vec> { + 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), - SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>), -} - -impl From for Line { - fn from(i: IndexingInstruction) -> Self { - Line::Indexing(i) - } + SwitchOnTerm(usize, usize, IndexingCodePtr, IndexingCodePtr, IndexingCodePtr), + SwitchOnConstant(IndexMap), + 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; -pub type ThirdLevelIndex = Vec; - pub type Code = Vec; - -pub type CodeDeque = VecDeque; diff --git a/src/iterators.rs b/src/iterators.rs index 218ed78e..9c549166 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -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) -> Self { let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))); diff --git a/src/lib/atts.pl b/src/lib/atts.pl index fbf440d0..8fa16e11 100644 --- a/src/lib/atts.pl +++ b/src/lib/atts.pl @@ -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), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 3d7aa79f..d17faf8c 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -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]), ! diff --git a/src/lib/clpb.pl b/src/lib/clpb.pl index 0b802a46..0310e775 100644 --- a/src/lib/clpb.pl +++ b/src/lib/clpb.pl @@ -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, diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 942f6b8e..b4e2fafc 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -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)) ). diff --git a/src/lib/diag.pl b/src/lib/diag.pl index d135238b..0fa3896f 100644 --- a/src/lib/diag.pl +++ b/src/lib/diag.pl @@ -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)) + ). diff --git a/src/lib/dif.pl b/src/lib/dif.pl index bb92979a..9c3b8ed8 100644 --- a/src/lib/dif.pl +++ b/src/lib/dif.pl @@ -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). diff --git a/src/lib/error.pl b/src/lib/error.pl index 7e2189c4..99592790 100644 --- a/src/lib/error.pl +++ b/src/lib/error.pl @@ -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) diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index e5ba94c1..dc83c2a4 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -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), diff --git a/src/lib/lists.pl b/src/lib/lists.pl index a1acdb6d..75095715 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -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 index 00000000..c16af3ad --- /dev/null +++ b/src/lib/ops_and_meta_predicates.pl @@ -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(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). diff --git a/src/lib/pairs.pl b/src/lib/pairs.pl index adcfb138..85914639 100644 --- a/src/lib/pairs.pl +++ b/src/lib/pairs.pl @@ -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). diff --git a/src/lib/tabling/wrapper.pl b/src/lib/tabling/wrapper.pl index c66be996..4c902e84 100644 --- a/src/lib/tabling/wrapper.pl +++ b/src/lib/tabling/wrapper.pl @@ -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). diff --git a/src/lib/time.pl b/src/lib/time.pl index 30ec0f45..933387be 100644 --- a/src/lib/time.pl +++ b/src/lib/time.pl @@ -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 index 00000000..9360e260 --- /dev/null +++ b/src/loader.pl @@ -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] + ) + ). diff --git a/src/machine/attributed_variables.pl b/src/machine/attributed_variables.pl index 8756eb3c..386ff101 100644 --- a/src/machine/attributed_variables.pl +++ b/src/machine/attributed_variables.pl @@ -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), diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index c7b198d5..790114fc 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -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] = diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs index b9045c72..092f6407 100644 --- a/src/machine/code_repo.rs +++ b/src/machine/code_repo.rs @@ -1,127 +1,52 @@ 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) { - 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, - ) -> 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::::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> { 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 + } +*/ } } } diff --git a/src/machine/code_walker.rs b/src/machine/code_walker.rs index 152395c5..94944889 100644 --- a/src/machine/code_walker.rs +++ b/src/machine/code_walker.rs @@ -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, - 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) -> 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, 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, 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 } } } +*/ diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 36544eba..7b3fb49f 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1,1454 +1,1677 @@ -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, - mut path: PathBuf, -) -> Result -{ - 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 { - // 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 { - 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); - // throw errors if declaration or query found. +pub(super) fn compile_relation( cg: &mut CodeGenerator, tl: &TopLevel -) -> Result { +) -> Result { 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, + jmp_by_locs: Vec, + non_counted_bt: bool, + atom_tbl: TabledData, +) -> 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::::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, - non_counted_bt: bool, -) -> Result<(), ParserError> { - for tl in queue.iter() { - set_first_index(code); - let mut cg = CodeGenerator::::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, + settings: CodeGenSettings, + atom_tbl: TabledData, +) -> Result { + let mut cg = CodeGenerator::::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 { + 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, + 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::::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::::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::::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, - queue: VecDeque, -) -> Result<(Code, AllocVarDict), ParserError> { - // count backtracking inferences. - let mut cg = CodeGenerator::::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), +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 { + // 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, - toplevel_results: Vec, - 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, -} + 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::::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, - user_term_dir: TermDir, - orig_term_expansion_lens: (usize, usize), - orig_goal_expansion_lens: (usize, usize), - initialization_goals: (Vec, VecDeque), - 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 { + 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 { - 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, + 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 { + 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, - 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 { - 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::::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, - 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, - ) -> (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, - ) -> 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 { + 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, + queue: &VecDeque, + settings: CodeGenSettings, + ) -> Result { + 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::::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, - indices: &mut IndexStore, - ) -> Result { - 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, + non_counted_bt: bool, + append_or_prepend: AppendOrPrepend, + ) -> Result { + 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>( + &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 { - 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 index 6fc01b4c..00000000 --- a/src/machine/dynamic_database.rs +++ /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 { - 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, - 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); - } -} diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 8f741f66..612742c9 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -168,6 +168,9 @@ impl HeapTemplate { &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 HeapTemplate { 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 HeapTemplate { } } - #[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 HeapTemplate { ("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 HeapTemplate { 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 HeapTemplate { } #[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 index 00000000..1d5526a5 --- /dev/null +++ b/src/machine/load_state.rs @@ -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, + 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, + 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, + ) -> 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, + ) -> 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, + ) { + 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, + ) -> 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, + ) -> 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 index 00000000..a6704894 --- /dev/null +++ b/src/machine/loader.rs @@ -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), + 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), + 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), +} + +/* + * 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, +} + +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, + pub(super) clause_clauses: Vec<(Term, Term)>, + term_stream: TermStream, + pub(super) non_counted_bt_preds: IndexSet, + 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 { + while let Some(decl) = self.dequeue_terms()? { + self.load_decl(decl)?; + } + + TS::evacuate(self) + } + + fn dequeue_terms(&mut self) -> Result, 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 { + 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, 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, 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, + 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, + ); +} diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 1dcc1db8..dcea8448 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -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>(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 for CompilationError { + #[inline] + fn from(err: ArithmeticError) -> CompilationError { + CompilationError::Arithmetic(err) + } +} + +impl From 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 for EvalSession { + #[inline] fn from(err: SessionError) -> Self { EvalSession::Error(err) } } +impl From for SessionError { + #[inline] + fn from(err: std::io::Error) -> SessionError { + SessionError::from(ParserError::from(err)) + } +} + impl From for SessionError { + #[inline] fn from(err: ParserError) -> Self { - SessionError::ParserError(err) + SessionError::CompilationError(CompilationError::from(err)) + } +} + +impl From for SessionError { + #[inline] + fn from(err: CompilationError) -> Self { + SessionError::CompilationError(err) } } impl From for EvalSession { + #[inline] fn from(err: ParserError) -> Self { - EvalSession::from(SessionError::ParserError(err)) + EvalSession::from(SessionError::from(err)) } } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 13fb6ae7..14489b76 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -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), 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), DBRef(DBRef), Integer(Rc), + LoadStatePayload(LoadStatePayload), NamedStr(usize, ClauseName, Option), // arity, name, precedence/Specifier if it has one. Rational(Rc), 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 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>); +pub struct CodeIndex(pub Rc>); -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; #[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 { - 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, 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 for CodePtr { fn partial_cmp(&self, other: &CodePtr) -> Option { match (self, other) { @@ -667,11 +654,8 @@ impl PartialOrd for CodePtr { impl PartialOrd for LocalCodePtr { fn partial_cmp(&self, other: &LocalCodePtr) -> Option { 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 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 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 for LocalCodePtr { impl Sub for LocalCodePtr { type Output = Option; + #[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 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 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 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 for CodePtr { } } -pub type HeapVarDict = IndexMap, Addr>; -pub type AllocVarDict = IndexMap, 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 for CodePtr { + #[inline] + fn sub_assign(&mut self, rhs: usize) { + match self { + CodePtr::Local(ref mut local) => *local -= rhs, + _ => unreachable!(), } } } -pub type InSituCodeDir = IndexMap; -// key type: module name, predicate indicator. -pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>; +pub type HeapVarDict = IndexMap, Addr>; +pub type AllocVarDict = IndexMap, VarData>; +pub type InSituCodeDir = IndexMap; pub type GlobalVarDir = IndexMap)>; #[derive(Debug)] pub(crate) struct ModuleStub { - pub(crate) atom_tbl: TabledData, pub(crate) in_situ_code_dir: InSituCodeDir, } -impl ModuleStub { - pub(crate) fn new(atom_tbl: TabledData) -> Self { - ModuleStub { - atom_tbl, - in_situ_code_dir: InSituCodeDir::new(), - } - } -} - -pub(crate) type ModuleStubDir = IndexMap; +// pub(crate) type ModuleStubDir = IndexMap; pub(crate) type StreamAliasDir = IndexMap; pub(crate) type StreamDir = BTreeSet; +pub type MetaPredicateDir = IndexMap>; + +pub type ExtensiblePredicates = IndexMap; + #[derive(Debug)] pub struct IndexStore { - pub(super) atom_tbl: TabledData, 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, - ) -> 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 { + 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 { - 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 { - 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> { + 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 { - 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; -pub type TermDir = IndexMap)>; - -#[derive(Debug)] -pub struct TermDirQuantumEntry { - pub old_terms: (Predicate, VecDeque), - pub new_terms: (Predicate, VecDeque), - 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) -> 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); - -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(), diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index e8799566..ab04a532 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -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, -} - -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 { - 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 { - 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 { - 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, 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, 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 -{ - 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>; 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, )?; diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 5de07140..a387970e 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -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, + call_policy: &mut Box, + ) { + 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, @@ -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(); - } } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index daaf4e81..f8d661a2 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -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 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 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, } -impl SubModuleUser for IndexStore { - fn atom_tbl(&self) -> TabledData { - 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 { - 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, - ) -> 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, 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(&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(&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 index 42576032..00000000 --- a/src/machine/modules.rs +++ /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, - 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, - ) { - 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, - ) { - 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)> - { - 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; - fn op_dir(&mut self) -> &mut OpDir; - fn remove_code_index(&mut self, _: PredicateKey); - fn get_code_index(&self, _: PredicateKey, _: ClauseName) -> Option; - - fn insert_dir_entry(&mut self, _: ClauseName, _: usize, _: CodeIndex); - - fn get_op_module_name(&mut self, name: ClauseName, fixity: Fixity) -> Option { - 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, - ) -> Result<(), SessionError>; - - fn use_module( - &mut self, - _: &mut CodeRepo, - _: MachineFlags, - _: &Module - ) -> Result<(), SessionError>; -} - -pub fn use_qualified_module( - user: &mut User, - submodule: &Module, - exports: &Vec, -) -> 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: &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 { - self.atom_tbl.clone() - } - - fn op_dir(&mut self) -> &mut OpDir { - &mut self.op_dir - } - - fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option { - 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, - ) -> 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(()) - } -} diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 1413b37c..7d865d49 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -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, +} + +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 { + 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 { + 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 { + 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 index 00000000..7054796a --- /dev/null +++ b/src/machine/preprocessor.rs @@ -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(terms: I, mut term: Term, sym: ClauseName) -> Term +where + I: DoubleEndedIterator, +{ + 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 { + 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>, + atom_tbl: TabledData, +) -> Result { + 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 +{ + 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 +{ + 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, +) -> Result { + 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, +) -> Result, 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>, + atom_tbl: TabledData, +) -> Result { + 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>) -> Result { + 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>) -> Result { + 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); + +fn setup_qualified_import( + mut terms: Vec>, + atom_tbl: TabledData, +) -> Result { + 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>, + load_state: &LoadState<'a>, +) -> Result<(ClauseName, ClauseName, Vec), CompilationError> +{ + fn get_name_and_meta_specs( + name: ClauseName, + terms: &mut [Box], + ) -> Result<(ClauseName, Vec), 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) -> Result +{ + 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, 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) -> 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) { + 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>, +) -> Result { + 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>, + fixity: Option, +) -> 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>, + fixity: Option, +) -> 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>, +} + +impl Preprocessor { + pub(super) + fn new(flags: MachineFlags) -> Self { + Preprocessor { + flags, + queue: VecDeque::new(), + } + } + + fn setup_fact(&mut self, term: Term) -> Result { + match term { + Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => { + Ok(term) + } + _ => { + Err(CompilationError::InadmissibleFact) + } + } + } + + fn compute_head(&self, term: &Term) -> Vec { + 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, 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) { + // 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) { + 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) { + 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 { + 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 { + 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>, + cut_context: CutContext, + ) -> Result, 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>, + cut_context: CutContext, + ) -> Result { + 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>, + cut_context: CutContext, + ) -> Result { + 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 { + 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>( + &mut self, + load_state: &mut LoadState<'a>, + terms: I, + cut_context: CutContext, + ) -> Result, 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, 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) + } +} diff --git a/src/machine/project_attributes.pl b/src/machine/project_attributes.pl index 0d7a82d0..cee4f1ce 100644 --- a/src/machine/project_attributes.pl +++ b/src/machine/project_attributes.pl @@ -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]). diff --git a/src/machine/stack.rs b/src/machine/stack.rs index 4bd3802b..ab7d48e2 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -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 { diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 1375cb65..644e6ee7 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -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(); } _ => { } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index da31e966..0623df76 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -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 index 6ee8f8d3..00000000 --- a/src/machine/term_expansion.rs +++ /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(terms: I, mut term: Term, sym: ClauseName) -> Term -where - I: DoubleEndedIterator, -{ - 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, - tail: Box, -) -> Result>, 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, - 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), - goal_expansion_additions: (Predicate, VecDeque), -} - -impl ExpansionAdditionResult { - pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque) { - 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) { - 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, - atom_tbl: TabledData, - 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) { - self.parser.set_atom_tbl(atom_tbl); - } - - #[inline] - pub fn eof(&mut self) -> Result { - 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 { - 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 { - 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 { - 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 { - 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, - ) -> Result, 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 { - 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 index 00000000..bceec683 --- /dev/null +++ b/src/machine/term_stream.rs @@ -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; + fn eof(&mut self) -> Result; + fn listing_src(&self) -> &ListingSource; + fn evacuate<'a>(loader: Loader<'a, Self>) -> Result; +} + +#[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, + 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 { + self.parser.reset(); + self.parser.read_term(op_dir) + .map_err(CompilationError::from) + } + + #[inline] + fn eof(&mut self) -> Result { + 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) -> Result { + 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, + 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, + pub(super) preprocessor: Preprocessor, + pub(super) predicates: Vec, + 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 { + Ok(self.term_queue.pop_front().unwrap()) + } + + #[inline] + fn eof(&mut self) -> Result { + return Ok(self.term_queue.is_empty()); + } + + #[inline] + fn listing_src(&self) -> &ListingSource { + &self.listing_src + } + + #[inline] + fn evacuate(loader: Loader) -> Result { + Ok(loader.to_load_state_payload()) + } +} diff --git a/src/machine/toplevel.rs b/src/machine/toplevel.rs deleted file mode 100644 index eaa17691..00000000 --- a/src/machine/toplevel.rs +++ /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> -} - -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>, - ) -> Self { - CompositeIndices { - term_stream, - index_src, - static_code_dir, - } - } - - fn atom_tbl(&self) -> TabledData { - 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, - ) -> 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>, -) -> Option { - 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>) -> Option { - 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); - -pub fn to_op_decl(prec: usize, spec: &str, name: ClauseName) -> Result { - 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>, - atom_tbl: TabledData, -) -> Result { - 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 -{ - 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 -{ - 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, -) -> Result { - 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>, - atom_tbl: TabledData, -) -> Result { - 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, -) -> Option { - 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>, atom_tbl: TabledData) -> Result { - 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>) -> Result { - 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); - -fn setup_qualified_import( - mut terms: Vec>, - atom_tbl: TabledData, -) -> Result { - 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) -> Result -{ - let mut clauses: Vec = 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, 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) -> 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) { - 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, - queue: &mut VecDeque -) { - 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, - top_level_term_dirs: &mut TermDirQuantum, - key: &PredicateKey, - preds: &mut Vec, - queue: &mut VecDeque, -) { - 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>, - line_num: usize, - col_num: usize, -) -> Result { - 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>, - 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 { - 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 { - 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, 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) { - // 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) { - 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) { - 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 { - 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 { - 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>, - blocks_cuts: bool, - assume_dyn: bool, - ) -> Result<(Vec, 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 { - 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>, - blocks_cuts: bool, - assume_dyn: bool, - ) -> Result { - 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>, - blocks_cuts: bool, - ) -> Result { - 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 { - 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, ParserError> - where - I: IntoIterator - { - 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, 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)>, - pub(crate) dynamic_clause_map: DynamicClauseMap, - pub(crate) in_module: bool, - pub(crate) term_dirs: TermDirQuantum, - pub(crate) intra_module_term_dirs: IndexMap, - pub(crate) non_counted_bt_preds: IndexSet, -} - -impl<'a> TopLevelBatchWorker<'a> { - pub fn new( - stream: &'a mut ParsingStream, - atom_tbl: TabledData, - 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, - ) -> 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, 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) - } -} diff --git a/src/macros.rs b/src/macros.rs index 7de7da2f..aa043327 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -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; + } + } + }}; +} diff --git a/src/main.rs b/src/main.rs index 89168bf9..2495257e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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; diff --git a/src/read.rs b/src/read.rs index 5e972a08..f240ab28 100644 --- a/src/read.rs +++ b/src/read.rs @@ -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 index 00000000..c02bbc94 --- /dev/null +++ b/src/term_and_goal_expansion.pl @@ -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 + ). diff --git a/src/toplevel.pl b/src/toplevel.pl index bbada3a2..9513b671 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -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 - ). diff --git a/src/write.rs b/src/write.rs index cf40509d..b0dd010a 100644 --- a/src/write.rs +++ b/src/write.rs @@ -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), } -- 2.54.0