From 0404c3bd949b09d6713d3869e37d30a6b8a77f97 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 14 Nov 2021 13:39:56 -0700 Subject: [PATCH] use new heap term representation --- .gitignore | 2 + Cargo.lock | 561 +- Cargo.toml | 31 +- build.rs | 18 + crates/prolog_parser/Cargo.lock | 265 - crates/prolog_parser/src/ast.rs | 782 --- crates/prolog_parser/src/put_back_n.rs | 71 - crates/prolog_parser/src/tabled_rc.rs | 154 - crates/prolog_parser/tests/bom.rs | 40 - crates/prolog_parser/tests/parse_tokens.rs | 112 - crates/static-string-indexing/Cargo.toml | 11 + crates/static-string-indexing/src/lib.rs | 161 + src/allocator.rs | 25 +- src/arena.rs | 797 +++ src/arithmetic.rs | 574 +- src/atom_table.rs | 366 + src/bin/scryer-prolog.rs | 8 +- src/clause_types.rs | 1145 ++- src/codegen.rs | 213 +- src/debray_allocator.rs | 36 +- src/fixtures.rs | 20 +- src/forms.rs | 474 +- src/heap_iter.rs | 2723 +++++++- src/heap_print.rs | 1704 +++-- src/indexing.rs | 312 +- src/instructions.rs | 448 +- src/iterators.rs | 208 +- src/lib.rs | 24 +- src/lib/atts.pl | 52 +- src/lib/between.pl | 17 +- src/lib/builtins.pl | 51 +- src/lib/iso_ext.pl | 9 +- src/lib/lists.pl | 2 +- src/lib/serialization/abnf.pl | 14 +- src/lib/serialization/json.pl | 18 +- src/lib/uuid.pl | 6 +- src/loader.pl | 4 +- src/machine/arithmetic_ops.rs | 2012 +++--- src/machine/attributed_variables.rs | 113 +- src/machine/code_repo.rs | 2 +- src/machine/compile.rs | 463 +- src/machine/copier.rs | 418 +- src/machine/gc.rs | 1101 +++ src/machine/heap.rs | 580 +- src/machine/load_state.rs | 542 +- src/machine/loader.rs | 1923 +++--- src/machine/machine_errors.rs | 830 ++- src/machine/machine_indices.rs | 515 +- src/machine/machine_state.rs | 1754 +++-- src/machine/machine_state_impl.rs | 4466 ++++++------ src/machine/mock_wam.rs | 766 +++ src/machine/mod.rs | 294 +- src/machine/partial_string.rs | 1323 +++- src/machine/preprocessor.rs | 518 +- src/machine/stack.rs | 202 +- src/machine/streams.rs | 1762 +++-- src/machine/system_calls.rs | 6108 ++++++++--------- src/machine/term_stream.rs | 89 +- src/macros.rs | 660 +- src/parser/ast.rs | 631 ++ src/parser/char_reader.rs | 747 ++ .../prolog_parser/src => src/parser}/lexer.rs | 653 +- .../src => src/parser}/macros.rs | 8 +- .../src/lib.rs => src/parser/mod.rs | 14 +- .../src => src/parser}/parser.rs | 483 +- src/raw_block.rs | 105 + src/read.rs | 466 +- src/targets.rs | 54 +- src/toplevel.pl | 73 +- src/types.rs | 739 ++ src/write.rs | 304 +- tests/scryer/helper.rs | 28 +- 72 files changed, 25735 insertions(+), 16469 deletions(-) delete mode 100644 crates/prolog_parser/Cargo.lock delete mode 100644 crates/prolog_parser/src/ast.rs delete mode 100644 crates/prolog_parser/src/put_back_n.rs delete mode 100644 crates/prolog_parser/src/tabled_rc.rs delete mode 100644 crates/prolog_parser/tests/bom.rs delete mode 100644 crates/prolog_parser/tests/parse_tokens.rs create mode 100644 crates/static-string-indexing/Cargo.toml create mode 100644 crates/static-string-indexing/src/lib.rs create mode 100644 src/arena.rs create mode 100644 src/atom_table.rs create mode 100644 src/machine/gc.rs create mode 100644 src/machine/mock_wam.rs create mode 100644 src/parser/ast.rs create mode 100644 src/parser/char_reader.rs rename {crates/prolog_parser/src => src/parser}/lexer.rs (53%) rename {crates/prolog_parser/src => src/parser}/macros.rs (100%) rename crates/prolog_parser/src/lib.rs => src/parser/mod.rs (57%) rename {crates/prolog_parser/src => src/parser}/parser.rs (68%) create mode 100644 src/raw_block.rs create mode 100644 src/types.rs diff --git a/.gitignore b/.gitignore index eafdaf522..f63be9e99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +src/static_atoms.rs target/ + diff --git a/Cargo.lock b/Cargo.lock index 7e94a23e5..d5b4dc146 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "arrayvec" version = "0.5.2" @@ -8,9 +10,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "assert_cmd" -version = "1.0.3" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2475b58cd94eb4f70159f4fd8844ba3b807532fe3131b3373fae060bbe30396" +checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe" dependencies = [ "bstr", "doc-comment", @@ -34,9 +36,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "az" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a" +checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325" [[package]] name = "base64" @@ -61,9 +63,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2" @@ -100,9 +102,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -111,9 +113,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" [[package]] name = "byte-tools" @@ -123,15 +125,15 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.66" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -153,7 +155,7 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ "libc", "num-integer", - "num-traits 0.2.14", + "num-traits", "time", "winapi 0.3.9", ] @@ -169,9 +171,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" dependencies = [ "core-foundation-sys", "libc", @@ -179,9 +181,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpu-time" @@ -229,10 +231,10 @@ dependencies = [ ] [[package]] -name = "difference" -version = "2.0.0" +name = "difflib" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" @@ -282,6 +284,21 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" +[[package]] +name = "ed25519" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" +dependencies = [ + "signature", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "foreign-types" version = "0.3.2" @@ -341,18 +358,18 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ "typenum", ] [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", "libc", @@ -361,9 +378,9 @@ dependencies = [ [[package]] name = "git-version" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94918e83f1e01dedc2e361d00ce9487b14c58c7f40bab148026fa39d42cb41e2" +checksum = "f6b0decc02f4636b9ccad390dcbe77b722a77efedfa393caf8379a51d5c61899" dependencies = [ "git-version-macro", "proc-macro-hack", @@ -371,21 +388,21 @@ dependencies = [ [[package]] name = "git-version-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657" +checksum = "fe69f1cbdb6e28af2bac214e943b99ce8a0a06b447d15d3e61161b0423139f3f" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] name = "gmp-mpfr-sys" -version = "1.4.2" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e" +checksum = "a146a7357ce9573bdcc416fc4a99b960e166e72d8eaffa7c59966d51866b5bfb" dependencies = [ "libc", "winapi 0.3.9", @@ -393,9 +410,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "hostname" @@ -424,9 +441,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg 1.0.1", "hashbrown", @@ -441,17 +458,26 @@ dependencies = [ "libc", ] +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "js-sys" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -503,19 +529,20 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.85" +version = "0.2.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "libsodium-sys" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a685b64f837b339074115f2e7f7b431ac73681d08d75b389db7498b8892b8a58" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" dependencies = [ "cc", "libc", "pkg-config", + "walkdir", ] [[package]] @@ -558,7 +585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21" dependencies = [ "log", - "phf", + "phf 0.7.24", "phf_codegen", "serde", "serde_derive", @@ -576,9 +603,9 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mio" @@ -611,11 +638,30 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "git+https://github.com/mthom/modular-bitfield#213535c684af277563678179d8496f11b84a283f" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "git+https://github.com/mthom/modular-bitfield#213535c684af277563678179d8496f11b84a283f" +dependencies = [ + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", +] + [[package]] name = "native-tls" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" dependencies = [ "lazy_static", "libc", @@ -679,7 +725,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ "autocfg 1.0.1", "num-integer", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -689,7 +735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg 1.0.1", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -701,7 +747,7 @@ dependencies = [ "autocfg 1.0.1", "num-bigint", "num-integer", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -712,16 +758,7 @@ dependencies = [ "num-bigint", "num-integer", "num-rational", - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -735,9 +772,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.5.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "opaque-debug" @@ -747,38 +784,38 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "openssl" -version = "0.10.32" +version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags", "cfg-if 1.0.0", "foreign-types", - "lazy_static", "libc", + "once_cell", "openssl-sys", ] [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-src" -version = "111.13.0+1.1.1i" +version = "300.0.2+3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045e4dc48af57aad93d665885789b43222ae26f4886494da12d1ed58d309dcb6" +checksum = "14a760a11390b1a5daf72074d4f6ff1a6e772534ae191f999f57e9ee8146d1fb" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.60" +version = "0.9.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf" dependencies = [ "autocfg 1.0.1", "cc", @@ -790,12 +827,11 @@ dependencies = [ [[package]] name = "ordered-float" -version = "0.5.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" +checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d" dependencies = [ - "num-traits 0.1.43", - "unreachable", + "num-traits", ] [[package]] @@ -828,7 +864,18 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" dependencies = [ - "phf_shared", + "phf_shared 0.7.24", +] + +[[package]] +name = "phf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +dependencies = [ + "phf_macros", + "phf_shared 0.9.0", + "proc-macro-hack", ] [[package]] @@ -837,8 +884,8 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.7.24", + "phf_shared 0.7.24", ] [[package]] @@ -847,30 +894,63 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" dependencies = [ - "phf_shared", + "phf_shared 0.7.24", "rand 0.6.5", ] +[[package]] +name = "phf_generator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +dependencies = [ + "phf_shared 0.9.0", + "rand 0.8.4", +] + +[[package]] +name = "phf_macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +dependencies = [ + "phf_generator 0.9.1", + "phf_shared 0.9.0", + "proc-macro-hack", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", +] + [[package]] name = "phf_shared" version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" dependencies = [ - "siphasher", + "siphasher 0.2.3", +] + +[[package]] +name = "phf_shared" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +dependencies = [ + "siphasher 0.3.7", ] [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "precomputed-hash" @@ -880,11 +960,12 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "1.0.7" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb433456c1a57cc93554dea3ce40b4c19c4057e41c55d4a0f3d84ea71c325aa" +checksum = "5c6ce811d0b2e103743eec01db1c50612221f173084ce2f7941053e94b6bb474" dependencies = [ - "difference", + "difflib", + "itertools", "predicates-core", ] @@ -896,12 +977,12 @@ checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" [[package]] name = "predicates-tree" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2" +checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7" dependencies = [ "predicates-core", - "treeline", + "termtree", ] [[package]] @@ -921,23 +1002,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ - "unicode-xid 0.2.1", -] - -[[package]] -name = "prolog_parser" -version = "0.8.68" -dependencies = [ - "indexmap", - "lexical", - "num-rug-adapter", - "ordered-float", - "rug", - "unicode_reader", + "unicode-xid 0.2.2", ] [[package]] @@ -951,11 +1020,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.32", ] [[package]] @@ -979,14 +1048,14 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.1", - "rand_hc 0.3.0", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -1001,12 +1070,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.1", + "rand_core 0.6.3", ] [[package]] @@ -1026,9 +1095,9 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] @@ -1044,11 +1113,11 @@ dependencies = [ [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.1", + "rand_core 0.6.3", ] [[package]] @@ -1121,9 +1190,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.4" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -1135,7 +1204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", - "redox_syscall 0.2.4", + "redox_syscall 0.2.10", ] [[package]] @@ -1146,12 +1215,9 @@ checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6" [[package]] name = "regex-automata" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" -dependencies = [ - "byteorder", -] +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "remove_dir_all" @@ -1199,9 +1265,9 @@ dependencies = [ [[package]] name = "rug" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45" +checksum = "ee0c6e98de59509e62e09f3456b23cebb75dad21928882016f169bb628843459" dependencies = [ "az", "gmp-mpfr-sys", @@ -1235,6 +1301,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.19" @@ -1253,7 +1328,7 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scryer-prolog" -version = "0.8.128" +version = "0.9.0" dependencies = [ "assert_cmd", "base64", @@ -1268,14 +1343,17 @@ dependencies = [ "hostname", "indexmap", "lazy_static", + "lexical", "libc", + "modular-bitfield", "native-tls", "nix 0.15.0", "num-rug-adapter", "openssl", "ordered-float", + "phf 0.9.0", "predicates-core", - "prolog_parser", + "proc-macro2 1.0.32", "ref_thread_local", "ring", "ripemd160", @@ -1285,15 +1363,17 @@ dependencies = [ "select", "sha3", "slice-deque", + "smallvec", "sodiumoxide", - "unicode_reader", + "static-string-indexing", + "static_assertions", ] [[package]] name = "security-framework" -version = "2.0.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ "bitflags", "core-foundation", @@ -1304,9 +1384,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.0.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ "core-foundation-sys", "libc", @@ -1324,26 +1404,26 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.123" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" [[package]] name = "serde_derive" -version = "1.0.123" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3" dependencies = [ "itoa", "ryu", @@ -1376,24 +1456,36 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" + [[package]] name = "siphasher" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +[[package]] +name = "siphasher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" + [[package]] name = "slab" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "slice-deque" @@ -1408,16 +1500,17 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "sodiumoxide" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7038b67c941e23501573cb7242ffb08709abe9b11eb74bceff875bbda024a6a8" +checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" dependencies = [ + "ed25519", "libc", "libsodium-sys", "serde", @@ -1429,6 +1522,17 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "static-string-indexing" +version = "0.1.0" +dependencies = [ + "indexmap", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", + "walkdir", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -1443,7 +1547,7 @@ checksum = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67" dependencies = [ "lazy_static", "new_debug_unreachable", - "phf_shared", + "phf_shared 0.7.24", "precomputed-hash", "serde", "string_cache_codegen", @@ -1456,10 +1560,10 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6" dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2 1.0.24", - "quote 1.0.8", + "phf_generator 0.7.24", + "phf_shared 0.7.24", + "proc-macro2 1.0.32", + "quote 1.0.10", "string_cache_shared", ] @@ -1488,13 +1592,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.60" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "unicode-xid 0.2.1", + "proc-macro2 1.0.32", + "quote 1.0.10", + "unicode-xid 0.2.2", ] [[package]] @@ -1505,8 +1609,8 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", - "redox_syscall 0.2.4", + "rand 0.8.4", + "redox_syscall 0.2.10", "remove_dir_all", "winapi 0.3.9", ] @@ -1522,6 +1626,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termtree" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" + [[package]] name = "time" version = "0.1.43" @@ -1532,29 +1642,23 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "treeline" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" - [[package]] name = "typenum" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -1564,28 +1668,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "unicode_reader" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a" -dependencies = [ - "smallvec", - "unicode-segmentation", -] - -[[package]] -name = "unreachable" -version = "1.0.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -dependencies = [ - "void", -] +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "untrusted" @@ -1595,9 +1680,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "utf-8" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8parse" @@ -1607,9 +1692,9 @@ checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "void" @@ -1626,6 +1711,17 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi 0.3.9", + "winapi-util", +] + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -1634,9 +1730,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -1644,53 +1740,53 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ - "quote 1.0.8", + "quote 1.0.10", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "web-sys" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", @@ -1724,6 +1820,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 0e4b144e4..ee785cb45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.128" +version = "0.9.0" authors = ["Mark Thom "] edition = "2021" description = "A modern Prolog implementation written mostly in Rust." @@ -12,14 +12,19 @@ categories = ["command-line-utilities"] build = "build.rs" [workspace] -members = ["crates/prolog_parser", "crates/num-rug-adapter"] +members = ["crates/num-rug-adapter", "crates/static-string-indexing"] + +[features] +num = ["num-rug-adapter"] +# no default features to make num tests work +# workaround for --no-default-features and --features not working intuitively for workspaces with a root package +# see rust-lang/cargo#7160 +default = ["rug"] [build-dependencies] indexmap = "1.0.2" - -[features] -default = ["rug", "prolog_parser/rug"] -num = ["num-rug-adapter", "prolog_parser/num"] +static-string-indexing = { path = "./crates/static-string-indexing" } +proc-macro2 = "*" [dependencies] cpu-time = "1.0.0" @@ -31,15 +36,17 @@ git-version = "0.3.4" hostname = "0.3.1" indexmap = "1.0.2" lazy_static = "1.4.0" +lexical = "5.2.2" libc = "0.2.62" +# temporary to remove unnecessary braces warnings. +modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2" nix = "0.15.0" num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" } -ordered-float = "0.5.0" -prolog_parser = { path = "./crates/prolog_parser", default-features = false } +ordered-float = "2.1.1" +phf = { version = "0.9", features = ["macros"] } ref_thread_local = "0.0.0" -rug = { version = "1.4.0", optional = true } +rug = { version = "1.12.0", optional = true } rustyline = "7.0.0" -unicode_reader = "1.0.0" ring = "0.16.13" ripemd160 = "0.8.0" sha3 = "0.8.2" @@ -50,9 +57,11 @@ chrono = "0.4.11" select = "0.4.3" roxmltree = "0.11.0" base64 = "0.12.3" +smallvec = "*" sodiumoxide = "0.2.6" +static_assertions = "1.1.0" slice-deque = "0.3.0" [dev-dependencies] assert_cmd = "1.0.3" -predicates-core = "1.0.2" +predicates-core = "1.0.2" \ No newline at end of file diff --git a/build.rs b/build.rs index 0133c93ec..88267cdc5 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,11 @@ +use static_string_indexing::index_static_strings; + use std::env; use std::fs; use std::fs::File; use std::io::Write; use std::path::Path; +use std::process::Command; fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) { let entries = match current_dir.read_dir() { @@ -48,6 +51,21 @@ fn main() { let mut m = IndexMap::new();\n", ) .unwrap(); + find_prolog_files(&mut libraries, "", &lib_path); libraries.write_all(b"\n m\n };\n}\n").unwrap(); + + let static_atoms_path = Path::new("src/static_atoms.rs"); + let mut static_atoms_file = File::create(&static_atoms_path).unwrap(); + + let quoted_output = index_static_strings(); + + static_atoms_file + .write_all(quoted_output.to_string().as_bytes()) + .unwrap(); + + Command::new("rustfmt") + .arg(static_atoms_path.as_os_str()) + .spawn().unwrap() + .wait().unwrap(); } diff --git a/crates/prolog_parser/Cargo.lock b/crates/prolog_parser/Cargo.lock deleted file mode 100644 index 57d62880e..000000000 --- a/crates/prolog_parser/Cargo.lock +++ /dev/null @@ -1,265 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "az" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "gmp-mpfr-sys" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "lexical" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e0d09e60c187a6d0a3fa418aec8587c6a4ae9de872f6126f2134f319b5ed10d" -dependencies = [ - "cfg-if", - "lexical-core", - "rustc_version", -] - -[[package]] -name = "lexical-core" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14" -dependencies = [ - "arrayvec", - "cfg-if", - "rustc_version", - "ryu", - "static_assertions", -] - -[[package]] -name = "libc" -version = "0.2.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits 0.2.14", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits 0.2.14", -] - -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits 0.2.14", -] - -[[package]] -name = "num-rug-adapter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7470b6acf85abce0771203112db4181d03f7b8a6be49f0e842a78030192f8a58" -dependencies = [ - "libc", - "num-bigint", - "num-integer", - "num-rational", - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "ordered-float" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" -dependencies = [ - "num-traits 0.1.43", - "unreachable", -] - -[[package]] -name = "prolog_parser" -version = "0.8.68" -dependencies = [ - "lexical", - "num-rug-adapter", - "ordered-float", - "rug", - "unicode_reader", -] - -[[package]] -name = "rug" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45" -dependencies = [ - "az", - "gmp-mpfr-sys", - "libc", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "smallvec" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" - -[[package]] -name = "static_assertions" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" - -[[package]] -name = "unicode-segmentation" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" - -[[package]] -name = "unicode_reader" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a" -dependencies = [ - "smallvec", - "unicode-segmentation", -] - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -dependencies = [ - "void", -] - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/crates/prolog_parser/src/ast.rs b/crates/prolog_parser/src/ast.rs deleted file mode 100644 index ac794e6e2..000000000 --- a/crates/prolog_parser/src/ast.rs +++ /dev/null @@ -1,782 +0,0 @@ -use crate::rug::{Integer, Rational}; -use crate::tabled_rc::*; -use ordered_float::*; - -use crate::put_back_n::*; - -use std::cell::Cell; -use std::cmp::Ordering; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::io::{Bytes, Error as IOError, Read}; -use std::ops::Deref; -use std::rc::Rc; -use std::vec::Vec; - -use indexmap::IndexMap; -use unicode_reader::CodePoints; - -pub type Atom = String; - -pub type Var = String; - -pub type Specifier = u32; - -pub const MAX_ARITY: usize = 1023; - -pub const XFX: u32 = 0x0001; -pub const XFY: u32 = 0x0002; -pub const YFX: u32 = 0x0004; -pub const XF: u32 = 0x0010; -pub const YF: u32 = 0x0020; -pub const FX: u32 = 0x0040; -pub const FY: u32 = 0x0080; -pub const DELIMITER: u32 = 0x0100; -pub const TERM: u32 = 0x1000; -pub const LTERM: u32 = 0x3000; - -pub const NEGATIVE_SIGN: u32 = 0x0200; - -#[macro_export] -macro_rules! clause_name { - ($name: expr, $tbl: expr) => { - $crate::ast::ClauseName::User($crate::tabled_rc::TabledRc::new($name, $tbl.clone())) - }; - ($name: expr) => { - $crate::ast::ClauseName::BuiltIn($name) - }; -} - -#[macro_export] -macro_rules! atom { - ($e:expr, $tbl:expr) => { - $crate::ast::Constant::Atom( - $crate::ast::ClauseName::User($crate::tabled_rc!($e, $tbl)), - None, - ) - }; - ($e:expr) => { - $crate::ast::Constant::Atom($crate::clause_name!($e), None) - }; -} - -#[macro_export] -macro_rules! rc_atom { - ($e:expr) => { - Rc::new(String::from($e)) - }; -} -macro_rules! is_term { - ($x:expr) => { - ($x & $crate::ast::TERM) != 0 - }; -} - -macro_rules! is_lterm { - ($x:expr) => { - ($x & $crate::ast::LTERM) != 0 - }; -} - -macro_rules! is_op { - ($x:expr) => { - $x & ($crate::ast::XF - | $crate::ast::YF - | $crate::ast::FX - | $crate::ast::FY - | $crate::ast::XFX - | $crate::ast::XFY - | $crate::ast::YFX) - != 0 - }; -} - -macro_rules! is_negate { - ($x:expr) => { - ($x & $crate::ast::NEGATIVE_SIGN) != 0 - }; -} - -#[macro_export] -macro_rules! is_prefix { - ($x:expr) => { - $x & ($crate::ast::FX | $crate::ast::FY) != 0 - }; -} - -#[macro_export] -macro_rules! is_postfix { - ($x:expr) => { - $x & ($crate::ast::XF | $crate::ast::YF) != 0 - }; -} - -#[macro_export] -macro_rules! is_infix { - ($x:expr) => { - ($x & ($crate::ast::XFX | $crate::ast::XFY | $crate::ast::YFX)) != 0 - }; -} - -#[macro_export] -macro_rules! is_xfx { - ($x:expr) => { - ($x & $crate::ast::XFX) != 0 - }; -} - -#[macro_export] -macro_rules! is_xfy { - ($x:expr) => { - ($x & $crate::ast::XFY) != 0 - }; -} - -#[macro_export] -macro_rules! is_yfx { - ($x:expr) => { - ($x & $crate::ast::YFX) != 0 - }; -} - -#[macro_export] -macro_rules! is_yf { - ($x:expr) => { - ($x & $crate::ast::YF) != 0 - }; -} - -#[macro_export] -macro_rules! is_xf { - ($x:expr) => { - ($x & $crate::ast::XF) != 0 - }; -} - -#[macro_export] -macro_rules! is_fx { - ($x:expr) => { - ($x & $crate::ast::FX) != 0 - }; -} - -#[macro_export] -macro_rules! is_fy { - ($x:expr) => { - ($x & $crate::ast::FY) != 0 - }; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum RegType { - Perm(usize), - Temp(usize), -} - -impl Default for RegType { - fn default() -> Self { - RegType::Temp(0) - } -} - -impl RegType { - pub fn reg_num(self) -> usize { - match self { - RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num, - } - } - - pub fn is_perm(self) -> bool { - matches!(self, RegType::Perm(_)) - } -} - -impl fmt::Display for RegType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - RegType::Perm(val) => write!(f, "Y{}", val), - RegType::Temp(val) => write!(f, "X{}", val), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum VarReg { - ArgAndNorm(RegType, usize), - Norm(RegType), -} - -impl VarReg { - pub fn norm(self) -> RegType { - match self { - VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, - } - } -} - -impl fmt::Display for VarReg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), - VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), - VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), - VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), - } - } -} - -impl Default for VarReg { - fn default() -> Self { - VarReg::Norm(RegType::default()) - } -} - -#[macro_export] -macro_rules! temp_v { - ($x:expr) => { - $crate::ast::RegType::Temp($x) - }; -} - -#[macro_export] -macro_rules! perm_v { - ($x:expr) => { - $crate::ast::RegType::Perm($x) - }; -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub enum GenContext { - Head, - Mid(usize), - Last(usize), // Mid & Last: chunk_num -} - -impl GenContext { - pub fn chunk_num(self) -> usize { - match self { - GenContext::Head => 0, - GenContext::Mid(cn) | GenContext::Last(cn) => cn, - } - } -} - -pub type OpDirKey = (ClauseName, Fixity); - -#[derive(Debug, Clone)] -pub struct OpDirValue(pub SharedOpDesc); - -impl OpDirValue { - pub fn new(spec: Specifier, priority: usize) -> Self { - OpDirValue(SharedOpDesc::new(priority, spec)) - } - - #[inline] - pub fn shared_op_desc(&self) -> SharedOpDesc { - self.0.clone() - } -} - -// name and fixity -> operator type and precedence. -pub type OpDir = IndexMap; - -#[derive(Debug, Clone, Copy)] -pub struct MachineFlags { - pub double_quotes: DoubleQuotes, -} - -impl Default for MachineFlags { - fn default() -> Self { - MachineFlags { - double_quotes: DoubleQuotes::default(), - } - } -} - -#[derive(Debug, Clone, Copy)] -pub enum DoubleQuotes { - Atom, - Chars, - Codes, -} - -impl DoubleQuotes { - pub fn is_chars(self) -> bool { - matches!(self, DoubleQuotes::Chars) - } - - pub fn is_atom(self) -> bool { - matches!(self, DoubleQuotes::Atom) - } - - pub fn is_codes(self) -> bool { - matches!(self, DoubleQuotes::Codes) - } -} - -impl Default for DoubleQuotes { - fn default() -> Self { - DoubleQuotes::Chars - } -} - -pub fn default_op_dir() -> OpDir { - let mut op_dir = OpDir::new(); - - op_dir.insert((clause_name!(":-"), Fixity::In), OpDirValue::new(XFX, 1200)); - op_dir.insert((clause_name!(":-"), Fixity::Pre), OpDirValue::new(FX, 1200)); - op_dir.insert((clause_name!("?-"), Fixity::Pre), OpDirValue::new(FX, 1200)); - op_dir.insert((clause_name!(","), Fixity::In), OpDirValue::new(XFY, 1000)); - - op_dir -} - -#[derive(Debug, Clone)] -pub enum ArithmeticError { - NonEvaluableFunctor(Constant, usize), - UninstantiatedVar, -} - -#[derive(Debug)] -pub enum ParserError { - BackQuotedString(usize, usize), - UnexpectedChar(char, usize, usize), - UnexpectedEOF, - IO(IOError), - IncompleteReduction(usize, usize), - InvalidSingleQuotedCharacter(char), - MissingQuote(usize, usize), - NonPrologChar(usize, usize), - ParseBigInt(usize, usize), - Utf8Error(usize, usize), -} - -impl ParserError { - pub fn line_and_col_num(&self) -> Option<(usize, usize)> { - match self { - &ParserError::BackQuotedString(line_num, col_num) - | &ParserError::UnexpectedChar(_, line_num, col_num) - | &ParserError::IncompleteReduction(line_num, col_num) - | &ParserError::MissingQuote(line_num, col_num) - | &ParserError::NonPrologChar(line_num, col_num) - | &ParserError::ParseBigInt(line_num, col_num) - | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), - _ => None, - } - } - - pub fn as_str(&self) -> &'static str { - match self { - ParserError::BackQuotedString(..) => "back_quoted_string", - ParserError::UnexpectedChar(..) => "unexpected_char", - ParserError::UnexpectedEOF => "unexpected_end_of_file", - ParserError::IncompleteReduction(..) => "incomplete_reduction", - ParserError::InvalidSingleQuotedCharacter(..) => "invalid_single_quoted_character", - ParserError::IO(_) => "input_output_error", - ParserError::MissingQuote(..) => "missing_quote", - ParserError::NonPrologChar(..) => "non_prolog_character", - ParserError::ParseBigInt(..) => "cannot_parse_big_int", - ParserError::Utf8Error(..) => "utf8_conversion_error", - } - } -} - -impl From for ParserError { - fn from(err: IOError) -> ParserError { - ParserError::IO(err) - } -} - -impl From<&IOError> for ParserError { - fn from(error: &IOError) -> ParserError { - if error.get_ref().filter(|e| e.is::()).is_some() { - ParserError::Utf8Error(0, 0) - } else { - ParserError::IO(error.kind().into()) - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct CompositeOpDir<'a, 'b> { - pub primary_op_dir: Option<&'b OpDir>, - pub secondary_op_dir: &'a OpDir, -} - -impl<'a, 'b> CompositeOpDir<'a, 'b> { - #[inline] - pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self { - CompositeOpDir { - primary_op_dir, - secondary_op_dir, - } - } - - #[inline] - pub(crate) fn get(&self, name: ClauseName, fixity: Fixity) -> Option<&OpDirValue> { - let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir { - primary_op_dir.get(&(name.clone(), fixity)) - } else { - None - }; - - entry.or_else(move || self.secondary_op_dir.get(&(name, fixity))) - } -} - -#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] -pub enum Fixity { - In, - Post, - Pre, -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct SharedOpDesc(Rc>); - -impl SharedOpDesc { - #[inline] - pub fn new(priority: usize, spec: Specifier) -> Self { - SharedOpDesc(Rc::new(Cell::new((priority, spec)))) - } - - #[inline] - pub fn ptr_eq(lop_desc: &SharedOpDesc, rop_desc: &SharedOpDesc) -> bool { - Rc::ptr_eq(&lop_desc.0, &rop_desc.0) - } - - #[inline] - pub fn arity(&self) -> usize { - if self.get().1 & (XFX | XFY | YFX) == 0 { - 1 - } else { - 2 - } - } - - #[inline] - pub fn get(&self) -> (usize, Specifier) { - self.0.get() - } - - #[inline] - pub fn set(&self, prec: usize, spec: Specifier) { - self.0.set((prec, spec)); - } - - #[inline] - pub fn prec(&self) -> usize { - self.0.get().0 - } - - #[inline] - pub fn assoc(&self) -> Specifier { - self.0.get().1 - } -} - -impl Deref for SharedOpDesc { - type Target = Cell<(usize, Specifier)>; - - #[inline] - fn deref(&self) -> &Self::Target { - self.0.deref() - } -} - -// this ensures that SharedOpDesc (which is not consistently placed in -// every atom!) doesn't affect the value of an atom hash. If -// SharedOpDesc values are to be indexed, a BTreeMap or BTreeSet -// should be used, obviously. -impl Hash for SharedOpDesc { - fn hash(&self, state: &mut H) { - 0.hash(state) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Constant { - Atom(ClauseName, Option), - Char(char), - EmptyList, - Fixnum(isize), - Integer(Rc), - Rational(Rc), - Float(OrderedFloat), - String(Rc), - Usize(usize), -} - -impl fmt::Display for Constant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Constant::Atom(ref atom, _) => { - if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) { - write!(f, "'{}'", atom.as_str()) - } else { - write!(f, "{}", atom.as_str()) - } - } - Constant::Char(c) => write!(f, "'{}'", *c as u32), - Constant::EmptyList => write!(f, "[]"), - Constant::Fixnum(n) => write!(f, "{}", n), - Constant::Integer(ref n) => write!(f, "{}", n), - Constant::Rational(ref n) => write!(f, "{}", n), - Constant::Float(ref n) => write!(f, "{}", n), - Constant::String(ref s) => write!(f, "\"{}\"", &s), - Constant::Usize(integer) => write!(f, "u{}", integer), - } - } -} - -impl Constant { - pub fn to_atom(&self) -> Option { - match self { - Constant::Atom(a, _) => Some(a.defrock_brackets()), - _ => None, - } - } -} - -#[derive(Debug, Clone)] -pub enum ClauseName { - BuiltIn(&'static str), - User(TabledRc), -} - -impl fmt::Display for ClauseName { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl Hash for ClauseName { - fn hash(&self, state: &mut H) { - (*self.as_str()).hash(state) - } -} - -impl PartialEq for ClauseName { - fn eq(&self, other: &ClauseName) -> bool { - *self.as_str() == *other.as_str() - } -} - -impl Eq for ClauseName {} - -impl Ord for ClauseName { - fn cmp(&self, other: &ClauseName) -> Ordering { - (*self.as_str()).cmp(other.as_str()) - } -} - -impl PartialOrd for ClauseName { - fn partial_cmp(&self, other: &ClauseName) -> Option { - Some(self.cmp(other)) - } -} - -impl<'a> From<&'a TabledRc> for ClauseName { - fn from(name: &'a TabledRc) -> ClauseName { - ClauseName::User(name.clone()) - } -} - -impl ClauseName { - #[inline] - pub fn owning_module(&self) -> Self { - match self { - ClauseName::User(ref name) => { - let module = name.owning_module(); - ClauseName::User(TabledRc { - atom: module.clone(), - table: TabledData::new(module), - }) - } - _ => clause_name!("user"), - } - } - - #[inline] - pub fn to_rc(&self) -> Rc { - match self { - ClauseName::BuiltIn(s) => Rc::new(s.to_string()), - ClauseName::User(ref rc) => rc.inner(), - } - } - - #[inline] - pub fn with_table(self, atom_tbl: TabledData) -> Self { - match self { - ClauseName::BuiltIn(_) => self, - ClauseName::User(mut name) => { - name.table = atom_tbl; - ClauseName::User(name) - } - } - } - - #[inline] - pub fn has_table(&self, atom_tbl: &TabledData) -> bool { - match self { - ClauseName::BuiltIn(_) => false, - ClauseName::User(ref name) => &name.table == atom_tbl, - } - } - - #[inline] - pub fn has_table_of(&self, other: &ClauseName) -> bool { - match self { - ClauseName::BuiltIn(_) => { - matches!(other, ClauseName::BuiltIn(_)) - } - ClauseName::User(ref name) => other.has_table(&name.table), - } - } - - #[inline] - pub fn as_str(&self) -> &str { - match self { - ClauseName::BuiltIn(s) => s, - ClauseName::User(ref name) => name.as_ref(), - } - } - - #[inline] - pub fn is_char(&self) -> bool { - !self.as_str().is_empty() && self.as_str().chars().nth(1).is_none() - } - - pub fn defrock_brackets(&self) -> Self { - fn defrock_brackets(s: &str) -> &str { - if s.starts_with('(') && s.ends_with(')') { - &s[1..s.len() - 1] - } else { - s - } - } - - match self { - ClauseName::BuiltIn(s) => ClauseName::BuiltIn(defrock_brackets(s)), - ClauseName::User(s) => { - ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(), s.table)) - } - } - } -} - -impl AsRef for ClauseName { - #[inline] - fn as_ref(&self) -> &str { - self.as_str() - } -} - -#[derive(Debug, Clone)] -pub enum Term { - AnonVar, - Clause( - Cell, - ClauseName, - Vec>, - Option, - ), - Cons(Cell, Box, Box), - Constant(Cell, Constant), - Var(Cell, Rc), -} - -impl Term { - pub fn shared_op_desc(&self) -> Option { - match self { - Term::Clause(_, _, _, ref spec) => spec.clone(), - Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(), - _ => None, - } - } - - pub fn into_constant(self) -> Option { - match self { - Term::Constant(_, c) => Some(c), - _ => None, - } - } - - pub fn first_arg(&self) -> Option<&Term> { - match self { - Term::Clause(_, _, ref terms, _) => terms.first().map(|bt| bt.as_ref()), - _ => None, - } - } - - pub fn set_name(&mut self, new_name: ClauseName) { - match self { - Term::Constant(_, Constant::Atom(ref mut atom, _)) - | Term::Clause(_, ref mut atom, ..) => { - *atom = new_name; - } - _ => {} - } - } - - pub fn name(&self) -> Option { - match self { - &Term::Constant(_, Constant::Atom(ref atom, _)) | &Term::Clause(_, ref atom, ..) => { - Some(atom.clone()) - } - _ => None, - } - } - - pub fn arity(&self) -> usize { - match self { - Term::Clause(_, _, ref child_terms, ..) => child_terms.len(), - _ => 0, - } - } -} - -fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> { - if let Term::Clause(_, ref name, ref mut subterms, _) = term { - if name.as_str() == s && subterms.len() == 2 { - let snd = *subterms.pop().unwrap(); - let fst = *subterms.pop().unwrap(); - - return Some((fst, snd)); - } - } - - None -} - -pub fn unfold_by_str(mut term: Term, s: &str) -> Vec { - let mut terms = vec![]; - - while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) { - terms.push(fst); - term = snd; - } - - terms.push(term); - terms -} - -pub type ParsingStream = PutBackN>>; - -use unicode_reader::BadUtf8Error; - -#[inline] -pub fn parsing_stream(src: R) -> Result, ParserError> { - let mut stream = put_back_n(CodePoints::from(src.bytes())); - match stream.peek() { - None => Ok(stream), // empty stream is handled gracefully by Lexer::eof - Some(Err(error)) => Err(ParserError::from(error)), - Some(Ok(c)) => { - if *c == '\u{feff}' { - // skip UTF-8 BOM - stream.next(); - } - Ok(stream) - } - } -} diff --git a/crates/prolog_parser/src/put_back_n.rs b/crates/prolog_parser/src/put_back_n.rs deleted file mode 100644 index 8bef7f30e..000000000 --- a/crates/prolog_parser/src/put_back_n.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::iter::Peekable; - -#[derive(Debug, Clone)] -pub struct PutBackN { - top: Vec, - iter: Peekable, -} - -pub fn put_back_n(iterable: I) -> PutBackN - where I: IntoIterator -{ - PutBackN { - top: Vec::new(), - iter: iterable.into_iter().peekable(), - } -} - -impl PutBackN { - #[inline] - pub(crate) - fn put_back(&mut self, item: I::Item) { - self.top.push(item); - } - - #[inline] - pub fn take_buf(&mut self) -> Vec { - std::mem::replace(&mut self.top, vec![]) - } - - #[inline] - pub(crate) - fn peek(&mut self) -> Option<&I::Item> { - if self.top.is_empty() { - /* This is a kludge for Ctrl-D not being - * handled properly if self.iter().peek() isn't called - * first. */ - match self.iter.peek() { - Some(_) => { - self.iter.next().and_then(move |item| { - self.top.push(item); - self.top.last() - }) - } - None => { - None - } - } - } else { - self.top.last() - } - } - - #[inline] - pub(crate) - fn put_back_all>(&mut self, iter: DEI) { - self.top.extend(iter.rev()); - } -} - -impl Iterator for PutBackN { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.top.is_empty() { - self.iter.next() - } else { - self.top.pop() - } - } -} diff --git a/crates/prolog_parser/src/tabled_rc.rs b/crates/prolog_parser/src/tabled_rc.rs deleted file mode 100644 index 47f87d302..000000000 --- a/crates/prolog_parser/src/tabled_rc.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::cell::{RefCell, RefMut}; -use std::cmp::Ordering; -use std::collections::HashSet; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::rc::Rc; - -pub struct TabledData { - table: Rc>>>, - pub(crate) module_name: Rc, -} - -impl fmt::Debug for TabledData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TabledData") - .field("table", &self.table) - .field("module_name", &self.table) - .finish() - } -} - -impl Clone for TabledData { - fn clone(&self) -> Self { - TabledData { - table: self.table.clone(), - module_name: self.module_name.clone(), - } - } -} - -impl PartialEq for TabledData { - fn eq(&self, other: &TabledData) -> bool { - Rc::ptr_eq(&self.table, &other.table) && self.module_name == other.module_name - } -} - -impl TabledData { - #[inline] - pub fn new(module_name: Rc) -> Self { - TabledData { - table: Rc::new(RefCell::new(HashSet::new())), - module_name, - } - } - - #[inline] - pub fn borrow_mut(&self) -> RefMut>> { - self.table.borrow_mut() - } -} - -pub struct TabledRc { - pub(crate) atom: Rc, - pub table: TabledData, -} - -impl fmt::Debug for TabledRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TabledRc") - .field("atom", &self.atom) - .field("table", &self.table) - .finish() - } -} - -// this Clone instance is manually defined to prevent the compiler -// from complaining when deriving Clone for StringList. -impl Clone for TabledRc { - fn clone(&self) -> Self { - TabledRc { - atom: self.atom.clone(), - table: self.table.clone(), - } - } -} - -impl PartialOrd for TabledRc { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.atom.cmp(&other.atom)) - } -} - -impl Ord for TabledRc { - fn cmp(&self, other: &Self) -> Ordering { - self.atom.cmp(&other.atom) - } -} - -impl PartialEq for TabledRc { - fn eq(&self, other: &TabledRc) -> bool { - self.atom == other.atom - } -} - -impl Eq for TabledRc {} - -impl Hash for TabledRc { - fn hash(&self, state: &mut H) { - self.atom.hash(state) - } -} - -impl TabledRc { - pub fn new(atom: T, table: TabledData) -> Self { - let atom = match table.borrow_mut().take(&atom) { - Some(atom) => atom, - None => Rc::new(atom), - }; - - table.borrow_mut().insert(atom.clone()); - - TabledRc { atom, table } - } - - #[inline] - pub fn inner(&self) -> Rc { - self.atom.clone() - } - - #[inline] - pub(crate) fn owning_module(&self) -> Rc { - self.table.module_name.clone() - } -} - -impl Drop for TabledRc { - fn drop(&mut self) { - if Rc::strong_count(&self.atom) == 2 { - self.table.borrow_mut().remove(&self.atom); - } - } -} - -impl Deref for TabledRc { - type Target = T; - - fn deref(&self) -> &Self::Target { - &*self.atom - } -} - -impl fmt::Display for TabledRc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", &*self.atom) - } -} - -#[macro_export] -macro_rules! tabled_rc { - ($e:expr, $tbl:expr) => { - $crate::tabled_rc::TabledRc::new(String::from($e), $tbl.clone()) - }; -} diff --git a/crates/prolog_parser/tests/bom.rs b/crates/prolog_parser/tests/bom.rs deleted file mode 100644 index 8a92c1276..000000000 --- a/crates/prolog_parser/tests/bom.rs +++ /dev/null @@ -1,40 +0,0 @@ -use prolog_parser::ast::*; -use prolog_parser::lexer::{Lexer, Token}; -use prolog_parser::tabled_rc::TabledData; - -use std::rc::Rc; - -#[test] -fn valid_token() { - let stream = parsing_stream("valid text".as_bytes()); - assert!(stream.is_ok()); -} - -#[test] -fn empty_stream() { - let bytes: &[u8] = &[]; - assert!(parsing_stream(bytes).is_ok()); -} - -#[test] -fn skip_utf8_bom() { - let atom_tbl = TabledData::new(Rc::new("my_module".to_string())); - let flags = MachineFlags::default(); - let bytes: &[u8] = &[0xEF, 0xBB, 0xBF, '4' as u8, '\n' as u8]; - let mut stream = parsing_stream(bytes).expect("valid stream"); - let mut lexer = Lexer::new(atom_tbl, flags, &mut stream); - match lexer.next_token() { - Ok(Token::Constant(Constant::Fixnum(4))) => (), - _ => assert!(false), - } -} - -#[test] -fn invalid_utf16_bom() { - let bytes: &[u8] = &[0xFF, 0xFE, 'a' as u8, '\n' as u8]; - let stream = parsing_stream(bytes); - match stream { - Err(ParserError::Utf8Error(0, 0)) => (), - _ => assert!(false), - } -} diff --git a/crates/prolog_parser/tests/parse_tokens.rs b/crates/prolog_parser/tests/parse_tokens.rs deleted file mode 100644 index 69b632865..000000000 --- a/crates/prolog_parser/tests/parse_tokens.rs +++ /dev/null @@ -1,112 +0,0 @@ -use prolog_parser::ast::*; -use prolog_parser::lexer::{Lexer, Token}; -use prolog_parser::tabled_rc::TabledData; - -use std::rc::Rc; - -fn read_all_tokens(text: &str) -> Result, ParserError> { - let atom_tbl = TabledData::new(Rc::new("my_module".to_string())); - let flags = MachineFlags::default(); - let mut stream = parsing_stream(text.as_bytes())?; - let mut lexer = Lexer::new(atom_tbl, flags, &mut stream); - - let mut tokens = Vec::new(); - while !lexer.eof()? { - let token = lexer.next_token()?; - tokens.push(token); - } - Ok(tokens) -} - -#[test] -fn empty_multiline_comment() -> Result<(), ParserError> { - let tokens = read_all_tokens("/**/ 4\n")?; - assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]); - Ok(()) -} - -#[test] -fn any_char_multiline_comment() -> Result<(), ParserError> { - let tokens = read_all_tokens("/* █╗╚═══╝ © */ 4\n")?; - assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]); - Ok(()) -} - -#[test] -fn simple_char() -> Result<(), ParserError> { - let tokens = read_all_tokens("'a'\n")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('a'))]); - Ok(()) -} - -#[test] -fn char_with_meta_seq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r#"'\\' '\'' '\"' '\`' "#)?; // use literal string so \ are escaped - assert_eq!( - tokens, - [ - Token::Constant(Constant::Char('\\')), - Token::Constant(Constant::Char('\'')), - Token::Constant(Constant::Char('"')), - Token::Constant(Constant::Char('`')) - ] - ); - Ok(()) -} - -#[test] -fn char_with_control_seq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\a' '\b' '\r' '\f' '\t' '\n' '\v' ")?; - assert_eq!( - tokens, - [ - Token::Constant(Constant::Char('\u{07}')), - Token::Constant(Constant::Char('\u{08}')), - Token::Constant(Constant::Char('\r')), - Token::Constant(Constant::Char('\u{0c}')), - Token::Constant(Constant::Char('\t')), - Token::Constant(Constant::Char('\n')), - Token::Constant(Constant::Char('\u{0b}')), - ] - ); - Ok(()) -} - -#[test] -fn char_with_octseq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\60433\' ")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('愛'))]); // Japanese character - Ok(()) -} - -#[test] -fn char_with_octseq_0() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\0\' ")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('\u{0000}'))]); - Ok(()) -} - -#[test] -fn char_with_hexseq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\x2124\' ")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('ℤ'))]); // Z math symbol - Ok(()) -} - -#[test] -fn char_with_hexseq_invalid() { - assert!(read_all_tokens(r"'\x\' ").is_err()); -} - -#[test] -fn empty() -> Result<(), ParserError> { - let tokens = read_all_tokens("")?; - assert!(tokens.is_empty()); - Ok(()) -} - -#[test] -fn comment_then_eof() -> Result<(), ParserError> { - assert!(read_all_tokens("% only a comment").is_err()); - Ok(()) -} diff --git a/crates/static-string-indexing/Cargo.toml b/crates/static-string-indexing/Cargo.toml new file mode 100644 index 000000000..a6da96b95 --- /dev/null +++ b/crates/static-string-indexing/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "static-string-indexing" +version = "0.1.0" +edition = "2018" + +[dependencies] +proc-macro2 = "*" +syn = { version = "*", features = ['full', 'visit', 'extra-traits'] } +indexmap = "*" +walkdir = "2" +quote = "*" diff --git a/crates/static-string-indexing/src/lib.rs b/crates/static-string-indexing/src/lib.rs new file mode 100644 index 000000000..22b87cc01 --- /dev/null +++ b/crates/static-string-indexing/src/lib.rs @@ -0,0 +1,161 @@ +use proc_macro2::TokenStream; +use syn::*; +use syn::parse::*; +use syn::visit::*; + +use indexmap::IndexSet; + +struct StaticStrVisitor { + static_strs: IndexSet, +} + +impl StaticStrVisitor { + fn new() -> Self { + Self { static_strs: IndexSet::new() } + } +} + +struct MacroFnArgs { + args: Vec, +} + +struct ReadHeapCellExprAndArms { + expr: Expr, + arms: Vec, +} + +impl Parse for ReadHeapCellExprAndArms { + fn parse(input: ParseStream) -> Result { + let mut arms = vec![]; + let expr = input.parse()?; + + input.parse::()?; + arms.push(input.parse()?); + + while !input.is_empty() { + if let Ok(_) = input.parse::() {} + arms.push(input.parse()?); + } + + Ok(ReadHeapCellExprAndArms { expr, arms }) + } +} + +impl Parse for MacroFnArgs { + fn parse(input: ParseStream) -> Result { + let mut args = vec![]; + + if !input.is_empty() { + args.push(input.parse()?); + } + + while !input.is_empty() { + if let Ok(_) = input.parse::() {} + args.push(input.parse()?); + } + + Ok(MacroFnArgs { args }) + } +} + +impl<'ast> Visit<'ast> for StaticStrVisitor { + fn visit_macro(&mut self, m: &'ast Macro) { + let Macro { path, .. } = m; + + if path.is_ident("atom") { + if let Some(Lit::Str(string)) = m.parse_body::().ok() { + self.static_strs.insert(string.value()); + } + } else if path.is_ident("read_heap_cell") { + if let Some(m) = m.parse_body::().ok() { + self.visit_expr(&m.expr); + + for e in m.arms { + self.visit_arm(&e); + } + } + } else { + if let Some(m) = m.parse_body::().ok() { + for e in m.args { + self.visit_expr(&e); + } + } + } + } +} + +pub fn index_static_strings() -> TokenStream { + use quote::*; + + use std::ffi::OsStr; + use std::fs::File; + use std::io::Read; + + use walkdir::WalkDir; + + fn filter_rust_files(e: &walkdir::DirEntry) -> bool { + if e.path().is_dir() { + return true; + } + + e.path().extension().and_then(OsStr::to_str) == Some("rs") + } + + let mut visitor = StaticStrVisitor::new(); + + for entry in WalkDir::new("src/").into_iter().filter_entry(filter_rust_files) { + let entry = entry.unwrap(); + + if entry.path().is_dir() { + continue; + } + + let mut file = match File::open(entry.path()) { + Ok(file) => file, + Err(_) => continue, + }; + + let mut src = String::new(); + + match file.read_to_string(&mut src) { + Ok(_) => {} + Err(e) => { + panic!("error reading file: {:?}", e); + } + } + + let syntax = match syn::parse_file(&src) { + Ok(s) => s, + Err(e) => { + panic!("parse error: {} in file {:?}", e, entry.path()); + } + }; + + visitor.visit_file(&syntax); + } + + let indices = (0 .. visitor.static_strs.len()).map(|i| i << 3); + let indices_iter = indices.clone(); + + let static_strs_len = visitor.static_strs.len(); + let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); + + quote! { + use phf; + + static STRINGS: [&'static str; #static_strs_len] = [ + #( + #static_strs, + )* + ]; + + #[macro_export] + macro_rules! atom { + #((#static_strs) => { Atom { index: #indices_iter } };)* + } + + static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! { + #(#static_strs => { Atom { index: #indices } },)* + }; + } +} diff --git a/src/allocator.rs b/src/allocator.rs index cc8de305c..c29adc928 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,10 +1,9 @@ -use prolog_parser::ast::*; -use prolog_parser::temp_v; +use crate::parser::ast::*; +use crate::temp_v; use crate::fixtures::*; use crate::forms::*; use crate::machine::machine_indices::*; -use crate::targets::*; use std::cell::Cell; use std::rc::Rc; @@ -14,7 +13,7 @@ pub(crate) trait Allocator<'a> { fn mark_anon_var(&mut self, _: Level, _: GenContext, _: &mut Vec) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn mark_non_var( &mut self, _: Level, @@ -22,10 +21,10 @@ pub(crate) trait Allocator<'a> { _: &'a Cell, _: &mut Vec, ) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn mark_reserved_var( &mut self, - _: Rc, + _: Rc, _: Level, _: &'a Cell, _: GenContext, @@ -33,21 +32,21 @@ pub(crate) trait Allocator<'a> { _: RegType, _: bool, ) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn mark_var( &mut self, - _: Rc, + _: Rc, _: Level, _: &'a Cell, _: GenContext, _: &mut Vec, ) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn reset(&mut self); fn reset_contents(&mut self) {} fn reset_arg(&mut self, _: usize); - fn reset_at_head(&mut self, _: &Vec>); + fn reset_at_head(&mut self, args: &Vec); fn advance_arg(&mut self); @@ -83,17 +82,17 @@ pub(crate) trait Allocator<'a> { perm_vs } - fn get(&self, var: Rc) -> RegType { + fn get(&self, var: Rc) -> RegType { self.bindings() .get(&var) .map_or(temp_v!(0), |v| v.as_reg_type()) } - fn is_unbound(&self, var: Rc) -> bool { + fn is_unbound(&self, var: Rc) -> bool { self.get(var).reg_num() == 0 } - fn record_register(&mut self, var: Rc, r: RegType) { + fn record_register(&mut self, var: Rc, r: RegType) { match self.bindings_mut().get_mut(&var).unwrap() { &mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(), &mut VarData::Perm(ref mut s) => *s = r.reg_num(), diff --git a/src/arena.rs b/src/arena.rs new file mode 100644 index 000000000..2ba73d27e --- /dev/null +++ b/src/arena.rs @@ -0,0 +1,797 @@ +use crate::machine::loader::LiveLoadState; +use crate::machine::machine_indices::*; +use crate::machine::streams::*; +use crate::read::*; + +use modular_bitfield::prelude::*; +use ordered_float::OrderedFloat; +use rug::{Integer, Rational}; + +use std::alloc; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::mem; +use std::net::TcpListener; +use std::ops::{Deref, DerefMut}; +use std::ptr; + +#[macro_export] +macro_rules! arena_alloc { + ($e:expr, $arena:expr) => {{ + let result = $e; + #[allow(unused_unsafe)] + unsafe { $arena.alloc(result) } + }}; +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)] +#[bits = 7] +pub enum ArenaHeaderTag { + F64 = 0b01, + Integer = 0b10, + Rational = 0b11, + OssifiedOpDir = 0b0000100, + LiveLoadState = 0b0001000, + InactiveLoadState = 0b1011000, + InputFileStream = 0b10000, + OutputFileStream = 0b10100, + NamedTcpStream = 0b011100, + NamedTlsStream = 0b100000, + // PausedPrologStream = 0b101100, + ReadlineStream = 0b110000, + StaticStringStream = 0b110100, + ByteStream = 0b111000, + // StandardInputStream = 0b100, + StandardOutputStream = 0b1100, + StandardErrorStream = 0b11000, + NullStream = 0b111100, + TcpListener = 0b1000000, + Dropped = 0b1000100, +} + +#[bitfield] +#[derive(Copy, Clone, Debug)] +pub struct ArenaHeader { + size: B56, + m: bool, + tag: ArenaHeaderTag, +} + +const_assert!(mem::size_of::() == 8); + +impl ArenaHeader { + #[inline] + pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self { + ArenaHeader::new() + .with_size(size) + .with_tag(tag) + .with_m(false) + } + + #[inline] + pub fn get_tag(self) -> ArenaHeaderTag { + self.tag() + } +} + +#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)] +pub struct TypedArenaPtr(ptr::NonNull); + +impl Hash for TypedArenaPtr { + #[inline(always)] + fn hash(&self, hasher: &mut H) { + (&*self as &T).hash(hasher) + } +} + +impl Clone for TypedArenaPtr { + fn clone(&self) -> Self { + TypedArenaPtr(self.0) + } +} + +impl Copy for TypedArenaPtr {} + +impl Deref for TypedArenaPtr { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { self.0.as_ref() } + } +} + +impl DerefMut for TypedArenaPtr { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { self.0.as_mut() } + } +} + +impl fmt::Display for TypedArenaPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", **self) + } +} + +impl TypedArenaPtr { + #[inline] + pub const fn new(data: *mut T) -> Self { + unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) } + } + + #[inline] + pub fn as_ptr(&self) -> *mut T { + self.0.as_ptr() + } + + #[inline] + pub fn header_ptr(&self) -> *const ArenaHeader { + let mut ptr = self.as_ptr() as *const u8 as usize; + ptr -= mem::size_of::<*const ArenaHeader>(); + ptr as *const ArenaHeader + } + + #[inline] + fn header_ptr_mut(&mut self) -> *mut ArenaHeader { + let mut ptr = self.as_ptr() as *const u8 as usize; + ptr -= mem::size_of::<*const ArenaHeader>(); + ptr as *mut ArenaHeader + } + + #[inline] + pub fn get_mark_bit(&self) -> bool { + unsafe { (*self.header_ptr()).m() } + } + + #[inline] + pub fn set_tag(&mut self, tag: ArenaHeaderTag) { + unsafe { (*self.header_ptr_mut()).set_tag(tag); } + } + + #[inline] + pub fn get_tag(&self) -> ArenaHeaderTag { + unsafe { (*self.header_ptr()).get_tag() } + } + + #[inline] + pub fn mark(&mut self) { + unsafe { + (*self.header_ptr_mut()).set_m(true); + } + } + + #[inline] + pub fn unmark(&mut self) { + unsafe { + (*self.header_ptr_mut()).set_m(false); + } + } +} + +pub trait ArenaAllocated { + type PtrToAllocated; + + fn tag() -> ArenaHeaderTag; + fn size(&self) -> usize; + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated + where + Self: Sized; +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct F64Ptr(pub TypedArenaPtr>); + +impl fmt::Display for F64Ptr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", *self) + } +} + +impl Deref for F64Ptr { + type Target = TypedArenaPtr>; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for F64Ptr { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl ArenaAllocated for OrderedFloat { + type PtrToAllocated = F64Ptr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::F64 + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + F64Ptr(TypedArenaPtr::new(dst as *mut Self)) + } + } +} + +impl ArenaAllocated for Integer { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::Integer + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for Rational { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::Rational + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for OssifiedOpDir { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::OssifiedOpDir + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for LiveLoadState { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::LiveLoadState + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for TcpListener { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::TcpListener + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +#[derive(Clone, Copy, Debug)] +struct AllocSlab { + next: *mut AllocSlab, + header: ArenaHeader, +} + +#[derive(Debug)] +pub struct Arena(*mut AllocSlab); + +unsafe impl Send for Arena {} +unsafe impl Sync for Arena {} + +impl Arena { + #[inline] + pub fn new() -> Self { + Arena(ptr::null_mut()) + } + + pub unsafe fn alloc(&mut self, value: T) -> T::PtrToAllocated { + let size = value.size() + mem::size_of::(); + + let align = mem::align_of::(); + let layout = alloc::Layout::from_size_align_unchecked(size, align); + + let slab = alloc::alloc(layout) as *mut AllocSlab; + + (*slab).next = self.0; + (*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag()); + + let offset = (*slab).payload_offset(); + let result = value.copy_to_arena(offset as *mut T); + + self.0 = slab; + + result + } +} + +unsafe fn drop_slab_in_place(value: &mut AllocSlab) { + match value.header.tag() { + ArenaHeaderTag::Integer => { + ptr::drop_in_place(value.payload_offset() as *mut Integer); + } + ArenaHeaderTag::Rational => { + ptr::drop_in_place(value.payload_offset() as *mut Rational); + } + ArenaHeaderTag::InputFileStream => { + ptr::drop_in_place(value.payload_offset() as *mut InputFileStream); + } + ArenaHeaderTag::OutputFileStream => { + ptr::drop_in_place(value.payload_offset() as *mut OutputFileStream); + } + ArenaHeaderTag::NamedTcpStream => { + ptr::drop_in_place(value.payload_offset() as *mut NamedTcpStream); + } + ArenaHeaderTag::NamedTlsStream => { + ptr::drop_in_place(value.payload_offset() as *mut NamedTlsStream); + } + // ArenaHeaderTag::PausedPrologStream => { + // // idea: PausedPrologStream with only the buffer of unread characters. + // // no stream to be wrapped, no nuttin'. + // ptr::drop_in_place(value.payload_offset() as *mut PausedPrologStream); + // } + ArenaHeaderTag::ReadlineStream => { + ptr::drop_in_place(value.payload_offset() as *mut ReadlineStream); + } + ArenaHeaderTag::StaticStringStream => { + ptr::drop_in_place(value.payload_offset() as *mut StaticStringStream); + } + ArenaHeaderTag::ByteStream => { + ptr::drop_in_place(value.payload_offset() as *mut ByteStream); + } + ArenaHeaderTag::OssifiedOpDir => { + ptr::drop_in_place( + mem::transmute::<_, *mut OssifiedOpDir>(value.payload_offset()) + ); + } + ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => { + ptr::drop_in_place( + mem::transmute::<_, *mut LiveLoadState>(value.payload_offset()) + ); + } + ArenaHeaderTag::Dropped => { + } + ArenaHeaderTag::TcpListener => { + ptr::drop_in_place(value.payload_offset() as *mut TcpListener); + } + ArenaHeaderTag::F64 | ArenaHeaderTag::StandardOutputStream | + ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::NullStream => { + } + } +} + +impl Drop for Arena { + fn drop(&mut self) { + let mut ptr = self.0; + + while !ptr.is_null() { + unsafe { + let ptr_r = &*ptr; + + let layout = alloc::Layout::from_size_align_unchecked( + ptr_r.slab_size(), + mem::align_of::(), + ); + + drop_slab_in_place(&mut *ptr); + + let next_ptr = ptr_r.next; + alloc::dealloc(ptr as *mut u8, layout); + ptr = next_ptr; + } + } + + self.0 = ptr::null_mut(); + } +} + +const_assert!(mem::size_of::() == 16); + +impl AllocSlab { + #[inline] + fn slab_size(&self) -> usize { + self.header.size() as usize + mem::size_of::() + } + + fn payload_offset(&self) -> *const u8 { + let mut ptr = (self as *const AllocSlab) as usize; + ptr += mem::size_of::(); + ptr as *const u8 + } +} + +const_assert!(mem::size_of::>() == 8); + +#[cfg(test)] +mod tests { + use crate::machine::mock_wam::*; + use crate::machine::partial_string::*; + + use ordered_float::OrderedFloat; + use rug::{Integer, Rational}; + + #[test] + fn float_ptr_cast() { + let mut wam = MockWAM::new(); + + let f = OrderedFloat(0f64); + let mut fp = arena_alloc!(f, &mut wam.machine_st.arena); + let cell = HeapCellValue::from(fp); + + assert_eq!(cell.get_tag(), HeapCellValueTag::F64); + assert_eq!(fp.get_mark_bit(), false); + assert_eq!(**fp, f); + + fp.mark(); + + assert_eq!(fp.get_mark_bit(), true); + + read_heap_cell!(cell, + (HeapCellValueTag::F64, ptr) => { + assert_eq!(**ptr, f) + } + _ => { unreachable!() } + ); + } + + #[test] + fn heap_cell_value_const_cast() { + let mut wam = MockWAM::new(); + let const_value = HeapCellValue::from(ConsPtr::build_with( + 0x0000_5555_ff00_0431 as *const _, + ConsPtrMaskTag::Cons, + )); + + match const_value.to_untyped_arena_ptr() { + Some(arena_ptr) => { + assert_eq!(arena_ptr.into_bytes(), const_value.into_bytes()); + } + None => { + assert!(false); + } + } + + let stream = Stream::from_static_string("test", &mut wam.machine_st.arena); + let stream_cell = + HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons)); + + match stream_cell.to_untyped_arena_ptr() { + Some(arena_ptr) => { + assert_eq!(arena_ptr.into_bytes(), stream_cell.into_bytes()); + } + None => { + assert!(false); + } + } + } + + #[test] + fn heap_put_literal_tests() { + let mut wam = MockWAM::new(); + + // integer + + let big_int = 2 * Integer::from(1u64 << 63); + let big_int_ptr: TypedArenaPtr = arena_alloc!(big_int, &mut wam.machine_st.arena); + + assert!(!big_int_ptr.as_ptr().is_null()); + + let cell = HeapCellValue::from(Literal::Integer(big_int_ptr)); + assert_eq!(cell.get_tag(), HeapCellValueTag::Cons); + + let untyped_arena_ptr = match cell.to_untyped_arena_ptr() { + Some(ptr) => ptr, + None => { + assert!(false); + unreachable!() + } + }; + + match_untyped_arena_ptr!(untyped_arena_ptr, + (ArenaHeaderTag::Integer, n) => { + assert_eq!(&*n, &(2 * Integer::from(1u64 << 63))) + } + _ => unreachable!() + ); + + read_heap_cell!(cell, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Integer, n) => { + assert_eq!(&*n, &(2 * Integer::from(1u64 << 63))) + } + _ => { unreachable!() } + ) + } + _ => { unreachable!() } + ); + + // rational + + let big_rat = 2 * Rational::from(1u64 << 63); + let big_rat_ptr: TypedArenaPtr = arena_alloc!(big_rat, &mut wam.machine_st.arena); + + assert!(!big_rat_ptr.as_ptr().is_null()); + + let rat_cell = typed_arena_ptr_as_cell!(big_rat_ptr); + assert_eq!(cell.get_tag(), HeapCellValueTag::Cons); + + match rat_cell.to_untyped_arena_ptr() { + Some(untyped_arena_ptr) => { + assert_eq!( + Some(big_rat_ptr.header_ptr()), + Some(untyped_arena_ptr.into()), + ); + } + None => { + assert!(false); // we fail. + } + } + + // assert_eq!(wam.machine_st.heap[1usize].get_tag(), HeapCellValueTag::Cons); + + read_heap_cell!(rat_cell, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Rational, n) => { + assert_eq!(&*n, &(2 * Rational::from(1u64 << 63))); + } + _ => unreachable!() + ) + } + _ => { unreachable!() } + ); + + // atom + + let f_atom = atom!("f"); + let g_atom = atom!("g"); + + assert_eq!(f_atom.as_str(), "f"); + assert_eq!(g_atom.as_str(), "g"); + + let f_atom_cell = atom_as_cell!(f_atom); + let g_atom_cell = atom_as_cell!(g_atom); + + assert_eq!(f_atom_cell.get_tag(), HeapCellValueTag::Atom); + + match f_atom_cell.to_atom() { + Some(atom) => { + assert_eq!(f_atom, atom); + assert_eq!(atom.as_str(), "f"); + } + None => { + assert!(false); + } + } + + read_heap_cell!(f_atom_cell, + (HeapCellValueTag::Atom, (atom, arity)) => { + assert_eq!(f_atom, atom); + assert_eq!(arity, 0); + assert_eq!(atom.as_str(), "f"); + } + _ => { unreachable!() } + ); + + read_heap_cell!(g_atom_cell, + (HeapCellValueTag::Atom, (atom, arity)) => { + assert_eq!(g_atom, atom); + assert_eq!(arity, 0); + assert_eq!(atom.as_str(), "g"); + } + _ => { unreachable!() } + ); + + // complete string + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "ronan", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr); + + match pstr_cell.to_pstr() { + Some(pstr) => { + assert_eq!(pstr.as_str_from(0), "ronan"); + } + None => { + assert!(false); + } + } + + read_heap_cell!(pstr_cell, + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + assert_eq!(pstr.as_str_from(0), "ronan"); + } + _ => { unreachable!() } + ); + + // fixnum + + let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3)); + + assert_eq!(fixnum_cell.get_tag(), HeapCellValueTag::Fixnum); + + match fixnum_cell.to_fixnum() { + Some(n) => assert_eq!(n.get_num(), 3), + None => assert!(false), + } + + read_heap_cell!(fixnum_cell, + (HeapCellValueTag::Fixnum, n) => { + assert_eq!(n.get_num(), 3); + } + _ => { unreachable!() } + ); + + let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 55)); + + assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum); + + match fixnum_b_cell.to_fixnum() { + Some(n) => assert_eq!(n.get_num(), 1 << 55), + None => assert!(false), + } + + match Fixnum::build_with_checked(1 << 57) { + Ok(_) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(i64::MAX) { + Ok(_) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(i64::MIN) { + Ok(_) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(-1) { + Ok(n) => assert_eq!(n.get_num(), -1), + _ => assert!(false), + } + + match Fixnum::build_with_checked((1 << 56) - 1) { + Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1), + _ => assert!(false), + } + + match Fixnum::build_with_checked(-(1 << 56)) { + Ok(n) => assert_eq!(n.get_num(), -(1 << 56)), + _ => assert!(false), + } + + match Fixnum::build_with_checked(-(1 << 56) - 1) { + Ok(_n) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(-1) { + Ok(n) => assert_eq!(-n, Fixnum::build_with(1)), + _ => assert!(false), + } + + // float + + let float = OrderedFloat(3.1415926f64); + let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena); + + assert!(!float_ptr.as_ptr().is_null()); + + let float_cell = typed_arena_ptr_as_cell!(float_ptr); + assert_eq!(cell.get_tag(), HeapCellValueTag::Cons); + + match float_cell.to_untyped_arena_ptr() { + Some(untyped_arena_ptr) => { + assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),); + } + None => { + assert!(false); // we fail. + } + } + + // char + + let c = 'c'; + let char_cell = char_as_cell!(c); + + read_heap_cell!(char_cell, + (HeapCellValueTag::Char, c) => { + assert_eq!(c, 'c'); + } + _ => { unreachable!() } + ); + + let c = 'Ћ'; + let cyrillic_char_cell = char_as_cell!(c); + + read_heap_cell!(cyrillic_char_cell, + (HeapCellValueTag::Char, c) => { + assert_eq!(c, 'Ћ'); + } + _ => { unreachable!() } + ); + + // empty list + + let cell = empty_list_as_cell!(); + + read_heap_cell!(cell, + (HeapCellValueTag::Atom, (el, _arity)) => { + assert_eq!(el.flat_index() as usize, empty_list_as_cell!().get_value()); + assert_eq!(el.as_str(), "[]"); + } + _ => { unreachable!() } + ); + } +} diff --git a/src/arithmetic.rs b/src/arithmetic.rs index f5a3beeb2..d09187f81 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -1,18 +1,19 @@ -use prolog_parser::ast::*; -use prolog_parser::{atom, clause_name}; - +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; +use crate::types::*; + +use crate::parser::ast::*; +use crate::parser::rug::ops::PowAssign; +use crate::parser::rug::{Assign, Integer, Rational}; -use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::rug::ops::PowAssign; -use crate::rug::{Assign, Integer, Rational}; use ordered_float::*; use std::cell::Cell; @@ -20,7 +21,7 @@ use std::cmp::{max, min, Ordering}; use std::convert::TryFrom; use std::f64; use std::num::FpCategory; -use std::ops::{Add, Div, Mul, Neg, Sub}; +use std::ops::Div; use std::rc::Rc; use std::vec::Vec; @@ -37,31 +38,30 @@ impl<'a> ArithInstructionIterator<'a> { .push(TermIterState::subterm_to_state(lvl, term)); } - fn new(term: &'a Term) -> Result { + fn from(term: &'a Term) -> Result { let state = match term { - &Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), - &Term::Clause(ref cell, ref name, ref terms, ref fixity) => { - match ClauseType::from(name.clone(), terms.len(), fixity.clone()) { - ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => { - Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) - } - ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { - let ct = ClauseType::Named(clause_name!("float"), 1, CodeIndex::default()); - Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) - } - _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name.clone(), fixity.clone()), - terms.len(), - )), - }? - } - &Term::Constant(ref cell, ref cons) => { - TermIterState::Constant(Level::Shallow, cell, cons) - } - &Term::Cons(_, _, _) => { - return Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2)) - } - &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Shallow, cell, var.clone()), + Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), + Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) { + ct @ ClauseType::Named(..) => { + Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) + } + ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { + let ct = ClauseType::Named(atom!("float"), 1, CodeIndex::default()); + Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) + } + _ => Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(*name), + terms.len(), + )), + }?, + Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons), + Term::Cons(..) | Term::PartialString(..) => { + return Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(atom!(".")), + 2, + )) + } + Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, var.clone()), }; Ok(ArithInstructionIterator { @@ -72,9 +72,9 @@ impl<'a> ArithInstructionIterator<'a> { #[derive(Debug)] pub(crate) enum ArithTermRef<'a> { - Constant(&'a Constant), - Op(ClauseName, usize), // name, arity. - Var(&'a Cell, Rc), + Literal(&'a Literal), + Op(Atom, usize), // name, arity. + Var(&'a Cell, Rc), } impl<'a> Iterator for ArithInstructionIterator<'a> { @@ -97,14 +97,20 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { ct, subterms, )); - self.push_subterm(lvl, subterms[child_num].as_ref()); + + self.push_subterm(lvl, &subterms[child_num]); } } - TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))), + TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))), TermIterState::Var(_, cell, var) => { - return Some(Ok(ArithTermRef::Var(cell, var.clone()))) + return Some(Ok(ArithTermRef::Var(cell, var.clone()))); + } + _ => { + return Some(Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(atom!(".")), + 2, + ))); } - _ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))), }; } @@ -129,8 +135,29 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term { type Iter = ArithInstructionIterator<'a>; fn iter(self) -> Result { - ArithInstructionIterator::new(self) + ArithInstructionIterator::from(self) + } +} + +fn push_literal(interm: &mut Vec, c: &Literal) -> Result<(), ArithmeticError> { + match c { + Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))), + Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))), + Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))), + Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))), + Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(f64::consts::E)), + )), + Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(f64::consts::PI)), + )), + Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(f64::EPSILON)), + )), + _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)), } + + Ok(()) } impl<'a> ArithmeticEvaluator<'a> { @@ -143,68 +170,64 @@ impl<'a> ArithmeticEvaluator<'a> { } fn get_unary_instr( - name: ClauseName, + &self, + name: Atom, a1: ArithmeticTerm, t: usize, ) -> Result { - match name.as_str() { - "abs" => Ok(ArithmeticInstruction::Abs(a1, t)), - "-" => Ok(ArithmeticInstruction::Neg(a1, t)), - "+" => Ok(ArithmeticInstruction::Plus(a1, t)), - "cos" => Ok(ArithmeticInstruction::Cos(a1, t)), - "sin" => Ok(ArithmeticInstruction::Sin(a1, t)), - "tan" => Ok(ArithmeticInstruction::Tan(a1, t)), - "log" => Ok(ArithmeticInstruction::Log(a1, t)), - "exp" => Ok(ArithmeticInstruction::Exp(a1, t)), - "sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)), - "acos" => Ok(ArithmeticInstruction::ACos(a1, t)), - "asin" => Ok(ArithmeticInstruction::ASin(a1, t)), - "atan" => Ok(ArithmeticInstruction::ATan(a1, t)), - "float" => Ok(ArithmeticInstruction::Float(a1, t)), - "truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)), - "round" => Ok(ArithmeticInstruction::Round(a1, t)), - "ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)), - "floor" => Ok(ArithmeticInstruction::Floor(a1, t)), - "sign" => Ok(ArithmeticInstruction::Sign(a1, t)), - "\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name, None), - 1, - )), + match name { + atom!("abs") => Ok(ArithmeticInstruction::Abs(a1, t)), + atom!("-") => Ok(ArithmeticInstruction::Neg(a1, t)), + atom!("+") => Ok(ArithmeticInstruction::Plus(a1, t)), + atom!("cos") => Ok(ArithmeticInstruction::Cos(a1, t)), + atom!("sin") => Ok(ArithmeticInstruction::Sin(a1, t)), + atom!("tan") => Ok(ArithmeticInstruction::Tan(a1, t)), + atom!("log") => Ok(ArithmeticInstruction::Log(a1, t)), + atom!("exp") => Ok(ArithmeticInstruction::Exp(a1, t)), + atom!("sqrt") => Ok(ArithmeticInstruction::Sqrt(a1, t)), + atom!("acos") => Ok(ArithmeticInstruction::ACos(a1, t)), + atom!("asin") => Ok(ArithmeticInstruction::ASin(a1, t)), + atom!("atan") => Ok(ArithmeticInstruction::ATan(a1, t)), + atom!("float") => Ok(ArithmeticInstruction::Float(a1, t)), + atom!("truncate") => Ok(ArithmeticInstruction::Truncate(a1, t)), + atom!("round") => Ok(ArithmeticInstruction::Round(a1, t)), + atom!("ceiling") => Ok(ArithmeticInstruction::Ceiling(a1, t)), + atom!("floor") => Ok(ArithmeticInstruction::Floor(a1, t)), + atom!("sign") => Ok(ArithmeticInstruction::Sign(a1, t)), + atom!("\\") => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)), } } fn get_binary_instr( - name: ClauseName, + &self, + name: Atom, a1: ArithmeticTerm, a2: ArithmeticTerm, t: usize, ) -> Result { - match name.as_str() { - "+" => Ok(ArithmeticInstruction::Add(a1, a2, t)), - "-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)), - "/" => Ok(ArithmeticInstruction::Div(a1, a2, t)), - "//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)), - "max" => Ok(ArithmeticInstruction::Max(a1, a2, t)), - "min" => Ok(ArithmeticInstruction::Min(a1, a2, t)), - "div" => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)), - "rdiv" => Ok(ArithmeticInstruction::RDiv(a1, a2, t)), - "*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)), - "**" => Ok(ArithmeticInstruction::Pow(a1, a2, t)), - "^" => Ok(ArithmeticInstruction::IntPow(a1, a2, t)), - ">>" => Ok(ArithmeticInstruction::Shr(a1, a2, t)), - "<<" => Ok(ArithmeticInstruction::Shl(a1, a2, t)), - "/\\" => Ok(ArithmeticInstruction::And(a1, a2, t)), - "\\/" => Ok(ArithmeticInstruction::Or(a1, a2, t)), - "xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)), - "mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)), - "rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)), - "gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)), - "atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name, None), - 2, - )), + match name { + atom!("+") => Ok(ArithmeticInstruction::Add(a1, a2, t)), + atom!("-") => Ok(ArithmeticInstruction::Sub(a1, a2, t)), + atom!("/") => Ok(ArithmeticInstruction::Div(a1, a2, t)), + atom!("//") => Ok(ArithmeticInstruction::IDiv(a1, a2, t)), + atom!("max") => Ok(ArithmeticInstruction::Max(a1, a2, t)), + atom!("min") => Ok(ArithmeticInstruction::Min(a1, a2, t)), + atom!("div") => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)), + atom!("rdiv") => Ok(ArithmeticInstruction::RDiv(a1, a2, t)), + atom!("*") => Ok(ArithmeticInstruction::Mul(a1, a2, t)), + atom!("**") => Ok(ArithmeticInstruction::Pow(a1, a2, t)), + atom!("^") => Ok(ArithmeticInstruction::IntPow(a1, a2, t)), + atom!(">>") => Ok(ArithmeticInstruction::Shr(a1, a2, t)), + atom!("<<") => Ok(ArithmeticInstruction::Shl(a1, a2, t)), + atom!("/\\") => Ok(ArithmeticInstruction::And(a1, a2, t)), + atom!("\\/") => Ok(ArithmeticInstruction::Or(a1, a2, t)), + atom!("xor") => Ok(ArithmeticInstruction::Xor(a1, a2, t)), + atom!("mod") => Ok(ArithmeticInstruction::Mod(a1, a2, t)), + atom!("rem") => Ok(ArithmeticInstruction::Rem(a1, a2, t)), + atom!("gcd") => Ok(ArithmeticInstruction::Gcd(a1, a2, t)), + atom!("atan2") => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)), } } @@ -219,7 +242,7 @@ impl<'a> ArithmeticEvaluator<'a> { fn instr_from_clause( &mut self, - name: ClauseName, + name: Atom, arity: usize, ) -> Result { match arity { @@ -233,7 +256,7 @@ impl<'a> ArithmeticEvaluator<'a> { a1.interm_or(0) }; - Self::get_unary_instr(name, a1, ninterm) + self.get_unary_instr(name, a1, ninterm) } 2 => { let a2 = self.interm.pop().unwrap(); @@ -257,60 +280,22 @@ impl<'a> ArithmeticEvaluator<'a> { min_interm }; - Self::get_binary_instr(name, a1, a2, ninterm) + self.get_binary_instr(name, a1, a2, ninterm) } _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name, None), + Literal::Atom(name), arity, )), } } - fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> { - match c { - &Constant::Fixnum(n) => self.interm.push(ArithmeticTerm::Number(Number::Fixnum(n))), - &Constant::Integer(ref n) => self - .interm - .push(ArithmeticTerm::Number(Number::Integer(n.clone()))), - &Constant::Float(ref n) => self - .interm - .push(ArithmeticTerm::Number(Number::Float(n.clone()))), - &Constant::Rational(ref n) => self - .interm - .push(ArithmeticTerm::Number(Number::Rational(n.clone()))), - &Constant::Atom(ref name, _) if name.as_str() == "e" => { - self.interm - .push(ArithmeticTerm::Number(Number::Float(OrderedFloat( - f64::consts::E, - )))) - } - &Constant::Atom(ref name, _) if name.as_str() == "pi" => { - self.interm - .push(ArithmeticTerm::Number(Number::Float(OrderedFloat( - f64::consts::PI, - )))) - } - &Constant::Atom(ref name, _) if name.as_str() == "epsilon" => { - self.interm - .push(ArithmeticTerm::Number(Number::Float(OrderedFloat( - f64::EPSILON, - )))) - } - _ => return Err(ArithmeticError::NonEvaluableFunctor(c.clone(), 0)), - } - - Ok(()) - } - - pub(crate) fn eval(&mut self, src: Iter) -> Result - where - Iter: ArithmeticTermIter<'a>, - { + pub(crate) fn eval(&mut self, src: &'a Term) -> Result { let mut code = vec![]; + let mut iter = src.iter()?; - for term_ref in src.iter()? { + while let Some(term_ref) = iter.next() { match term_ref? { - ArithTermRef::Constant(c) => self.push_constant(c)?, + ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?, ArithTermRef::Var(cell, name) => { let r = if cell.get().norm().reg_num() == 0 { match self.bindings.get(&name) { @@ -335,27 +320,31 @@ impl<'a> ArithmeticEvaluator<'a> { } // integer division rounding function -- 9.1.3.1. -pub(crate) fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> { +pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number { match n { - &Number::Integer(_) => RefOrOwned::Borrowed(n), - &Number::Float(OrderedFloat(f)) => RefOrOwned::Owned(Number::from( - Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)), - )), - &Number::Fixnum(n) => RefOrOwned::Owned(Number::from(n)), + &Number::Integer(_) | &Number::Fixnum(_) => *n, + &Number::Float(OrderedFloat(f)) => fixnum!(Number, f.round() as i64, arena), &Number::Rational(ref r) => { let r_ref = r.fract_floor_ref(); let (mut fract, mut floor) = (Rational::new(), Integer::new()); (&mut fract, &mut floor).assign(r_ref); - RefOrOwned::Owned(Number::from(floor)) + Number::Integer(arena_alloc!(floor, arena)) } } } +impl From for Integer { + #[inline] + fn from(n: Fixnum) -> Integer { + Integer::from(n.get_num()) + } +} + // floating point rounding function -- 9.1.4.1. pub(crate) fn rnd_f(n: &Number) -> f64 { match n { - &Number::Fixnum(n) => n as f64, + &Number::Fixnum(n) => n.get_num() as f64, &Number::Integer(ref n) => n.to_f64(), &Number::Float(OrderedFloat(f)) => f, &Number::Rational(ref r) => r.to_f64(), @@ -392,27 +381,27 @@ where } #[inline] -fn float_fn_to_f(n: isize) -> Result { +pub(crate) fn float_fn_to_f(n: i64) -> Result { classify_float(n as f64, rnd_f) } #[inline] -fn float_i_to_f(n: &Integer) -> Result { +pub(crate) fn float_i_to_f(n: &Integer) -> Result { classify_float(n.to_f64(), rnd_f) } #[inline] -fn float_r_to_f(r: &Rational) -> Result { +pub(crate) fn float_r_to_f(r: &Rational) -> Result { classify_float(r.to_f64(), rnd_f) } #[inline] -fn add_f(f1: f64, f2: f64) -> Result, EvalError> { +pub(crate) fn add_f(f1: f64, f2: f64) -> Result, EvalError> { Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?)) } #[inline] -fn mul_f(f1: f64, f2: f64) -> Result, EvalError> { +pub(crate) fn mul_f(f1: f64, f2: f64) -> Result, EvalError> { Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?)) } @@ -425,161 +414,36 @@ fn div_f(f1: f64, f2: f64) -> Result, EvalError> { } } -impl Add for Number { - type Output = Result; - - fn add(self, rhs: Number) -> Self::Output { - match (self, rhs) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - Ok(if let Some(result) = n1.checked_add(n2) { - Number::Fixnum(result) - } else { - Number::from(Integer::from(n1) + Integer::from(n2)) - }) - } - (Number::Fixnum(n1), Number::Integer(n2)) - | (Number::Integer(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Integer::from(n1) + &*n2)) - } - (Number::Fixnum(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Rational::from(n1) + &*n2)) - } - (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { - Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?)) - } - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i - } - (Number::Integer(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { - Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?)) - } - (Number::Integer(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Integer(n1)) => { - Ok(Number::from(Rational::from(&*n1) + &*n2)) - } - (Number::Rational(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { - Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?)) - } - (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { - Ok(Number::Float(add_f(f1, f2)?)) - } - (Number::Rational(r1), Number::Rational(r2)) => { - Ok(Number::from(Rational::from(&*r1) + &*r2)) - } - } - } -} - -impl Neg for Number { - type Output = Number; - - fn neg(self) -> Self::Output { - match self { - Number::Fixnum(n) => { - if let Some(n) = n.checked_neg() { - Number::Fixnum(n) - } else { - Number::from(-Integer::from(n)) - } - } - Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))), - Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), - Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))), - } - } -} - -impl Sub for Number { - type Output = Result; - - fn sub(self, rhs: Number) -> Self::Output { - self.add(-rhs) - } -} - -impl Mul for Number { - type Output = Result; - - fn mul(self, rhs: Number) -> Self::Output { - match (self, rhs) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - Ok(if let Some(result) = n1.checked_mul(n2) { - Number::Fixnum(result) - } else { - Number::from(Integer::from(n1) * Integer::from(n2)) - }) - } - (Number::Fixnum(n1), Number::Integer(n2)) - | (Number::Integer(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Integer::from(n1) * &*n2)) - } - (Number::Fixnum(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Rational::from(n1) * &*n2)) - } - (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { - Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?)) - } - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i - } - (Number::Integer(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { - Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?)) - } - (Number::Integer(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Integer(n1)) => { - Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2))) - } - (Number::Rational(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { - Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?)) - } - (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { - Ok(Number::Float(mul_f(f1, f2)?)) - } - (Number::Rational(r1), Number::Rational(r2)) => { - Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2))) - } - } - } -} - impl Div for Number { type Output = Result; fn div(self, rhs: Number) -> Self::Output { match (self, rhs) { (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f( - float_fn_to_f(n1)?, - float_fn_to_f(n2)?, + float_fn_to_f(n1.get_num())?, + float_fn_to_f(n2.get_num())?, )?)), (Number::Fixnum(n1), Number::Integer(n2)) => Ok(Number::Float(div_f( - float_fn_to_f(n1)?, + float_fn_to_f(n1.get_num())?, float_i_to_f(&n2)?, )?)), (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f( float_i_to_f(&n1)?, - float_fn_to_f(n2)?, + float_fn_to_f(n2.get_num())?, )?)), (Number::Fixnum(n1), Number::Rational(n2)) => Ok(Number::Float(div_f( - float_fn_to_f(n1)?, + float_fn_to_f(n1.get_num())?, float_r_to_f(&n2)?, )?)), (Number::Rational(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f( float_r_to_f(&n1)?, - float_fn_to_f(n2)?, + float_fn_to_f(n2.get_num())?, )?)), (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => { - Ok(Number::Float(div_f(float_fn_to_f(n1)?, n2)?)) + Ok(Number::Float(div_f(float_fn_to_f(n1.get_num())?, n2)?)) } (Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => { - Ok(Number::Float(div_f(n1, float_fn_to_f(n2)?)?)) + Ok(Number::Float(div_f(n1, float_fn_to_f(n2.get_num())?)?)) } (Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f( float_i_to_f(&n1)?, @@ -620,14 +484,14 @@ impl PartialEq for Number { fn eq(&self, rhs: &Self) -> bool { match (self, rhs) { (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2), - (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2), - (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), - (&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2), - (&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), - (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).eq(&n2), - (&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2 as f64)), + (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().eq(&**n2), + (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()), + (&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.get_num().eq(&**n2), + (&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()), + (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2), + (&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2.get_num() as f64)), (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2), - (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(&n2), + (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(n2), (&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())), (&Number::Integer(ref n1), &Number::Rational(ref n2)) => { #[cfg(feature = "num")] @@ -659,6 +523,46 @@ impl PartialEq for Number { impl Eq for Number {} +impl PartialOrd for Number { + #[inline] + fn partial_cmp(&self, rhs: &usize) -> Option { + match self { + Number::Fixnum(n) => { + let n = n.get_num(); + + if n < 0i64 { + Some(Ordering::Less) + } else { + (n as usize).partial_cmp(rhs) + } + } + Number::Integer(n) => (&**n).partial_cmp(rhs), + Number::Rational(r) => (&**r).partial_cmp(rhs), + Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)), + } + } +} + +impl PartialEq for Number { + #[inline] + fn eq(&self, rhs: &usize) -> bool { + match self { + Number::Fixnum(n) => { + let n = n.get_num(); + + if n < 0i64 { + false + } else { + (n as usize).eq(rhs) + } + } + Number::Integer(n) => (&**n).eq(rhs), + Number::Rational(r) => (&**r).eq(rhs), + Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)), + } + } +} + impl PartialOrd for Number { fn partial_cmp(&self, rhs: &Number) -> Option { Some(self.cmp(rhs)) @@ -668,15 +572,17 @@ impl PartialOrd for Number { impl Ord for Number { fn cmp(&self, rhs: &Number) -> Ordering { match (self, rhs) { - (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2), - (&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2), - (Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)), - (&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2), - (Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)), - (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).cmp(&n2), - (&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2 as f64)), + (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()), + (&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(&*n2), + (Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2.get_num())), + (&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(&*n2), + (Number::Rational(n1), &Number::Fixnum(n2)) => { + (&**n1).cmp(&Rational::from(n2.get_num())) + } + (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2), + (&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)), (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2), - (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2), + (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2), (&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())), (&Number::Integer(ref n1), &Number::Rational(ref n2)) => { #[cfg(feature = "num")] @@ -706,54 +612,38 @@ impl Ord for Number { } } -impl<'a> TryFrom<(Addr, &'a Heap)> for Number { +impl TryFrom for Number { type Error = (); - fn try_from((addr, heap): (Addr, &'a Heap)) -> Result { - match addr { - Addr::Fixnum(n) => Ok(Number::from(n)), - Addr::Float(n) => Ok(Number::Float(n)), - Addr::Usize(n) => { - if let Ok(n) = isize::try_from(n) { - Ok(Number::from(n)) - } else { - Ok(Number::from(Integer::from(n))) - } - } - Addr::Con(h) => Number::try_from(&heap[h]), - _ => Err(()), - } - } -} - -impl<'a> TryFrom<&'a HeapCellValue> for Number { - type Error = (); - - fn try_from(value: &'a HeapCellValue) -> Result { - match value { - HeapCellValue::Addr(addr) => match addr { - &Addr::Fixnum(n) => Ok(Number::from(n)), - &Addr::Float(n) => Ok(Number::Float(n)), - &Addr::Usize(n) => { - if let Ok(n) = isize::try_from(n) { - Ok(Number::from(n)) - } else { - Ok(Number::from(Integer::from(n))) - } - } - _ => Err(()), - }, - HeapCellValue::Integer(n) => Ok(Number::Integer(n.clone())), - HeapCellValue::Rational(n) => Ok(Number::Rational(n.clone())), - _ => Err(()), - } - } -} - -impl<'a> From<&'a Integer> for Number { #[inline] - fn from(src: &'a Integer) -> Self { - Number::Integer(Rc::new(Integer::from(src))) + fn try_from(value: HeapCellValue) -> Result { + read_heap_cell!(value, + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::F64, n) => { + Ok(Number::Float(*n)) + } + (ArenaHeaderTag::Integer, n) => { + Ok(Number::Integer(n)) + } + (ArenaHeaderTag::Rational, n) => { + Ok(Number::Rational(n)) + } + _ => { + Err(()) + } + ) + } + (HeapCellValueTag::F64, n) => { + Ok(Number::Float(**n)) + } + (HeapCellValueTag::Fixnum, n) => { + Ok(Number::Fixnum(n)) + } + _ => { + Err(()) + } + ) } } diff --git a/src/atom_table.rs b/src/atom_table.rs new file mode 100644 index 000000000..71771cc2c --- /dev/null +++ b/src/atom_table.rs @@ -0,0 +1,366 @@ +use crate::parser::ast::MAX_ARITY; +use crate::raw_block::*; +use crate::types::*; + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::hash::{Hash, Hasher}; +use std::mem; +use std::ptr; +use std::slice; +use std::str; + +use indexmap::IndexSet; + +use modular_bitfield::prelude::*; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Atom { + pub index: usize, +} + +const_assert!(mem::size_of::() == 8); + +include!("./static_atoms.rs"); + +impl<'a> From<&'a Atom> for Atom { + #[inline] + fn from(atom: &'a Atom) -> Self { + *atom + } +} + +impl From for Atom { + #[inline] + fn from(value: bool) -> Self { + if value { atom!("true") } else { atom!("false") } + } +} + +#[cfg(test)] +use std::cell::RefCell; + +const ATOM_TABLE_INIT_SIZE: usize = 1 << 16; +const ATOM_TABLE_ALIGN: usize = 8; + +#[cfg(test)] +thread_local! { + static ATOM_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut()); +} + +#[cfg(not(test))] +static mut ATOM_TABLE_BUF_BASE: *const u8 = ptr::null_mut(); + +#[cfg(test)] +fn set_atom_tbl_buf_base(ptr: *const u8) { + ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| { + *atom_table_buf_base.borrow_mut() = ptr; + }); +} + +#[cfg(test)] +pub(crate) fn get_atom_tbl_buf_base() -> *const u8 { + ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| *atom_table_buf_base.borrow()) +} + +#[cfg(not(test))] +fn set_atom_tbl_buf_base(ptr: *const u8) { + unsafe { + ATOM_TABLE_BUF_BASE = ptr; + } +} + +#[cfg(not(test))] +pub(crate) fn get_atom_tbl_buf_base() -> *const u8 { + unsafe { ATOM_TABLE_BUF_BASE } +} + +impl RawBlockTraits for AtomTable { + #[inline] + fn init_size() -> usize { + ATOM_TABLE_INIT_SIZE + } + + #[inline] + fn align() -> usize { + ATOM_TABLE_ALIGN + } +} + +#[bitfield] +#[derive(Copy, Clone, Debug)] +struct AtomHeader { + #[allow(unused)] m: bool, + len: B50, + #[allow(unused)] padding: B13, +} + +impl AtomHeader { + fn build_with(len: u64) -> Self { + AtomHeader::new().with_len(len).with_m(false) + } +} + +impl Borrow for Atom { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl Hash for Atom { + #[inline] + fn hash(&self, hasher: &mut H) { + self.as_str().hash(hasher) + // hasher.write_usize(self.index) + } +} + +#[macro_export] +macro_rules! is_char { + ($s:expr) => { + !$s.is_empty() && $s.chars().nth(1).is_none() + }; +} + +impl Atom { + #[inline] + pub fn buf(self) -> *const u8 { + let ptr = self.as_ptr(); + + if ptr.is_null() { + return ptr::null(); + } + + (ptr as usize + mem::size_of::()) as *const u8 + } + + #[inline(always)] + pub fn is_static(self) -> bool { + self.index < STRINGS.len() << 3 + } + + #[inline(always)] + pub fn as_ptr(self) -> *const u8 { + if self.is_static() { + ptr::null() + } else { + (get_atom_tbl_buf_base() as usize + self.index - (STRINGS.len() << 3)) as *const u8 + } + } + + #[inline(always)] + pub fn from(index: usize) -> Self { + Self { index } + } + + #[inline(always)] + pub fn len(self) -> usize { + if self.is_static() { + STRINGS[self.index >> 3].len() + } else { + unsafe { ptr::read(self.as_ptr() as *const AtomHeader).len() as _ } + } + } + + #[inline(always)] + pub fn flat_index(self) -> u64 { + (self.index >> 3) as u64 + } + + pub fn as_char(self) -> Option { + let s = self.as_str(); + let mut it = s.chars(); + + let c1 = it.next(); + let c2 = it.next(); + + if c2.is_none() { c1 } else { None } + } + + #[inline] + pub fn chars(&self) -> str::Chars { + self.as_str().chars() + } + + #[inline] + pub fn as_str(&self) -> &str { + unsafe { + let ptr = self.as_ptr(); + + if ptr.is_null() { + return STRINGS[self.index >> 3]; + } + + let header = ptr::read::(ptr as *const _); + let len = header.len() as usize; + let buf = (ptr as usize + mem::size_of::()) as *mut u8; + + str::from_utf8_unchecked(slice::from_raw_parts(buf, len)) + } + } + + pub fn defrock_brackets(&self, atom_tbl: &mut AtomTable) -> Self { + let s = self.as_str(); + + let s = if s.starts_with('(') && s.ends_with(')') { + &s['('.len_utf8()..s.len() - ')'.len_utf8()] + } else { + return *self; + }; + + atom_tbl.build_with(s) + } +} + +unsafe fn write_to_ptr(string: &str, ptr: *mut u8) { + ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64)); + let str_ptr = (ptr as usize + mem::size_of::()) as *mut u8; + ptr::copy_nonoverlapping(string.as_ptr(), str_ptr as *mut u8, string.len()); +} + +impl PartialOrd for Atom { + #[inline] + fn partial_cmp(&self, other: &Atom) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Atom { + #[inline] + fn cmp(&self, other: &Atom) -> Ordering { + self.as_str().cmp(other.as_str()) + } +} + +#[derive(Debug)] +pub struct AtomTable { + block: RawBlock, + pub table: IndexSet, +} + +impl Drop for AtomTable { + fn drop(&mut self) { + self.block.deallocate(); + } +} + +impl AtomTable { + #[inline] + pub fn new() -> Self { + let table = Self { + block: RawBlock::new(), + table: IndexSet::new(), + }; + + set_atom_tbl_buf_base(table.block.base); + table + } + + #[inline] + pub fn buf(&self) -> *const u8 { + self.block.base as *const u8 + } + + #[inline] + pub fn top(&self) -> *const u8 { + self.block.top + } + + #[inline(always)] + fn lookup_str(&self, string: &str) -> Option { + STATIC_ATOMS_MAP.get(string).or_else(|| self.table.get(string)).cloned() + } + + pub fn build_with(&mut self, string: &str) -> Atom { + if let Some(atom) = self.lookup_str(string) { + return atom; + } + + unsafe { + let size = mem::size_of::() + string.len(); + let align_offset = 8 * mem::align_of::(); + let size = (size & !(align_offset - 1)) + align_offset; + + let len_ptr = { + let mut ptr; + + loop { + ptr = self.block.alloc(size); + + if ptr.is_null() { + self.block.grow(); + set_atom_tbl_buf_base(self.block.base); + } else { + break; + } + } + + ptr + }; + + let ptr_base = self.block.base as usize; + + write_to_ptr(string, len_ptr); + + let atom = Atom { + index: (STRINGS.len() << 3) + len_ptr as usize - ptr_base, + }; + + self.table.insert(atom); + + atom + } + } +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub struct AtomCell { + name: B46, + arity: B10, + #[allow(unused)] f: bool, + #[allow(unused)] m: bool, + #[allow(unused)] tag: B6, +} + +impl AtomCell { + #[inline] + pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self { + if arity > 0 { + debug_assert!(arity as usize <= MAX_ARITY); + + AtomCell::new() + .with_name(name) + .with_arity(arity) + .with_f(false) + .with_tag(tag as u8) + } else { + AtomCell::new() + .with_name(name) + .with_f(false) + .with_tag(tag as u8) + } + } + + #[inline] + pub fn get_index(self) -> usize { + self.name() as usize + } + + #[inline] + pub fn get_name(self) -> Atom { + Atom::from(self.get_index() << 3) + } + + #[inline] + pub fn get_arity(self) -> usize { + self.arity() as usize + } + + #[inline] + pub fn get_name_and_arity(self) -> (Atom, usize) { + (Atom::from(self.get_index() << 3), self.get_arity()) + } +} diff --git a/src/bin/scryer-prolog.rs b/src/bin/scryer-prolog.rs index a1cf2a999..f8d3aa6e9 100644 --- a/src/bin/scryer-prolog.rs +++ b/src/bin/scryer-prolog.rs @@ -1,16 +1,12 @@ fn main() { use nix::sys::signal; - use scryer_prolog::read::readline; use scryer_prolog::*; let handler = signal::SigHandler::Handler(handle_sigint); unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap(); - let mut wam = machine::Machine::new( - readline::input_stream(), - machine::Stream::stdout(), - machine::Stream::stderr(), - ); + let mut wam = machine::Machine::new(); + wam.run_top_level(); } diff --git a/src/clause_types.rs b/src/clause_types.rs index cb6548676..e7c2c8534 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -1,16 +1,15 @@ -use prolog_parser::ast::*; -use prolog_parser::{clause_name, temp_v}; - -use crate::forms::Number; +use crate::atom_table::*; use crate::machine::machine_indices::*; -use crate::rug::rand::RandState; +use crate::parser::ast::*; +use crate::parser::rug::rand::RandState; -use ref_thread_local::{ref_thread_local, RefThreadLocal}; +use crate::forms::Number; +use crate::temp_v; -use std::collections::BTreeMap; +use ref_thread_local::{ref_thread_local}; #[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub(crate) enum CompareNumberQT { +pub enum CompareNumberQT { GreaterThan, LessThan, GreaterThanOrEqual, @@ -20,20 +19,20 @@ pub(crate) enum CompareNumberQT { } impl CompareNumberQT { - fn name(self) -> &'static str { + fn name(self) -> Atom { match self { - CompareNumberQT::GreaterThan => ">", - CompareNumberQT::LessThan => "<", - CompareNumberQT::GreaterThanOrEqual => ">=", - CompareNumberQT::LessThanOrEqual => "=<", - CompareNumberQT::NotEqual => "=\\=", - CompareNumberQT::Equal => "=:=", + CompareNumberQT::GreaterThan => atom!(">"), + CompareNumberQT::LessThan => atom!("<"), + CompareNumberQT::GreaterThanOrEqual => atom!(">="), + CompareNumberQT::LessThanOrEqual => atom!("=<"), + CompareNumberQT::NotEqual => atom!("=\\="), + CompareNumberQT::Equal => atom!("=:="), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum CompareTermQT { +pub enum CompareTermQT { LessThan, LessThanOrEqual, GreaterThanOrEqual, @@ -41,18 +40,18 @@ pub(crate) enum CompareTermQT { } impl CompareTermQT { - fn name<'a>(self) -> &'a str { + fn name(self) -> Atom { match self { - CompareTermQT::GreaterThan => "@>", - CompareTermQT::LessThan => "@<", - CompareTermQT::GreaterThanOrEqual => "@>=", - CompareTermQT::LessThanOrEqual => "@=<", + CompareTermQT::GreaterThan => atom!("@>"), + CompareTermQT::LessThan => atom!("@<"), + CompareTermQT::GreaterThanOrEqual => atom!("@>="), + CompareTermQT::LessThanOrEqual => atom!("@=<"), } } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum ArithmeticTerm { +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ArithmeticTerm { Reg(RegType), Interm(usize), Number(Number), @@ -68,8 +67,8 @@ impl ArithmeticTerm { } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) enum InlinedClauseType { +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum InlinedClauseType { CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm), IsAtom(RegType), IsAtomic(RegType), @@ -83,73 +82,106 @@ pub(crate) enum InlinedClauseType { } ref_thread_local! { - pub(crate)static managed RANDOM_STATE: RandState<'static> = RandState::new(); + pub(crate) static managed RANDOM_STATE: RandState<'static> = RandState::new(); } -ref_thread_local! { - pub(crate)static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = { - let mut m = BTreeMap::new(); - - let r1 = temp_v!(1); - let r2 = temp_v!(2); - - m.insert((">", 2), - ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThan, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("<", 2), - ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThan, ar_reg!(r1), ar_reg!(r2)))); - m.insert((">=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThanOrEqual, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("=<", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("=:=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::Equal, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("=\\=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("atom", 1), ClauseType::Inlined(InlinedClauseType::IsAtom(r1))); - m.insert(("atomic", 1), ClauseType::Inlined(InlinedClauseType::IsAtomic(r1))); - m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1))); - m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1))); - m.insert(("number", 1), ClauseType::Inlined(InlinedClauseType::IsNumber(r1))); - m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1))); - m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1))); - m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1))); - m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1))); - m.insert(("acyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm)); - m.insert(("arg", 3), ClauseType::BuiltIn(BuiltInClauseType::Arg)); - m.insert(("compare", 3), ClauseType::BuiltIn(BuiltInClauseType::Compare)); - m.insert(("@>", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThan))); - m.insert(("@<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThan))); - m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual))); - m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual))); - m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)); - m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq)); - m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor)); - m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground)); - m.insert(("is", 2), ClauseType::BuiltIn(BuiltInClauseType::Is(r1, ar_reg!(r2)))); - m.insert(("keysort", 2), ClauseType::BuiltIn(BuiltInClauseType::KeySort)); - m.insert(("\\==", 2), ClauseType::BuiltIn(BuiltInClauseType::NotEq)); - m.insert(("read", 2), ClauseType::BuiltIn(BuiltInClauseType::Read)); - m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort)); - - m - }; +pub fn clause_type_form(name: Atom, arity: usize) -> Option { + match (name, arity) { + (atom!(">"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::GreaterThan, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::LessThan, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!(">="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::GreaterThanOrEqual, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("=<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::LessThanOrEqual, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("=:="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::Equal, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("=\\="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::NotEqual, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("atom"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtom(temp_v!(1)))), + (atom!("atomic"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtomic(temp_v!(1)))), + (atom!("compound"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsCompound(temp_v!( + 1 + )))), + (atom!("integer"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsInteger(temp_v!( + 1 + )))), + (atom!("number"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNumber(temp_v!(1)))), + (atom!("rational"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsRational(temp_v!( + 1 + )))), + (atom!("float"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsFloat(temp_v!(1)))), + (atom!("nonvar"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNonVar(temp_v!(1)))), + (atom!("var"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsVar(temp_v!(1)))), + (atom!("acyclic_term"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm)), + (atom!("arg"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Arg)), + (atom!("compare"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Compare)), + (atom!("@>"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::GreaterThan, + ))), + (atom!("@<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::LessThan, + ))), + (atom!("@>="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::GreaterThanOrEqual, + ))), + (atom!("@=<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::LessThanOrEqual, + ))), + (atom!("copy_term"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)), + (atom!("=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Eq)), + (atom!("functor"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Functor)), + (atom!("ground"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::Ground)), + (atom!("is"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Is( + temp_v!(1), + ar_reg!(temp_v!(2)), + ))), + (atom!("keysort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::KeySort)), + (atom!("\\=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::NotEq)), + (atom!("read"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::Read)), + (atom!("sort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Sort)), + _ => None, + } } impl InlinedClauseType { - pub(crate) fn name(&self) -> &'static str { + pub(crate) fn name(&self) -> Atom { match self { &InlinedClauseType::CompareNumber(qt, ..) => qt.name(), - &InlinedClauseType::IsAtom(..) => "atom", - &InlinedClauseType::IsAtomic(..) => "atomic", - &InlinedClauseType::IsCompound(..) => "compound", - &InlinedClauseType::IsNumber(..) => "number", - &InlinedClauseType::IsInteger(..) => "integer", - &InlinedClauseType::IsRational(..) => "rational", - &InlinedClauseType::IsFloat(..) => "float", - &InlinedClauseType::IsNonVar(..) => "nonvar", - &InlinedClauseType::IsVar(..) => "var", + &InlinedClauseType::IsAtom(..) => atom!("atom"), + &InlinedClauseType::IsAtomic(..) => atom!("atomic"), + &InlinedClauseType::IsCompound(..) => atom!("compound"), + &InlinedClauseType::IsNumber(..) => atom!("number"), + &InlinedClauseType::IsInteger(..) => atom!("integer"), + &InlinedClauseType::IsRational(..) => atom!("rational"), + &InlinedClauseType::IsFloat(..) => atom!("float"), + &InlinedClauseType::IsNonVar(..) => atom!("nonvar"), + &InlinedClauseType::IsVar(..) => atom!("var"), } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub(crate) enum SystemClauseType { +pub enum SystemClauseType { AtomChars, AtomCodes, AtomLength, @@ -176,8 +208,8 @@ pub(crate) enum SystemClauseType { MakeDirectoryPath, DeleteFile, RenameFile, - DeleteDirectory, WorkingDirectory, + DeleteDirectory, PathCanonical, FileTime, DeleteAttribute, @@ -203,8 +235,6 @@ pub(crate) enum SystemClauseType { GetNextDBRef, GetNextOpDBRef, IsPartialString, - LookupDBRef, - LookupOpDBRef, Halt, GetLiftedHeapFromOffset, GetLiftedHeapFromOffsetDiff, @@ -278,11 +308,11 @@ pub(crate) enum SystemClauseType { Succeed, TermAttributedVariables, TermVariables, + TermVariablesUnderMaxDepth, TruncateLiftedHeapTo, UnifyWithOccursCheck, UnwindEnvironments, UnwindStack, - Variant, WAMInstructions, WriteTerm, WriteTermToChars, @@ -319,566 +349,509 @@ pub(crate) enum SystemClauseType { } impl SystemClauseType { - pub(crate) fn name(&self) -> ClauseName { + pub(crate) fn name(&self) -> Atom { match self { - &SystemClauseType::AtomChars => clause_name!("$atom_chars"), - &SystemClauseType::AtomCodes => clause_name!("$atom_codes"), - &SystemClauseType::AtomLength => clause_name!("$atom_length"), - &SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"), - &SystemClauseType::CallContinuation => clause_name!("$call_continuation"), - &SystemClauseType::CharCode => clause_name!("$char_code"), - &SystemClauseType::CharType => clause_name!("$char_type"), - &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), - &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), - &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), + &SystemClauseType::AtomChars => atom!("$atom_chars"), + &SystemClauseType::AtomCodes => atom!("$atom_codes"), + &SystemClauseType::AtomLength => atom!("$atom_length"), + &SystemClauseType::BindFromRegister => atom!("$bind_from_register"), + &SystemClauseType::CallContinuation => atom!("$call_continuation"), + &SystemClauseType::CharCode => atom!("$char_code"), + &SystemClauseType::CharType => atom!("$char_type"), + &SystemClauseType::CharsToNumber => atom!("$chars_to_number"), + &SystemClauseType::CheckCutPoint => atom!("$check_cp"), + &SystemClauseType::CodesToNumber => atom!("$codes_to_number"), &SystemClauseType::CopyTermWithoutAttrVars => { - clause_name!("$copy_term_without_attr_vars") - } - &SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"), - &SystemClauseType::CurrentInput => clause_name!("$current_input"), - &SystemClauseType::CurrentHostname => clause_name!("$current_hostname"), - &SystemClauseType::CurrentOutput => clause_name!("$current_output"), - &SystemClauseType::DirectoryFiles => clause_name!("$directory_files"), - &SystemClauseType::FileSize => clause_name!("$file_size"), - &SystemClauseType::FileExists => clause_name!("$file_exists"), - &SystemClauseType::DirectoryExists => clause_name!("$directory_exists"), - &SystemClauseType::DirectorySeparator => clause_name!("$directory_separator"), - &SystemClauseType::MakeDirectory => clause_name!("$make_directory"), - &SystemClauseType::MakeDirectoryPath => clause_name!("$make_directory_path"), - &SystemClauseType::DeleteFile => clause_name!("$delete_file"), - &SystemClauseType::RenameFile => clause_name!("$rename_file"), - &SystemClauseType::DeleteDirectory => clause_name!("$delete_directory"), - &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"), - &SystemClauseType::PathCanonical => clause_name!("$path_canonical"), - &SystemClauseType::FileTime => clause_name!("$file_time"), + atom!("$copy_term_without_attr_vars") + } + &SystemClauseType::CreatePartialString => atom!("$create_partial_string"), + &SystemClauseType::CurrentInput => atom!("$current_input"), + &SystemClauseType::CurrentHostname => atom!("$current_hostname"), + &SystemClauseType::CurrentOutput => atom!("$current_output"), + &SystemClauseType::DirectoryFiles => atom!("$directory_files"), + &SystemClauseType::FileSize => atom!("$file_size"), + &SystemClauseType::FileExists => atom!("$file_exists"), + &SystemClauseType::DirectoryExists => atom!("$directory_exists"), + &SystemClauseType::DirectorySeparator => atom!("$directory_separator"), + &SystemClauseType::MakeDirectory => atom!("$make_directory"), + &SystemClauseType::MakeDirectoryPath => atom!("$make_directory_path"), + &SystemClauseType::DeleteFile => atom!("$delete_file"), + &SystemClauseType::RenameFile => atom!("$rename_file"), + &SystemClauseType::DeleteDirectory => atom!("$delete_directory"), + &SystemClauseType::WorkingDirectory => atom!("$working_directory"), + &SystemClauseType::PathCanonical => atom!("$path_canonical"), + &SystemClauseType::FileTime => atom!("$file_time"), &SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => { - clause_name!("$add_discontiguous_predicate") - } - &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => { - clause_name!("$add_dynamic_predicate") + atom!("$add_discontiguous_predicate") } + &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => atom!("$add_dynamic_predicate"), &SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => { - clause_name!("$add_multifile_predicate") + atom!("$add_multifile_predicate") } &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => { - clause_name!("$add_goal_expansion_clause") + atom!("$add_goal_expansion_clause") } &SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => { - clause_name!("$add_term_expansion_clause") - } - &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => { - clause_name!("$clause_to_evacuable") + atom!("$add_term_expansion_clause") } + &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => atom!("$clause_to_evacuable"), &SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable) => { - clause_name!("$scoped_clause_to_evacuable") - } - &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => clause_name!("$conclude_load"), - &SystemClauseType::REPL(REPLCodePtr::DeclareModule) => clause_name!("$declare_module"), - &SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => { - clause_name!("$load_compiled_library") + atom!("$scoped_clause_to_evacuable") } + &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => atom!("$conclude_load"), + &SystemClauseType::REPL(REPLCodePtr::DeclareModule) => atom!("$declare_module"), + &SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => atom!("$load_compiled_library"), &SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) => { - clause_name!("$push_load_state_payload") + atom!("$push_load_state_payload") } &SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule) => { - clause_name!("$add_in_situ_filename_module") - } - &SystemClauseType::REPL(REPLCodePtr::Asserta) => clause_name!("$asserta"), - &SystemClauseType::REPL(REPLCodePtr::Assertz) => clause_name!("$assertz"), - &SystemClauseType::REPL(REPLCodePtr::Retract) => clause_name!("$retract_clause"), - &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), - &SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => { - clause_name!("$push_load_context") - } - &SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => { - clause_name!("$pop_load_context") - } - &SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => { - clause_name!("$pop_load_state_payload") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => { - clause_name!("$prolog_lc_source") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => { - clause_name!("$prolog_lc_file") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => { - clause_name!("$prolog_lc_dir") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => { - clause_name!("$prolog_lc_module") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => { - clause_name!("$prolog_lc_stream") - } + atom!("$add_in_situ_filename_module") + } + &SystemClauseType::REPL(REPLCodePtr::Asserta) => atom!("$asserta"), + &SystemClauseType::REPL(REPLCodePtr::Assertz) => atom!("$assertz"), + &SystemClauseType::REPL(REPLCodePtr::Retract) => atom!("$retract_clause"), + &SystemClauseType::REPL(REPLCodePtr::UseModule) => atom!("$use_module"), + &SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => atom!("$push_load_context"), + &SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => atom!("$pop_load_context"), + &SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => atom!("$pop_load_state_payload"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => atom!("$prolog_lc_source"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => atom!("$prolog_lc_file"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => atom!("$prolog_lc_dir"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => atom!("$prolog_lc_module"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => atom!("$prolog_lc_stream"), &SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => { - clause_name!("$cpp_meta_predicate_property") - } - &SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => { - clause_name!("$cpp_built_in_property") - } - &SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => { - clause_name!("$cpp_dynamic_property") - } - &SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => { - clause_name!("$cpp_multifile_property") + atom!("$cpp_meta_predicate_property") } + &SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => atom!("$cpp_built_in_property"), + &SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => atom!("$cpp_dynamic_property"), + &SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => atom!("$cpp_multifile_property"), &SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => { - clause_name!("$cpp_discontiguous_property") + atom!("$cpp_discontiguous_property") } - &SystemClauseType::REPL(REPLCodePtr::AbolishClause) => clause_name!("$abolish_clause"), + &SystemClauseType::REPL(REPLCodePtr::AbolishClause) => atom!("$abolish_clause"), &SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => { - clause_name!("$is_consistent_with_term_queue") - } - &SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => { - clause_name!("$flush_term_queue") - } - &SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => { - clause_name!("$remove_module_exports") + atom!("$is_consistent_with_term_queue") } + &SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => atom!("$flush_term_queue"), + &SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => atom!("$remove_module_exports"), &SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => { - clause_name!("$add_non_counted_backtracking") - } - &SystemClauseType::Close => clause_name!("$close"), - &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), - &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), - &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"), - &SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"), - &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"), - &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"), - &SystemClauseType::FirstStream => clause_name!("$first_stream"), - &SystemClauseType::FlushOutput => clause_name!("$flush_output"), - &SystemClauseType::GetByte => clause_name!("$get_byte"), - &SystemClauseType::GetChar => clause_name!("$get_char"), - &SystemClauseType::GetNChars => clause_name!("$get_n_chars"), - &SystemClauseType::GetCode => clause_name!("$get_code"), - &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"), - &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"), - &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { - clause_name!("$truncate_if_no_lh_growth") - } - &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { - clause_name!("$truncate_if_no_lh_growth_diff") - } - &SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"), - &SystemClauseType::GetAttrVarQueueDelimiter => { - clause_name!("$get_attr_var_queue_delim") - } - &SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"), - &SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"), - &SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"), - &SystemClauseType::GetLiftedHeapFromOffsetDiff => { - clause_name!("$get_lh_from_offset_diff") - } - &SystemClauseType::GetBValue => clause_name!("$get_b_value"), - // &SystemClauseType::GetClause => clause_name!("$get_clause"), - &SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"), - &SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"), - &SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"), - &SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"), - &SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"), - // &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"), - &SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"), - &SystemClauseType::Halt => clause_name!("$halt"), - &SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"), - &SystemClauseType::Open => clause_name!("$open"), - &SystemClauseType::SetStreamOptions => clause_name!("$set_stream_options"), - &SystemClauseType::OpDeclaration => clause_name!("$op"), - &SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"), - &SystemClauseType::InstallInferenceCounter => { - clause_name!("$install_inference_counter") - } - &SystemClauseType::IsPartialString => clause_name!("$is_partial_string"), - &SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"), - &SystemClauseType::PeekByte => clause_name!("$peek_byte"), - &SystemClauseType::PeekChar => clause_name!("$peek_char"), - &SystemClauseType::PeekCode => clause_name!("$peek_code"), - &SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"), - &SystemClauseType::Maybe => clause_name!("maybe"), - &SystemClauseType::CpuNow => clause_name!("$cpu_now"), - &SystemClauseType::CurrentTime => clause_name!("$current_time"), - // &SystemClauseType::ModuleAssertDynamicPredicateToFront => { - // clause_name!("$module_asserta") - // } - // &SystemClauseType::ModuleAssertDynamicPredicateToBack => { - // clause_name!("$module_assertz") - // } - // &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"), - &SystemClauseType::ModuleExists => clause_name!("$module_exists"), - &SystemClauseType::NextStream => clause_name!("$next_stream"), - &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"), - &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"), - &SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"), + atom!("$add_non_counted_backtracking") + } + &SystemClauseType::Close => atom!("$close"), + &SystemClauseType::CopyToLiftedHeap => atom!("$copy_to_lh"), + &SystemClauseType::DeleteAttribute => atom!("$del_attr_non_head"), + &SystemClauseType::DeleteHeadAttribute => atom!("$del_attr_head"), + &SystemClauseType::DynamicModuleResolution(_) => atom!("$module_call"), + &SystemClauseType::EnqueueAttributedVar => atom!("$enqueue_attr_var"), + &SystemClauseType::FetchGlobalVar => atom!("$fetch_global_var"), + &SystemClauseType::FirstStream => atom!("$first_stream"), + &SystemClauseType::FlushOutput => atom!("$flush_output"), + &SystemClauseType::GetByte => atom!("$get_byte"), + &SystemClauseType::GetChar => atom!("$get_char"), + &SystemClauseType::GetNChars => atom!("$get_n_chars"), + &SystemClauseType::GetCode => atom!("$get_code"), + &SystemClauseType::GetSingleChar => atom!("$get_single_char"), + &SystemClauseType::ResetAttrVarState => atom!("$reset_attr_var_state"), + &SystemClauseType::TruncateIfNoLiftedHeapGrowth => atom!("$truncate_if_no_lh_growth"), + &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => atom!("$truncate_if_no_lh_growth_diff"), + &SystemClauseType::GetAttributedVariableList => atom!("$get_attr_list"), + &SystemClauseType::GetAttrVarQueueDelimiter => atom!("$get_attr_var_queue_delim"), + &SystemClauseType::GetAttrVarQueueBeyond => atom!("$get_attr_var_queue_beyond"), + &SystemClauseType::GetContinuationChunk => atom!("$get_cont_chunk"), + &SystemClauseType::GetLiftedHeapFromOffset => atom!("$get_lh_from_offset"), + &SystemClauseType::GetLiftedHeapFromOffsetDiff => atom!("$get_lh_from_offset_diff"), + &SystemClauseType::GetBValue => atom!("$get_b_value"), + &SystemClauseType::GetNextDBRef => atom!("$get_next_db_ref"), + &SystemClauseType::GetNextOpDBRef => atom!("$get_next_op_db_ref"), + &SystemClauseType::GetDoubleQuotes => atom!("$get_double_quotes"), + &SystemClauseType::GetSCCCleaner => atom!("$get_scc_cleaner"), + &SystemClauseType::Halt => atom!("$halt"), + &SystemClauseType::HeadIsDynamic => atom!("$head_is_dynamic"), + &SystemClauseType::Open => atom!("$open"), + &SystemClauseType::OpDeclaration => atom!("$op"), + &SystemClauseType::InstallSCCCleaner => atom!("$install_scc_cleaner"), + &SystemClauseType::InstallInferenceCounter => atom!("$install_inference_counter"), + &SystemClauseType::IsPartialString => atom!("$is_partial_string"), + &SystemClauseType::PartialStringTail => atom!("$partial_string_tail"), + &SystemClauseType::PeekByte => atom!("$peek_byte"), + &SystemClauseType::PeekChar => atom!("$peek_char"), + &SystemClauseType::PeekCode => atom!("$peek_code"), + &SystemClauseType::LiftedHeapLength => atom!("$lh_length"), + &SystemClauseType::Maybe => atom!("maybe"), + &SystemClauseType::CpuNow => atom!("$cpu_now"), + &SystemClauseType::CurrentTime => atom!("$current_time"), + // &SystemClauseType::ModuleHeadIsDynamic => atom!("$module_head_is_dynamic"), + &SystemClauseType::ModuleExists => atom!("$module_exists"), + &SystemClauseType::NextStream => atom!("$next_stream"), + &SystemClauseType::NoSuchPredicate => atom!("$no_such_predicate"), + &SystemClauseType::NumberToChars => atom!("$number_to_chars"), + &SystemClauseType::NumberToCodes => atom!("$number_to_codes"), &SystemClauseType::PointsToContinuationResetMarker => { - clause_name!("$points_to_cont_reset_marker") + atom!("$points_to_cont_reset_marker") } &SystemClauseType::PutByte => { - clause_name!("$put_byte") + atom!("$put_byte") } &SystemClauseType::PutChar => { - clause_name!("$put_char") + atom!("$put_char") } &SystemClauseType::PutChars => { - clause_name!("$put_chars") + atom!("$put_chars") } &SystemClauseType::PutCode => { - clause_name!("$put_code") + atom!("$put_code") } &SystemClauseType::QuotedToken => { - clause_name!("$quoted_token") - } - &SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"), - &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), - &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), - &SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"), - &SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"), - &SystemClauseType::SetInput => clause_name!("$set_input"), - &SystemClauseType::SetOutput => clause_name!("$set_output"), - &SystemClauseType::SetSeed => clause_name!("$set_seed"), - &SystemClauseType::StreamProperty => clause_name!("$stream_property"), - &SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"), + atom!("$quoted_token") + } + &SystemClauseType::RedoAttrVarBinding => atom!("$redo_attr_var_binding"), + &SystemClauseType::RemoveCallPolicyCheck => atom!("$remove_call_policy_check"), + &SystemClauseType::RemoveInferenceCounter => atom!("$remove_inference_counter"), + &SystemClauseType::RestoreCutPolicy => atom!("$restore_cut_policy"), + &SystemClauseType::SetCutPoint(_) => atom!("$set_cp"), + &SystemClauseType::SetInput => atom!("$set_input"), + &SystemClauseType::SetOutput => atom!("$set_output"), + &SystemClauseType::SetSeed => atom!("$set_seed"), + &SystemClauseType::StreamProperty => atom!("$stream_property"), + &SystemClauseType::SetStreamPosition => atom!("$set_stream_position"), + &SystemClauseType::SetStreamOptions => atom!("$set_stream_options"), &SystemClauseType::StoreBacktrackableGlobalVar => { - clause_name!("$store_back_trackable_global_var") - } - &SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"), - &SystemClauseType::InferenceLevel => clause_name!("$inference_level"), - &SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"), - &SystemClauseType::EraseBall => clause_name!("$erase_ball"), - &SystemClauseType::Fail => clause_name!("$fail"), - &SystemClauseType::GetBall => clause_name!("$get_ball"), - &SystemClauseType::GetCutPoint => clause_name!("$get_cp"), - &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"), - &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"), - &SystemClauseType::NextEP => clause_name!("$nextEP"), - &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"), - &SystemClauseType::ReadTerm => clause_name!("$read_term"), - &SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"), - &SystemClauseType::ResetBlock => clause_name!("$reset_block"), - &SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"), - &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"), - &SystemClauseType::SetBall => clause_name!("$set_ball"), - &SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"), - &SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"), - &SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"), - &SystemClauseType::Sleep => clause_name!("$sleep"), - &SystemClauseType::SocketClientOpen => clause_name!("$socket_client_open"), - &SystemClauseType::SocketServerOpen => clause_name!("$socket_server_open"), - &SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"), - &SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"), - &SystemClauseType::TLSAcceptClient => clause_name!("$tls_accept_client"), - &SystemClauseType::TLSClientConnect => clause_name!("$tls_client_connect"), - &SystemClauseType::Succeed => clause_name!("$succeed"), + atom!("$store_back_trackable_global_var") + } + &SystemClauseType::StoreGlobalVar => atom!("$store_global_var"), + &SystemClauseType::InferenceLevel => atom!("$inference_level"), + &SystemClauseType::CleanUpBlock => atom!("$clean_up_block"), + &SystemClauseType::EraseBall => atom!("$erase_ball"), + &SystemClauseType::Fail => atom!("$fail"), + &SystemClauseType::GetBall => atom!("$get_ball"), + &SystemClauseType::GetCutPoint => atom!("$get_cp"), + &SystemClauseType::GetCurrentBlock => atom!("$get_current_block"), + &SystemClauseType::InstallNewBlock => atom!("$install_new_block"), + &SystemClauseType::NextEP => atom!("$nextEP"), + &SystemClauseType::ReadQueryTerm => atom!("$read_query_term"), + &SystemClauseType::ReadTerm => atom!("$read_term"), + &SystemClauseType::ReadTermFromChars => atom!("$read_term_from_chars"), + &SystemClauseType::ResetBlock => atom!("$reset_block"), + &SystemClauseType::ResetContinuationMarker => atom!("$reset_cont_marker"), + &SystemClauseType::ReturnFromVerifyAttr => atom!("$return_from_verify_attr"), + &SystemClauseType::SetBall => atom!("$set_ball"), + &SystemClauseType::SetCutPointByDefault(_) => atom!("$set_cp_by_default"), + &SystemClauseType::SetDoubleQuotes => atom!("$set_double_quotes"), + &SystemClauseType::SkipMaxList => atom!("$skip_max_list"), + &SystemClauseType::Sleep => atom!("$sleep"), + &SystemClauseType::SocketClientOpen => atom!("$socket_client_open"), + &SystemClauseType::SocketServerOpen => atom!("$socket_server_open"), + &SystemClauseType::SocketServerAccept => atom!("$socket_server_accept"), + &SystemClauseType::SocketServerClose => atom!("$socket_server_close"), + &SystemClauseType::TLSAcceptClient => atom!("$tls_accept_client"), + &SystemClauseType::TLSClientConnect => atom!("$tls_client_connect"), + &SystemClauseType::Succeed => atom!("$succeed"), &SystemClauseType::TermAttributedVariables => { - clause_name!("$term_attributed_variables") - } - &SystemClauseType::TermVariables => clause_name!("$term_variables"), - &SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"), - &SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"), - &SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"), - &SystemClauseType::UnwindStack => clause_name!("$unwind_stack"), - &SystemClauseType::Variant => clause_name!("$variant"), - &SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"), - &SystemClauseType::WriteTerm => clause_name!("$write_term"), - &SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"), - &SystemClauseType::ScryerPrologVersion => clause_name!("$scryer_prolog_version"), - &SystemClauseType::CryptoRandomByte => clause_name!("$crypto_random_byte"), - &SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"), - &SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"), - &SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"), - &SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"), - &SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"), - &SystemClauseType::CryptoCurveScalarMult => clause_name!("$crypto_curve_scalar_mult"), - &SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"), - &SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"), - &SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"), + atom!("$term_attributed_variables") + } + &SystemClauseType::TermVariables => atom!("$term_variables"), + &SystemClauseType::TermVariablesUnderMaxDepth => atom!("$term_variables_under_max_depth"), + &SystemClauseType::TruncateLiftedHeapTo => atom!("$truncate_lh_to"), + &SystemClauseType::UnifyWithOccursCheck => atom!("$unify_with_occurs_check"), + &SystemClauseType::UnwindEnvironments => atom!("$unwind_environments"), + &SystemClauseType::UnwindStack => atom!("$unwind_stack"), + &SystemClauseType::WAMInstructions => atom!("$wam_instructions"), + &SystemClauseType::WriteTerm => atom!("$write_term"), + &SystemClauseType::WriteTermToChars => atom!("$write_term_to_chars"), + &SystemClauseType::ScryerPrologVersion => atom!("$scryer_prolog_version"), + &SystemClauseType::CryptoRandomByte => atom!("$crypto_random_byte"), + &SystemClauseType::CryptoDataHash => atom!("$crypto_data_hash"), + &SystemClauseType::CryptoDataHKDF => atom!("$crypto_data_hkdf"), + &SystemClauseType::CryptoPasswordHash => atom!("$crypto_password_hash"), + &SystemClauseType::CryptoDataEncrypt => atom!("$crypto_data_encrypt"), + &SystemClauseType::CryptoDataDecrypt => atom!("$crypto_data_decrypt"), + &SystemClauseType::CryptoCurveScalarMult => atom!("$crypto_curve_scalar_mult"), + &SystemClauseType::Ed25519Sign => atom!("$ed25519_sign"), + &SystemClauseType::Ed25519Verify => atom!("$ed25519_verify"), + &SystemClauseType::Ed25519NewKeyPair => atom!("$ed25519_new_keypair"), &SystemClauseType::Ed25519KeyPairPublicKey => { - clause_name!("$ed25519_keypair_public_key") - } - &SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"), - &SystemClauseType::FirstNonOctet => clause_name!("$first_non_octet"), - &SystemClauseType::LoadHTML => clause_name!("$load_html"), - &SystemClauseType::LoadXML => clause_name!("$load_xml"), - &SystemClauseType::GetEnv => clause_name!("$getenv"), - &SystemClauseType::SetEnv => clause_name!("$setenv"), - &SystemClauseType::UnsetEnv => clause_name!("$unsetenv"), - &SystemClauseType::Shell => clause_name!("$shell"), - &SystemClauseType::PID => clause_name!("$pid"), - &SystemClauseType::CharsBase64 => clause_name!("$chars_base64"), - &SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"), - &SystemClauseType::DevourWhitespace => clause_name!("$devour_whitespace"), - &SystemClauseType::IsSTOEnabled => clause_name!("$is_sto_enabled"), - &SystemClauseType::SetSTOAsUnify => clause_name!("$set_sto_as_unify"), - &SystemClauseType::SetNSTOAsUnify => clause_name!("$set_nsto_as_unify"), - &SystemClauseType::HomeDirectory => clause_name!("$home_directory"), + atom!("$ed25519_keypair_public_key") + } + &SystemClauseType::Curve25519ScalarMult => atom!("$curve25519_scalar_mult"), + &SystemClauseType::FirstNonOctet => atom!("$first_non_octet"), + &SystemClauseType::LoadHTML => atom!("$load_html"), + &SystemClauseType::LoadXML => atom!("$load_xml"), + &SystemClauseType::GetEnv => atom!("$getenv"), + &SystemClauseType::SetEnv => atom!("$setenv"), + &SystemClauseType::UnsetEnv => atom!("$unsetenv"), + &SystemClauseType::Shell => atom!("$shell"), + &SystemClauseType::PID => atom!("$pid"), + &SystemClauseType::CharsBase64 => atom!("$chars_base64"), + &SystemClauseType::LoadLibraryAsStream => atom!("$load_library_as_stream"), + &SystemClauseType::DevourWhitespace => atom!("$devour_whitespace"), + &SystemClauseType::IsSTOEnabled => atom!("$is_sto_enabled"), + &SystemClauseType::SetSTOAsUnify => atom!("$set_sto_as_unify"), + &SystemClauseType::SetNSTOAsUnify => atom!("$set_nsto_as_unify"), + &SystemClauseType::HomeDirectory => atom!("$home_directory"), &SystemClauseType::SetSTOWithErrorAsUnify => { - clause_name!("$set_sto_with_error_as_unify") + atom!("$set_sto_with_error_as_unify") } - &SystemClauseType::DebugHook => clause_name!("$debug_hook"), - &SystemClauseType::PopCount => clause_name!("$popcount"), + &SystemClauseType::DebugHook => atom!("$debug_hook"), + &SystemClauseType::PopCount => atom!("$popcount"), } } - pub(crate) fn from(name: &str, arity: usize) -> Option { + pub(crate) fn from(name: Atom, arity: usize) -> Option { match (name, arity) { - ("$abolish_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)), - ("$add_dynamic_predicate", 4) => { + (atom!("$abolish_clause"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)), + (atom!("$add_dynamic_predicate"), 4) => { Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate)) } - ("$add_multifile_predicate", 4) => { + (atom!("$add_multifile_predicate"), 4) => { Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate)) } - ("$add_discontiguous_predicate", 4) => Some(SystemClauseType::REPL( + (atom!("$add_discontiguous_predicate"), 4) => Some(SystemClauseType::REPL( REPLCodePtr::AddDiscontiguousPredicate, )), - ("$add_goal_expansion_clause", 3) => { + (atom!("$add_goal_expansion_clause"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause)) } - ("$add_term_expansion_clause", 2) => { + (atom!("$add_term_expansion_clause"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause)) } - ("$atom_chars", 2) => Some(SystemClauseType::AtomChars), - ("$atom_codes", 2) => Some(SystemClauseType::AtomCodes), - ("$atom_length", 2) => Some(SystemClauseType::AtomLength), - ("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister), - ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation), - ("$char_code", 2) => Some(SystemClauseType::CharCode), - ("$char_type", 2) => Some(SystemClauseType::CharType), - ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), - ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), - ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), - ("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString), - ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), - ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), - ("$close", 2) => Some(SystemClauseType::Close), - ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname), - ("$current_input", 1) => Some(SystemClauseType::CurrentInput), - ("$current_output", 1) => Some(SystemClauseType::CurrentOutput), - ("$first_stream", 1) => Some(SystemClauseType::FirstStream), - ("$next_stream", 2) => Some(SystemClauseType::NextStream), - ("$flush_output", 1) => Some(SystemClauseType::FlushOutput), - ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), - ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute), - ("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef), - ("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef), - ("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef), - ("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef), - ("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)), - ("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar), - ("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail), - ("$peek_byte", 2) => Some(SystemClauseType::PeekByte), - ("$peek_char", 2) => Some(SystemClauseType::PeekChar), - ("$peek_code", 2) => Some(SystemClauseType::PeekCode), - ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString), - ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), - ("$get_byte", 2) => Some(SystemClauseType::GetByte), - ("$get_char", 2) => Some(SystemClauseType::GetChar), - ("$get_n_chars", 3) => Some(SystemClauseType::GetNChars), - ("$get_code", 2) => Some(SystemClauseType::GetCode), - ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar), - ("$points_to_cont_reset_marker", 1) => { + (atom!("$atom_chars"), 2) => Some(SystemClauseType::AtomChars), + (atom!("$atom_codes"), 2) => Some(SystemClauseType::AtomCodes), + (atom!("$atom_length"), 2) => Some(SystemClauseType::AtomLength), + (atom!("$bind_from_register"), 2) => Some(SystemClauseType::BindFromRegister), + (atom!("$call_continuation"), 1) => Some(SystemClauseType::CallContinuation), + (atom!("$char_code"), 2) => Some(SystemClauseType::CharCode), + (atom!("$char_type"), 2) => Some(SystemClauseType::CharType), + (atom!("$chars_to_number"), 2) => Some(SystemClauseType::CharsToNumber), + (atom!("$codes_to_number"), 2) => Some(SystemClauseType::CodesToNumber), + (atom!("$copy_term_without_attr_vars"), 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), + (atom!("$create_partial_string"), 3) => Some(SystemClauseType::CreatePartialString), + (atom!("$check_cp"), 1) => Some(SystemClauseType::CheckCutPoint), + (atom!("$copy_to_lh"), 2) => Some(SystemClauseType::CopyToLiftedHeap), + (atom!("$close"), 2) => Some(SystemClauseType::Close), + (atom!("$current_hostname"), 1) => Some(SystemClauseType::CurrentHostname), + (atom!("$current_input"), 1) => Some(SystemClauseType::CurrentInput), + (atom!("$current_output"), 1) => Some(SystemClauseType::CurrentOutput), + (atom!("$first_stream"), 1) => Some(SystemClauseType::FirstStream), + (atom!("$next_stream"), 2) => Some(SystemClauseType::NextStream), + (atom!("$flush_output"), 1) => Some(SystemClauseType::FlushOutput), + (atom!("$del_attr_non_head"), 1) => Some(SystemClauseType::DeleteAttribute), + (atom!("$del_attr_head"), 1) => Some(SystemClauseType::DeleteHeadAttribute), + (atom!("$get_next_db_ref"), 2) => Some(SystemClauseType::GetNextDBRef), + (atom!("$get_next_op_db_ref"), 2) => Some(SystemClauseType::GetNextOpDBRef), + (atom!("$module_call"), _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)), + (atom!("$enqueue_attr_var"), 1) => Some(SystemClauseType::EnqueueAttributedVar), + (atom!("$partial_string_tail"), 2) => Some(SystemClauseType::PartialStringTail), + (atom!("$peek_byte"), 2) => Some(SystemClauseType::PeekByte), + (atom!("$peek_char"), 2) => Some(SystemClauseType::PeekChar), + (atom!("$peek_code"), 2) => Some(SystemClauseType::PeekCode), + (atom!("$is_partial_string"), 1) => Some(SystemClauseType::IsPartialString), + (atom!("$fetch_global_var"), 2) => Some(SystemClauseType::FetchGlobalVar), + (atom!("$get_byte"), 2) => Some(SystemClauseType::GetByte), + (atom!("$get_char"), 2) => Some(SystemClauseType::GetChar), + (atom!("$get_n_chars"), 3) => Some(SystemClauseType::GetNChars), + (atom!("$get_code"), 2) => Some(SystemClauseType::GetCode), + (atom!("$get_single_char"), 1) => Some(SystemClauseType::GetSingleChar), + (atom!("$points_to_cont_reset_marker"), 1) => { Some(SystemClauseType::PointsToContinuationResetMarker) } - ("$put_byte", 2) => Some(SystemClauseType::PutByte), - ("$put_char", 2) => Some(SystemClauseType::PutChar), - ("$put_chars", 2) => Some(SystemClauseType::PutChars), - ("$put_code", 2) => Some(SystemClauseType::PutCode), - ("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState), - ("$truncate_if_no_lh_growth", 1) => { + (atom!("$put_byte"), 2) => Some(SystemClauseType::PutByte), + (atom!("$put_char"), 2) => Some(SystemClauseType::PutChar), + (atom!("$put_chars"), 2) => Some(SystemClauseType::PutChars), + (atom!("$put_code"), 2) => Some(SystemClauseType::PutCode), + (atom!("$reset_attr_var_state"), 0) => Some(SystemClauseType::ResetAttrVarState), + (atom!("$truncate_if_no_lh_growth"), 1) => { Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth) } - ("$truncate_if_no_lh_growth_diff", 2) => { + (atom!("$truncate_if_no_lh_growth_diff"), 2) => { Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff) } - ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList), - ("$get_b_value", 1) => Some(SystemClauseType::GetBValue), - ("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset), - ("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff), - ("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes), - ("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner), - ("$halt", 1) => Some(SystemClauseType::Halt), - ("$head_is_dynamic", 2) => Some(SystemClauseType::HeadIsDynamic), - ("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner), - ("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter), - ("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength), - ("$maybe", 0) => Some(SystemClauseType::Maybe), - ("$cpu_now", 1) => Some(SystemClauseType::CpuNow), - ("$current_time", 1) => Some(SystemClauseType::CurrentTime), - ("$module_exists", 1) => Some(SystemClauseType::ModuleExists), - ("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate), - ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars), - ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), - ("$op", 3) => Some(SystemClauseType::OpDeclaration), - ("$open", 7) => Some(SystemClauseType::Open), - ("$set_stream_options", 5) => Some(SystemClauseType::SetStreamOptions), - ("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding), - ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck), - ("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter), - ("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy), - ("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))), - ("$set_input", 1) => Some(SystemClauseType::SetInput), - ("$set_output", 1) => Some(SystemClauseType::SetOutput), - ("$stream_property", 3) => Some(SystemClauseType::StreamProperty), - ("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition), - ("$inference_level", 2) => Some(SystemClauseType::InferenceLevel), - ("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock), - ("$erase_ball", 0) => Some(SystemClauseType::EraseBall), - ("$fail", 0) => Some(SystemClauseType::Fail), - ("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond), - ("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter), - ("$get_ball", 1) => Some(SystemClauseType::GetBall), - ("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk), - ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock), - ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), - ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), - ("$quoted_token", 1) => Some(SystemClauseType::QuotedToken), - ("$nextEP", 3) => Some(SystemClauseType::NextEP), - ("$read_query_term", 5) => Some(SystemClauseType::ReadQueryTerm), - ("$read_term", 5) => Some(SystemClauseType::ReadTerm), - ("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars), - ("$reset_block", 1) => Some(SystemClauseType::ResetBlock), - ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker), - ("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr), - ("$set_ball", 1) => Some(SystemClauseType::SetBall), - ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), - ("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes), - ("$set_seed", 1) => Some(SystemClauseType::SetSeed), - ("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList), - ("$sleep", 1) => Some(SystemClauseType::Sleep), - ("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen), - ("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen), - ("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept), - ("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose), - ("$tls_accept_client", 4) => Some(SystemClauseType::TLSAcceptClient), - ("$tls_client_connect", 3) => Some(SystemClauseType::TLSClientConnect), - ("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar), - ("$store_backtrackable_global_var", 2) => { + (atom!("$get_attr_list"), 2) => Some(SystemClauseType::GetAttributedVariableList), + (atom!("$get_b_value"), 1) => Some(SystemClauseType::GetBValue), + (atom!("$get_lh_from_offset"), 2) => Some(SystemClauseType::GetLiftedHeapFromOffset), + (atom!("$get_lh_from_offset_diff"), 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff), + (atom!("$get_double_quotes"), 1) => Some(SystemClauseType::GetDoubleQuotes), + (atom!("$get_scc_cleaner"), 1) => Some(SystemClauseType::GetSCCCleaner), + (atom!("$halt"), 1) => Some(SystemClauseType::Halt), + (atom!("$head_is_dynamic"), 2) => Some(SystemClauseType::HeadIsDynamic), + (atom!("$install_scc_cleaner"), 2) => Some(SystemClauseType::InstallSCCCleaner), + (atom!("$install_inference_counter"), 3) => Some(SystemClauseType::InstallInferenceCounter), + (atom!("$lh_length"), 1) => Some(SystemClauseType::LiftedHeapLength), + (atom!("$maybe"), 0) => Some(SystemClauseType::Maybe), + (atom!("$cpu_now"), 1) => Some(SystemClauseType::CpuNow), + (atom!("$current_time"), 1) => Some(SystemClauseType::CurrentTime), + (atom!("$module_exists"), 1) => Some(SystemClauseType::ModuleExists), + (atom!("$no_such_predicate"), 2) => Some(SystemClauseType::NoSuchPredicate), + (atom!("$number_to_chars"), 2) => Some(SystemClauseType::NumberToChars), + (atom!("$number_to_codes"), 2) => Some(SystemClauseType::NumberToCodes), + (atom!("$op"), 3) => Some(SystemClauseType::OpDeclaration), + (atom!("$open"), 7) => Some(SystemClauseType::Open), + (atom!("$set_stream_options"), 5) => Some(SystemClauseType::SetStreamOptions), + (atom!("$redo_attr_var_binding"), 2) => Some(SystemClauseType::RedoAttrVarBinding), + (atom!("$remove_call_policy_check"), 1) => Some(SystemClauseType::RemoveCallPolicyCheck), + (atom!("$remove_inference_counter"), 2) => Some(SystemClauseType::RemoveInferenceCounter), + (atom!("$restore_cut_policy"), 0) => Some(SystemClauseType::RestoreCutPolicy), + (atom!("$set_cp"), 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))), + (atom!("$set_input"), 1) => Some(SystemClauseType::SetInput), + (atom!("$set_output"), 1) => Some(SystemClauseType::SetOutput), + (atom!("$stream_property"), 3) => Some(SystemClauseType::StreamProperty), + (atom!("$set_stream_position"), 2) => Some(SystemClauseType::SetStreamPosition), + (atom!("$inference_level"), 2) => Some(SystemClauseType::InferenceLevel), + (atom!("$clean_up_block"), 1) => Some(SystemClauseType::CleanUpBlock), + (atom!("$erase_ball"), 0) => Some(SystemClauseType::EraseBall), + (atom!("$fail"), 0) => Some(SystemClauseType::Fail), + (atom!("$get_attr_var_queue_beyond"), 2) => Some(SystemClauseType::GetAttrVarQueueBeyond), + (atom!("$get_attr_var_queue_delim"), 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter), + (atom!("$get_ball"), 1) => Some(SystemClauseType::GetBall), + (atom!("$get_cont_chunk"), 3) => Some(SystemClauseType::GetContinuationChunk), + (atom!("$get_current_block"), 1) => Some(SystemClauseType::GetCurrentBlock), + (atom!("$get_cp"), 1) => Some(SystemClauseType::GetCutPoint), + (atom!("$install_new_block"), 1) => Some(SystemClauseType::InstallNewBlock), + (atom!("$quoted_token"), 1) => Some(SystemClauseType::QuotedToken), + (atom!("$nextEP"), 3) => Some(SystemClauseType::NextEP), + (atom!("$read_query_term"), 5) => Some(SystemClauseType::ReadQueryTerm), + (atom!("$read_term"), 5) => Some(SystemClauseType::ReadTerm), + (atom!("$read_term_from_chars"), 2) => Some(SystemClauseType::ReadTermFromChars), + (atom!("$reset_block"), 1) => Some(SystemClauseType::ResetBlock), + (atom!("$reset_cont_marker"), 0) => Some(SystemClauseType::ResetContinuationMarker), + (atom!("$return_from_verify_attr"), 0) => Some(SystemClauseType::ReturnFromVerifyAttr), + (atom!("$set_ball"), 1) => Some(SystemClauseType::SetBall), + (atom!("$set_cp_by_default"), 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), + (atom!("$set_double_quotes"), 1) => Some(SystemClauseType::SetDoubleQuotes), + (atom!("$set_seed"), 1) => Some(SystemClauseType::SetSeed), + (atom!("$skip_max_list"), 4) => Some(SystemClauseType::SkipMaxList), + (atom!("$sleep"), 1) => Some(SystemClauseType::Sleep), + (atom!("$tls_accept_client"), 4) => Some(SystemClauseType::TLSAcceptClient), + (atom!("$tls_client_connect"), 3) => Some(SystemClauseType::TLSClientConnect), + (atom!("$socket_client_open"), 8) => Some(SystemClauseType::SocketClientOpen), + (atom!("$socket_server_open"), 3) => Some(SystemClauseType::SocketServerOpen), + (atom!("$socket_server_accept"), 7) => Some(SystemClauseType::SocketServerAccept), + (atom!("$socket_server_close"), 1) => Some(SystemClauseType::SocketServerClose), + (atom!("$store_global_var"), 2) => Some(SystemClauseType::StoreGlobalVar), + (atom!("$store_backtrackable_global_var"), 2) => { Some(SystemClauseType::StoreBacktrackableGlobalVar) } - ("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables), - ("$term_variables", 2) => Some(SystemClauseType::TermVariables), - ("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo), - ("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments), - ("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack), - ("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck), - ("$directory_files", 2) => Some(SystemClauseType::DirectoryFiles), - ("$file_size", 2) => Some(SystemClauseType::FileSize), - ("$file_exists", 1) => Some(SystemClauseType::FileExists), - ("$directory_exists", 1) => Some(SystemClauseType::DirectoryExists), - ("$directory_separator", 1) => Some(SystemClauseType::DirectorySeparator), - ("$make_directory", 1) => Some(SystemClauseType::MakeDirectory), - ("$make_directory_path", 1) => Some(SystemClauseType::MakeDirectoryPath), - ("$delete_file", 1) => Some(SystemClauseType::DeleteFile), - ("$rename_file", 2) => Some(SystemClauseType::RenameFile), - ("$delete_directory", 1) => Some(SystemClauseType::DeleteDirectory), - ("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory), - ("$path_canonical", 2) => Some(SystemClauseType::PathCanonical), - ("$file_time", 3) => Some(SystemClauseType::FileTime), - ("$clause_to_evacuable", 2) => { + (atom!("$term_attributed_variables"), 2) => Some(SystemClauseType::TermAttributedVariables), + (atom!("$term_variables"), 2) => Some(SystemClauseType::TermVariables), + (atom!("$term_variables_under_max_depth"), 3) => Some(SystemClauseType::TermVariablesUnderMaxDepth), + (atom!("$truncate_lh_to"), 1) => Some(SystemClauseType::TruncateLiftedHeapTo), + (atom!("$unwind_environments"), 0) => Some(SystemClauseType::UnwindEnvironments), + (atom!("$unwind_stack"), 0) => Some(SystemClauseType::UnwindStack), + (atom!("$unify_with_occurs_check"), 2) => Some(SystemClauseType::UnifyWithOccursCheck), + (atom!("$directory_files"), 2) => Some(SystemClauseType::DirectoryFiles), + (atom!("$file_size"), 2) => Some(SystemClauseType::FileSize), + (atom!("$file_exists"), 1) => Some(SystemClauseType::FileExists), + (atom!("$directory_exists"), 1) => Some(SystemClauseType::DirectoryExists), + (atom!("$directory_separator"), 1) => Some(SystemClauseType::DirectorySeparator), + (atom!("$make_directory"), 1) => Some(SystemClauseType::MakeDirectory), + (atom!("$make_directory_path"), 1) => Some(SystemClauseType::MakeDirectoryPath), + (atom!("$delete_file"), 1) => Some(SystemClauseType::DeleteFile), + (atom!("$rename_file"), 2) => Some(SystemClauseType::RenameFile), + (atom!("$delete_directory"), 1) => Some(SystemClauseType::DeleteDirectory), + (atom!("$working_directory"), 2) => Some(SystemClauseType::WorkingDirectory), + (atom!("$path_canonical"), 2) => Some(SystemClauseType::PathCanonical), + (atom!("$file_time"), 3) => Some(SystemClauseType::FileTime), + (atom!("$clause_to_evacuable"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable)) } - ("$scoped_clause_to_evacuable", 3) => { + (atom!("$scoped_clause_to_evacuable"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable)) } - ("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)), - ("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), - ("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)), - ("$load_compiled_library", 3) => { + (atom!("$conclude_load"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)), + (atom!("$use_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), + (atom!("$declare_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)), + (atom!("$load_compiled_library"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary)) } - ("$push_load_state_payload", 1) => { + (atom!("$push_load_state_payload"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload)) } - ("$add_in_situ_filename_module", 1) => { + (atom!("$add_in_situ_filename_module"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule)) } - ("$asserta", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)), - ("$assertz", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)), - ("$retract_clause", 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)), - ("$is_consistent_with_term_queue", 4) => Some(SystemClauseType::REPL( + (atom!("$asserta"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)), + (atom!("$assertz"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)), + (atom!("$retract_clause"), 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)), + (atom!("$is_consistent_with_term_queue"), 4) => Some(SystemClauseType::REPL( REPLCodePtr::IsConsistentWithTermQueue, )), - ("$flush_term_queue", 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)), - ("$remove_module_exports", 2) => { + (atom!("$flush_term_queue"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)), + (atom!("$remove_module_exports"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports)) } - ("$add_non_counted_backtracking", 3) => Some(SystemClauseType::REPL( + (atom!("$add_non_counted_backtracking"), 3) => Some(SystemClauseType::REPL( REPLCodePtr::AddNonCountedBacktracking, )), - ("$variant", 2) => Some(SystemClauseType::Variant), - ("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions), - ("$write_term", 7) => Some(SystemClauseType::WriteTerm), - ("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars), - ("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion), - ("$crypto_random_byte", 1) => Some(SystemClauseType::CryptoRandomByte), - ("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash), - ("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF), - ("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash), - ("$crypto_data_encrypt", 7) => Some(SystemClauseType::CryptoDataEncrypt), - ("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt), - ("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult), - ("$ed25519_sign", 4) => Some(SystemClauseType::Ed25519Sign), - ("$ed25519_verify", 4) => Some(SystemClauseType::Ed25519Verify), - ("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair), - ("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), - ("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult), - ("$first_non_octet", 2) => Some(SystemClauseType::FirstNonOctet), - ("$load_html", 3) => Some(SystemClauseType::LoadHTML), - ("$load_xml", 3) => Some(SystemClauseType::LoadXML), - ("$getenv", 2) => Some(SystemClauseType::GetEnv), - ("$setenv", 2) => Some(SystemClauseType::SetEnv), - ("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv), - ("$shell", 2) => Some(SystemClauseType::Shell), - ("$pid", 1) => Some(SystemClauseType::PID), - ("$chars_base64", 4) => Some(SystemClauseType::CharsBase64), - ("$load_library_as_stream", 3) => Some(SystemClauseType::LoadLibraryAsStream), - ("$push_load_context", 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)), - ("$pop_load_state_payload", 1) => { + (atom!("$wam_instructions"), 4) => Some(SystemClauseType::WAMInstructions), + (atom!("$write_term"), 7) => Some(SystemClauseType::WriteTerm), + (atom!("$write_term_to_chars"), 7) => Some(SystemClauseType::WriteTermToChars), + (atom!("$scryer_prolog_version"), 1) => Some(SystemClauseType::ScryerPrologVersion), + (atom!("$crypto_random_byte"), 1) => Some(SystemClauseType::CryptoRandomByte), + (atom!("$crypto_data_hash"), 4) => Some(SystemClauseType::CryptoDataHash), + (atom!("$crypto_data_hkdf"), 7) => Some(SystemClauseType::CryptoDataHKDF), + (atom!("$crypto_password_hash"), 4) => Some(SystemClauseType::CryptoPasswordHash), + (atom!("$crypto_data_encrypt"), 7) => Some(SystemClauseType::CryptoDataEncrypt), + (atom!("$crypto_data_decrypt"), 6) => Some(SystemClauseType::CryptoDataDecrypt), + (atom!("$crypto_curve_scalar_mult"), 5) => Some(SystemClauseType::CryptoCurveScalarMult), + (atom!("$ed25519_sign"), 4) => Some(SystemClauseType::Ed25519Sign), + (atom!("$ed25519_verify"), 4) => Some(SystemClauseType::Ed25519Verify), + (atom!("$ed25519_new_keypair"), 1) => Some(SystemClauseType::Ed25519NewKeyPair), + (atom!("$ed25519_keypair_public_key"), 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), + (atom!("$curve25519_scalar_mult"), 3) => Some(SystemClauseType::Curve25519ScalarMult), + (atom!("$load_html"), 3) => Some(SystemClauseType::LoadHTML), + (atom!("$load_xml"), 3) => Some(SystemClauseType::LoadXML), + (atom!("$getenv"), 2) => Some(SystemClauseType::GetEnv), + (atom!("$setenv"), 2) => Some(SystemClauseType::SetEnv), + (atom!("$unsetenv"), 1) => Some(SystemClauseType::UnsetEnv), + (atom!("$pid"), 1) => Some(SystemClauseType::PID), + (atom!("$chars_base64"), 4) => Some(SystemClauseType::CharsBase64), + (atom!("$load_library_as_stream"), 3) => Some(SystemClauseType::LoadLibraryAsStream), + (atom!("$push_load_context"), 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)), + (atom!("$pop_load_state_payload"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload)) } - ("$pop_load_context", 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)), - ("$prolog_lc_source", 1) => { + (atom!("$pop_load_context"), 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)), + (atom!("$prolog_lc_source"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource)) } - ("$prolog_lc_file", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)), - ("$prolog_lc_dir", 1) => { + (atom!("$prolog_lc_file"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)), + (atom!("$prolog_lc_dir"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory)) } - ("$prolog_lc_module", 1) => { + (atom!("$prolog_lc_module"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule)) } - ("$prolog_lc_stream", 1) => { + (atom!("$prolog_lc_stream"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream)) } - ("$cpp_meta_predicate_property", 4) => { + (atom!("$cpp_meta_predicate_property"), 4) => { Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty)) } - ("$cpp_built_in_property", 2) => { + (atom!("$cpp_built_in_property"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty)) } - ("$cpp_dynamic_property", 3) => { + (atom!("$cpp_dynamic_property"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::DynamicProperty)) } - ("$cpp_multifile_property", 3) => { + (atom!("$cpp_multifile_property"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::MultifileProperty)) } - ("$cpp_discontiguous_property", 3) => { + (atom!("$cpp_discontiguous_property"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty)) } - ("$devour_whitespace", 1) => Some(SystemClauseType::DevourWhitespace), - ("$is_sto_enabled", 1) => Some(SystemClauseType::IsSTOEnabled), - ("$set_sto_as_unify", 0) => Some(SystemClauseType::SetSTOAsUnify), - ("$set_nsto_as_unify", 0) => Some(SystemClauseType::SetNSTOAsUnify), - ("$set_sto_with_error_as_unify", 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify), - ("$home_directory", 1) => Some(SystemClauseType::HomeDirectory), - ("$debug_hook", 0) => Some(SystemClauseType::DebugHook), - ("$popcount", 2) => Some(SystemClauseType::PopCount), + (atom!("$devour_whitespace"), 1) => Some(SystemClauseType::DevourWhitespace), + (atom!("$is_sto_enabled"), 1) => Some(SystemClauseType::IsSTOEnabled), + (atom!("$set_sto_as_unify"), 0) => Some(SystemClauseType::SetSTOAsUnify), + (atom!("$set_nsto_as_unify"), 0) => Some(SystemClauseType::SetNSTOAsUnify), + (atom!("$set_sto_with_error_as_unify"), 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify), + (atom!("$home_directory"), 1) => Some(SystemClauseType::HomeDirectory), + (atom!("$debug_hook"), 0) => Some(SystemClauseType::DebugHook), _ => None, } } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) enum BuiltInClauseType { +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum BuiltInClauseType { AcyclicTerm, Arg, Compare, @@ -895,31 +868,30 @@ pub(crate) enum BuiltInClauseType { } #[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum ClauseType { +pub enum ClauseType { BuiltIn(BuiltInClauseType), CallN, Inlined(InlinedClauseType), - Named(ClauseName, usize, CodeIndex), // name, arity, index. - Op(ClauseName, SharedOpDesc, CodeIndex), + Named(Atom, usize, CodeIndex), // name, arity, index. System(SystemClauseType), } impl BuiltInClauseType { - pub(crate) fn name(&self) -> ClauseName { + pub(crate) fn name(&self) -> Atom { match self { - &BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"), - &BuiltInClauseType::Arg => clause_name!("arg"), - &BuiltInClauseType::Compare => clause_name!("compare"), - &BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()), - &BuiltInClauseType::CopyTerm => clause_name!("copy_term"), - &BuiltInClauseType::Eq => clause_name!("=="), - &BuiltInClauseType::Functor => clause_name!("functor"), - &BuiltInClauseType::Ground => clause_name!("ground"), - &BuiltInClauseType::Is(..) => clause_name!("is"), - &BuiltInClauseType::KeySort => clause_name!("keysort"), - &BuiltInClauseType::NotEq => clause_name!("\\=="), - &BuiltInClauseType::Read => clause_name!("read"), - &BuiltInClauseType::Sort => clause_name!("sort"), + &BuiltInClauseType::AcyclicTerm => atom!("acyclic_term"), + &BuiltInClauseType::Arg => atom!("arg"), + &BuiltInClauseType::Compare => atom!("compare"), + &BuiltInClauseType::CompareTerm(qt) => qt.name(), + &BuiltInClauseType::CopyTerm => atom!("copy_term"), + &BuiltInClauseType::Eq => atom!("=="), + &BuiltInClauseType::Functor => atom!("functor"), + &BuiltInClauseType::Ground => atom!("ground"), + &BuiltInClauseType::Is(..) => atom!("is"), + &BuiltInClauseType::KeySort => atom!("keysort"), + &BuiltInClauseType::NotEq => atom!("\\=="), + &BuiltInClauseType::Read => atom!("read"), + &BuiltInClauseType::Sort => atom!("sort"), } } @@ -936,54 +908,35 @@ impl BuiltInClauseType { &BuiltInClauseType::Is(..) => 2, &BuiltInClauseType::KeySort => 2, &BuiltInClauseType::NotEq => 2, - &BuiltInClauseType::Read => 2, + &BuiltInClauseType::Read => 1, &BuiltInClauseType::Sort => 2, } } } impl ClauseType { - pub(crate) fn spec(&self) -> Option { - match self { - &ClauseType::Op(_, ref spec, _) => Some(spec.clone()), - &ClauseType::Inlined(InlinedClauseType::CompareNumber(..)) - | &ClauseType::BuiltIn(BuiltInClauseType::Is(..)) - | &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_)) - | &ClauseType::BuiltIn(BuiltInClauseType::NotEq) - | &ClauseType::BuiltIn(BuiltInClauseType::Eq) => Some(SharedOpDesc::new(700, XFX)), - _ => None, - } - } - - pub(crate) fn name(&self) -> ClauseName { + pub(crate) fn name(&self) -> Atom { match self { &ClauseType::BuiltIn(ref built_in) => built_in.name(), - &ClauseType::CallN => clause_name!("$call"), - &ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()), - &ClauseType::Op(ref name, ..) => name.clone(), - &ClauseType::Named(ref name, ..) => name.clone(), + &ClauseType::CallN => atom!("$call"), + &ClauseType::Inlined(ref inlined) => inlined.name(), + &ClauseType::Named(name, ..) => name, &ClauseType::System(ref system) => system.name(), } } - pub(crate) fn from(name: ClauseName, arity: usize, spec: Option) -> Self { - CLAUSE_TYPE_FORMS - .borrow() - .get(&(name.as_str(), arity)) - .cloned() - .unwrap_or_else(|| { - SystemClauseType::from(name.as_str(), arity) - .map(ClauseType::System) - .unwrap_or_else(|| { - if let Some(spec) = spec { - ClauseType::Op(name, spec, CodeIndex::default()) - } else if name.as_str() == "$call" { - ClauseType::CallN - } else { - ClauseType::Named(name, arity, CodeIndex::default()) - } - }) - }) + pub(crate) fn from(name: Atom, arity: usize) -> Self { + clause_type_form(name, arity).unwrap_or_else(|| { + SystemClauseType::from(name, arity) + .map(ClauseType::System) + .unwrap_or_else(|| { + if name == atom!("$call") { + ClauseType::CallN + } else { + ClauseType::Named(name, arity, CodeIndex::default()) + } + }) + }) } } diff --git a/src/codegen.rs b/src/codegen.rs index a678549b1..243974aa1 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,7 +1,6 @@ -/// Code generation to WAM-like instructions. -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::TabledData; -use prolog_parser::{perm_v, temp_v}; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::{perm_v, temp_v}; use crate::allocator::*; use crate::arithmetic::*; @@ -12,6 +11,7 @@ use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; use crate::targets::*; +use crate::types::*; use crate::machine::machine_errors::*; @@ -108,7 +108,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicInternalElse( global_clock_time, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else { ChoiceInstruction::TryMeElse(offset) @@ -120,7 +124,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicElse( global_clock_tick, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else { ChoiceInstruction::TryMeElse(offset) @@ -132,7 +140,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicInternalElse( global_clock_tick, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else { ChoiceInstruction::RetryMeElse(offset) @@ -144,7 +156,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicElse( global_clock_tick, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else if self.non_counted_bt { ChoiceInstruction::DefaultRetryMeElse(offset) @@ -169,11 +185,7 @@ impl CodeGenSettings { pub(crate) fn trust_me(&self) -> ChoiceInstruction { if let Some(global_clock_tick) = self.global_clock_tick { - ChoiceInstruction::DynamicElse( - global_clock_tick, - Death::Infinity, - NextOrFail::Fail(0), - ) + ChoiceInstruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0)) } else if self.non_counted_bt { ChoiceInstruction::DefaultTrustMe(0) } else { @@ -183,18 +195,18 @@ impl CodeGenSettings { } #[derive(Debug)] -pub(crate) struct CodeGenerator { - atom_tbl: TabledData, +pub(crate) struct CodeGenerator<'a, TermMarker> { + pub(crate) atom_tbl: &'a mut AtomTable, marker: TermMarker, - pub(crate) var_count: IndexMap, usize>, + pub(crate) var_count: IndexMap, usize>, settings: CodeGenSettings, pub(crate) skeleton: PredicateSkeleton, pub(crate) jmp_by_locs: Vec, global_jmp_by_locs_offset: usize, } -impl<'a, TermMarker: Allocator<'a>> CodeGenerator { - pub(crate) fn new(atom_tbl: TabledData, settings: CodeGenSettings) -> Self { +impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { + pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self { CodeGenerator { atom_tbl, marker: Allocator::new(), @@ -215,13 +227,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - fn get_var_count(&self, var: &'a Var) -> usize { + fn get_var_count(&self, var: &'a String) -> usize { *self.var_count.get(var).unwrap() } fn mark_var_in_non_callable( &mut self, - name: Rc, + name: Rc, term_loc: GenContext, vr: &'a Cell, code: &mut Code, @@ -239,7 +251,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn mark_non_callable( &mut self, - name: Rc, + name: Rc, arg: usize, term_loc: GenContext, vr: &'a Cell, @@ -261,7 +273,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn add_or_increment_void_instr(target: &mut Vec) where - Target: CompilationTarget<'a>, + Target: crate::targets::CompilationTarget<'a>, { if let Some(ref mut instr) = target.last_mut() { if Target::is_void_instr(&*instr) { @@ -273,10 +285,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { target.push(Target::to_void(1)); } - fn deep_var_instr>( + fn deep_var_instr>( &mut self, cell: &'a Cell, - var: &'a Rc, + var: &'a Rc, term_loc: GenContext, is_exposed: bool, target: &mut Vec, @@ -289,7 +301,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - fn subterm_to_instr>( + fn subterm_to_instr>( &mut self, subterm: &'a Term, term_loc: GenContext, @@ -303,12 +315,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { &Term::AnonVar => { Self::add_or_increment_void_instr(target); } - &Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => { + &Term::Cons(ref cell, ..) + | &Term::Clause(ref cell, ..) + | Term::PartialString(ref cell, ..) => { self.marker .mark_non_var(Level::Deep, term_loc, cell, target); target.push(Target::clause_arg_to_instr(cell.get())); } - &Term::Constant(_, ref constant) => { + &Term::Literal(_, ref constant) => { target.push(Target::constant_subterm(constant.clone())); } &Term::Var(ref cell, ref var) => { @@ -324,7 +338,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { is_exposed: bool, ) -> Vec where - Target: CompilationTarget<'a>, + Target: crate::targets::CompilationTarget<'a>, Iter: Iterator>, { let mut target = Vec::new(); @@ -343,7 +357,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { target.push(Target::to_structure(ct, terms.len(), cell.get())); for subterm in terms { - self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, &mut target); + self.subterm_to_instr(subterm, term_loc, is_exposed, &mut target); } } TermRef::Cons(lvl, cell, head, tail) => { @@ -353,13 +367,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { self.subterm_to_instr(head, term_loc, is_exposed, &mut target); self.subterm_to_instr(tail, term_loc, is_exposed, &mut target); } - TermRef::Constant(lvl @ Level::Shallow, cell, Constant::String(ref string)) => { + TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => { self.marker.mark_non_var(lvl, term_loc, cell, &mut target); - target.push(Target::to_pstr(lvl, string.to_string(), cell.get(), false)); + target.push(Target::to_pstr(lvl, *string, cell.get(), false)); } - TermRef::Constant(lvl @ Level::Shallow, cell, constant) => { + TermRef::Literal(lvl @ Level::Shallow, cell, constant) => { self.marker.mark_non_var(lvl, term_loc, cell, &mut target); - target.push(Target::to_constant(lvl, constant.clone(), cell.get())); + target.push(Target::to_constant(lvl, *constant, cell.get())); } TermRef::PartialString(lvl, cell, string, tail) => { self.marker.mark_non_var(lvl, term_loc, cell, &mut target); @@ -418,6 +432,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { }; self.update_var_count(chunked_term.post_order_iter()); + vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc); } } @@ -476,7 +491,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn compile_inlined( &mut self, ct: &InlinedClauseType, - terms: &'a Vec>, + terms: &'a Vec, term_loc: GenContext, code: &mut Code, ) -> Result<(), CompilationError> { @@ -484,16 +499,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { &InlinedClauseType::CompareNumber(cmp, ..) => { self.marker.reset_arg(2); - let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?; - let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?; + let (mut lcode, at_1) = self.call_arith_eval(&terms[0], 1)?; + let (mut rcode, at_2) = self.call_arith_eval(&terms[1], 2)?; - let at_1 = if let &Term::Var(ref vr, ref name) = terms[0].as_ref() { + let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] { ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code)) } else { at_1.unwrap_or(interm!(1)) }; - let at_2 = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() { + let at_2 = if let &Term::Var(ref vr, ref name) = &terms[1] { ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code)) } else { at_2.unwrap_or(interm!(2)) @@ -504,10 +519,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(compare_number_instr!(cmp, at_1, at_2)); } - &InlinedClauseType::IsAtom(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Char(_)) - | &Term::Constant(_, Constant::EmptyList) - | &Term::Constant(_, Constant::Atom(..)) => { + &InlinedClauseType::IsAtom(..) => match &terms[0] { + &Term::Literal(_, Literal::Char(_)) + | &Term::Literal(_, Literal::Atom(atom!("[]"))) + | &Term::Literal(_, Literal::Atom(..)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -519,11 +534,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsAtomic(..) => match terms[0].as_ref() { - &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => { + &InlinedClauseType::IsAtomic(..) => match &terms[0] { + &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => { code.push(fail!()); } - &Term::Constant(..) => { + &Term::Literal(..) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -532,7 +547,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(is_atomic!(r)); } }, - &InlinedClauseType::IsCompound(..) => match terms[0].as_ref() { + &InlinedClauseType::IsCompound(..) => match &terms[0] { &Term::Clause(..) | &Term::Cons(..) => { code.push(succeed!()); } @@ -545,8 +560,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsRational(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Rational(_)) => { + &InlinedClauseType::IsRational(..) => match &terms[0] { + &Term::Literal(_, Literal::Rational(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -558,8 +573,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsFloat(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Float(_)) => { + &InlinedClauseType::IsFloat(..) => match &terms[0] { + &Term::Literal(_, Literal::Float(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -571,12 +586,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsNumber(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Float(_)) - | &Term::Constant(_, Constant::Rational(_)) - | &Term::Constant(_, Constant::Integer(_)) - | &Term::Constant(_, Constant::Fixnum(_)) - | &Term::Constant(_, Constant::Usize(_)) => { + &InlinedClauseType::IsNumber(..) => match &terms[0] { + &Term::Literal(_, Literal::Float(_)) + | &Term::Literal(_, Literal::Rational(_)) + | &Term::Literal(_, Literal::Integer(_)) + | &Term::Literal(_, Literal::Fixnum(_)) => { + // | &Term::Literal(_, Literal::Usize(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -588,7 +603,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() { + &InlinedClauseType::IsNonVar(..) => match &terms[0] { &Term::AnonVar => { code.push(fail!()); } @@ -601,10 +616,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(succeed!()); } }, - &InlinedClauseType::IsInteger(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Integer(_)) - | &Term::Constant(_, Constant::Fixnum(_)) - | &Term::Constant(_, Constant::Usize(_)) => { + &InlinedClauseType::IsInteger(..) => match &terms[0] { + &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => { + // | &Term::Literal(_, Literal::Usize(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -616,8 +630,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsVar(..) => match terms[0].as_ref() { - &Term::Constant(..) | &Term::Clause(..) | &Term::Cons(..) => { + &InlinedClauseType::IsVar(..) => match &terms[0] { + &Term::Literal(..) + | &Term::Clause(..) + | &Term::Cons(..) + | &Term::PartialString(..) => { code.push(fail!()); } &Term::AnonVar => { @@ -635,7 +652,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } fn call_arith_eval( - &self, + &mut self, term: &'a Term, target_int: usize, ) -> Result { @@ -645,17 +662,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn compile_is_call( &mut self, - terms: &'a Vec>, + terms: &'a Vec, code: &mut Code, term_loc: GenContext, use_default_call_policy: bool, ) -> Result<(), CompilationError> { - let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?; + let (mut acode, at) = self.call_arith_eval(&terms[1], 1)?; code.append(&mut acode); self.marker.reset_arg(2); - match terms[0].as_ref() { + match &terms[0] { &Term::Var(ref vr, ref name) => { let mut target = vec![]; @@ -666,31 +683,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.extend(target.into_iter().map(Line::Query)); } } - &Term::Constant(_, ref c @ Constant::Integer(_)) - | &Term::Constant(_, ref c @ Constant::Fixnum(_)) => { - code.push(Line::Query(put_constant!( - Level::Shallow, - c.clone(), - temp_v!(1) - ))); + &Term::Literal(_, c @ Literal::Integer(_)) + | &Term::Literal(_, c @ Literal::Fixnum(_)) => { + let v = HeapCellValue::from(c); + code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); self.marker.advance_arg(); } - &Term::Constant(_, ref c @ Constant::Float(_)) => { - code.push(Line::Query(put_constant!( - Level::Shallow, - c.clone(), - temp_v!(1) - ))); + &Term::Literal(_, c @ Literal::Float(_)) => { + let v = HeapCellValue::from(c); + code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); self.marker.advance_arg(); } - &Term::Constant(_, ref c @ Constant::Rational(_)) => { - code.push(Line::Query(put_constant!( - Level::Shallow, - c.clone(), - temp_v!(1) - ))); + &Term::Literal(_, c @ Literal::Rational(_)) => { + let v = HeapCellValue::from(c); + code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); self.marker.advance_arg(); } @@ -700,7 +708,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - let at = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() { + let at = if let &Term::Var(ref vr, ref name) = &terms[1] { ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code)) } else { at.unwrap_or(interm!(1)) @@ -724,7 +732,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { &mut self, code: &mut Code, cell: &'a Cell, - var: Rc, + var: Rc, term_loc: GenContext, ) { let mut target = Vec::new(); @@ -837,9 +845,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - pub(crate) fn compile_rule<'b: 'a>( + pub(crate) fn compile_rule<'c: 'a>( &mut self, - rule: &'b Rule, + rule: &'c Rule, ) -> Result { let iter = ChunkedIterator::from_rule(rule); let conjunct_info = self.collect_var_data(iter); @@ -897,10 +905,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { UnsafeVarMarker::from_safe_vars(safe_vars) } - pub(crate) fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code { + pub(crate) fn compile_fact<'c: 'a>(&mut self, term: &'c Term) -> Code { self.update_var_count(post_order_iter(term)); let mut vs = VariableFixtures::new(); + vs.mark_vars_in_chunk(post_order_iter(term), term.arity(), GenContext::Head); vs.populate_restricting_sets(); @@ -908,7 +917,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { let mut code = Vec::new(); - if let &Term::Clause(_, _, ref args, _) = term { + if let &Term::Clause(_, _, ref args) = term { self.marker.reset_at_head(args); let iter = FactInstruction::iter(term); @@ -979,7 +988,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { break; } } - match **arg { + match arg { Term::AnonVar | Term::Var(..) => (), _ => { match optimal_index { @@ -1003,7 +1012,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { for (right_index, clause) in clauses.iter().enumerate() { // Can unwrap safely. if let Some(arg) = clause.args().unwrap().iter().nth(optimal_index) { - match **arg { + match arg { Term::Var(..) | Term::AnonVar => { if left_index < right_index { subseqs.push((left_index, right_index)); @@ -1025,17 +1034,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { subseqs } - fn compile_pred_subseq<'b: 'a, I: Indexer>( + fn compile_pred_subseq<'c: 'a, I: Indexer>( &mut self, - clauses: &'b [PredicateClause], + clauses: &'c [PredicateClause], optimal_index: usize, ) -> Result { let mut code = VecDeque::new(); - let mut code_offsets = CodeOffsets::new( - self.atom_tbl.clone(), - I::new(), - optimal_index + 1, - ); + let mut code_offsets = CodeOffsets::new(I::new(), optimal_index + 1); let mut skip_stub_try_me_else = false; let jmp_by_locs_len = self.jmp_by_locs.len(); @@ -1087,7 +1092,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { if let Some(arg) = arg { let index = code.len(); - code_offsets.index_term(arg, index, &mut clause_index_info); + code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl); } if !(clauses.len() == 1 && self.settings.is_extensible) { @@ -1122,9 +1127,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { Ok(Vec::from(code)) } - pub(crate) fn compile_predicate<'b: 'a>( + pub(crate) fn compile_predicate<'c: 'a>( &mut self, - clauses: &'b Vec, + clauses: &'c Vec, ) -> Result { let mut code = Code::new(); diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 7525a79ad..2b67c56d8 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -1,13 +1,13 @@ use indexmap::IndexMap; -use prolog_parser::ast::*; -use prolog_parser::temp_v; - use crate::allocator::*; use crate::fixtures::*; -use crate::forms::*; +use crate::forms::Level; use crate::machine::machine_indices::*; -use crate::targets::*; +use crate::parser::ast::*; +use crate::targets::CompilationTarget; + +use crate::temp_v; use std::cell::Cell; use std::collections::BTreeSet; @@ -15,23 +15,23 @@ use std::rc::Rc; #[derive(Debug)] pub(crate) struct DebrayAllocator { - bindings: IndexMap, VarData>, + bindings: IndexMap, VarData>, arg_c: usize, temp_lb: usize, arity: usize, // 0 if not at head. - contents: IndexMap>, + contents: IndexMap>, in_use: BTreeSet, } impl DebrayAllocator { - fn is_curr_arg_distinct_from(&self, var: &Var) -> bool { + fn is_curr_arg_distinct_from(&self, var: &String) -> bool { match self.contents.get(&self.arg_c) { Some(t_var) if **t_var != *var => true, _ => false, } } - fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool { + fn occurs_shallowly_in_head(&self, var: &String, r: usize) -> bool { match self.bindings.get(var).unwrap() { &VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)), _ => false, @@ -44,7 +44,7 @@ impl DebrayAllocator { in_use_range || self.in_use.contains(&r) } - fn alloc_with_cr(&self, var: &Var) -> usize { + fn alloc_with_cr(&self, var: &String) -> usize { match self.bindings.get(var) { Some(&VarData::Temp(_, _, ref tvd)) => { for &(_, reg) in tvd.use_set.iter() { @@ -70,7 +70,7 @@ impl DebrayAllocator { } } - fn alloc_with_ca(&self, var: &Var) -> usize { + fn alloc_with_ca(&self, var: &String) -> usize { match self.bindings.get(var) { Some(&VarData::Temp(_, _, ref tvd)) => { for &(_, reg) in tvd.use_set.iter() { @@ -98,7 +98,7 @@ impl DebrayAllocator { } } - fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc, usize)> { + fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc, usize)> { // we want to allocate a register to the k^{th} parameter, par_k. // par_k may not be a temporary variable. let k = self.arg_c; @@ -149,7 +149,7 @@ impl DebrayAllocator { fn alloc_reg_to_var<'a, Target>( &mut self, - var: &Var, + var: &String, lvl: Level, term_loc: GenContext, target: &mut Vec, @@ -193,7 +193,7 @@ impl DebrayAllocator { final_index } - fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool { + fn in_place(&self, var: &String, term_loc: GenContext, r: RegType, k: usize) -> bool { match term_loc { GenContext::Head if !r.is_perm() => r.reg_num() == k, _ => match self.bindings().get(var).unwrap() { @@ -272,7 +272,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { fn mark_var( &mut self, - var: Rc, + var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, @@ -302,7 +302,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { fn mark_reserved_var( &mut self, - var: Rc, + var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, @@ -382,12 +382,12 @@ impl<'a> Allocator<'a> for DebrayAllocator { self.bindings } - fn reset_at_head(&mut self, args: &Vec>) { + fn reset_at_head(&mut self, args: &Vec) { self.reset_arg(args.len()); self.arity = args.len(); for (idx, arg) in args.iter().enumerate() { - if let &Term::Var(_, ref var) = arg.as_ref() { + if let &Term::Var(_, ref var) = arg { let r = self.get(var.clone()); if !r.is_perm() && r.reg_num() == 0 { diff --git a/src/fixtures.rs b/src/fixtures.rs index 0ecdd9e86..d6a1eea9e 100644 --- a/src/fixtures.rs +++ b/src/fixtures.rs @@ -1,4 +1,4 @@ -use prolog_parser::ast::*; +use crate::parser::ast::*; use crate::forms::*; use crate::instructions::*; @@ -84,8 +84,8 @@ type VariableFixture<'a> = (VarStatus, Vec<&'a Cell>); #[derive(Debug)] pub(crate) struct VariableFixtures<'a> { - perm_vars: IndexMap, VariableFixture<'a>>, - last_chunk_temp_vars: IndexSet>, + perm_vars: IndexMap, VariableFixture<'a>>, + last_chunk_temp_vars: IndexSet>, } impl<'a> VariableFixtures<'a> { @@ -96,11 +96,11 @@ impl<'a> VariableFixtures<'a> { } } - pub(crate) fn insert(&mut self, var: Rc, vs: VariableFixture<'a>) { + pub(crate) fn insert(&mut self, var: Rc, vs: VariableFixture<'a>) { self.perm_vars.insert(var, vs); } - pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc) { + pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc) { self.last_chunk_temp_vars.insert(var); } @@ -115,7 +115,7 @@ impl<'a> VariableFixtures<'a> { // Compute the conflict set of u. // 1. - let mut use_sets: IndexMap, OccurrenceSet> = IndexMap::new(); + let mut use_sets: IndexMap, OccurrenceSet> = IndexMap::new(); for (var, &mut (ref mut var_status, _)) in self.iter_mut() { if let &mut VarStatus::Temp(_, ref mut var_data) = var_status { @@ -153,11 +153,11 @@ impl<'a> VariableFixtures<'a> { } } - fn get_mut(&mut self, u: Rc) -> Option<&mut VariableFixture<'a>> { + fn get_mut(&mut self, u: Rc) -> Option<&mut VariableFixture<'a>> { self.perm_vars.get_mut(&u) } - fn iter_mut(&mut self) -> indexmap::map::IterMut, VariableFixture<'a>> { + fn iter_mut(&mut self) -> indexmap::map::IterMut, VariableFixture<'a>> { self.perm_vars.iter_mut() } @@ -218,11 +218,11 @@ impl<'a> VariableFixtures<'a> { } } - pub(crate) fn into_iter(self) -> indexmap::map::IntoIter, VariableFixture<'a>> { + pub(crate) fn into_iter(self) -> indexmap::map::IntoIter, VariableFixture<'a>> { self.perm_vars.into_iter() } - fn values(&self) -> indexmap::map::Values, VariableFixture<'a>> { + fn values(&self) -> indexmap::map::Values, VariableFixture<'a>> { self.perm_vars.values() } diff --git a/src/forms.rs b/src/forms.rs index 4f579c8c9..4cda02370 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,33 +1,38 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::OpDesc; -use prolog_parser::{clause_name, is_infix, is_postfix}; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::parser::CompositeOpDesc; +use crate::parser::rug::{Integer, Rational}; +use crate::{is_infix, is_postfix}; use crate::clause_types::*; +use crate::machine::heap::*; use crate::machine::loader::PredicateQueue; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::rug::{Integer, Rational}; -use ordered_float::OrderedFloat; +use crate::types::*; use indexmap::{IndexMap, IndexSet}; +use ordered_float::OrderedFloat; use slice_deque::*; use std::cell::Cell; +use std::convert::TryFrom; use std::ops::AddAssign; use std::path::PathBuf; use std::rc::Rc; -pub(crate) type PredicateKey = (ClauseName, usize); // name, arity. +pub type PredicateKey = (Atom, usize); // name, arity. -pub(crate) type Predicate = Vec; +pub type Predicate = Vec; // vars of predicate, toplevel offset. Vec is always a vector // of vars (we get their adjoining cells this way). -pub(crate) type JumpStub = Vec; +pub type JumpStub = Vec; #[derive(Debug, Clone)] -pub(crate) enum TopLevel { +pub enum TopLevel { Fact(Term), // Term, line_num, col_num Predicate(Predicate), Query(Vec), @@ -35,7 +40,7 @@ pub(crate) enum TopLevel { } #[derive(Debug, Clone, Copy)] -pub(crate) enum AppendOrPrepend { +pub enum AppendOrPrepend { Append, Prepend, } @@ -51,7 +56,7 @@ impl AppendOrPrepend { } #[derive(Debug, Clone, Copy)] -pub(crate) enum Level { +pub enum Level { Deep, Root, Shallow, @@ -67,12 +72,12 @@ impl Level { } #[derive(Debug, Clone)] -pub(crate) enum QueryTerm { +pub enum QueryTerm { // register, clause type, subterms, use default call policy. - Clause(Cell, ClauseType, Vec>, bool), + Clause(Cell, ClauseType, Vec, bool), BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q. UnblockedCut(Cell), - GetLevelAndUnify(Cell, Rc), + GetLevelAndUnify(Cell, Rc), Jump(JumpStub), } @@ -95,25 +100,25 @@ impl QueryTerm { } #[derive(Debug, Clone)] -pub(crate) struct Rule { - pub(crate) head: (ClauseName, Vec>, QueryTerm), +pub struct Rule { + pub(crate) head: (Atom, Vec, QueryTerm), pub(crate) clauses: Vec, } #[derive(Clone, Debug, Hash)] -pub(crate) enum ListingSource { +pub enum ListingSource { DynamicallyGenerated, - File(ClauseName, PathBuf), // filename, path + File(Atom, PathBuf), // filename, path User, } impl ListingSource { - pub(crate) fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self { + pub(crate) fn from_file_and_path(filename: Atom, path_buf: PathBuf) -> Self { ListingSource::File(filename, path_buf) } } -pub(crate) trait ClauseInfo { +pub trait ClauseInfo { fn is_consistent(&self, clauses: &PredicateQueue) -> bool { match clauses.first() { Some(cl) => { @@ -123,14 +128,14 @@ pub(crate) trait ClauseInfo { } } - fn name(&self) -> Option; + fn name(&self) -> Option; fn arity(&self) -> usize; } impl ClauseInfo for PredicateKey { #[inline] - fn name(&self) -> Option { - Some(self.0.clone()) + fn name(&self) -> Option { + Some(self.0) } #[inline] @@ -140,28 +145,32 @@ impl ClauseInfo for PredicateKey { } impl ClauseInfo for Term { - fn name(&self) -> Option { + fn name(&self) -> Option { + //, atom_tbl: &AtomTable) -> Option { match self { - Term::Clause(_, ref name, ref terms, _) => { + Term::Clause(_, name, terms) => { + // let str_buf = StringBuffer::from(*name, atom_tbl); + match name.as_str() { + // str_buf.as_str() { ":-" => { match terms.len() { - 1 => None, // a declaration. - 2 => terms[0].name(), - _ => Some(clause_name!(":-")), + 1 => None, // a declaration. + 2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)), + _ => Some(*name), } } - _ => Some(name.clone()), + _ => Some(*name), //str_buf), } } - Term::Constant(_, Constant::Atom(ref name, _)) => Some(name.clone()), + Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)), _ => None, } } fn arity(&self) -> usize { match self { - Term::Clause(_, ref name, ref terms, _) => match name.as_str() { + Term::Clause(_, name, terms) => match name.as_str() { ":-" => match terms.len() { 1 => 0, 2 => terms[0].arity(), @@ -175,8 +184,8 @@ impl ClauseInfo for Term { } impl ClauseInfo for Rule { - fn name(&self) -> Option { - Some(self.head.0.clone()) + fn name(&self) -> Option { + Some(self.head.0) } fn arity(&self) -> usize { @@ -185,7 +194,7 @@ impl ClauseInfo for Rule { } impl ClauseInfo for PredicateClause { - fn name(&self) -> Option { + fn name(&self) -> Option { match self { &PredicateClause::Fact(ref term, ..) => term.name(), &PredicateClause::Rule(ref rule, ..) => rule.name(), @@ -200,23 +209,21 @@ impl ClauseInfo for PredicateClause { } } -// pub(crate) type CompiledResult = (Predicate, VecDeque); - #[derive(Debug, Clone)] -pub(crate) enum PredicateClause { +pub enum PredicateClause { Fact(Term), Rule(Rule), } impl PredicateClause { - // TODO: add this to `Term` in `prolog_parser` like `first_arg`. - pub(crate) fn args(&self) -> Option<&[Box]> { - match *self { - PredicateClause::Fact(ref term, ..) => match term { - Term::Clause(_, _, args, _) => Some(&args), + // TODO: add this to `Term` in `crate::parser` like `first_arg`. + pub(crate) fn args(&self) -> Option<&[Term]> { + match self { + PredicateClause::Fact(term, ..) => match term { + Term::Clause(_, _, args) => Some(&args), _ => None, }, - PredicateClause::Rule(ref rule, ..) => { + PredicateClause::Rule(rule, ..) => { if rule.head.1.is_empty() { None } else { @@ -228,36 +235,26 @@ impl PredicateClause { } #[derive(Debug, Clone)] -pub(crate) enum ModuleSource { - Library(ClauseName), - File(ClauseName), +pub enum ModuleSource { + Library(Atom), + File(Atom), } impl ModuleSource { pub(crate) fn as_functor_stub(&self) -> MachineStub { match self { - ModuleSource::Library(ref name) => { - functor!("library", [clause_name(name.clone())]) + ModuleSource::Library(name) => { + functor!(atom!("library"), [atom(name)]) } - ModuleSource::File(ref name) => { - functor!(clause_name(name.clone())) + ModuleSource::File(name) => { + functor!(name) } } } } -// pub(crate) type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator. - -/* -#[derive(Debug, Clone)] -pub(crate) enum MultiFileIndicator { - LocalScoped(ClauseName, usize), // name, arity - ModuleScoped(ScopedPredicateKey), -} -*/ - #[derive(Clone, Copy, Hash, Debug)] -pub(crate) enum MetaSpec { +pub enum MetaSpec { Minus, Plus, Either, @@ -265,71 +262,71 @@ pub(crate) enum MetaSpec { } #[derive(Debug, Clone)] -pub(crate) enum Declaration { - Dynamic(ClauseName, usize), - MetaPredicate(ClauseName, ClauseName, Vec), // module name, name, meta-specs +pub enum Declaration { + Dynamic(Atom, usize), + MetaPredicate(Atom, Atom, Vec), // module name, name, meta-specs Module(ModuleDecl), - NonCountedBacktracking(ClauseName, usize), // name, arity + NonCountedBacktracking(Atom, usize), // name, arity Op(OpDecl), UseModule(ModuleSource), UseQualifiedModule(ModuleSource, IndexSet), } -#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)] -pub(crate) struct OpDecl { - pub(crate) prec: usize, - pub(crate) spec: Specifier, - pub(crate) name: ClauseName, +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub struct OpDecl { + pub(crate) op_desc: OpDesc, + pub(crate) name: Atom, +} + +#[inline(always)] +pub(crate) fn fixity(spec: u32) -> Fixity { + match spec { + XFY | XFX | YFX => Fixity::In, + XF | YF => Fixity::Post, + FX | FY => Fixity::Pre, + _ => unreachable!(), + } } + impl OpDecl { #[inline] - pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self { - Self { prec, spec, name } + pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self { + Self { op_desc, name } } #[inline] pub(crate) fn remove(&mut self, op_dir: &mut OpDir) { - let prec = self.prec; - self.prec = 0; + let prec = self.op_desc.get_prec(); + self.op_desc.set(0, self.op_desc.get_spec()); self.insert_into_op_dir(op_dir); - self.prec = prec; - } - - #[inline] - pub(crate) fn fixity(&self) -> Fixity { - match self.spec { - XFY | XFX | YFX => Fixity::In, - XF | YF => Fixity::Post, - FX | FY => Fixity::Pre, - _ => unreachable!(), - } + self.op_desc.set(prec, self.op_desc.get_spec()); } - pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> { - let key = (self.name.clone(), self.fixity()); + pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option { + let key = (self.name, fixity(self.op_desc.get_spec() as u32)); - match op_dir.get(&key) { + match op_dir.get_mut(&key) { Some(cell) => { - return Some(cell.shared_op_desc().replace((self.prec, self.spec))); + let (old_prec, old_spec) = cell.get(); + cell.set(self.op_desc.get_prec(), self.op_desc.get_spec()); + return Some(OpDesc::build_with(old_prec, old_spec)); } None => {} } - op_dir - .insert(key, OpDirValue::new(self.spec, self.prec)) - .map(|op_dir_value| op_dir_value.shared_op_desc().get()) + op_dir.insert(key, self.op_desc) } pub(crate) fn submit( &self, - existing_desc: Option, + existing_desc: Option, op_dir: &mut OpDir, ) -> Result<(), SessionError> { - let (spec, name) = (self.spec, self.name.clone()); + let (spec, name) = (self.op_desc.get_spec(), self.name.clone()); - if is_infix!(spec) { + if is_infix!(spec as u32) { if let Some(desc) = existing_desc { if desc.post > 0 { return Err(SessionError::OpIsInfixAndPostFix(name)); @@ -337,7 +334,7 @@ impl OpDecl { } } - if is_postfix!(spec) { + if is_postfix!(spec as u32) { if let Some(desc) = existing_desc { if desc.inf > 0 { return Err(SessionError::OpIsInfixAndPostFix(name)); @@ -350,22 +347,51 @@ impl OpDecl { } } +#[derive(Debug)] +pub enum AtomOrString { + Atom(Atom), + String(String), +} + +impl AtomOrString { + #[inline] + pub fn as_str(&self) -> &str { + match self { + AtomOrString::Atom(atom) => atom.as_str(), + AtomOrString::String(string) => string.as_str(), + } + } + + #[inline] + pub fn to_string(self) -> String { + match self { + AtomOrString::Atom(atom) => { + atom.as_str().to_owned() + } + AtomOrString::String(string) => { + string + } + } + } +} + +//TODO: try to rid yourself and the earth of the next two functions. pub(crate) fn fetch_atom_op_spec( - name: ClauseName, - spec: Option, + name: Atom, + spec: Option, op_dir: &OpDir, -) -> Option { - fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir) +) -> Option { + fetch_op_spec_from_existing(name, 1, spec, op_dir) .or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir)) } pub(crate) fn fetch_op_spec_from_existing( - name: ClauseName, + name: Atom, arity: usize, - spec: Option, + op_desc: Option, op_dir: &OpDir, -) -> Option { - if let Some(ref op_desc) = &spec { +) -> Option { + if let Some(ref op_desc) = &op_desc { if op_desc.arity() != arity { /* it's possible to extend operator functors with * additional terms. When that happens, @@ -374,61 +400,53 @@ pub(crate) fn fetch_op_spec_from_existing( } } - spec.or_else(|| fetch_op_spec(name, arity, op_dir)) + op_desc.or_else(|| fetch_op_spec(name, arity, op_dir)) } -pub(crate) fn fetch_op_spec( - name: ClauseName, - arity: usize, - op_dir: &OpDir, -) -> Option { +pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option { match arity { - 2 => op_dir - .get(&(name, Fixity::In)) - .and_then(|OpDirValue(spec)| { - if spec.prec() > 0 { - Some(spec.clone()) - } else { - None - } - }), + 2 => op_dir.get(&(name, Fixity::In)).and_then(|op_desc| { + if op_desc.get_prec() > 0 { + Some(*op_desc) + } else { + None + } + }), 1 => { - if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) { - if spec.prec() > 0 { - return Some(spec.clone()); + if let Some(op_desc) = op_dir.get(&(name.clone(), Fixity::Pre)) { + if op_desc.get_prec() > 0 { + return Some(*op_desc); } } - op_dir - .get(&(name.clone(), Fixity::Post)) - .and_then(|OpDirValue(spec)| { - if spec.prec() > 0 { - Some(spec.clone()) - } else { - None - } - }) + op_dir.get(&(name, Fixity::Post)).and_then(|op_desc| { + if op_desc.get_prec() > 0 { + Some(*op_desc) + } else { + None + } + }) } _ => None, } } -pub(crate) type ModuleDir = IndexMap; +pub(crate) type ModuleDir = IndexMap; #[derive(Debug, Clone, Eq, Hash, PartialEq)] -pub(crate) enum ModuleExport { +pub enum ModuleExport { OpDecl(OpDecl), PredicateKey(PredicateKey), } #[derive(Debug, Clone)] -pub(crate) struct ModuleDecl { - pub(crate) name: ClauseName, +pub struct ModuleDecl { + pub(crate) name: Atom, pub(crate) exports: Vec, } #[derive(Debug)] -pub(crate) struct Module { +pub struct Module { pub(crate) module_decl: ModuleDecl, pub(crate) code_dir: CodeDir, pub(crate) op_dir: OpDir, @@ -440,7 +458,10 @@ pub(crate) struct Module { // Module's and related types are defined in forms. impl Module { - pub(crate) fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self { + pub(crate) fn new( + module_decl: ModuleDecl, + listing_src: ListingSource, + ) -> Self { Module { module_decl, code_dir: CodeDir::new(), @@ -465,61 +486,115 @@ impl Module { } } -#[derive(Debug, Clone)] -pub(crate) enum Number { +#[derive(Debug, Copy, Clone)] +pub enum Number { Float(OrderedFloat), - Integer(Rc), - Rational(Rc), - Fixnum(isize), + Integer(TypedArenaPtr), + Rational(TypedArenaPtr), + Fixnum(Fixnum), } -impl From for Number { +impl Default for Number { #[inline] - fn from(n: Integer) -> Self { - Number::Integer(Rc::new(n)) + fn default() -> Self { + Number::Fixnum(Fixnum::build_with(0)) } } -impl From for Number { +pub trait ArenaFrom { + fn arena_from(value: T, arena: &mut Arena) -> Self; +} + +impl ArenaFrom for Number { #[inline] - fn from(n: Rational) -> Self { - Number::Rational(Rc::new(n)) + fn arena_from(value: Integer, arena: &mut Arena) -> Number { + Number::Integer(arena_alloc!(value, arena)) } } -impl From for Number { +impl ArenaFrom for Number { #[inline] - fn from(n: isize) -> Self { - Number::Fixnum(n) + fn arena_from(value: Rational, arena: &mut Arena) -> Number { + Number::Rational(arena_alloc!(value, arena)) } } -impl Default for Number { - fn default() -> Self { - Number::Float(OrderedFloat(0f64)) +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: usize, arena: &mut Arena) -> Number { + match i64::try_from(value) { + Ok(value) => Fixnum::build_with_checked(value) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))), + Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)), + } } } -impl Into for Number { +impl ArenaFrom for Number { #[inline] - fn into(self) -> Constant { - match self { - Number::Fixnum(n) => Constant::Fixnum(n), - Number::Integer(n) => Constant::Integer(n), - Number::Float(f) => Constant::Float(f), - Number::Rational(r) => Constant::Rational(r), + fn arena_from(value: u64, arena: &mut Arena) -> Number { + match i64::try_from(value) { + Ok(value) => Fixnum::build_with_checked(value) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))), + Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)), } } } -impl Into for Number { +impl ArenaFrom for Number { #[inline] - fn into(self) -> HeapCellValue { - match self { - Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)), - Number::Integer(n) => HeapCellValue::Integer(n), - Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)), - Number::Rational(r) => HeapCellValue::Rational(r), + fn arena_from(value: i64, arena: &mut Arena) -> Number { + Fixnum::build_with_checked(value) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))) + } +} + +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: isize, arena: &mut Arena) -> Number { + Fixnum::build_with_checked(value as i64) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))) + } +} + +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: u32, _arena: &mut Arena) -> Number { + Number::Fixnum(Fixnum::build_with(value as i64)) + } +} + +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: i32, _arena: &mut Arena) -> Number { + Number::Fixnum(Fixnum::build_with(value as i64)) + } +} + +impl ArenaFrom for Literal { + #[inline] + fn arena_from(value: Number, arena: &mut Arena) -> Literal { + match value { + Number::Fixnum(n) => Literal::Fixnum(n), + Number::Integer(n) => Literal::Integer(n), + Number::Float(f) => Literal::Float(arena_alloc!(f, arena)), + Number::Rational(r) => Literal::Rational(r), + } + } +} + +impl ArenaFrom for HeapCellValue { + #[inline] + fn arena_from(value: Number, arena: &mut Arena) -> HeapCellValue { + match value { + Number::Fixnum(n) => fixnum_as_cell!(n), + Number::Integer(n) => typed_arena_ptr_as_cell!(n), + Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)), + Number::Rational(n) => typed_arena_ptr_as_cell!(n), } } } @@ -528,9 +603,9 @@ impl Number { #[inline] pub(crate) fn is_positive(&self) -> bool { match self { - &Number::Fixnum(n) => n > 0, + &Number::Fixnum(n) => n.get_num() > 0, &Number::Integer(ref n) => &**n > &0, - &Number::Float(OrderedFloat(f)) => f.is_sign_positive(), + &Number::Float(f) => f.is_sign_positive(), &Number::Rational(ref r) => &**r > &0, } } @@ -538,7 +613,7 @@ impl Number { #[inline] pub(crate) fn is_negative(&self) -> bool { match self { - &Number::Fixnum(n) => n < 0, + &Number::Fixnum(n) => n.get_num() < 0, &Number::Integer(ref n) => &**n < &0, &Number::Float(OrderedFloat(f)) => f.is_sign_negative(), &Number::Rational(ref r) => &**r < &0, @@ -548,36 +623,20 @@ impl Number { #[inline] pub(crate) fn is_zero(&self) -> bool { match self { - &Number::Fixnum(n) => n == 0, + &Number::Fixnum(n) => n.get_num() == 0, &Number::Integer(ref n) => &**n == &0, &Number::Float(f) => f == OrderedFloat(0f64), &Number::Rational(ref r) => &**r == &0, } } - - #[inline] - pub(crate) fn abs(self) -> Self { - match self { - Number::Fixnum(n) => { - if let Some(n) = n.checked_abs() { - Number::from(n) - } else { - Number::from(Integer::from(n).abs()) - } - } - Number::Integer(n) => Number::from(Integer::from(n.abs_ref())), - Number::Float(f) => Number::Float(OrderedFloat(f.abs())), - Number::Rational(r) => Number::from(Rational::from(r.abs_ref())), - } - } } #[derive(Debug, Clone)] pub(crate) enum OptArgIndexKey { - Constant(usize, usize, Constant, Vec), // index, IndexingCode location, opt arg, alternatives - List(usize, usize), // index, IndexingCode location + Literal(usize, usize, Literal, Vec), // index, IndexingCode location, opt arg, alternatives + List(usize, usize), // index, IndexingCode location None, - Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity + Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity } impl OptArgIndexKey { @@ -589,7 +648,7 @@ impl OptArgIndexKey { #[inline] pub(crate) fn arg_num(&self) -> usize { match &self { - OptArgIndexKey::Constant(arg_num, ..) + OptArgIndexKey::Literal(arg_num, ..) | OptArgIndexKey::Structure(arg_num, ..) | OptArgIndexKey::List(arg_num, _) => { // these are always at least 1. @@ -607,7 +666,7 @@ impl OptArgIndexKey { #[inline] pub(crate) fn switch_on_term_loc(&self) -> Option { match &self { - OptArgIndexKey::Constant(_, loc, ..) + OptArgIndexKey::Literal(_, loc, ..) | OptArgIndexKey::Structure(_, loc, ..) | OptArgIndexKey::List(_, loc) => Some(*loc), OptArgIndexKey::None => None, @@ -617,7 +676,7 @@ impl OptArgIndexKey { #[inline] pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) { match self { - OptArgIndexKey::Constant(_, ref mut loc, ..) + OptArgIndexKey::Literal(_, ref mut loc, ..) | OptArgIndexKey::Structure(_, ref mut loc, ..) | OptArgIndexKey::List(_, ref mut loc) => { *loc = value; @@ -631,7 +690,7 @@ impl AddAssign for OptArgIndexKey { #[inline] fn add_assign(&mut self, n: usize) { match self { - OptArgIndexKey::Constant(_, ref mut o, ..) + OptArgIndexKey::Literal(_, ref mut o, ..) | OptArgIndexKey::List(_, ref mut o) | OptArgIndexKey::Structure(_, ref mut o, ..) => { *o += n; @@ -700,6 +759,7 @@ pub(crate) struct LocalPredicateSkeleton { pub(crate) is_multifile: bool, pub(crate) clause_clause_locs: SliceDeque, pub(crate) clause_assert_margin: usize, + pub(crate) retracted_dynamic_clauses: Option>, // always None if non-dynamic. } impl LocalPredicateSkeleton { @@ -711,6 +771,7 @@ impl LocalPredicateSkeleton { is_multifile: false, clause_clause_locs: sdeq![], clause_assert_margin: 0, + retracted_dynamic_clauses: Some(vec![]), } } @@ -730,6 +791,20 @@ impl LocalPredicateSkeleton { self.clause_clause_locs.clear(); self.clause_assert_margin = 0; } + + #[inline] + pub(crate) fn add_retracted_dynamic_clause_info(&mut self, clause_info: ClauseIndexInfo) { + debug_assert_eq!(self.is_dynamic, true); + + if self.retracted_dynamic_clauses.is_none() { + self.retracted_dynamic_clauses = Some(vec![]); + } + + self.retracted_dynamic_clauses + .as_mut() + .unwrap() + .push(clause_info); + } } #[derive(Clone, Debug)] @@ -781,3 +856,12 @@ impl PredicateSkeleton { } } } + +#[derive(Debug, Clone, Copy)] +pub(crate) enum IndexingCodePtr { + External(usize), // the index points past the indexing instruction prelude. + DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction. + Fail, + Internal(usize), // the index points into the indexing instruction prelude. +} + diff --git a/src/heap_iter.rs b/src/heap_iter.rs index fd057ac3c..b5c83a223 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -1,155 +1,274 @@ -use crate::machine::machine_indices::*; -use crate::machine::machine_state::*; +pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter}; +use crate::machine::heap::*; -use indexmap::IndexSet; +use crate::atom_table::*; +use crate::types::*; + +use modular_bitfield::prelude::*; -use std::cmp::Ordering; use std::ops::Deref; use std::vec::Vec; +#[inline] +fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) { + read_heap_cell!(heap[h], + (HeapCellValueTag::Str + | HeapCellValueTag::Lis + | HeapCellValueTag::AttrVar + | HeapCellValueTag::Var + | HeapCellValueTag::PStrLoc, vh) => { + if heap[vh].get_mark_bit() { + heap[h].set_forwarding_bit(true); + } + } + _ => {} + ) +} + +#[bitfield] +#[repr(u64)] +#[derive(Clone, Copy, Debug)] +pub struct IterStackLoc { + value: B63, + m: bool, +} + +impl IterStackLoc { + #[inline] + pub fn iterable_heap_loc(h: usize) -> Self { + IterStackLoc::new().with_m(false).with_value(h as u64) + } + + #[inline] + pub fn mark_heap_loc(h: usize) -> Self { + IterStackLoc::new().with_m(true).with_value(h as u64) + } +} + #[derive(Debug)] -pub(crate) struct HCPreOrderIterator<'a> { - pub(crate) machine_st: &'a MachineState, - pub(crate) state_stack: Vec, +pub struct StackfulPreOrderHeapIter<'a> { + pub heap: &'a mut Vec, + stack: Vec, + h: usize, +} + +impl<'a> Drop for StackfulPreOrderHeapIter<'a> { + fn drop(&mut self) { + while let Some(h) = self.stack.pop() { + let h = h.value() as usize; + + self.heap[h].set_forwarding_bit(false); + self.heap[h].set_mark_bit(false); + } + + self.heap.pop(); + } } -impl<'a> HCPreOrderIterator<'a> { - pub(crate) fn new(machine_st: &'a MachineState, a: Addr) -> Self { - HCPreOrderIterator { - machine_st, - state_stack: vec![a], +impl<'a> StackfulPreOrderHeapIter<'a> { + #[inline] + fn new(heap: &'a mut Vec, cell: HeapCellValue) -> Self { + let h = heap.len(); + heap.push(cell); + + Self { + heap, + h, + stack: vec![IterStackLoc::iterable_heap_loc(h)], } } #[inline] - pub(crate) fn machine_st(&self) -> &MachineState { - &self.machine_st + pub fn push_stack(&mut self, h: usize) { + self.stack.push(IterStackLoc::iterable_heap_loc(h)); } - fn follow_heap(&mut self, h: usize) -> Addr { - match &self.machine_st.heap[h] { - &HeapCellValue::NamedStr(arity, _, _) => { - for idx in (1..arity + 1).rev() { - self.state_stack.push(Addr::HeapCell(h + idx)); - } + #[inline] + pub fn stack_last(&self) -> Option { + for h in self.stack.iter().rev() { + let is_readable_marked = h.m(); + let h = h.value() as usize; + let cell = self.heap[h]; - Addr::Str(h) + if cell.get_forwarding_bit() == Some(true) { + return Some(h); + } else if cell.get_mark_bit() && !is_readable_marked { + continue; } - &HeapCellValue::Addr(a) => self.follow(a), - HeapCellValue::PartialString(..) => self.follow(Addr::PStrLocation(h, 0)), - HeapCellValue::Atom(..) - | HeapCellValue::DBRef(_) - | HeapCellValue::Integer(_) - | HeapCellValue::Rational(_) => Addr::Con(h), - HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(h), - HeapCellValue::Stream(_) => Addr::Stream(h), - HeapCellValue::TcpListener(_) => Addr::TcpListener(h), + + return Some(h); } + + None } - // called under the assumption that the location at r is about to - // be visited, and so any follow up states need to be added to - // state_stack. returns the dereferenced Addr from Ref. - fn follow(&mut self, addr: Addr) -> Addr { - let da = self.machine_st.store(self.machine_st.deref(addr)); + #[inline] + pub fn stack_is_empty(&self) -> bool { + self.stack.is_empty() + } - match da { - Addr::Lis(a) => { - self.state_stack.push(Addr::HeapCell(a + 1)); - self.state_stack.push(Addr::HeapCell(a)); + #[inline] + pub fn focus(&self) -> usize { + self.h + } - da - } - Addr::PStrLocation(h, n) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] - { - if let Some(c) = pstr.range_from(n..).next() { - if !pstr.at_end(n + c.len_utf8()) { - self.state_stack - .push(Addr::PStrLocation(h, n + c.len_utf8())); - } else if has_tail { - self.state_stack.push(Addr::HeapCell(h + 1)); - } else { - self.state_stack.push(Addr::EmptyList); - } + #[inline] + pub fn pop_stack(&mut self) -> Option { + while let Some(h) = self.stack.pop() { + let is_readable_marked = h.m(); + let h = h.value() as usize; + self.h = h; - self.state_stack.push(Addr::Char(c)); - } else if has_tail { - return self.follow(Addr::HeapCell(h + 1)); - } - } else { - unreachable!() - } + let cell = &mut self.heap[h]; - Addr::PStrLocation(h, n) - } - Addr::Str(s) => { - self.follow_heap(s) // record terms of structure. + if cell.get_forwarding_bit() == Some(true) { + cell.set_forwarding_bit(false); + } else if cell.get_mark_bit() && !is_readable_marked { + cell.set_mark_bit(false); + continue; } - Addr::Con(h) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] - { - if let Some(c) = pstr.range_from(0..).next() { - self.state_stack.push(Addr::PStrLocation(h, c.len_utf8())); - self.state_stack.push(Addr::Char(c)); - - Addr::PStrLocation(h, 0) - } else if has_tail { - self.follow(Addr::HeapCell(h + 1)) - } else { - Addr::EmptyList - } - } else { - Addr::Con(h) - } + + return Some(*cell); + } + + None + } + + fn push_if_unmarked(&mut self, h: usize) { + if !self.heap[h].get_mark_bit() { + self.heap[h].set_mark_bit(true); + self.stack.push(IterStackLoc::iterable_heap_loc(h)); + } + } + + fn follow(&mut self) -> Option { + while let Some(h) = self.stack.pop() { + let is_readable_marked = h.m(); + let h = h.value() as usize; + + self.h = h; + let cell = &mut self.heap[h]; + + if cell.get_forwarding_bit() == Some(true) { + let copy = *cell; + cell.set_forwarding_bit(false); + return Some(copy); + } else if cell.get_mark_bit() && !is_readable_marked { + cell.set_mark_bit(false); + continue; } - da => da, + + read_heap_cell!(*cell, + (HeapCellValueTag::Str, vh) => { + self.stack.push(IterStackLoc::iterable_heap_loc(vh)); + } + (HeapCellValueTag::Lis, vh) => { + self.push_if_unmarked(vh); + + self.stack.push(IterStackLoc::iterable_heap_loc(vh + 1)); + forward_if_referent_marked(&mut self.heap, vh + 1); + + self.stack.push(IterStackLoc::mark_heap_loc(vh)); + forward_if_referent_marked(&mut self.heap, vh); + + return Some(self.heap[h]); + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::Var, vh) => { + self.push_if_unmarked(h); + self.stack.push(IterStackLoc::iterable_heap_loc(vh)); + forward_if_referent_marked(&mut self.heap, vh); + } + (HeapCellValueTag::PStrOffset, offset) => { + self.push_if_unmarked(offset); + self.stack.push(IterStackLoc::iterable_heap_loc(h+1)); + + return Some(self.heap[h]); + } + (HeapCellValueTag::PStr) => { + self.push_if_unmarked(h); + + forward_if_referent_marked(&mut self.heap, h+1); + self.stack.push(IterStackLoc::iterable_heap_loc(h+1)); + + return Some(self.heap[h]); + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity > 0 { + self.push_if_unmarked(h); + } + + for h in (h + 1 .. h + arity + 1).rev() { + forward_if_referent_marked(&mut self.heap, h); + self.stack.push(IterStackLoc::iterable_heap_loc(h)); + } + + return Some(self.heap[h]); + } + // (HeapCellValueTag::StackVar) => { + // unreachable!() // TODO: here, crashing. + // } + _ => { + return Some(*cell); + } + ) } + + None } } -impl<'a> Iterator for HCPreOrderIterator<'a> { - type Item = Addr; +impl<'a> Iterator for StackfulPreOrderHeapIter<'a> { + type Item = HeapCellValue; + #[inline] fn next(&mut self) -> Option { - self.state_stack.pop().map(|a| self.follow(a)) + self.follow() } } -pub(crate) trait MutStackHCIterator<'b> -where - Self: Iterator, -{ - type MutStack; +#[inline(always)] +pub(crate) fn stackless_preorder_iter( + heap: &mut Vec, + cell: HeapCellValue, +) -> StacklessPreOrderHeapIter { + StacklessPreOrderHeapIter::new(heap, cell) +} - fn stack(&'b mut self) -> Self::MutStack; +#[inline(always)] +pub(crate) fn stackful_preorder_iter( + heap: &mut Vec, + cell: HeapCellValue, +) -> StackfulPreOrderHeapIter { + StackfulPreOrderHeapIter::new(heap, cell) } #[derive(Debug)] -pub(crate) struct HCPostOrderIterator<'a> { - base_iter: HCPreOrderIterator<'a>, - parent_stack: Vec<(usize, Addr)>, // number of children, parent node. +pub(crate) struct PostOrderIterator> { + base_iter: Iter, + base_iter_valid: bool, + parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node. } -impl<'a> Deref for HCPostOrderIterator<'a> { - type Target = HCPreOrderIterator<'a>; +impl> Deref for PostOrderIterator { + type Target = Iter; fn deref(&self) -> &Self::Target { &self.base_iter } } -impl<'a> HCPostOrderIterator<'a> { - pub(crate) fn new(base_iter: HCPreOrderIterator<'a>) -> Self { - HCPostOrderIterator { +impl> PostOrderIterator { + pub(crate) fn new(base_iter: Iter) -> Self { + PostOrderIterator { base_iter, + base_iter_valid: true, parent_stack: vec![], } } } -impl<'a> Iterator for HCPostOrderIterator<'a> { - type Item = Addr; +impl> Iterator for PostOrderIterator { + type Item = HeapCellValue; fn next(&mut self) -> Option { loop { @@ -161,179 +280,2317 @@ impl<'a> Iterator for HCPostOrderIterator<'a> { self.parent_stack.push((child_count - 1, node)); } - if let Some(item) = self.base_iter.next() { - match self.base_iter.machine_st.heap.index_addr(&item).as_ref() { - &HeapCellValue::NamedStr(arity, ..) => { - self.parent_stack.push((arity, item)); - } - &HeapCellValue::Addr(Addr::Lis(a)) => { - self.parent_stack.push((2, Addr::Lis(a))); - } - &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { - match &self.machine_st.heap[h] { - &HeapCellValue::PartialString(..) => { - // ref pstr, _) => { - /* - let c = pstr.range_from(n ..).next().unwrap(); - let next_n = n + c.len_utf8(); - - if !pstr.at_end(next_n) { - */ - // self.parent_stack.push((2, Addr::PStrLocation(h, next_n))); - // } - - self.parent_stack.push((2, Addr::PStrLocation(h, n))); - } - _ => { - unreachable!() - } + if self.base_iter_valid { + if let Some(item) = self.base_iter.next() { + read_heap_cell!(item, + (HeapCellValueTag::Atom, (_name, arity)) => { + self.parent_stack.push((arity, item)); } - } - _ => { - return Some(item); - } + (HeapCellValueTag::Lis) => { + self.parent_stack.push((2, item)); + } + (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + self.parent_stack.push((1, item)); + } + _ => { + return Some(item); + } + ); + + continue; + } else { + self.base_iter_valid = false; } - } else { + } + + if self.parent_stack.is_empty() { return None; } } } } -impl MachineState { - pub(crate) fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> { - HCPreOrderIterator::new(self, a) - } +pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator>; - pub(crate) fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> { - HCPostOrderIterator::new(HCPreOrderIterator::new(self, a)) - } +impl<'a> LeftistPostOrderHeapIter<'a> { + #[inline] + pub fn pop_stack(&mut self) { + if let Some((child_count, _)) = self.parent_stack.last() { + for _ in 0 .. *child_count { + self.base_iter.pop_stack(); + } - pub(crate) fn acyclic_pre_order_iter<'a>(&'a self, a: Addr) -> HCAcyclicIterator<'a> { - HCAcyclicIterator::new(HCPreOrderIterator::new(self, a)) + self.parent_stack.pop(); + } } - pub(crate) fn zipped_acyclic_pre_order_iter<'a>( - &'a self, - a1: Addr, - a2: Addr, - ) -> HCZippedAcyclicIterator<'a> { - HCZippedAcyclicIterator::new( - HCPreOrderIterator::new(self, a1), - HCPreOrderIterator::new(self, a2), - ) + #[inline] + pub fn parent_stack_len(&self) -> usize { + self.parent_stack.len() } } -impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCPreOrderIterator<'a> { - type MutStack = &'b mut Vec; - - fn stack(&'b mut self) -> Self::MutStack { - &mut self.state_stack - } +#[inline] +pub(crate) fn stackful_post_order_iter<'a>( + heap: &'a mut Heap, + cell: HeapCellValue, +) -> LeftistPostOrderHeapIter<'a> { + PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell)) } -#[derive(Debug)] -pub(crate) struct HCAcyclicIterator<'a> { - iter: HCPreOrderIterator<'a>, - seen: IndexSet, +pub(crate) type RightistPostOrderHeapIter<'a> = + PostOrderIterator>; + +#[inline] +pub(crate) fn stackless_post_order_iter<'a>( + heap: &'a mut Heap, + cell: HeapCellValue, +) -> RightistPostOrderHeapIter<'a> { + PostOrderIterator::new(stackless_preorder_iter(heap, cell)) } -impl<'a> HCAcyclicIterator<'a> { - pub(crate) fn new(iter: HCPreOrderIterator<'a>) -> Self { - HCAcyclicIterator { - iter, - seen: IndexSet::new(), +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn heap_stackless_iter_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st + .heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom, 0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom, 0) + ); + + assert_eq!(iter.next(), None); } - } -} -impl<'a> Deref for HCAcyclicIterator<'a> { - type Target = HCPreOrderIterator<'a>; + all_cells_unmarked(&wam.machine_st.heap); - fn deref(&self) -> &Self::Target { - &self.iter - } -} + wam.machine_st.heap.clear(); -impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCAcyclicIterator<'a> { - type MutStack = &'b mut Vec; + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); - fn stack(&'b mut self) -> Self::MutStack { - self.iter.stack() - } -} + for _ in 0..20 { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); -impl<'a> Iterator for HCAcyclicIterator<'a> { - type Item = Addr; + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); - fn next(&mut self) -> Option { - while let Some(addr) = self.iter.stack().pop() { - if !self.seen.contains(&addr) { - self.iter.stack().push(addr.clone()); - self.seen.insert(addr); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); - break; - } + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); } - self.iter.next() - } -} + all_cells_unmarked(&wam.machine_st.heap); -#[derive(Debug)] -pub(crate) struct HCZippedAcyclicIterator<'a> { - i1: HCPreOrderIterator<'a>, - i2: HCPreOrderIterator<'a>, - seen: IndexSet<(Addr, Addr)>, - pub(crate) first_to_expire: Ordering, -} + wam.machine_st.heap.clear(); -impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCZippedAcyclicIterator<'a> { - type MutStack = (&'b mut Vec, &'b mut Vec); + wam.machine_st.heap.push(str_loc_as_cell!(1)); - fn stack(&'b mut self) -> Self::MutStack { - (self.i1.stack(), self.i2.stack()) - } -} + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(1)) + ] + )); -impl<'a> HCZippedAcyclicIterator<'a> { - pub(crate) fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self { - HCZippedAcyclicIterator { - i1, - i2, - seen: IndexSet::new(), - first_to_expire: Ordering::Equal, + for _ in 0..2 { //00000 { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); } - } -} -impl<'a> Iterator for HCZippedAcyclicIterator<'a> { - type Item = (Addr, Addr); + all_cells_unmarked(&wam.machine_st.heap); - fn next(&mut self) -> Option { - while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) { - if !self.seen.contains(&(a1.clone(), a2.clone())) { - self.i1.stack().push(a1.clone()); - self.i2.stack().push(a2.clone()); + wam.machine_st.heap.clear(); - self.seen.insert((a1, a2)); + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); - break; - } + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0)); + assert_eq!(iter.next(), None); } - match (self.i1.next(), self.i2.next()) { - (Some(v1), Some(v2)) => Some((v1, v2)), - (Some(_), None) => { - self.first_to_expire = Ordering::Greater; - None - } - (None, Some(_)) => { - self.first_to_expire = Ordering::Less; - None - } - _ => None, + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a two-part complete string, + // then a three-part cyclic string involving an uncompacted list of chars. + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(iter.next(), None); } + + assert_eq!(wam.machine_st.heap[0], pstr_cell); + assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "def", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + + assert_eq!(iter.next(), None); + } + + assert_eq!(wam.machine_st.heap[0], pstr_cell); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[2], pstr_second_cell); + assert_eq!(wam.machine_st.heap[3], heap_loc_as_cell!(3)); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(4)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + pstr_loc_as_cell!(4), + ); + + let pstr_offset_cell = pstr_offset_as_cell!(0); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap.truncate(4); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let pstr_offset_cell = pstr_offset_as_cell!(0); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(iter.next(), None); + + assert_eq!(iter.heap[4], pstr_offset_as_cell!(0)); + assert_eq!(iter.heap[5], fixnum_as_cell!(Fixnum::build_with(1i64))); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + // drop the iterator before the iteration is complete to test + // that modified heap cells are restored to their + // pre-traversal state by the stackless iterator's Drop + // instance. + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + // drop the iterator before the iteration is complete to test + // that modified heap cells are restored to their + // pre-traversal state by the stackless iterator's Drop + // instance. + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), heap_loc_as_cell!(3)); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3)); + + wam.machine_st.heap.clear(); + + // print L = [L|L]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + // this is what happens! this next line! We would like it not to happen though. + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(1)); + + wam.machine_st.heap.clear(); + + // term is [X,f(Y),Z]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 + wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 + wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 + wam.machine_st.heap.push(heap_loc_as_cell!(8)); + wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 + wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 + wam.machine_st.heap.push(list_loc_as_cell!(9)); + wam.machine_st.heap.push(heap_loc_as_cell!(9)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. + wam.machine_st.heap.push(heap_loc_as_cell!(12)); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(4) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + attr_var_as_cell!(11) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + assert_eq!(iter.next(), None); + } + + // now populate the attributes list. the iteration must not change. + let clpz_atom = atom!("clpz"); + let p_atom = atom!("p"); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 + wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 + wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 + wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 + wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 + wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 + wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 + wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 + wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 + wam.machine_st.heap.push(empty_list_as_cell!()); // 21 + wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 + wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(4) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + attr_var_as_cell!(11) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + assert_eq!(iter.next(), None); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23)); + + wam.machine_st.heap.clear(); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + fixnum_as_cell!(Fixnum::build_with(0)) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + fixnum_as_cell!(Fixnum::build_with(0)) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap.len(), 0); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + + wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(1), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"),2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("y")) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(1) + ); + + assert!(iter.next().is_none()); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2)); + wam.machine_st.heap.push(str_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"),2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("y")) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(0) + ); + + assert!(iter.next().is_none()); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(list_loc_as_cell!(8)); + wam.machine_st.heap.push(str_loc_as_cell!(4)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(7), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(8) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("="), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("y")) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("X")) + ); + + assert!(iter.next().is_none()); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2)); + assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(0)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(atom!("y"))); + assert_eq!(wam.machine_st.heap[4], atom_as_cell!(atom!("="), 2)); + assert_eq!(wam.machine_st.heap[5], atom_as_cell!(atom!("X"))); + assert_eq!(wam.machine_st.heap[6], heap_loc_as_cell!(0)); + assert_eq!(wam.machine_st.heap[7], list_loc_as_cell!(8)); + assert_eq!(wam.machine_st.heap[8], str_loc_as_cell!(4)); + assert_eq!(wam.machine_st.heap[9], empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("f"), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + + assert!(iter.next().is_none()); + } + + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2)); + assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1)); + } + + #[test] + fn heap_stackful_iter_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + for _ in 0..20 { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + let mut var = heap_loc_as_cell!(0); + + // self-referencing variables are copied with their forwarding + // and marking bits set to true. it suffices to check only the + // forwarding bit to detect cycles of all kinds, including + // unbound/self-referencing variables. + + var.set_forwarding_bit(true); + var.set_mark_bit(true); + + assert_eq!(iter.next().unwrap(), var); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + // mutually referencing variables. + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // the cycle will be iterated twice before being detected. + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // cut the iteration short to check that all cells are + // unmarked and unforwarded by the Drop instance of + // StackfulPreOrderHeapIter. + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(iter.next(), None); + } + + // here + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let pstr_offset_cell = pstr_offset_as_cell!(0); + + // pstr_offset_cell.set_forwarding_bit(true); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); + + assert_eq!(iter.next(), None); + } + + /* + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + let string: String = iter.chars().collect(); + assert_eq!(string, "abc def"); + } + */ + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let pstr_offset_cell = pstr_offset_as_cell!(0); + + // pstr_offset_cell.set_forwarding_bit(true); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64))); + + let h = iter.focus(); + + assert_eq!(h, 5); + assert_eq!(unmark_cell_bits!(iter.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.heap[5]), fixnum_as_cell!(Fixnum::build_with(1i64))); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + let mut link_back = list_loc_as_cell!(1); + link_back.set_forwarding_bit(true); + + assert_eq!(iter.next().unwrap(), link_back); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + { + let mut iter = StackfulPreOrderHeapIter::new( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + let mut cyclic_link = list_loc_as_cell!(1); + cyclic_link.set_forwarding_bit(true); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!(iter.next().unwrap(), cyclic_link); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(pstr_as_cell!(atom!("a string"))); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackful_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_as_cell!(atom!("a string")) + ); + + assert_eq!( + iter.next().unwrap(), + empty_list_as_cell!() + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(list_loc_as_cell!(8)); + wam.machine_st.heap.push(str_loc_as_cell!(4)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackful_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(1) + ); + + assert_eq!( + iter.next().unwrap(), + atom_as_cell!(atom!("y")) + ); + + assert!(iter.next().is_none()); + } + } + + #[test] + fn heap_stackful_post_order_iter() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + for _ in 0..20 { // 0000 { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + let mut var = heap_loc_as_cell!(0); + + // self-referencing variables are copied with their forwarding + // and marking bits set to true. it suffices to check only the + // forwarding bit to detect cycles of all kinds, including + // unbound/self-referencing variables. + + var.set_forwarding_bit(true); + var.set_mark_bit(true); + + assert_eq!(iter.next().unwrap(), var); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + // mutually referencing variables. + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // the cycle will be iterated twice before being detected. + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + { + let mut iter = stackful_post_order_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + // cut the iteration short to check that all cells are + // unmarked and unforwarded by the Drop instance of + // StackfulPreOrderHeapIter. + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + let mut link_back = list_loc_as_cell!(1); + link_back.set_forwarding_bit(true); + + assert_eq!(iter.next().unwrap(), link_back); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + wam.machine_st.heap.clear(); + } + + #[test] + fn heap_stackless_post_order_iter() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = stackless_post_order_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + for _ in 0..20 { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + // mutually referencing variables. + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // the cycle will be iterated twice before being detected. + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // cut the iteration short to check that all cells are + // unmarked and unforwarded by the Drop instance of + // StacklessPreOrderHeapIter. + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "def", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let mut pstr_loc_cell = pstr_loc_as_cell!(0); + + pstr_loc_cell.set_forwarding_bit(true); + + // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 09af815fc..7a0c2c5db 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1,9 +1,11 @@ -use prolog_parser::ast::*; -use prolog_parser::{ - alpha_numeric_char, capital_letter_char, clause_name, cut_char, decimal_digit_char, - graphic_token_char, is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, - semicolon_char, sign_char, single_quote_char, small_letter_char, solo_char, - variable_indicator_char, +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::rug::{Integer, Rational}; +use crate::{ + alpha_numeric_char, capital_letter_char, cut_char, decimal_digit_char, graphic_token_char, + is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, semicolon_char, + sign_char, single_quote_char, small_letter_char, solo_char, variable_indicator_char, }; use crate::clause_types::*; @@ -11,40 +13,41 @@ use crate::forms::*; use crate::heap_iter::*; use crate::machine::heap::*; use crate::machine::machine_indices::*; -use crate::machine::machine_state::*; +use crate::machine::partial_string::*; use crate::machine::streams::*; -use crate::rug::{Integer, Rational}; +use crate::types::*; + use ordered_float::OrderedFloat; use indexmap::{IndexMap, IndexSet}; use std::cell::Cell; use std::convert::TryFrom; -use std::iter::{once, FromIterator}; +use std::iter::once; use std::net::{IpAddr, TcpListener}; use std::ops::{Range, RangeFrom}; use std::rc::Rc; /* contains the location, name, precision and Specifier of the parent op. */ -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] pub(crate) enum DirectedOp { - Left(ClauseName, SharedOpDesc), - Right(ClauseName, SharedOpDesc), + Left(Atom, OpDesc), + Right(Atom, OpDesc), } impl DirectedOp { #[inline] - fn as_str(&self) -> &str { + fn as_atom(&self) -> Atom { match self { - &DirectedOp::Left(ref name, _) | &DirectedOp::Right(ref name, _) => name.as_str(), + &DirectedOp::Left(name, _) | &DirectedOp::Right(name, _) => name, } } #[inline] fn is_negative_sign(&self) -> bool { match self { - &DirectedOp::Left(ref name, ref cell) | &DirectedOp::Right(ref name, ref cell) => { - name.as_str() == "-" && is_prefix!(cell.assoc()) + &DirectedOp::Left(name, cell) | &DirectedOp::Right(name, cell) => { + name == atom!("-") && is_prefix!(cell.get_spec() as u32) } } } @@ -59,29 +62,33 @@ impl DirectedOp { } } -fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool { +fn needs_bracketing(child_desc: OpDesc, op: &DirectedOp) -> bool { match op { - &DirectedOp::Left(ref name, ref cell) => { + DirectedOp::Left(name, cell) => { let (priority, spec) = cell.get(); if name.as_str() == "-" { - let child_assoc = child_spec.assoc(); + let child_assoc = child_desc.get_spec(); if is_prefix!(spec) && (is_postfix!(child_assoc) || is_infix!(child_assoc)) { return true; } } let is_strict_right = is_yfx!(spec) || is_xfx!(spec) || is_fx!(spec); - child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_right) + child_desc.get_prec() > priority + || (child_desc.get_prec() == priority && is_strict_right) } - &DirectedOp::Right(_, ref cell) => { + DirectedOp::Right(_, cell) => { let (priority, spec) = cell.get(); let is_strict_left = is_xfx!(spec) || is_xfy!(spec) || is_xf!(spec); - if child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_left) { + if child_desc.get_prec() > priority + || (child_desc.get_prec() == priority && is_strict_left) + { true - } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_spec.assoc()) { - !SharedOpDesc::ptr_eq(&cell, &child_spec) && child_spec.prec() == priority + } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_desc.get_spec()) + { + *cell == child_desc && child_desc.get_prec() == priority } else { false } @@ -89,59 +96,67 @@ fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool { } } -impl<'a> HCPreOrderIterator<'a> { +impl<'a> StackfulPreOrderHeapIter<'a> { /* * descend into the subtree where the iterator is currently parked * and check that the leftmost leaf is a number, with every node * encountered on the way an infix or postfix operator, unblocked * by brackets. */ - fn leftmost_leaf_has_property

(&self, property_check: P) -> bool + fn leftmost_leaf_has_property

(&self, op_dir: &OpDir, property_check: P) -> bool where - P: Fn(Addr, &Heap) -> bool, + P: Fn(HeapCellValue) -> bool, { - let mut addr = match self.state_stack.last().cloned() { - Some(addr) => addr, + let mut h = match self.stack_last() { + Some(h) => h, None => return false, }; - let mut parent_spec = DirectedOp::Left(clause_name!("-"), SharedOpDesc::new(200, FY)); + let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8)); loop { - match self.machine_st.store(self.machine_st.deref(addr)) { - Addr::Str(s) => match &self.machine_st.heap[s] { - &HeapCellValue::NamedStr(_, ref name, Some(ref spec)) - if is_postfix!(spec.assoc()) || is_infix!(spec.assoc()) => - { - if needs_bracketing(spec, &parent_spec) { + // match self.machine_st.store(self.machine_st.deref(addr)) { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::Str, s) => { + read_heap_cell!(self.heap[s], + (HeapCellValueTag::Atom, (name, _arity)) => { + if let Some(spec) = fetch_atom_op_spec(name, None, op_dir) { + if is_postfix!(spec.get_spec() as u32) || is_infix!(spec.get_spec() as u32) { + if needs_bracketing(spec, &parent_spec) { + return false; + } else { + h = s + 1; + parent_spec = DirectedOp::Right(name, spec); + continue; + } + } + } + return false; - } else { - addr = Addr::HeapCell(s + 1); - parent_spec = DirectedOp::Right(name.clone(), spec.clone()); } - } - _ => { - return false; - } - }, - addr => { - return property_check(addr, &self.machine_st.heap); + _ => { + return false; + } + ) } - } + _ => { + return property_check(self.heap[h]); + } + ) } } fn immediate_leaf_has_property

(&self, property_check: P) -> bool where - P: Fn(Addr, &Heap) -> bool, + P: Fn(HeapCellValue) -> bool, { - let addr = match self.state_stack.last().cloned() { - Some(addr) => addr, + let addr = match self.stack_last() { + Some(h) => self.heap[h], None => return false, }; - let addr = self.machine_st.store(self.machine_st.deref(addr)); - property_check(addr, &self.machine_st.heap) + // let addr = self.machine_st.store(self.machine_st.deref(addr)); + property_check(addr) } } @@ -168,20 +183,36 @@ fn char_to_string(is_quoted: bool, c: char) -> String { } } +#[derive(Clone, Copy, Debug)] +enum NumberFocus { + Unfocused(Number), + Denominator(TypedArenaPtr), + Numerator(TypedArenaPtr), +} + +impl NumberFocus { + fn is_positive(&self) -> bool { + match self { + NumberFocus::Unfocused(n) => n.is_positive(), + NumberFocus::Denominator(r) | NumberFocus::Numerator(r) => **r > 0, + } + } +} + #[derive(Debug, Clone)] enum TokenOrRedirect { - Atom(ClauseName), + Atom(Atom), BarAsOp, - Op(ClauseName, SharedOpDesc), + Op(Atom, OpDesc), NumberedVar(String), CompositeRedirect(usize, DirectedOp), FunctorRedirect(usize), - IpAddr(IpAddr), - Number(Number, Option), + #[allow(unused)] IpAddr(IpAddr), + NumberFocus(NumberFocus, Option), Open, Close, Comma, - RawPtr(*const u8), + RawPtr(*const ArenaHeader), Space, LeftCurly, RightCurly, @@ -190,7 +221,89 @@ enum TokenOrRedirect { HeadTailSeparator, } -pub(crate) trait HCValueOutputter { +pub(crate) fn requires_space(atom: &str, op: &str) -> bool { + match atom.chars().last() { + Some(ac) => op + .chars() + .next() + .map(|oc| { + if ac == '0' { + oc == '\'' || oc == '(' || alpha_numeric_char!(oc) + } else if alpha_numeric_char!(ac) { + oc == '(' || alpha_numeric_char!(oc) + } else if graphic_token_char!(ac) { + graphic_token_char!(oc) + } else if variable_indicator_char!(ac) { + alpha_numeric_char!(oc) + } else if capital_letter_char!(ac) { + alpha_numeric_char!(oc) + } else if sign_char!(ac) { + sign_char!(oc) || decimal_digit_char!(oc) + } else if single_quote_char!(ac) { + single_quote_char!(oc) + } else { + false + } + }) + .unwrap_or(false), + _ => false, + } +} + +fn non_quoted_graphic_token>(mut iter: Iter, c: char) -> bool { + if c == '/' { + return match iter.next() { + None => true, + Some('*') => false, // if we start with comment token, we must quote. + Some(c) => { + if graphic_token_char!(c) { + iter.all(|c| graphic_token_char!(c)) + } else { + false + } + } + }; + } else if c == '.' { + return match iter.next() { + None => false, + Some(c) => { + if graphic_token_char!(c) { + iter.all(|c| graphic_token_char!(c)) + } else { + false + } + } + }; + } else { + iter.all(|c| graphic_token_char!(c)) + } +} + +pub(super) fn non_quoted_token>(mut iter: Iter) -> bool { + if let Some(c) = iter.next() { + if small_letter_char!(c) { + iter.all(|c| alpha_numeric_char!(c)) + } else if graphic_token_char!(c) { + non_quoted_graphic_token(iter, c) + } else if semicolon_char!(c) { + iter.next().is_none() + } else if cut_char!(c) { + iter.next().is_none() + } else if c == '[' { + iter.next() == Some(']') && iter.next().is_none() + } else if c == '{' { + iter.next() == Some('}') && iter.next().is_none() + } else if solo_char!(c) { + !(c == '(' || c == ')' || c == '}' || c == ']' || c == ',' || c == '%' || c == '|') + } else { + false + } + } else { + false + } +} + +pub trait HCValueOutputter { type Output; fn new() -> Self; @@ -207,7 +320,7 @@ pub(crate) trait HCValueOutputter { } #[derive(Debug)] -pub(crate) struct PrinterOutputter { +pub struct PrinterOutputter { contents: String, } @@ -273,11 +386,15 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool { } #[inline] -fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option) -> bool { +fn negated_op_needs_bracketing( + iter: &StackfulPreOrderHeapIter, + op_dir: &OpDir, + op: &Option, +) -> bool { if let Some(ref op) = op { op.is_negative_sign() - && iter.leftmost_leaf_has_property(|addr, heap| match Number::try_from((addr, heap)) { - Ok(Number::Fixnum(n)) => n > 0, + && iter.leftmost_leaf_has_property(op_dir, |addr| match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => n.get_num() > 0, Ok(Number::Float(f)) => f > OrderedFloat(0f64), Ok(Number::Integer(n)) => &*n > &0, Ok(Number::Rational(n)) => &*n > &0, @@ -288,66 +405,103 @@ fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option Var { - static CHAR_CODES: [char; 26] = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - ]; +pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option { + fn numbervar(n: Integer) -> String { + static CHAR_CODES: [char; 26] = [ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + ]; - let i = n.mod_u(26) as usize; - let j = n.div_rem_floor(Integer::from(26)); - let j = <(Integer, Integer)>::from(j).0; + let i = n.mod_u(26) as usize; + let j = n.div_rem_floor(Integer::from(26)); + let j = <(Integer, Integer)>::from(j).0; - if j == 0 { - CHAR_CODES[i].to_string() - } else { - format!("{}{}", CHAR_CODES[i], j) + if j == 0 { + CHAR_CODES[i].to_string() + } else { + format!("{}{}", CHAR_CODES[i], j) + } } -} -impl MachineState { - pub(crate) fn numbervar(&self, offset: &Integer, addr: Addr) -> Option { - let addr = self.store(self.deref(addr)); - - match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => { - if n >= 0 { - Some(numbervar(Integer::from(offset + Integer::from(n)))) - } else { - None - } + match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => { + if n.get_num() >= 0 { + Some(numbervar(offset + Integer::from(n.get_num()))) + } else { + None } - Ok(Number::Integer(n)) => { - if &*n >= &0 { - Some(numbervar(Integer::from(offset + &*n))) - } else { - None - } + } + Ok(Number::Integer(n)) => { + if &*n >= &0 { + Some(numbervar(Integer::from(offset + &*n))) + } else { + None } - _ => None, } + _ => None, } } -type ReverseHeapVarDict = IndexMap>; +macro_rules! push_char { + ($self:ident, $c:expr) => {{ + $self.outputter.push_char($c); + $self.last_item_idx = $self.outputter.len(); + }}; +} + +macro_rules! append_str { + ($self:ident, $s:expr) => {{ + $self.last_item_idx = $self.outputter.len(); + $self.outputter.append($s); + }}; +} + +macro_rules! print_char { + ($self:ident, $is_quoted:expr, $c:expr) => { + if non_quoted_token(once($c)) { + let result = char_to_string(false, $c); + + push_space_if_amb!($self, &result, { + append_str!($self, &result); + }); + } else { + let mut result = String::new(); + + if $self.quoted { + result.push('\''); + result += &char_to_string($is_quoted, $c); + result.push('\''); + } else { + result += &char_to_string($is_quoted, $c); + } + + push_space_if_amb!($self, &result, { + append_str!($self, result.as_str()); + }); + } + }; +} #[derive(Debug)] -pub(crate) struct HCPrinter<'a, Outputter> { +pub struct HCPrinter<'a, Outputter> { outputter: Outputter, - machine_st: &'a MachineState, + iter: StackfulPreOrderHeapIter<'a>, + arena: &'a mut Arena, op_dir: &'a OpDir, state_stack: Vec, toplevel_spec: Option, - heap_locs: ReverseHeapVarDict, + // heap_locs: ReverseHeapVarDict, + printed_vars: IndexSet, last_item_idx: usize, - cyclic_terms: IndexMap, - non_cyclic_terms: IndexSet, - pub(crate) var_names: IndexMap, - pub(crate) numbervars_offset: Integer, - pub(crate) numbervars: bool, - pub(crate) quoted: bool, - pub(crate) ignore_ops: bool, - pub(crate) max_depth: usize, + // cyclic_terms: IndexMap, + // non_cyclic_terms: IndexSet, + pub var_names: IndexMap>, + pub numbervars_offset: Integer, + pub numbervars: bool, + pub quoted: bool, + pub ignore_ops: bool, + pub print_strings_as_strs: bool, + pub max_depth: usize, } macro_rules! push_space_if_amb { @@ -361,117 +515,29 @@ macro_rules! push_space_if_amb { }; } -pub(crate) fn requires_space(atom: &str, op: &str) -> bool { - match atom.chars().last() { - Some(ac) => op - .chars() - .next() - .map(|oc| { - if ac == '0' { - oc == '\'' || oc == '(' || alpha_numeric_char!(oc) - } else if alpha_numeric_char!(ac) { - oc == '(' || alpha_numeric_char!(oc) - } else if graphic_token_char!(ac) { - graphic_token_char!(oc) - } else if variable_indicator_char!(ac) { - alpha_numeric_char!(oc) - } else if capital_letter_char!(ac) { - alpha_numeric_char!(oc) - } else if sign_char!(ac) { - sign_char!(oc) || decimal_digit_char!(oc) - } else if single_quote_char!(ac) { - single_quote_char!(oc) - } else { - false - } - }) - .unwrap_or(false), - _ => false, - } -} - -fn non_quoted_graphic_token>(mut iter: Iter, c: char) -> bool { - if c == '/' { - return match iter.next() { - None => true, - Some('*') => false, // if we start with comment token, we must quote. - Some(c) => { - if graphic_token_char!(c) { - iter.all(|c| graphic_token_char!(c)) - } else { - false - } - } - }; - } else if c == '.' { - return match iter.next() { - None => false, - Some(c) => { - if graphic_token_char!(c) { - iter.all(|c| graphic_token_char!(c)) - } else { - false - } - } - }; - } else { - iter.all(|c| graphic_token_char!(c)) - } -} - -pub(super) fn non_quoted_token>(mut iter: Iter) -> bool { - if let Some(c) = iter.next() { - if small_letter_char!(c) { - iter.all(|c| alpha_numeric_char!(c)) - } else if graphic_token_char!(c) { - non_quoted_graphic_token(iter, c) - } else if semicolon_char!(c) { - iter.next().is_none() - } else if cut_char!(c) { - iter.next().is_none() - } else if c == '[' { - iter.next() == Some(']') && iter.next().is_none() - } else if c == '{' { - iter.next() == Some('}') && iter.next().is_none() - } else if solo_char!(c) { - !(c == '(' || c == ')' || c == '}' || c == ']' || c == ',' || c == '%' || c == '|') - } else { - false - } - } else { - false - } -} - -#[inline] -fn functor_location(addr: &Addr) -> Option { - Some(match addr { - &Addr::Lis(l) => l, - &Addr::Str(s) => s, - &Addr::PStrLocation(h, _) => h, - _ => { - return None; - } - }) -} - impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { - pub(crate) fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self { + pub fn new( + heap: &'a mut Heap, + arena: &'a mut Arena, + op_dir: &'a OpDir, + output: Outputter, + cell: HeapCellValue, + ) -> Self { HCPrinter { outputter: output, - machine_st, + iter: stackful_preorder_iter(heap, cell), + arena, op_dir, state_stack: vec![], - heap_locs: ReverseHeapVarDict::new(), toplevel_spec: None, + printed_vars: IndexSet::new(), last_item_idx: 0, numbervars: false, numbervars_offset: Integer::from(0), quoted: false, ignore_ops: false, - cyclic_terms: IndexMap::new(), - non_cyclic_terms: IndexSet::new(), var_names: IndexMap::new(), + print_strings_as_strs: false, max_depth: 0, } } @@ -482,87 +548,82 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { requires_space(tail, atom) } - fn enqueue_op( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - ct: ClauseType, - spec: SharedOpDesc, - ) { - if is_postfix!(spec.assoc()) { + fn enqueue_op(&mut self, mut max_depth: usize, ct: ClauseType, spec: OpDesc) { + let name = ct.name(); + + if is_postfix!(spec.get_spec()) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); return; } - let right_directed_op = DirectedOp::Right(ct.name(), spec.clone()); + let right_directed_op = DirectedOp::Right(name, spec); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, right_directed_op, )); - } else if is_prefix!(spec.assoc()) { - match ct.name().as_str() { - "-" | "\\" => { - self.format_prefix_op_with_space(iter, max_depth, ct.name(), spec); + } else if is_prefix!(spec.get_spec()) { + match name { + atom!("-") | atom!("\\") => { + self.format_prefix_op_with_space(max_depth, name, spec); return; } _ => {} }; if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); return; } - let left_directed_op = DirectedOp::Left(ct.name(), spec.clone()); + let left_directed_op = DirectedOp::Left(name, spec); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, left_directed_op, )); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + + self.state_stack.push(TokenOrRedirect::Op(name, spec)); } else { - match ct.name().as_str() { + match name.as_str() { "|" => { - self.format_bar_separator_op(iter, max_depth, ct.name(), spec); + self.format_bar_separator_op(max_depth, name, spec); return; } _ => {} }; + let ellipsis_atom = atom!("..."); + if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); - iter.stack().pop(); + self.iter.pop_stack(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); return; } - let left_directed_op = DirectedOp::Left(ct.name(), spec.clone()); - let right_directed_op = DirectedOp::Right(ct.name(), spec.clone()); + let left_directed_op = DirectedOp::Left(name, spec); + let right_directed_op = DirectedOp::Right(name, spec); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, left_directed_op, )); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, right_directed_op, @@ -570,21 +631,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn format_struct( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - arity: usize, - name: ClauseName, - ) -> bool { + fn format_struct(&mut self, mut max_depth: usize, arity: usize, name: Atom) -> bool { if self.check_max_depth(&mut max_depth) { for _ in 0..arity { - iter.stack().pop(); + self.iter.pop_stack(); } self.state_stack.push(TokenOrRedirect::Close); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Atom(name)); @@ -608,25 +662,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { true } - fn format_prefix_op_with_space( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - name: ClauseName, - spec: SharedOpDesc, - ) { + fn format_prefix_op_with_space(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Atom(name)); return; } - let op = DirectedOp::Left(name.clone(), spec); + let op = DirectedOp::Left(name, spec); self.state_stack .push(TokenOrRedirect::CompositeRedirect(max_depth, op)); @@ -634,46 +681,43 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Atom(name)); } - fn format_bar_separator_op( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - name: ClauseName, - spec: SharedOpDesc, - ) { + fn format_bar_separator_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + let ellipsis_atom = atom!("..."); + + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); self.state_stack.push(TokenOrRedirect::BarAsOp); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); return; } - let left_directed_op = DirectedOp::Left(name.clone(), spec.clone()); - let right_directed_op = DirectedOp::Right(name.clone(), spec.clone()); + let left_directed_op = DirectedOp::Left(name, spec); + let right_directed_op = DirectedOp::Right(name, spec); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, left_directed_op, )); + self.state_stack.push(TokenOrRedirect::BarAsOp); + self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, right_directed_op, )); } - fn format_curly_braces(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) -> bool { + fn format_curly_braces(&mut self, mut max_depth: usize) -> bool { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); + + let ellipsis_atom = atom!("..."); self.state_stack.push(TokenOrRedirect::RightCurly); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); self.state_stack.push(TokenOrRedirect::LeftCurly); return false; @@ -687,12 +731,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { true } - fn format_numbered_vars(&mut self, iter: &mut HCPreOrderIterator) -> bool { - let addr = iter.stack().last().cloned().unwrap(); + fn format_numbered_vars(&mut self) -> bool { + let h = self.iter.stack_last().unwrap(); // 7.10.4 - if let Some(var) = iter.machine_st().numbervar(&self.numbervars_offset, addr) { - iter.stack().pop(); + if let Some(var) = numbervar(&self.numbervars_offset, self.iter.heap[h]) { + self.iter.pop_stack(); self.state_stack.push(TokenOrRedirect::NumberedVar(var)); return true; } @@ -702,198 +746,134 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn format_clause( &mut self, - iter: &mut HCPreOrderIterator, max_depth: usize, arity: usize, ct: ClauseType, + op_desc: Option, ) -> bool { if self.numbervars && is_numbered_var(&ct, arity) { - if self.format_numbered_vars(iter) { + if self.format_numbered_vars() { return true; } } - if let Some(spec) = ct.spec() { - if "." == ct.name().as_str() && is_infix!(spec.assoc()) { + let dot_atom = atom!("."); + let name = ct.name(); + + if let Some(spec) = op_desc { + if dot_atom == name && is_infix!(spec.get_spec()) { if !self.ignore_ops { - self.push_list(iter, max_depth); + self.push_list(max_depth); return true; } } - if !self.ignore_ops && spec.prec() > 0 { - self.enqueue_op(iter, max_depth, ct, spec); + if !self.ignore_ops && spec.get_prec() > 0 { + self.enqueue_op(max_depth, ct, spec); return true; } } - return match (ct.name().as_str(), arity) { - ("{}", 1) if !self.ignore_ops => self.format_curly_braces(iter, max_depth), - _ => self.format_struct(iter, max_depth, arity, ct.name()), + return match (name.as_str(), arity) { + ("{}", 1) if !self.ignore_ops => self.format_curly_braces(max_depth), + _ => self.format_struct(max_depth, arity, name), }; } - #[inline] - fn push_char(&mut self, c: char) { - self.outputter.push_char(c); - self.last_item_idx = self.outputter.len(); - } - - #[inline] - fn append_str(&mut self, s: &str) { - self.last_item_idx = self.outputter.len(); - self.outputter.append(s); - } + fn offset_as_string(&mut self, h: usize) -> Option { + let addr = self.iter.heap[h]; - fn offset_as_string(&mut self, iter: &mut HCPreOrderIterator, addr: Addr) -> Option { if let Some(var) = self.var_names.get(&addr) { - if addr.as_var().is_some() { - return Some(format!("{}", var)); - } else { - iter.stack().push(addr); - return None; - } + read_heap_cell!(addr, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + return Some(format!("{}", var.as_str())); + } + _ => { + self.iter.push_stack(h); + return None; + } + ); } - match addr { - Addr::Lis(h) | Addr::Str(h) => Some(format!("{}", h)), - _ => { - if let Some(r) = addr.as_var() { - match r { - Ref::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)), - Ref::HeapCell(h) | Ref::AttrVar(h) => Some(format!("_{}", h)), - } - } else { - None - } + read_heap_cell!(addr, + (HeapCellValueTag::Lis | HeapCellValueTag::Str, h) => { + Some(format!("{}", h)) } - } - } - - fn record_children_as_non_cyclic(&mut self, addr: &Addr) { - match addr { - &Addr::Lis(l) => { - let c1 = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(l))); - let c2 = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(l + 1))); - - if let Some(c) = functor_location(&c1) { - self.non_cyclic_terms.insert(c); - } - - if let Some(c) = functor_location(&c2) { - self.non_cyclic_terms.insert(c); - } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + Some(format!("_{}", h)) } - &Addr::Str(s) => { - let arity = match &self.machine_st.heap[s] { - HeapCellValue::NamedStr(arity, ..) => arity, - _ => { - unreachable!() - } - }; - - for i in 1..arity + 1 { - let c = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(s + i))); - - if let Some(c) = functor_location(&c) { - self.non_cyclic_terms.insert(c); - } - } + (HeapCellValueTag::StackVar, h) => { + Some(format!("_s_{}", h)) } - &Addr::PStrLocation(h, _) => { - let tail = self.machine_st.heap[h + 1].as_addr(h + 1); - let tail = self.machine_st.store(self.machine_st.deref(tail)); - - if let Some(c) = functor_location(&tail) { - self.non_cyclic_terms.insert(c); - } + _ => { + None } - _ => {} - } + ) } - fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option { - iter.stack().last().cloned().and_then(|addr| { - let addr = self.machine_st.store(self.machine_st.deref(addr)); + fn check_for_seen(&mut self) -> Option { + if let Some(addr) = self.iter.next() { + let is_cyclic = addr.is_forwarded(); - if let Some(var) = self.var_names.get(&addr) { - self.heap_locs.insert(addr.clone(), Rc::new(var.clone())); - } + let addr = heap_bound_store( + self.iter.heap, + heap_bound_deref(self.iter.heap, addr), + ); + + let addr = unmark_cell_bits!(addr); - match self.heap_locs.get(&addr).cloned() { - Some(var) if addr.is_ref() => { - iter.stack().pop(); + match self.var_names.get(&addr).cloned() { + Some(var) if addr.is_var() => { + // If addr is an unbound variable and maps to + // a name via heap_locs, append the name to + // the current output, and return None. None + // short-circuits handle_heap_term. + // self.iter.pop_stack(); - push_space_if_amb!(self, &var, { - self.append_str(&var); + let var_str = var.as_str(); + + push_space_if_amb!(self, var_str, { + append_str!(self, var_str); }); - return None; + None } var_opt => { - let offset = match functor_location(&addr) { - Some(offset) => offset, - None => { - return iter.next(); - } - }; - - if !self.non_cyclic_terms.contains(&offset) { - if let Some(reps) = self.cyclic_terms.get(&addr).cloned() { - if reps > 0 { - self.cyclic_terms.insert(addr, reps - 1); - } else { - match var_opt { - Some(var) => { - push_space_if_amb!(self, &var, { - self.append_str(&var); - }); - - iter.stack().pop(); - } - None => { - push_space_if_amb!(self, "...", { - self.append_str("..."); - }); - - iter.stack().pop(); - self.cyclic_terms.insert(addr, 2); - } - } - - return None; + if is_cyclic && addr.is_compound() { + // self-referential variables are marked "cyclic". + match var_opt { + Some(var) => { + // If the term is bound to a named variable, + // print the variable's name to output. + push_space_if_amb!(self, &var, { + append_str!(self, &var); + }); } - } else if self.machine_st.is_cyclic_term(addr.clone()) { - if var_opt.is_some() { - self.cyclic_terms.insert(addr, 0); - } else { - self.cyclic_terms.insert(addr, 2); + None => { + // otherwise, contract it to an ellipsis. + push_space_if_amb!(self, "...", { + append_str!(self, "..."); + }); } - } else { - self.record_children_as_non_cyclic(&addr); - self.non_cyclic_terms.insert(offset); } - } else { - self.record_children_as_non_cyclic(&addr); + + return None; } - iter.next() + Some(addr) } } - }) + } else { + while let Some(_) = self.iter.pop_stack() {} + None + } } - fn print_atom(&mut self, atom: &ClauseName) { + fn print_atom(&mut self, atom: Atom) { let result = self.print_op_addendum(atom.as_str()); push_space_if_amb!(self, result.as_str(), { - self.append_str(&result); + append_str!(self, &result); }); } @@ -929,23 +909,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }; push_space_if_amb!(self, &result, { - self.append_str(&result); + append_str!(self, &result); }); } #[inline] fn print_ip_addr(&mut self, ip: IpAddr) { - self.push_char('\''); - self.append_str(&format!("{}", ip)); - self.push_char('\''); + push_char!(self, '\''); + append_str!(self, &format!("{}", ip)); + push_char!(self, '\''); } #[inline] - fn print_raw_ptr(&mut self, ptr: *const u8) { - self.append_str(&format!("0x{:x}", ptr as usize)); + fn print_raw_ptr(&mut self, ptr: *const ArenaHeader) { + append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize)); } - fn print_number(&mut self, n: Number, op: &Option) { + fn print_number(&mut self, n: NumberFocus, op: &Option) { let add_brackets = if let Some(op) = op { op.is_negative_sign() && n.is_positive() } else { @@ -953,86 +933,106 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }; if add_brackets { - self.push_char('('); + push_char!(self, '('); } match n { - Number::Float(fl) => { - if &fl == &OrderedFloat(0f64) { - push_space_if_amb!(self, "0.0", { - self.append_str("0.0"); - }); - } else { - let OrderedFloat(fl) = fl; - let output_str = format!("{0:<20?}", fl); + NumberFocus::Unfocused(n) => match n { + Number::Float(fl) => { + if &fl == &OrderedFloat(0f64) { + push_space_if_amb!(self, "0.0", { + append_str!(self, "0.0"); + }); + } else { + let OrderedFloat(fl) = fl; + let output_str = format!("{0:<20?}", fl); + + push_space_if_amb!(self, &output_str, { + append_str!(self, &output_str.trim()); + }); + } + } + Number::Rational(r) => { + self.print_rational(r, add_brackets); + return; + } + n => { + let output_str = format!("{}", n); push_space_if_amb!(self, &output_str, { - self.append_str(&output_str.trim()); + append_str!(self, &output_str); }); } + }, + NumberFocus::Denominator(r) => { + let output_str = format!("{}", r.denom()); + + push_space_if_amb!(self, &output_str, { + append_str!(self, &output_str); + }); } - Number::Rational(r) => { - self.print_rational(&r, add_brackets); - return; - } - n => { - let output_str = format!("{}", n); + NumberFocus::Numerator(r) => { + let output_str = format!("{}", r.numer()); push_space_if_amb!(self, &output_str, { - self.append_str(&output_str); + append_str!(self, &output_str); }); } } if add_brackets { - self.push_char(')'); + push_char!(self, ')'); } } - fn print_rational(&mut self, r: &Rational, add_brackets: bool) { - match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) { - Some(OpDirValue(ref spec)) => { + fn print_rational(&mut self, r: TypedArenaPtr, add_brackets: bool) { + match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) { + Some(op_desc) => { if add_brackets { self.state_stack.push(TokenOrRedirect::Close); } - let rdiv_ct = clause_name!("rdiv"); + let rdiv_ct = atom!("rdiv"); - let left_directed_op = if spec.prec() > 0 { - Some(DirectedOp::Left(rdiv_ct.clone(), spec.clone())) + let left_directed_op = if op_desc.get_prec() > 0 { + Some(DirectedOp::Left(rdiv_ct, *op_desc)) } else { None }; - let right_directed_op = if spec.prec() > 0 { - Some(DirectedOp::Right(rdiv_ct.clone(), spec.clone())) + let right_directed_op = if op_desc.get_prec() > 0 { + Some(DirectedOp::Right(rdiv_ct, *op_desc)) } else { None }; - if spec.prec() > 0 { - self.state_stack.push(TokenOrRedirect::Number( - Number::from(r.denom()), + if op_desc.get_prec() > 0 { + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Denominator(r), left_directed_op, )); self.state_stack - .push(TokenOrRedirect::Op(rdiv_ct, spec.clone())); + .push(TokenOrRedirect::Op(rdiv_ct, *op_desc)); - self.state_stack.push(TokenOrRedirect::Number( - Number::from(r.numer()), + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Numerator(r), right_directed_op, )); } else { self.state_stack.push(TokenOrRedirect::Close); - self.state_stack - .push(TokenOrRedirect::Number(Number::from(r.denom()), None)); + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Denominator(r), + None, + )); self.state_stack.push(TokenOrRedirect::Comma); - self.state_stack - .push(TokenOrRedirect::Number(Number::from(r.numer()), None)); + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Numerator(r), + None, + )); self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Atom(rdiv_ct)); @@ -1046,157 +1046,164 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn print_char(&mut self, is_quoted: bool, c: char) { - if non_quoted_token(once(c)) { - let c = char_to_string(false, c); + // returns true if max_depth limit is reached and ellipsis is printed. + fn print_string_as_functor(&mut self, focus: usize, max_depth: usize) -> bool { + let iter = HeapPStrIter::new(self.iter.heap, focus); - push_space_if_amb!(self, &c, { - self.append_str(c.as_str()); - }); - } else { - let mut result = String::new(); + for (char_count, c) in iter.chars().enumerate() { + append_str!(self, "'.'"); + push_char!(self, '('); - if self.quoted { - result.push('\''); - result += &char_to_string(is_quoted, c); - result.push('\''); - } else { - result += &char_to_string(is_quoted, c); - } + print_char!(self, self.quoted, c); + push_char!(self, ','); - push_space_if_amb!(self, &result, { - self.append_str(result.as_str()); - }); + self.state_stack.push(TokenOrRedirect::Close); + + if max_depth >= char_count + 1 { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + return true; + } } + + false } - fn print_proper_string(&mut self, buf: String, max_depth: usize) { - self.push_char('"'); + fn print_proper_string(&mut self, focus: usize, max_depth: usize) { + push_char!(self, '"'); - let buf = if max_depth == 0 { - String::from_iter(buf.chars().map(|c| char_to_string(self.quoted, c))) + let iter = HeapPStrIter::new(self.iter.heap, focus); + + if max_depth == 0 { + for c in iter.chars() { + for c in char_to_string(self.quoted, c).chars() { + push_char!(self, c); + } + } } else { let mut char_count = 0; - let mut buf = String::from_iter(buf.chars().take(max_depth).map(|c| { + + for c in iter.chars().take(max_depth) { char_count += 1; - char_to_string(self.quoted, c) - })); + + for c in char_to_string(self.quoted, c).chars() { + push_char!(self, c); + } + } if char_count == max_depth { - buf += " ..."; + append_str!(self, " ..."); } + } - buf - }; + push_char!(self, '"'); + } - self.append_str(&buf); - self.push_char('"'); + fn remove_list_children(&mut self, h: usize) { + match self.iter.heap[h].get_tag() { + HeapCellValueTag::Lis => { + self.iter.pop_stack(); + self.iter.pop_stack(); + } + HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => { + self.iter.pop_stack(); + } + HeapCellValueTag::CStr => { + } + _ => { + unreachable!(); + } + } } - fn print_list_like(&mut self, iter: &mut HCPreOrderIterator, addr: Addr, mut max_depth: usize) { - if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); - iter.stack().pop(); + fn print_list_like(&mut self, mut max_depth: usize) { + let focus = self.iter.focus(); + let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - return; + if heap_pstr_iter.next().is_some() { + while let Some(_) = heap_pstr_iter.next() {} + } else { + return self.push_list(max_depth); } - let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(addr); + let end_h = heap_pstr_iter.focus(); + let end_cell = self.iter.heap[end_h]; - let buf = heap_pstr_iter.to_string(); + self.remove_list_children(focus); - if buf.is_empty() { - self.push_list(iter, max_depth); + if self.check_max_depth(&mut max_depth) { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); return; } - iter.stack().pop(); - iter.stack().pop(); - - let end_addr = heap_pstr_iter.focus(); - let at_cdr = self.at_cdr(","); - if !at_cdr && Addr::EmptyList == end_addr { - if !self.ignore_ops { - self.print_proper_string(buf, max_depth); - return; - } + if !at_cdr && !self.ignore_ops && end_cell.is_string_terminator(&self.iter.heap) { + return self.print_proper_string(focus, max_depth); } - let buf_len = buf.len(); - - let buf_iter: Box> = if self.max_depth == 0 { - Box::new(buf.chars()) - } else { - Box::new(buf.chars().take(max_depth)) - }; - - let mut byte_len = 0; - if self.ignore_ops { - let mut char_count = 0; - - for c in buf_iter { - self.append_str("'.'"); - self.push_char('('); - - self.print_char(self.quoted, c); - self.push_char(','); - - char_count += 1; - byte_len += c.len_utf8(); - } - - for _ in 0..char_count { - self.state_stack.push(TokenOrRedirect::Close); - } + if !self.print_string_as_functor(end_h, max_depth) { + if end_cell.get_tag() == HeapCellValueTag::CStr { + append_str!(self, "[]"); + } else { + if self.outputter.ends_with(",") { + self.outputter.truncate(self.outputter.len() - ','.len_utf8()); + } - if self.max_depth > 0 && buf_len > byte_len { - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - } else { - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); - iter.stack().push(end_addr); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.iter.push_stack(end_h); + } } } else { let switch = if !at_cdr { - self.push_char('['); + push_char!(self, '['); true } else { false }; - for c in buf_iter { - self.print_char(self.quoted, c); - self.push_char(','); + let heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus); + + let mut iter = heap_pstr_iter.chars(); + let mut char_count = 0; + + while let Some(c) = iter.next() { + print_char!(self, self.quoted, c); + push_char!(self, ','); + + char_count += 1; - byte_len += c.len_utf8(); + if max_depth > 0 && max_depth <= char_count { + break; + } } - self.state_stack - .push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0))))); + self.state_stack.push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0))))); - if self.max_depth > 0 && buf_len > byte_len { - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + if self.max_depth > 0 && iter.next().is_some() { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); } else { - self.outputter - .truncate(self.outputter.len() - ','.len_utf8()); - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); + if iter.cycle_detected() { + self.iter.heap[end_h].set_forwarding_bit(true); + } - iter.stack().push(end_addr); + if end_cell.get_tag() == HeapCellValueTag::CStr { + self.state_stack.push(TokenOrRedirect::Atom(atom!("[]"))); + } else { + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.iter.push_stack(end_h); + } } self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + + if self.outputter.ends_with(",") { + self.outputter.truncate(self.outputter.len() - ','.len_utf8()); + } } } - fn check_max_depth(&mut self, max_depth: &mut usize) -> bool { + fn check_max_depth(&self, max_depth: &mut usize) -> bool { if self.max_depth > 0 && *max_depth == 0 { return true; } @@ -1208,17 +1215,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { false } - fn push_list(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) { + fn push_list(&mut self, mut max_depth: usize) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); - iter.stack().pop(); + self.iter.pop_stack(); + self.iter.pop_stack(); let cell = Rc::new(Cell::new((true, 0))); - self.state_stack - .push(TokenOrRedirect::CloseList(cell.clone())); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::CloseList(cell.clone())); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::OpenList(cell)); return; @@ -1226,26 +1231,22 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let cell = Rc::new(Cell::new((true, max_depth))); - self.state_stack - .push(TokenOrRedirect::CloseList(cell.clone())); + self.state_stack.push(TokenOrRedirect::CloseList(cell.clone())); - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::OpenList(cell)); } fn handle_op_as_struct( &mut self, - name: ClauseName, + name: Atom, arity: usize, - iter: &mut HCPreOrderIterator, op: &Option, is_functor_redirect: bool, - spec: SharedOpDesc, + op_desc: OpDesc, negated_operand: bool, max_depth: usize, ) { @@ -1253,20 +1254,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { negated_operand || if let Some(ref op) = op { if self.numbervars && arity == 1 && name.as_str() == "$VAR" { - !iter.immediate_leaf_has_property(|addr, heap| { - match heap.index_addr(&addr).as_ref() { - &HeapCellValue::Integer(ref n) => &**n >= &0, - &HeapCellValue::Addr(Addr::Fixnum(n)) => n >= 0, - &HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64), - &HeapCellValue::Rational(ref r) => &**r >= &0, + !self.iter.immediate_leaf_has_property(|addr| { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => &*n >= &0, + Ok(Number::Fixnum(n)) => n.get_num() >= 0, + Ok(Number::Float(f)) => f >= OrderedFloat(0f64), + Ok(Number::Rational(r)) => &*r >= &0, _ => false, } - }) && needs_bracketing(&spec, op) + }) && needs_bracketing(op_desc, op) } else { - needs_bracketing(&spec, op) + needs_bracketing(op_desc, op) } } else { - is_functor_redirect && spec.prec() >= 1000 + is_functor_redirect && op_desc.get_prec() >= 1000 } } else { false @@ -1276,44 +1277,46 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Close); } - let ct = ClauseType::from(name.clone(), arity, Some(spec)); + let ct = ClauseType::from(name, arity); - if self.format_clause(iter, max_depth, arity, ct) { - if add_brackets { - self.state_stack.push(TokenOrRedirect::Open); + if self.format_clause(max_depth, arity, ct, Some(op_desc)) && add_brackets { + self.state_stack.push(TokenOrRedirect::Open); - if let Some(ref op) = &op { - if op.is_left() && requires_space(op.as_str(), "(") { - self.state_stack.push(TokenOrRedirect::Space); - } + if let Some(ref op) = &op { + if op.is_left() && requires_space(op.as_atom().as_str(), "(") { + self.state_stack.push(TokenOrRedirect::Space); } } } } - fn print_tcp_listener( - &mut self, - iter: &mut HCPreOrderIterator, - tcp_listener: &TcpListener, - max_depth: usize, - ) { + #[allow(dead_code)] + fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) { let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() { - (addr.ip(), Number::from(addr.port() as isize)) + ( + addr.ip(), + Number::arena_from(addr.port() as usize, self.arena), + ) } else { - let disconnected_atom = clause_name!("$disconnected_tcp_listener"); + let disconnected_atom = atom!("$disconnected_tcp_listener"); self.state_stack .push(TokenOrRedirect::Atom(disconnected_atom)); return; }; - if self.format_struct(iter, max_depth, 1, clause_name!("$tcp_listener")) { + let tcp_listener_atom = atom!("$tcp_listener"); + + if self.format_struct(max_depth, 1, tcp_listener_atom) { let atom = self.state_stack.pop().unwrap(); self.state_stack.pop(); self.state_stack.pop(); - self.state_stack.push(TokenOrRedirect::Number(port, None)); + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Unfocused(port), + None, + )); self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::IpAddr(ip)); @@ -1322,13 +1325,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn print_stream(&mut self, iter: &mut HCPreOrderIterator, stream: &Stream, max_depth: usize) { - if let Some(alias) = &stream.options().alias { + fn print_stream(&mut self, stream: Stream, max_depth: usize) { + if let Some(alias) = stream.options().get_alias() { self.print_atom(alias); } else { - if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) { - let atom = if stream.is_stdout() || stream.is_stdin() || stream.is_stderr() { - TokenOrRedirect::Atom(clause_name!("user")) + let stream_atom = atom!("$stream"); + + if self.format_struct(max_depth, 1, stream_atom) { + let atom = if stream.is_stdout() || stream.is_stdin() { + TokenOrRedirect::Atom(atom!("user")) } else { TokenOrRedirect::RawPtr(stream.as_ptr()) }; @@ -1347,121 +1352,144 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn handle_heap_term( &mut self, - iter: &mut HCPreOrderIterator, op: Option, is_functor_redirect: bool, max_depth: usize, ) { - let negated_operand = negated_op_needs_bracketing(iter, &op); + let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op); - let addr = match self.check_for_seen(iter) { + let addr = match self.check_for_seen() { Some(addr) => addr, None => return, }; - match self.machine_st.heap.index_addr(&addr).as_ref() { - &HeapCellValue::NamedStr(arity, ref name, ref spec) => { - let spec = - fetch_op_spec_from_existing(name.clone(), arity, spec.clone(), self.op_dir); - - if let Some(spec) = spec { - self.handle_op_as_struct( - name.clone(), - arity, - iter, - &op, - is_functor_redirect, - spec.clone(), - negated_operand, - max_depth, - ); - } else { - push_space_if_amb!(self, name.as_str(), { - let ct = ClauseType::from(name.clone(), arity, spec); - self.format_clause(iter, max_depth, arity, ct); - }); - } - } - &HeapCellValue::Atom(ref atom, ref spec) => { - if let Some(_) = fetch_atom_op_spec(atom.clone(), spec.clone(), self.op_dir) { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") { + if !self.at_cdr("") { + append_str!(self, "[]"); + } + } else if arity > 0 { + if let Some(spec) = fetch_op_spec(name, arity, self.op_dir) { + self.handle_op_as_struct( + name, + arity, + &op, + is_functor_redirect, + spec, + negated_operand, + max_depth, + ); + } else { + push_space_if_amb!(self, name.as_str(), { + let ct = ClauseType::from(name, arity); + self.format_clause(max_depth, arity, ct, None); + }); + } + } else if fetch_op_spec(name, arity, self.op_dir).is_some() { let mut result = String::new(); if let Some(ref op) = op { - if self.outputter.ends_with(&format!(" {}", op.as_str())) { + if self.outputter.ends_with(&format!(" {}", op.as_atom().as_str())) { result.push(' '); } result.push('('); } - result += &self.print_op_addendum(atom.as_str()); + result += &self.print_op_addendum(name.as_str()); if op.is_some() { result.push(')'); } push_space_if_amb!(self, &result, { - self.append_str(&result); + append_str!(self, &result); }); } else { - push_space_if_amb!(self, atom.as_str(), { - self.print_atom(&atom); + push_space_if_amb!(self, name.as_str(), { + self.print_atom(name); }); } } - &HeapCellValue::Addr(Addr::Char(c)) => { - self.print_char(self.quoted, c); - } - &HeapCellValue::Addr(Addr::CutPoint(b)) => { - self.append_str(&format!("{}", b)); - } - &HeapCellValue::Addr(Addr::EmptyList) => { - if !self.at_cdr("") { - self.append_str("[]"); + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.iter.heap[s]) + .get_name_and_arity(); + + if let Some(spec) = fetch_op_spec(name, arity, self.op_dir) { + self.handle_op_as_struct( + name, + arity, + &op, + is_functor_redirect, + spec, + negated_operand, + max_depth, + ); + } else { + push_space_if_amb!(self, name.as_str(), { + let ct = ClauseType::from(name, arity); + self.format_clause(max_depth, arity, ct, None); + }); } } - &HeapCellValue::Addr(Addr::Float(n)) => { - self.print_number(Number::Float(n), &op); + (HeapCellValueTag::Fixnum, n) => { + append_str!(self, &format!("{}", n.get_num())); } - &HeapCellValue::Addr(Addr::Fixnum(n)) => { - self.print_number(Number::Fixnum(n), &op); + (HeapCellValueTag::F64, f) => { + self.print_number(NumberFocus::Unfocused(Number::Float(**f)), &op); } - &HeapCellValue::Addr(Addr::Usize(u)) => { - self.append_str(&format!("{}", u)); + (HeapCellValueTag::PStrOffset) => { + self.print_list_like(max_depth); } - &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { - self.print_list_like(iter, Addr::PStrLocation(h, n), max_depth); + (HeapCellValueTag::PStr | HeapCellValueTag::CStr) => { + self.print_list_like(max_depth); } - &HeapCellValue::Addr(Addr::Lis(l)) => { + (HeapCellValueTag::Lis) => { if self.ignore_ops { - self.format_struct(iter, max_depth, 2, clause_name!(".")); + let period_atom = atom!("."); + self.format_struct(max_depth, 2, period_atom); } else { - self.print_list_like(iter, Addr::Lis(l), max_depth); + self.print_list_like(max_depth); } } - &HeapCellValue::Addr(addr) => { - if let Some(offset_str) = self.offset_as_string(iter, addr) { + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let h = self.iter.focus(); + + if let Some(offset_str) = self.offset_as_string(h) { push_space_if_amb!(self, &offset_str, { - self.append_str(offset_str.as_str()); + append_str!(self, offset_str.as_str()); }) } } - &HeapCellValue::Integer(ref n) => { - self.print_number(Number::Integer(n.clone()), &op); - } - &HeapCellValue::Rational(ref n) => { - self.print_number(Number::Rational(n.clone()), &op); - } - &HeapCellValue::Stream(ref stream) => { - self.print_stream(iter, stream, max_depth); + (HeapCellValueTag::Char, c) => { + print_char!(self, self.quoted, c); } - &HeapCellValue::TcpListener(ref tcp_listener) => { - self.print_tcp_listener(iter, tcp_listener, max_depth); + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::F64, f) => { + self.print_number(NumberFocus::Unfocused(Number::Float(*f)), &op); + } + (ArenaHeaderTag::Integer, n) => { + self.print_number(NumberFocus::Unfocused(Number::Integer(n)), &op); + } + (ArenaHeaderTag::Rational, r) => { + self.print_number(NumberFocus::Unfocused(Number::Rational(r)), &op); + } + (ArenaHeaderTag::Stream, stream) => { + self.print_stream(stream, max_depth); + } + (ArenaHeaderTag::OssifiedOpDir, _op_dir) => { + append_str!(self, "$ossified_op_dir"); + } + _ => { + } + ); } _ => { unreachable!() } - } + ); } fn at_cdr(&mut self, tr: &str) -> bool { @@ -1469,7 +1497,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if self.outputter.ends_with("|") { self.outputter.truncate(len - "|".len()); - self.append_str(tr); + append_str!(self, tr); true } else { @@ -1477,29 +1505,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - pub(crate) fn print(mut self, addr: Addr) -> Outputter { - let mut iter = self.machine_st.pre_order_iter(addr); - + pub fn print(mut self) -> Outputter { loop { if let Some(loc_data) = self.state_stack.pop() { match loc_data { - TokenOrRedirect::Atom(atom) => self.print_atom(&atom), - TokenOrRedirect::BarAsOp => self.append_str(" | "), + TokenOrRedirect::Atom(atom) => self.print_atom(atom), + TokenOrRedirect::BarAsOp => append_str!(self, " | "), TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()), - TokenOrRedirect::NumberedVar(num_var) => self.append_str(num_var.as_str()), + TokenOrRedirect::NumberedVar(num_var) => append_str!(self, &num_var), TokenOrRedirect::CompositeRedirect(max_depth, op) => { - self.handle_heap_term(&mut iter, Some(op), false, max_depth) + self.handle_heap_term(Some(op), false, max_depth) } TokenOrRedirect::FunctorRedirect(max_depth) => { - self.handle_heap_term(&mut iter, None, true, max_depth) + self.handle_heap_term(None, true, max_depth) } - TokenOrRedirect::Close => self.push_char(')'), + TokenOrRedirect::Close => push_char!(self, ')'), TokenOrRedirect::IpAddr(ip) => self.print_ip_addr(ip), TokenOrRedirect::RawPtr(ptr) => self.print_raw_ptr(ptr), - TokenOrRedirect::Open => self.push_char('('), + TokenOrRedirect::Open => push_char!(self, '('), TokenOrRedirect::OpenList(delimit) => { if !self.at_cdr(",") { - self.push_char('['); + push_char!(self, '['); } else { let (_, max_depth) = delimit.get(); delimit.set((false, max_depth)); @@ -1507,19 +1533,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } TokenOrRedirect::CloseList(delimit) => { if delimit.get().0 { - self.push_char(']'); + push_char!(self, ']'); } } - TokenOrRedirect::HeadTailSeparator => self.append_str("|"), - TokenOrRedirect::Number(n, op) => self.print_number(n, &op), - TokenOrRedirect::Comma => self.append_str(","), - TokenOrRedirect::Space => self.push_char(' '), - TokenOrRedirect::LeftCurly => self.push_char('{'), - TokenOrRedirect::RightCurly => self.push_char('}'), + TokenOrRedirect::HeadTailSeparator => append_str!(self, "|"), + TokenOrRedirect::NumberFocus(n, op) => self.print_number(n, &op), + TokenOrRedirect::Comma => append_str!(self, ","), + TokenOrRedirect::Space => push_char!(self, ' '), + TokenOrRedirect::LeftCurly => push_char!(self, '{'), + TokenOrRedirect::RightCurly => push_char!(self, '}'), } - } else if !iter.stack().is_empty() { + } else if !self.iter.stack_is_empty() { let spec = self.toplevel_spec.take(); - self.handle_heap_term(&mut iter, spec, false, self.max_depth); + self.handle_heap_term(spec, false, self.max_depth); } else { break; } @@ -1528,3 +1554,273 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.outputter } } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::machine::mock_wam::*; + + #[test] + fn term_printing_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + let c_atom = atom!("c"); + + wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "f(a,b)"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "f(a,b,a,...)"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + // print L = [L|L]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[...|...]"); + + let mut printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + printer + .var_names + .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); + + let output = printer.print(); + + assert_eq!(output.result(), "[L|L]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0), + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0), + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|...]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + { + let mut printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + printer + .var_names + .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); + + let output = printer.print(); + + assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|L]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + // issue #382 + wam.machine_st.heap.clear(); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + for idx in 0..3000 { + wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1)); + wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1)); + } + + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + printer.max_depth = 5; + + let output = printer.print(); + + assert_eq!(output.result(), "[_1,_3,_5,_7,_9,...]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + put_partial_string(&mut wam.machine_st.heap, "abc", &mut wam.machine_st.atom_tbl); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + pstr_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[a,b,c|_1]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(atom_as_cell!(c_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0), + ); + + let output = printer.print(); + + assert_eq!(output.result(), "\"abcabc\""); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + assert_eq!( + &wam.parse_and_print_term("=(X,[a,b,c|X]).").unwrap(), + "=(X,[a,b,c|X])" + ); + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!( + &wam.parse_and_print_term("[a,b,\"a\",[a,b,c]].").unwrap(), + "[a,b,\"a\",\"abc\"]" + ); + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!( + &wam.parse_and_print_term("[\"abc\",e,f,[g,e,h,Y,v|[X,Y]]].") + .unwrap(), + "[\"abc\",e,f,[g,e,h,Y,v,X,Y]]" + ); + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(&wam.parse_and_print_term("f((a,b)).").unwrap(), "f((a,b))"); + } +} diff --git a/src/indexing.rs b/src/indexing.rs index a71ab01f9..6d63ff794 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,33 +1,20 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; -use prolog_parser::tabled_rc::*; +use crate::atom_table::*; +use crate::parser::ast::*; use crate::forms::*; use crate::instructions::*; -use crate::rug::Integer; use indexmap::IndexMap; - use slice_deque::{sdeq, SliceDeque}; -use std::convert::TryFrom; use std::hash::Hash; use std::iter::once; use std::mem; -use std::rc::Rc; - -#[derive(Debug, Clone, Copy)] -pub(crate) enum IndexingCodePtr { - External(usize), // the index points past the indexing instruction prelude. - DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction. - Fail, - Internal(usize), // the index points into the indexing instruction prelude. -} #[derive(Debug, Clone, Copy)] enum OptArgIndexKeyType { Structure, - Constant, + Literal, // List, } @@ -35,7 +22,7 @@ impl OptArgIndexKey { #[inline] fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool { match (self, key_type) { - (OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant) + (OptArgIndexKey::Literal(..), OptArgIndexKeyType::Literal) | (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure) // | (OptArgIndexKey::List(..), OptArgIndexKeyType::List) => true, @@ -45,11 +32,12 @@ impl OptArgIndexKey { } #[inline] -fn search_skeleton_for_first_key_type( - skeleton: &[ClauseIndexInfo], +fn search_skeleton_for_first_key_type<'a>( + skeleton: &'a [ClauseIndexInfo], + retracted_dynamic_clauses: &'a Option>, key_type: OptArgIndexKeyType, append_or_prepend: AppendOrPrepend, -) -> Option<&OptArgIndexKey> { +) -> Option<&'a OptArgIndexKey> { if append_or_prepend.is_append() { for clause_index_info in skeleton.iter().rev() { if clause_index_info.opt_arg_index_key.has_key_type(key_type) { @@ -64,11 +52,20 @@ fn search_skeleton_for_first_key_type( } } + if let Some(retracted_clauses) = retracted_dynamic_clauses { + for clause_index_info in retracted_clauses.iter().rev() { + if clause_index_info.opt_arg_index_key.has_key_type(key_type) { + return Some(&clause_index_info.opt_arg_index_key); + } + } + } + None } struct IndexingCodeMergingPtr<'a> { skeleton: &'a mut [ClauseIndexInfo], + retracted_dynamic_clauses: &'a Option>, indexing_code: &'a mut Vec, offset: usize, append_or_prepend: AppendOrPrepend, @@ -79,22 +76,22 @@ impl<'a> IndexingCodeMergingPtr<'a> { #[inline] fn new( skeleton: &'a mut [ClauseIndexInfo], + retracted_dynamic_clauses: &'a Option>, indexing_code: &'a mut Vec, append_or_prepend: AppendOrPrepend, ) -> Self { let is_dynamic = match &indexing_code[0] { - IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => { - match v { - IndexingCodePtr::External(_) => false, - IndexingCodePtr::DynamicExternal(_) => true, - _ => unreachable!() - } - } - _ => unreachable!() + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v { + IndexingCodePtr::External(_) => false, + IndexingCodePtr::DynamicExternal(_) => true, + _ => unreachable!(), + }, + _ => unreachable!(), }; Self { skeleton, + retracted_dynamic_clauses, indexing_code, offset: 0, append_or_prepend, @@ -105,15 +102,16 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) { let constant_key = search_skeleton_for_first_key_type( self.skeleton, - OptArgIndexKeyType::Constant, + self.retracted_dynamic_clauses, + OptArgIndexKeyType::Literal, self.append_or_prepend, ); let mut constants = IndexMap::new(); match constant_key { - Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => { - constants.insert(constant.clone(), constant_ptr); + Some(OptArgIndexKey::Literal(_, _, constant, _)) => { + constants.insert(*constant, constant_ptr); } _ => { if let IndexingCodePtr::DynamicExternal(_) = constant_ptr { @@ -145,7 +143,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn add_static_indexed_choice_for_constant( &mut self, external: usize, - constant: Constant, + constant: Literal, index: usize, ) { let third_level_index = if self.append_or_prepend.is_append() { @@ -179,7 +177,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn add_dynamic_indexed_choice_for_constant( &mut self, external: usize, - constant: Constant, + constant: Literal, index: usize, ) { let third_level_index = if self.append_or_prepend.is_append() { @@ -232,8 +230,8 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn index_overlapping_constant( &mut self, - orig_constant: &Constant, - overlapping_constant: Constant, + orig_constant: Literal, + overlapping_constant: Literal, index: usize, ) { loop { @@ -252,7 +250,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { } IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { let mut constants = IndexMap::new(); - constants.insert(orig_constant.clone(), *c); + constants.insert(orig_constant, *c); *c = IndexingCodePtr::Internal(indexing_code_len); @@ -282,10 +280,18 @@ impl<'a> IndexingCodeMergingPtr<'a> { ); } Some(IndexingCodePtr::DynamicExternal(o)) => { - self.add_dynamic_indexed_choice_for_constant(o, overlapping_constant, index); + self.add_dynamic_indexed_choice_for_constant( + o, + overlapping_constant, + index, + ); } Some(IndexingCodePtr::External(o)) => { - self.add_static_indexed_choice_for_constant(o, overlapping_constant, index); + self.add_static_indexed_choice_for_constant( + o, + overlapping_constant, + index, + ); } Some(IndexingCodePtr::Internal(o)) => { self.offset += o; @@ -307,7 +313,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { } } - fn index_constant(&mut self, constant: Constant, index: usize) { + fn index_constant(&mut self, constant: Literal, index: usize) { loop { let indexing_code_len = self.indexing_code.len(); @@ -338,10 +344,16 @@ impl<'a> IndexingCodeMergingPtr<'a> { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => { match constants.get(&constant).cloned() { None | Some(IndexingCodePtr::Fail) if self.is_dynamic => { - constants.insert(constant, IndexingCodePtr::DynamicExternal(index)); + constants.insert( + constant, + IndexingCodePtr::DynamicExternal(index), + ); } None | Some(IndexingCodePtr::Fail) => { - constants.insert(constant, IndexingCodePtr::External(index)); + constants.insert( + constant, + IndexingCodePtr::External(index), + ); } Some(IndexingCodePtr::DynamicExternal(o)) => { self.add_dynamic_indexed_choice_for_constant(o, constant, index); @@ -372,6 +384,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) { let structure_key = search_skeleton_for_first_key_type( self.skeleton, + self.retracted_dynamic_clauses, OptArgIndexKeyType::Structure, self.append_or_prepend, ); @@ -379,8 +392,8 @@ impl<'a> IndexingCodeMergingPtr<'a> { let mut structures = IndexMap::new(); match structure_key { - Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => { - structures.insert((name.clone(), *arity), structure_ptr); + Some(OptArgIndexKey::Structure(_, _, name, arity)) => { + structures.insert((*name, *arity), structure_ptr); } _ => { if let IndexingCodePtr::DynamicExternal(_) = structure_ptr { @@ -428,8 +441,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { }; let indexing_code_len = self.indexing_code.len(); - self.indexing_code - .push(IndexingLine::IndexedChoice(third_level_index)); + self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index)); match &mut self.indexing_code[self.offset] { IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { @@ -599,6 +611,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { pub(crate) fn merge_clause_index( target_indexing_code: &mut Vec, skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton. + retracted_clauses: &Option>, new_clause_loc: usize, // the absolute location of the new clause in the code vector. append_or_prepend: AppendOrPrepend, ) { @@ -609,27 +622,28 @@ pub(crate) fn merge_clause_index( let mut merging_ptr = IndexingCodeMergingPtr::new( skeleton, + retracted_clauses, target_indexing_code, append_or_prepend, ); match &opt_arg_index_key { - OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => { + OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => { let offset = new_clause_loc - index_loc + 1; - merging_ptr.index_constant(constant.clone(), offset); + merging_ptr.index_constant(*constant, offset); for overlapping_constant in overlapping_constants { merging_ptr.offset = 0; merging_ptr.index_overlapping_constant( - constant, - overlapping_constant.clone(), + *constant, + *overlapping_constant, offset, ); } } - OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => { - merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1); + OptArgIndexKey::Structure(_, index_loc, name, arity) => { + merging_ptr.index_structure((*name, *arity), new_clause_loc - index_loc + 1); } OptArgIndexKey::List(_, index_loc) => { merging_ptr.index_list(new_clause_loc - index_loc + 1); @@ -650,13 +664,13 @@ pub(crate) fn merge_clause_index( } pub(crate) fn remove_constant_indices( - constant: &Constant, - overlapping_constants: &[Constant], + constant: Literal, + overlapping_constants: &[Literal], indexing_code: &mut Vec, offset: usize, ) { let mut index = 0; - let iter = once(constant).chain(overlapping_constants.iter()); + let iter = once(&constant).chain(overlapping_constants.iter()); match &mut indexing_code[index] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => { @@ -688,11 +702,13 @@ pub(crate) fn remove_constant_indices( )) => { constants_index = index; - match constants.get(constant).cloned() { - Some(IndexingCodePtr::DynamicExternal(_)) | - Some(IndexingCodePtr::External(_)) | - Some(IndexingCodePtr::Fail) => { - constants.remove(constant); + let constant = *constant; + + match constants.get(&constant).cloned() { + Some(IndexingCodePtr::DynamicExternal(_)) + | Some(IndexingCodePtr::External(_)) + | Some(IndexingCodePtr::Fail) => { + constants.remove(&constant); break; } Some(IndexingCodePtr::Internal(o)) => { @@ -704,13 +720,14 @@ pub(crate) fn remove_constant_indices( } } IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { - StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + StaticCodeIndices::remove_instruction_with_offset( + indexed_choice_instrs, + offset, + ); if indexed_choice_instrs.len() == 1 { if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { - let ext = IndexingCodePtr::External( - indexed_choice_instr.offset() - ); + let ext = IndexingCodePtr::External(indexed_choice_instr.offset()); match &mut indexing_code[constants_index] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( @@ -724,7 +741,7 @@ pub(crate) fn remove_constant_indices( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( ref mut constants, )) => { - constants.insert(constant.clone(), ext); + constants.insert(*constant, ext); } _ => { unreachable!() @@ -736,7 +753,10 @@ pub(crate) fn remove_constant_indices( break; } IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => { - DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + DynamicCodeIndices::remove_instruction_with_offset( + indexed_choice_instrs, + offset, + ); if indexed_choice_instrs.len() == 1 { if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { @@ -754,7 +774,7 @@ pub(crate) fn remove_constant_indices( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( ref mut constants, )) => { - constants.insert(constant.clone(), ext); + constants.insert(*constant, ext); } _ => { unreachable!() @@ -790,7 +810,7 @@ pub(crate) fn remove_constant_indices( } pub(crate) fn remove_structure_index( - name: &ClauseName, + name: Atom, arity: usize, indexing_code: &mut Vec, offset: usize, @@ -825,7 +845,8 @@ pub(crate) fn remove_structure_index( structures_index = index; match structures.get(&(name.clone(), arity)).cloned() { - Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => { + Some(IndexingCodePtr::DynamicExternal(_)) + | Some(IndexingCodePtr::External(_)) => { structures.remove(&(name.clone(), arity)); break; } @@ -1012,27 +1033,14 @@ pub(crate) fn remove_index( clause_loc: usize, ) { match opt_arg_index_key { - OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => { - remove_constant_indices( - constant, - overlapping_constants, - indexing_code, - clause_loc, - ); - } - OptArgIndexKey::Structure(_, _, ref name, ref arity) => { - remove_structure_index( - name, - *arity, - indexing_code, - clause_loc, - ); + OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => { + remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc); + } + OptArgIndexKey::Structure(_, _, name, arity) => { + remove_structure_index(*name, *arity, indexing_code, clause_loc); } OptArgIndexKey::List(..) => { - remove_list_index( - indexing_code, - clause_loc, - ); + remove_list_index(indexing_code, clause_loc); } OptArgIndexKey::None => { unreachable!() @@ -1076,49 +1084,52 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) { }); } -pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData) -> Vec { +pub(crate) fn constant_key_alternatives( + constant: Literal, + atom_tbl: &mut AtomTable, + // arena: &mut Arena, +) -> Vec { let mut constants = vec![]; match constant { - Constant::Atom(ref name, ref op) => { - if name.is_char() { - let c = name.as_str().chars().next().unwrap(); - constants.push(Constant::Char(c)); - } - - if op.is_some() { - constants.push(Constant::Atom(name.clone(), None)); + Literal::Atom(ref name) => { + if let Some(c) = name.as_char() { + constants.push(Literal::Char(c)); } } - Constant::Char(c) => { - let atom = clause_name!(c.to_string(), atom_tbl); - constants.push(Constant::Atom(atom, None)); + Literal::Char(c) => { + let atom = atom_tbl.build_with(&c.to_string()); + constants.push(Literal::Atom(atom)); } - Constant::Fixnum(ref n) => { - constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + /* + Literal::Fixnum(ref n) => { + constants.push(Literal::Integer(arena_alloc!(n, arena))); //Rc::new(Integer::from(*n)))); + /* if *n >= 0 { if let Ok(n) = usize::try_from(*n) { - constants.push(Constant::Usize(n)); + constants.push(Literal::Usize(n)); } } + */ } - Constant::Integer(ref n) => { + */ + Literal::Integer(ref n) => { if let Some(n) = n.to_isize() { - constants.push(Constant::Fixnum(n)); - } - - if let Some(n) = n.to_usize() { - constants.push(Constant::Usize(n)); + Fixnum::build_with_checked(n as i64).map(|n| { + constants.push(Literal::Fixnum(n)); + }).unwrap(); } } - Constant::Usize(n) => { - constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + /* + Literal::Usize(n) => { + constants.push(Literal::Integer(Rc::new(Integer::from(*n)))); if let Ok(n) = isize::try_from(*n) { - constants.push(Constant::Fixnum(n)); + constants.push(Literal::Fixnum(n)); } } + */ _ => {} } @@ -1127,16 +1138,16 @@ pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledDat #[derive(Debug)] pub(crate) struct StaticCodeIndices { - constants: IndexMap>, + constants: IndexMap>, lists: SliceDeque, - structures: IndexMap<(ClauseName, usize), SliceDeque>, + structures: IndexMap<(Atom, usize), SliceDeque>, } #[derive(Debug)] pub(crate) struct DynamicCodeIndices { - constants: IndexMap>, + constants: IndexMap>, lists: SliceDeque, - structures: IndexMap<(ClauseName, usize), SliceDeque>, + structures: IndexMap<(Atom, usize), SliceDeque>, } pub(crate) trait Indexer { @@ -1144,9 +1155,9 @@ pub(crate) trait Indexer { fn new() -> Self; - fn constants(&mut self) -> &mut IndexMap>; + fn constants(&mut self) -> &mut IndexMap>; fn lists(&mut self) -> &mut SliceDeque; - fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque>; + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque>; fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex; @@ -1166,10 +1177,7 @@ pub(crate) trait Indexer { prelude: &mut SliceDeque, ) -> IndexingCodePtr; - fn remove_instruction_with_offset( - code: &mut SliceDeque, - offset: usize, - ); + fn remove_instruction_with_offset(code: &mut SliceDeque, offset: usize); fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr; } @@ -1187,7 +1195,7 @@ impl Indexer for StaticCodeIndices { } #[inline] - fn constants(&mut self) -> &mut IndexMap> { + fn constants(&mut self) -> &mut IndexMap> { &mut self.constants } @@ -1197,7 +1205,7 @@ impl Indexer for StaticCodeIndices { } #[inline] - fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque> { + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque> { &mut self.structures } @@ -1271,7 +1279,10 @@ impl Indexer for StaticCodeIndices { } #[inline] - fn remove_instruction_with_offset(code: &mut SliceDeque, offset: usize) { + fn remove_instruction_with_offset( + code: &mut SliceDeque, + offset: usize, + ) { for (index, line) in code.iter().enumerate() { if offset == line.offset() { code.remove(index); @@ -1300,7 +1311,7 @@ impl Indexer for DynamicCodeIndices { } #[inline] - fn constants(&mut self) -> &mut IndexMap> { + fn constants(&mut self) -> &mut IndexMap> { &mut self.constants } @@ -1310,7 +1321,7 @@ impl Indexer for DynamicCodeIndices { } #[inline] - fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque> { + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque> { &mut self.structures } @@ -1395,19 +1406,13 @@ impl Indexer for DynamicCodeIndices { #[derive(Debug)] pub(crate) struct CodeOffsets { - atom_tbl: TabledData, indices: I, optimal_index: usize, } impl CodeOffsets { - pub(crate) fn new( - atom_tbl: TabledData, - indices: I, - optimal_index: usize, - ) -> Self { + pub(crate) fn new(indices: I, optimal_index: usize) -> Self { CodeOffsets { - atom_tbl, indices, optimal_index, } @@ -1419,15 +1424,24 @@ impl CodeOffsets { self.indices.lists().push_back(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.indices.constants().entry(constant.clone()).or_insert(sdeq![]); + fn index_constant( + &mut self, + atom_tbl: &mut AtomTable, + constant: Literal, + index: usize, + ) -> Vec { + let overlapping_constants = constant_key_alternatives(constant, atom_tbl); + let code = self.indices.constants().entry(constant).or_insert(sdeq![]); let is_initial_index = code.is_empty(); code.push_back(I::compute_index(is_initial_index, index)); for constant in &overlapping_constants { - let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]); + let code = self + .indices + .constants() + .entry(*constant) + .or_insert(sdeq![]); let is_initial_index = code.is_empty(); let index = I::compute_index(is_initial_index, index); @@ -1438,8 +1452,9 @@ impl CodeOffsets { overlapping_constants } - fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize { - let code = self.indices + fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize { + let code = self + .indices .structures() .entry((name.clone(), arity)) .or_insert(sdeq![]); @@ -1456,28 +1471,25 @@ impl CodeOffsets { optimal_arg: &Term, index: usize, clause_index_info: &mut ClauseIndexInfo, + atom_tbl: &mut AtomTable, ) { match optimal_arg { - &Term::Clause(_, ref name, ref terms, _) => { + &Term::Clause(_, name, ref terms) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len()); self.index_structure(name, terms.len(), index); } - &Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => { + &Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); self.index_list(index); } - &Term::Constant(_, ref constant) => { - let overlapping_constants = self.index_constant(constant, index); - - clause_index_info.opt_arg_index_key = OptArgIndexKey::Constant( - self.optimal_index, - 0, - constant.clone(), - overlapping_constants, - ); + &Term::Literal(_, constant) => { + let overlapping_constants = self.index_constant(atom_tbl, constant, index); + + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants); } _ => {} } diff --git a/src/instructions.rs b/src/instructions.rs index 90cbeeab0..76c9c76cf 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -1,46 +1,42 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; use crate::clause_types::*; use crate::forms::*; -use crate::indexing::IndexingCodePtr; +use crate::types::*; use crate::machine::heap::*; use crate::machine::machine_errors::MachineStub; -use crate::machine::machine_indices::*; -use crate::rug::Integer; use indexmap::IndexMap; - use slice_deque::SliceDeque; -use std::rc::Rc; - fn reg_type_into_functor(r: RegType) -> MachineStub { match r { - RegType::Temp(r) => functor!("x", [integer(r)]), - RegType::Perm(r) => functor!("y", [integer(r)]), + RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]), + RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]), } } impl Level { fn into_functor(self) -> MachineStub { match self { - Level::Root => functor!("level", [atom("root")]), - Level::Shallow => functor!("level", [atom("shallow")]), - Level::Deep => functor!("level", [atom("deep")]), + Level::Root => functor!(atom!("level"), [atom(atom!("root"))]), + Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]), + Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]), } } } impl ArithmeticTerm { - fn into_functor(&self) -> MachineStub { + fn into_functor(&self, arena: &mut Arena) -> MachineStub { match self { &ArithmeticTerm::Reg(r) => reg_type_into_functor(r), &ArithmeticTerm::Interm(i) => { - functor!("intermediate", [integer(i)]) + functor!(atom!("intermediate"), [fixnum(i)]) } - &ArithmeticTerm::Number(ref n) => { - vec![n.clone().into()] + &ArithmeticTerm::Number(n) => { + vec![HeapCellValue::from((n, arena))] } } } @@ -87,33 +83,30 @@ impl ChoiceInstruction { match (death, next_or_fail) { (Death::Infinity, NextOrFail::Next(i)) => { functor!( - "dynamic_else", - [integer(birth), atom("inf"), integer(i)] + atom!("dynamic_else"), + [fixnum(birth), atom(atom!("inf")), fixnum(i)] ) } (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_else", - [integer(birth), atom("inf"), aux(h, 0)], + atom!("dynamic_else"), + [fixnum(birth), atom(atom!("inf")), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_else", - [integer(birth), integer(d), aux(h, 0)], + atom!("dynamic_else"), + [fixnum(birth), fixnum(d), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Next(i)) => { - functor!( - "dynamic_else", - [integer(birth), integer(d), integer(i)] - ) + functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)]) } } } @@ -121,50 +114,50 @@ impl ChoiceInstruction { match (death, next_or_fail) { (Death::Infinity, NextOrFail::Next(i)) => { functor!( - "dynamic_internal_else", - [integer(birth), atom("inf"), integer(i)] + atom!("dynamic_internal_else"), + [fixnum(birth), atom(atom!("inf")), fixnum(i)] ) } (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_internal_else", - [integer(birth), atom("inf"), aux(h, 0)], + atom!("dynamic_internal_else"), + [fixnum(birth), atom(atom!("inf")), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_internal_else", - [integer(birth), integer(d), aux(h, 0)], + atom!("dynamic_internal_else"), + [fixnum(birth), fixnum(d), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Next(i)) => { functor!( - "dynamic_internal_else", - [integer(birth), integer(d), integer(i)] + atom!("dynamic_internal_else"), + [fixnum(birth), fixnum(d), fixnum(i)] ) } } } &ChoiceInstruction::TryMeElse(offset) => { - functor!("try_me_else", [integer(offset)]) + functor!(atom!("try_me_else"), [fixnum(offset)]) } &ChoiceInstruction::RetryMeElse(offset) => { - functor!("retry_me_else", [integer(offset)]) + functor!(atom!("retry_me_else"), [fixnum(offset)]) } &ChoiceInstruction::TrustMe(offset) => { - functor!("trust_me", [integer(offset)]) + functor!(atom!("trust_me"), [fixnum(offset)]) } &ChoiceInstruction::DefaultRetryMeElse(offset) => { - functor!("default_retry_me_else", [integer(offset)]) + functor!(atom!("default_retry_me_else"), [fixnum(offset)]) } &ChoiceInstruction::DefaultTrustMe(offset) => { - functor!("default_trust_me", [integer(offset)]) + functor!(atom!("default_trust_me"), [fixnum(offset)]) } } } @@ -183,18 +176,18 @@ impl CutInstruction { match self { &CutInstruction::Cut(r) => { let rt_stub = reg_type_into_functor(r); - functor!("cut", [aux(h, 0)], [rt_stub]) + functor!(atom!("cut"), [str(h, 0)], [rt_stub]) } &CutInstruction::GetLevel(r) => { let rt_stub = reg_type_into_functor(r); - functor!("get_level", [aux(h, 0)], [rt_stub]) + functor!(atom!("get_level"), [str(h, 0)], [rt_stub]) } &CutInstruction::GetLevelAndUnify(r) => { let rt_stub = reg_type_into_functor(r); - functor!("get_level_and_unify", [aux(h, 0)], [rt_stub]) + functor!(atom!("get_level_and_unify"), [str(h, 0)], [rt_stub]) } &CutInstruction::NeckCut => { - functor!("neck_cut") + functor!(atom!("neck_cut")) } } } @@ -219,13 +212,13 @@ impl IndexedChoiceInstruction { pub(crate) fn to_functor(&self) -> MachineStub { match self { &IndexedChoiceInstruction::Try(offset) => { - functor!("try", [integer(offset)]) + functor!(atom!("try"), [fixnum(offset)]) } &IndexedChoiceInstruction::Trust(offset) => { - functor!("trust", [integer(offset)]) + functor!(atom!("trust"), [fixnum(offset)]) } &IndexedChoiceInstruction::Retry(offset) => { - functor!("retry", [integer(offset)]) + functor!(atom!("retry"), [fixnum(offset)]) } } } @@ -276,9 +269,16 @@ impl Line { } } - pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec) { + pub(crate) fn enqueue_functors( + &self, + mut h: usize, + arena: &mut Arena, + functors: &mut Vec, + ) { match self { - &Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)), + &Line::Arithmetic(ref arith_instr) => { + functors.push(arith_instr.to_functor(h, arena)) + } &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)), &Line::Control(ref control_instr) => functors.push(control_instr.to_functor()), &Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)), @@ -300,7 +300,11 @@ impl Line { } IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => { for indexed_choice_instr in indexed_choice_instrs { - let section = functor!("dynamic", [integer(*indexed_choice_instr)]); + let section = functor!( + atom!("dynamic"), + [fixnum(*indexed_choice_instr)] + ); + h += section.len(); functors.push(section); } @@ -312,7 +316,7 @@ impl Line { functors.push(indexed_choice_instr.to_functor()) } &Line::DynamicIndexedChoice(ref indexed_choice_instr) => { - functors.push(functor!("dynamic", [integer(*indexed_choice_instr)])); + functors.push(functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)])); } &Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)), } @@ -336,7 +340,7 @@ pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec> { } #[derive(Debug, Clone)] -pub(crate) enum ArithmeticInstruction { +pub enum ArithmeticInstruction { Add(ArithmeticTerm, ArithmeticTerm, usize), Sub(ArithmeticTerm, ArithmeticTerm, usize), Mul(ArithmeticTerm, ArithmeticTerm, usize), @@ -380,132 +384,175 @@ pub(crate) enum ArithmeticInstruction { fn arith_instr_unary_functor( h: usize, - name: &'static str, + name: Atom, + arena: &mut Arena, at: &ArithmeticTerm, t: usize, ) -> MachineStub { - let at_stub = at.into_functor(); - - functor!(name, [aux(h, 0), integer(t)], [at_stub]) + let at_stub = at.into_functor(arena); + functor!(name, [str(h, 0), fixnum(t)], [at_stub]) } fn arith_instr_bin_functor( h: usize, - name: &'static str, + name: Atom, + arena: &mut Arena, at_1: &ArithmeticTerm, at_2: &ArithmeticTerm, t: usize, ) -> MachineStub { - let at_1_stub = at_1.into_functor(); - let at_2_stub = at_2.into_functor(); + let at_1_stub = at_1.into_functor(arena); + let at_2_stub = at_2.into_functor(arena); functor!( name, - [aux(h, 0), aux(h, 1), integer(t)], + [str(h, 0), str(h, 1), fixnum(t)], [at_1_stub, at_2_stub] ) } impl ArithmeticInstruction { - pub(crate) fn to_functor(&self, h: usize) -> MachineStub { + pub(crate) fn to_functor( + &self, + h: usize, + arena: &mut Arena, + ) -> MachineStub { match self { &ArithmeticInstruction::Add(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "add", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t) } &ArithmeticInstruction::Sub(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "sub", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t) } &ArithmeticInstruction::Mul(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "mul", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t) } &ArithmeticInstruction::IntPow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "int_pow", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t) } &ArithmeticInstruction::Pow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "pow", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t) } &ArithmeticInstruction::IDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "idiv", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t) } &ArithmeticInstruction::Max(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "max", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t) } &ArithmeticInstruction::Min(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "min", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t) } &ArithmeticInstruction::IntFloorDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "int_floor_div", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t) } &ArithmeticInstruction::RDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "rdiv", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t) } &ArithmeticInstruction::Div(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "div", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t) } &ArithmeticInstruction::Shl(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "shl", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t) } &ArithmeticInstruction::Shr(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "shr", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t) } &ArithmeticInstruction::Xor(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "xor", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t) } &ArithmeticInstruction::And(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "and", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t) } &ArithmeticInstruction::Or(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "or", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t) } &ArithmeticInstruction::Mod(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "mod", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t) } &ArithmeticInstruction::Rem(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "rem", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) } &ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "rem", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) } &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "gcd", at_1, at_2, t) - } - &ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t), - &ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t), - &ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t), - &ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t), - &ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t), - &ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t), - &ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t), - &ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t), - &ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t), - &ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t), - &ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t), + arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t) + } + &ArithmeticInstruction::Sign(ref at, t) => { + arith_instr_unary_functor(h, atom!("sign"), arena, at, t) + } + &ArithmeticInstruction::Cos(ref at, t) => { + arith_instr_unary_functor(h, atom!("cos"), arena, at, t) + } + &ArithmeticInstruction::Sin(ref at, t) => { + arith_instr_unary_functor(h, atom!("sin"), arena, at, t) + } + &ArithmeticInstruction::Tan(ref at, t) => { + arith_instr_unary_functor(h, atom!("tan"), arena, at, t) + } + &ArithmeticInstruction::Log(ref at, t) => { + arith_instr_unary_functor(h, atom!("log"), arena, at, t) + } + &ArithmeticInstruction::Exp(ref at, t) => { + arith_instr_unary_functor(h, atom!("exp"), arena, at, t) + } + &ArithmeticInstruction::ACos(ref at, t) => { + arith_instr_unary_functor(h, atom!("acos"), arena, at, t) + } + &ArithmeticInstruction::ASin(ref at, t) => { + arith_instr_unary_functor(h, atom!("asin"), arena, at, t) + } + &ArithmeticInstruction::ATan(ref at, t) => { + arith_instr_unary_functor(h, atom!("atan"), arena, at, t) + } + &ArithmeticInstruction::Sqrt(ref at, t) => { + arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t) + } + &ArithmeticInstruction::Abs(ref at, t) => { + arith_instr_unary_functor(h, atom!("abs"), arena, at, t) + } &ArithmeticInstruction::Float(ref at, t) => { - arith_instr_unary_functor(h, "float", at, t) + arith_instr_unary_functor(h, atom!("float"), arena, at, t) } &ArithmeticInstruction::Truncate(ref at, t) => { - arith_instr_unary_functor(h, "truncate", at, t) + arith_instr_unary_functor(h, atom!("truncate"), arena, at, t) } &ArithmeticInstruction::Round(ref at, t) => { - arith_instr_unary_functor(h, "round", at, t) + arith_instr_unary_functor(h, atom!("round"), arena, at, t) } &ArithmeticInstruction::Ceiling(ref at, t) => { - arith_instr_unary_functor(h, "ceiling", at, t) + arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t) } &ArithmeticInstruction::Floor(ref at, t) => { - arith_instr_unary_functor(h, "floor", at, t) - } - &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t), - &ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t), - &ArithmeticInstruction::BitwiseComplement(ref at, t) => { - arith_instr_unary_functor(h, "\\", at, t) - } + arith_instr_unary_functor(h, atom!("floor"), arena, at, t) + } + &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor( + h, + atom!("-"), + arena, + at, + t, + ), + &ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor( + h, + atom!("+"), + arena, + at, + t, + ), + &ArithmeticInstruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor( + h, + atom!("\\"), + arena, + at, + t, + ), } } } #[derive(Debug)] -pub(crate) enum ControlInstruction { +pub enum ControlInstruction { Allocate(usize), // num_frames. // name, arity, perm_vars after threshold, last call, use default call policy. CallClause(ClauseType, usize, usize, bool, bool), @@ -529,25 +576,25 @@ impl ControlInstruction { pub(crate) fn to_functor(&self) -> MachineStub { match self { &ControlInstruction::Allocate(num_frames) => { - functor!("allocate", [integer(num_frames)]) + functor!(atom!("allocate"), [fixnum(num_frames)]) } &ControlInstruction::CallClause(ref ct, arity, _, false, _) => { - functor!("call", [clause_name(ct.name()), integer(arity)]) + functor!(atom!("call"), [atom(ct.name()), fixnum(arity)]) } &ControlInstruction::CallClause(ref ct, arity, _, true, _) => { - functor!("execute", [clause_name(ct.name()), integer(arity)]) + functor!(atom!("execute"), [atom(ct.name()), fixnum(arity)]) } &ControlInstruction::Deallocate => { - functor!("deallocate") + functor!(atom!("deallocate")) } &ControlInstruction::JmpBy(_, offset, ..) => { - functor!("jmp_by", [integer(offset)]) + functor!(atom!("jmp_by"), [fixnum(offset)]) } &ControlInstruction::RevJmpBy(offset) => { - functor!("rev_jmp_by", [integer(offset)]) + functor!(atom!("rev_jmp_by"), [fixnum(offset)]) } &ControlInstruction::Proceed => { - functor!("proceed") + functor!(atom!("proceed")) } } } @@ -564,8 +611,22 @@ pub(crate) enum IndexingInstruction { IndexingCodePtr, IndexingCodePtr, ), - SwitchOnConstant(IndexMap), - SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>), + SwitchOnConstant(IndexMap), + SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>), +} + +impl IndexingCodePtr { + #[allow(dead_code)] + pub(crate) fn to_functor(self) -> MachineStub { + match self { + IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]), + IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), + IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), + IndexingCodePtr::Fail => { + vec![atom_as_cell!(atom!("fail"))] + }, + } + } } impl IndexingInstruction { @@ -573,9 +634,9 @@ impl IndexingInstruction { match self { &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { functor!( - "switch_on_term", + atom!("switch_on_term"), [ - integer(arg), + fixnum(arg), indexing_code_ptr(h, vars), indexing_code_ptr(h, constants), indexing_code_ptr(h, lists), @@ -591,26 +652,23 @@ impl IndexingInstruction { for (c, ptr) in constants.iter() { let key_value_pair = functor!( - ":", - SharedOpDesc::new(600, XFY), - [constant(c), indexing_code_ptr(h + 3, *ptr)] + atom!(":"), + [literal(*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(), - ))); + key_value_list_stub.push(list_loc_as_cell!(h + 1)); + key_value_list_stub.push(str_loc_as_cell!(h + 3)); + key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); h += key_value_pair.len() + 3; key_value_list_stub.extend(key_value_pair.into_iter()); } - key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList)); + key_value_list_stub.push(empty_list_as_cell!()); functor!( - "switch_on_constant", - [aux(orig_h, 0)], + atom!("switch_on_constant"), + [str(orig_h, 0)], [key_value_list_stub] ) } @@ -622,33 +680,29 @@ impl IndexingInstruction { for ((name, arity), ptr) in structures.iter() { let predicate_indicator_stub = functor!( - "/", - SharedOpDesc::new(400, YFX), - [clause_name(name.clone()), integer(*arity)] + atom!("/"), + [atom(name), fixnum(*arity)] ); let key_value_pair = functor!( - ":", - SharedOpDesc::new(600, XFY), - [aux(h + 3, 0), indexing_code_ptr(h + 3, *ptr)], + atom!(":"), + [str(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(), - ))); + key_value_list_stub.push(list_loc_as_cell!(h + 1)); + key_value_list_stub.push(str_loc_as_cell!(h + 3)); + key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); h += key_value_pair.len() + 3; key_value_list_stub.extend(key_value_pair.into_iter()); } - key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList)); + key_value_list_stub.push(empty_list_as_cell!()); functor!( - "switch_on_structure", - [aux(orig_h, 0)], + atom!("switch_on_structure"), + [str(orig_h, 0)], [key_value_list_stub] ) } @@ -657,14 +711,14 @@ impl IndexingInstruction { } #[derive(Debug, Clone)] -pub(crate) enum FactInstruction { - GetConstant(Level, Constant, RegType), +pub enum FactInstruction { + GetConstant(Level, HeapCellValue, RegType), GetList(Level, RegType), - GetPartialString(Level, String, RegType, bool), + GetPartialString(Level, Atom, RegType, bool), GetStructure(ClauseType, usize, RegType), GetValue(RegType, usize), GetVariable(RegType, usize), - UnifyConstant(Constant), + UnifyConstant(HeapCellValue), UnifyLocalValue(RegType), UnifyVariable(RegType), UnifyValue(RegType), @@ -674,13 +728,13 @@ pub(crate) enum FactInstruction { impl FactInstruction { pub(crate) fn to_functor(&self, h: usize) -> MachineStub { match self { - &FactInstruction::GetConstant(lvl, ref c, r) => { + &FactInstruction::GetConstant(lvl, c, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "get_constant", - [aux(h, 0), constant(h, c), aux(h, 1)], + atom!("get_constant"), + [str(h, 0), cell(c), str(h, 1)], [lvl_stub, rt_stub] ) } @@ -688,15 +742,24 @@ impl FactInstruction { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!("get_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub]) + functor!( + atom!("get_list"), + [str(h, 0), str(h, 1)], + [lvl_stub, rt_stub] + ) } - &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => { + &FactInstruction::GetPartialString(lvl, s, r, has_tail) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "get_partial_string", - [aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)], + atom!("get_partial_string"), + [ + str(h, 0), + string(h, s), + str(h, 1), + boolean(has_tail) + ], [lvl_stub, rt_stub] ) } @@ -704,41 +767,41 @@ impl FactInstruction { let rt_stub = reg_type_into_functor(r); functor!( - "get_structure", - [clause_name(ct.name()), integer(arity), aux(h, 0)], + atom!("get_structure"), + [atom(ct.name()), fixnum(arity), str(h, 0)], [rt_stub] ) } &FactInstruction::GetValue(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("get_value", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub]) } &FactInstruction::GetVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) } - &FactInstruction::UnifyConstant(ref c) => { - functor!("unify_constant", [constant(h, c)], []) + &FactInstruction::UnifyConstant(c) => { + functor!(atom!("unify_constant"), [cell(c)]) } &FactInstruction::UnifyLocalValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("unify_local_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub]) } &FactInstruction::UnifyVariable(r) => { let rt_stub = reg_type_into_functor(r); - functor!("unify_variable", [aux(h, 0)], [rt_stub]) + functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub]) } &FactInstruction::UnifyValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("unify_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("unify_value"), [str(h, 0)], [rt_stub]) } &FactInstruction::UnifyVoid(vars) => { - functor!("unify_void", [integer(vars)]) + functor!(atom!("unify_void"), [fixnum(vars)]) } } } @@ -747,14 +810,14 @@ impl FactInstruction { #[derive(Debug, Clone)] pub(crate) enum QueryInstruction { GetVariable(RegType, usize), - PutConstant(Level, Constant, RegType), + PutConstant(Level, HeapCellValue, RegType), PutList(Level, RegType), - PutPartialString(Level, String, RegType, bool), + PutPartialString(Level, Atom, RegType, bool), PutStructure(ClauseType, usize, RegType), PutUnsafeValue(usize, usize), PutValue(RegType, usize), PutVariable(RegType, usize), - SetConstant(Constant), + SetConstant(HeapCellValue), SetLocalValue(RegType), SetVariable(RegType), SetValue(RegType), @@ -765,15 +828,15 @@ impl QueryInstruction { pub(crate) fn to_functor(&self, h: usize) -> MachineStub { match self { &QueryInstruction::PutUnsafeValue(norm, arg) => { - functor!("put_unsafe_value", [integer(norm), integer(arg)]) + functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)]) } - &QueryInstruction::PutConstant(lvl, ref c, r) => { + &QueryInstruction::PutConstant(lvl, c, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "put_constant", - [aux(h, 0), constant(h, c), aux(h, 1)], + atom!("put_constant"), + [str(h, 0), cell(c), str(h, 1)], [lvl_stub, rt_stub] ) } @@ -781,15 +844,24 @@ impl QueryInstruction { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!("put_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub]) + functor!( + atom!("put_list"), + [str(h, 0), str(h, 1)], + [lvl_stub, rt_stub] + ) } - &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => { + &QueryInstruction::PutPartialString(lvl, s, r, has_tail) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "put_partial_string", - [aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)], + atom!("put_partial_string"), + [ + str(h, 0), + string(h, s), + str(h, 1), + boolean(has_tail) + ], [lvl_stub, rt_stub] ) } @@ -797,46 +869,46 @@ impl QueryInstruction { let rt_stub = reg_type_into_functor(r); functor!( - "put_structure", - [clause_name(ct.name()), integer(arity), aux(h, 0)], + atom!("put_structure"), + [atom(ct.name()), fixnum(arity), str(h, 0)], [rt_stub] ) } &QueryInstruction::PutValue(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("put_value", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub]) } &QueryInstruction::GetVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) } &QueryInstruction::PutVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) } - &QueryInstruction::SetConstant(ref c) => { - functor!("set_constant", [constant(h, c)], []) + &QueryInstruction::SetConstant(c) => { + functor!(atom!("set_constant"), [cell(c)], []) } &QueryInstruction::SetLocalValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("set_local_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub]) } &QueryInstruction::SetVariable(r) => { let rt_stub = reg_type_into_functor(r); - functor!("set_variable", [aux(h, 0)], [rt_stub]) + functor!(atom!("set_variable"), [str(h, 0)], [rt_stub]) } &QueryInstruction::SetValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("set_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("set_value"), [str(h, 0)], [rt_stub]) } &QueryInstruction::SetVoid(vars) => { - functor!("set_void", [integer(vars)]) + functor!(atom!("set_void"), [fixnum(vars)]) } } } diff --git a/src/iterators.rs b/src/iterators.rs index a83c57962..3c6e955c9 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -1,5 +1,5 @@ -use prolog_parser::ast::*; -use prolog_parser::rc_atom; +use crate::atom_table::*; +use crate::parser::ast::*; use crate::clause_types::*; use crate::forms::*; @@ -16,10 +16,10 @@ use std::vec::Vec; pub(crate) enum TermRef<'a> { AnonVar(Level), Cons(Level, &'a Cell, &'a Term, &'a Term), - Constant(Level, &'a Cell, &'a Constant), - Clause(Level, &'a Cell, ClauseType, &'a Vec>), - PartialString(Level, &'a Cell, String, Option<&'a Term>), - Var(Level, &'a Cell, Rc), + Literal(Level, &'a Cell, &'a Literal), + Clause(Level, &'a Cell, ClauseType, &'a Vec), + PartialString(Level, &'a Cell, Atom, &'a Option>), + Var(Level, &'a Cell, Rc), } impl<'a> TermRef<'a> { @@ -27,7 +27,7 @@ impl<'a> TermRef<'a> { match self { TermRef::AnonVar(lvl) | TermRef::Cons(lvl, ..) - | TermRef::Constant(lvl, ..) + | TermRef::Literal(lvl, ..) | TermRef::Var(lvl, ..) | TermRef::Clause(lvl, ..) => lvl, TermRef::PartialString(lvl, ..) => lvl, @@ -38,82 +38,31 @@ impl<'a> TermRef<'a> { #[derive(Debug)] pub(crate) enum TermIterState<'a> { AnonVar(Level), - Constant(Level, &'a Cell, &'a Constant), - Clause( - Level, - usize, - &'a Cell, - ClauseType, - &'a Vec>, - ), + Literal(Level, &'a Cell, &'a Literal), + Clause(Level, usize, &'a Cell, ClauseType, &'a Vec), InitialCons(Level, &'a Cell, &'a Term, &'a Term), FinalCons(Level, &'a Cell, &'a Term, &'a Term), - PartialString(Level, &'a Cell, String, Option<&'a Term>), - Var(Level, &'a Cell, Rc), -} - -fn is_partial_string<'a>(head: &'a Term, mut tail: &'a Term) -> Option<(String, Option<&'a Term>)> { - let mut string = match head { - &Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => { - atom.as_str().chars().next().unwrap().to_string() - } - &Term::Constant(_, Constant::Char(c)) => c.to_string(), - _ => { - return None; - } - }; - - while let Term::Cons(_, ref head, ref succ) = tail { - match head.as_ref() { - &Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => { - string.push(atom.as_str().chars().next().unwrap()); - } - &Term::Constant(_, Constant::Char(c)) => { - string.push(c); - } - _ => { - return None; - } - }; - - tail = succ.as_ref(); - } - - match tail { - Term::AnonVar | Term::Var(..) => { - return Some((string, Some(tail))); - } - Term::Constant(_, Constant::EmptyList) => { - return Some((string, None)); - } - Term::Constant(_, Constant::String(tail)) => { - string += &tail; - return Some((string, None)); - } - _ => { - return None; - } - } + InitialPartialString(Level, &'a Cell, Atom, &'a Option>), + FinalPartialString(Level, &'a Cell, Atom, &'a Option>), + Var(Level, &'a Cell, Rc), } impl<'a> TermIterState<'a> { pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> { match term { - &Term::AnonVar => TermIterState::AnonVar(lvl), - &Term::Clause(ref cell, ref name, ref subterms, ref spec) => { - let ct = if let Some(spec) = spec { - ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default()) - } else { - ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default()) - }; - + Term::AnonVar => TermIterState::AnonVar(lvl), + Term::Clause(cell, name, subterms) => { + let ct = ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default()); TermIterState::Clause(lvl, 0, cell, ct, subterms) } - &Term::Cons(ref cell, ref head, ref tail) => { + Term::Cons(cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) } - &Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant), - &Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()), + Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), + Term::PartialString(cell, string_buf, tail) => { + TermIterState::InitialPartialString(lvl, cell, *string_buf, tail) + } + Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()), } } } @@ -129,11 +78,11 @@ impl<'a> QueryIterator<'a> { .push(TermIterState::subterm_to_state(lvl, term)); } - fn from_rule_head_clause(terms: &'a Vec>) -> Self { + fn from_rule_head_clause(terms: &'a Vec) -> Self { let state_stack = terms .iter() .rev() - .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) + .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) .collect(); QueryIterator { state_stack } @@ -141,29 +90,19 @@ impl<'a> QueryIterator<'a> { fn from_term(term: &'a Term) -> Self { let state = match term { - &Term::AnonVar => { + Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => { return QueryIterator { state_stack: vec![], } } - &Term::Clause(ref r, ref name, ref terms, ref fixity) => TermIterState::Clause( + Term::Clause(r, name, terms) => TermIterState::Clause( Level::Root, 0, r, - ClauseType::from(name.clone(), terms.len(), fixity.clone()), + ClauseType::from(*name, terms.len()), terms, ), - &Term::Cons(..) => { - return QueryIterator { - state_stack: vec![], - } - } - &Term::Constant(_, _) => { - return QueryIterator { - state_stack: vec![], - } - } - &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Root, cell, (*var).clone()), + Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()), }; QueryIterator { @@ -186,7 +125,7 @@ impl<'a> QueryIterator<'a> { } } &QueryTerm::UnblockedCut(ref cell) => { - let state = TermIterState::Var(Level::Root, cell, rc_atom!("!")); + let state = TermIterState::Var(Level::Root, cell, Rc::new("!".to_string())); QueryIterator { state_stack: vec![state], } @@ -226,9 +165,9 @@ impl<'a> Iterator for QueryIterator<'a> { if child_num == child_terms.len() { match ct { ClauseType::CallN => { - self.push_subterm(Level::Shallow, child_terms[0].as_ref()) + self.push_subterm(Level::Shallow, &child_terms[0]); } - ClauseType::Named(..) | ClauseType::Op(..) => { + ClauseType::Named(..) => { return match lvl { Level::Root => None, lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)), @@ -247,33 +186,30 @@ impl<'a> Iterator for QueryIterator<'a> { child_terms, )); - self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref()); + self.push_subterm(lvl.child_level(), &child_terms[child_num]); } } TermIterState::InitialCons(lvl, cell, head, tail) => { - if let Some((string, tail)) = is_partial_string(head, tail) { - self.state_stack - .push(TermIterState::PartialString(lvl, cell, string, tail)); + self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail)); - if let Some(tail) = tail { - self.push_subterm(lvl.child_level(), tail); - } - } else { - self.state_stack - .push(TermIterState::FinalCons(lvl, cell, head, tail)); + self.push_subterm(lvl.child_level(), tail); + self.push_subterm(lvl.child_level(), head); + } + TermIterState::InitialPartialString(lvl, cell, string, tail) => { + self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail)); + if let Some(tail) = tail { self.push_subterm(lvl.child_level(), tail); - self.push_subterm(lvl.child_level(), head); } } - TermIterState::PartialString(lvl, cell, string, tail) => { + TermIterState::FinalPartialString(lvl, cell, string, tail) => { return Some(TermRef::PartialString(lvl, cell, string, tail)); } TermIterState::FinalCons(lvl, cell, head, tail) => { return Some(TermRef::Cons(lvl, cell, head, tail)); } - TermIterState::Constant(lvl, cell, constant) => { - return Some(TermRef::Constant(lvl, cell, constant)); + TermIterState::Literal(lvl, cell, constant) => { + return Some(TermRef::Literal(lvl, cell, constant)); } TermIterState::Var(lvl, cell, var) => { return Some(TermRef::Var(lvl, cell, var)); @@ -297,10 +233,10 @@ impl<'a> FactIterator<'a> { .push_back(TermIterState::subterm_to_state(lvl, term)); } - pub(crate) fn from_rule_head_clause(terms: &'a Vec>) -> Self { + pub(crate) fn from_rule_head_clause(terms: &'a Vec) -> Self { let state_queue = terms .iter() - .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) + .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) .collect(); FactIterator { @@ -311,23 +247,31 @@ impl<'a> FactIterator<'a> { fn new(term: &'a Term, iterable_root: bool) -> Self { let states = match term { - &Term::AnonVar => { + Term::AnonVar => { vec![TermIterState::AnonVar(Level::Root)] } - &Term::Clause(ref cell, ref name, ref terms, ref fixity) => { - let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone()); + Term::Clause(cell, name, terms) => { + let ct = ClauseType::from(*name, terms.len()); vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)] } - &Term::Cons(ref cell, ref head, ref tail) => vec![TermIterState::InitialCons( + Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( Level::Root, cell, head.as_ref(), tail.as_ref(), )], - &Term::Constant(ref cell, ref constant) => { - vec![TermIterState::Constant(Level::Root, cell, constant)] + Term::PartialString(cell, string_buf, tail_opt) => { + vec![TermIterState::InitialPartialString( + Level::Root, + cell, + *string_buf, + tail_opt, + )] } - &Term::Var(ref cell, ref var) => { + Term::Literal(cell, constant) => { + vec![TermIterState::Literal(Level::Root, cell, constant)] + } + Term::Var(cell, var) => { vec![TermIterState::Var(Level::Root, cell, var.clone())] } }; @@ -359,21 +303,20 @@ impl<'a> Iterator for FactIterator<'a> { }; } TermIterState::InitialCons(lvl, cell, head, tail) => { - if let Some((string, tail)) = is_partial_string(head, tail) { - if let Some(tail) = tail { - self.push_subterm(Level::Deep, tail); - } + self.push_subterm(Level::Deep, head); + self.push_subterm(Level::Deep, tail); - return Some(TermRef::PartialString(lvl, cell, string, tail)); - } else { - self.push_subterm(Level::Deep, head); + return Some(TermRef::Cons(lvl, cell, head, tail)); + } + TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => { + if let Some(tail) = tail_opt { self.push_subterm(Level::Deep, tail); - - return Some(TermRef::Cons(lvl, cell, head, tail)); } + + return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt)); } - TermIterState::Constant(lvl, cell, constant) => { - return Some(TermRef::Constant(lvl, cell, constant)) + TermIterState::Literal(lvl, cell, constant) => { + return Some(TermRef::Literal(lvl, cell, constant)) } TermIterState::Var(lvl, cell, var) => { return Some(TermRef::Var(lvl, cell, var)); @@ -386,17 +329,17 @@ impl<'a> Iterator for FactIterator<'a> { } } -pub(crate) fn post_order_iter(term: &Term) -> QueryIterator { +pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> { QueryIterator::from_term(term) } -pub(crate) fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator { +pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> { FactIterator::new(term, iterable_root) } #[derive(Debug)] pub(crate) enum ChunkedTerm<'a> { - HeadClause(ClauseName, &'a Vec>), + HeadClause(Atom, &'a Vec), BodyTerm(&'a QueryTerm), } @@ -407,7 +350,7 @@ pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> Query impl<'a> ChunkedTerm<'a> { pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> { match self { - &ChunkedTerm::BodyTerm(ref qt) => QueryIterator::new(qt), + &ChunkedTerm::BodyTerm(qt) => QueryIterator::new(qt), &ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms), } } @@ -517,7 +460,7 @@ impl<'a> ChunkedIterator<'a> { while let Some(term) = item { match term { ChunkedTerm::HeadClause(_, terms) => { - if contains_cut_var(terms.iter().map(|t| t.as_ref())) { + if contains_cut_var(terms.iter()) { self.cut_var_in_head = true; } @@ -547,7 +490,10 @@ impl<'a> ChunkedIterator<'a> { arity = 1; break; } - ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => result.push(term), + ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => { + self.deep_cut_encountered = true; + result.push(term); + } ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => { result.push(term) } diff --git a/src/lib.rs b/src/lib.rs index 1fd4a4fb4..458ad485a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,25 +1,29 @@ -#[cfg(feature = "num-rug-adapter")] -use num_rug_adapter as rug; -#[cfg(feature = "rug")] -use rug; +#[macro_use] +extern crate static_assertions; #[macro_use] -mod macros; +pub mod macros; +#[macro_use] +pub mod atom_table; +#[macro_use] +pub mod arena; +#[macro_use] +pub mod parser; mod allocator; mod arithmetic; mod clause_types; -mod codegen; +pub mod codegen; mod debray_allocator; mod fixtures; mod forms; mod heap_iter; -mod heap_print; +pub mod heap_print; mod indexing; mod instructions; mod iterators; pub mod machine; +mod raw_block; pub mod read; mod targets; -mod write; - -use machine::*; +pub mod types; +pub mod write; diff --git a/src/lib/atts.pl b/src/lib/atts.pl index 5906466b5..a9369426e 100644 --- a/src/lib/atts.pl +++ b/src/lib/atts.pl @@ -24,30 +24,42 @@ '$absent_from_list'(Ls, Attr). '$absent_from_list'(X, Attr) :- - ( var(X) -> true - ; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr) + ( var(X) -> + true + ; X = [L|Ls], + L \= Attr -> + '$absent_from_list'(Ls, Attr) ). '$get_attr'(V, Attr) :- - '$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr). + '$get_attr_list'(V, Ls), + nonvar(Ls), + '$get_from_list'(Ls, V, Attr). '$get_from_list'([L|Ls], V, Attr) :- nonvar(L), - ( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr) - ; L = Attr, '$enqueue_attr_var'(V) + ( L \= Attr -> + nonvar(Ls), + '$get_from_list'(Ls, V, Attr) + ; L = Attr, + '$enqueue_attr_var'(V) ). '$put_attr'(V, Attr) :- - '$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr). + '$get_attr_list'(V, Ls), + '$add_to_list'(Ls, V, Attr). '$add_to_list'(Ls, V, Attr) :- - ( var(Ls) -> - Ls = [Attr | _], '$enqueue_attr_var'(V) - ; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr) + ( var(Ls) -> + Ls = [Attr | _], + '$enqueue_attr_var'(V) + ; Ls = [_ | Ls0], + '$add_to_list'(Ls0, V, Attr) ). '$del_attr'(Ls0, _, _) :- - var(Ls0), !. + var(Ls0), + !. '$del_attr'(Ls0, V, Attr) :- Ls0 = [Att | Ls1], nonvar(Att), @@ -134,22 +146,22 @@ [(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), - functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), - atts:'$del_attr'(Ls, V, Module:AttrForm), - atts:'$put_attr'(V, Module:Attr)), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + atts:'$del_attr'(Ls, V, Module:AttrForm), + atts:'$put_attr'(V, Module:Attr)), (put_atts(V, Attr) :- !, functor(Attr, Head, Arity), - functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), - atts:'$del_attr'(Ls, V, Module:AttrForm), - atts:'$put_attr'(V, Module:Attr)), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + atts:'$del_attr'(Ls, V, Module:AttrForm), + atts:'$put_attr'(V, Module:Attr)), (put_atts(V, -Attr) :- !, functor(Attr, _, _), - '$get_attr_list'(V, Ls), - atts:'$del_attr'(Ls, V, Module:Attr))]. + '$get_attr_list'(V, Ls), + atts:'$del_attr'(Ls, V, Module:Attr))]. get_attr(Name, Arity, Module) --> { functor(Attr, Name, Arity) }, diff --git a/src/lib/between.pl b/src/lib/between.pl index 5a0d5babe..b162e0234 100644 --- a/src/lib/between.pl +++ b/src/lib/between.pl @@ -12,10 +12,22 @@ ( nonvar(X) -> Lower =< X, X =< Upper - ; compare(Ord, Lower, Upper), - between_(Ord, Lower, Upper, X) + ; % compare(Ord, Lower, Upper), + % between_(Ord, Lower, Upper, X) + Lower =< Upper, + between_(Lower, Upper, X) ). +between_(Lower, Lower, Lower) :- !. +between_(Lower, Upper, Lower1) :- + ( Lower < Upper, + ( Lower1 = Lower + ; Lower0 is Lower + 1, + between_(Lower0, Upper, Lower1) + ) + ). + +/* between_(<, Lower0, Upper, X) :- ( X = Lower0 ; Lower1 is Lower0 + 1, @@ -23,6 +35,7 @@ between_(Ord, Lower1, Upper, X) ). between_(=, Upper, Upper, Upper). +*/ enumerate_nats(I, I). enumerate_nats(I0, N) :- diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 00a26238a..0c9d33f9b 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -347,11 +347,11 @@ :- non_counted_backtracking univ_errors/3. univ_errors(Term, List, N) :- '$skip_max_list'(N, -1, List, R), - ( var(R) -> - ( var(Term), - throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) - ; true - ) + ( var(R) -> + ( var(Term), + throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) + ; true + ) ; R \== [] -> throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b) ; List = [H|T] -> @@ -388,9 +388,10 @@ !, '$call_with_default_policy'(List = [Term]). univ_worker(Term, [Name|Args], N) :- - var(Term), !, + var(Term), + !, '$call_with_default_policy'(Arity is N-1), - '$call_with_default_policy'(functor(Term, Name, Arity)), + '$call_with_default_policy'(functor(Term, Name, Arity)), % Term = {var}, Name = nonvar, Arity = 0. '$call_with_default_policy'(get_args(Args, Term, 1, Arity)). univ_worker(Term, List, _) :- '$call_with_default_policy'(functor(Term, Name, Arity)), @@ -679,9 +680,9 @@ set_difference(Xs, [], Xs). group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :- - iso_ext:variant(V1, V2), + V1 = V2, % \+ \+ (V1 = V2), % (2) % iso_ext:variant(V1, V2), % (1) !, - V1 = V2, + % V1 = V2, % (3) group_by_variant(Pairs, V2-S2, Solutions, Pairs0). group_by_variant(Pairs, _, [], Pairs). @@ -1075,17 +1076,16 @@ ; throw(error(type_error(predicate_indicator, Pred), abolish/1)) ). -'$iterate_db_refs'(Ref, Name/Arity) :- - '$lookup_db_ref'(Ref, Name, Arity). -'$iterate_db_refs'(Ref, Name/Arity) :- - '$get_next_db_ref'(Ref, NextRef), - '$iterate_db_refs'(NextRef, Name/Arity). - +'$iterate_db_refs'(Name, Arity, Name/Arity). % :- +% '$lookup_db_ref'(Ref, Name, Arity). +'$iterate_db_refs'(RName, RArity, Name/Arity) :- + '$get_next_db_ref'(RName, RArity, RRName, RRArity), + '$iterate_db_refs'(RRName, RRArity, Name/Arity). current_predicate(Pred) :- ( var(Pred) -> - '$get_next_db_ref'(Ref, _), - '$iterate_db_refs'(Ref, Pred) + '$get_next_db_ref'(RN, RA, _, _), + '$iterate_db_refs'(RN, RA, Pred) ; Pred \= _/_ -> throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) ; Pred = Name/Arity, @@ -1094,15 +1094,14 @@ ; integer(Arity), Arity < 0 ) -> throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) - ; '$get_next_db_ref'(Ref, _), - '$iterate_db_refs'(Ref, Pred) + ; '$get_next_db_ref'(RN, RA, _, _), + '$iterate_db_refs'(RN, RA, Pred) ). -'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :- - '$lookup_op_db_ref'(Ref, Priority, Spec, Op). -'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :- - '$get_next_op_db_ref'(Ref, NextRef), - '$iterate_op_db_refs'(NextRef, Priority, Spec, Op). +'$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp). +'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :- + '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp), + '$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op). can_be_op_priority(Priority) :- var(Priority). can_be_op_priority(Priority) :- op_priority(Priority). @@ -1114,8 +1113,8 @@ ( can_be_op_priority(Priority), can_be_op_specifier(Spec), error:can_be(atom, Op) -> - '$get_next_op_db_ref'(Ref, _), - '$iterate_op_db_refs'(Ref, Priority, Spec, Op) + '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op), + '$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) ). list_of_op_atoms(Var) :- diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index 378d495a9..f48af1d29 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -14,7 +14,7 @@ partial_string_tail/2, setup_call_cleanup/3, call_nth/2, - variant/2, +% variant/2, copy_term_nat/2]). :- use_module(library(error), [can_be/2, @@ -22,6 +22,7 @@ instantiation_error/1, type_error/3]). +:- use_module(library(lists), [maplist/3]). :- meta_predicate(call_cleanup(0, 0)). @@ -160,14 +161,12 @@ '$erase_ball', '$call_with_default_policy'(handle_ile(B, Ball, R)). -variant(X, Y) :- '$variant'(X, Y). - partial_string(String, L, L0) :- ( String == [] -> L = L0 ; catch(atom_chars(Atom, String), - error(E, _), - throw(error(E, partial_string/3))), + error(E, _), + throw(error(E, partial_string/3))), '$create_partial_string'(Atom, L, L0) ). diff --git a/src/lib/lists.pl b/src/lib/lists.pl index 20631588b..a64c3ad36 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -3,7 +3,7 @@ maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, sum_list/2, transpose/2, list_to_set/2, list_max/2, - list_min/2, permutation/2]). + list_min/2, permutation/2]). /* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe Copyright (c) 2018-2021, Mark Thom diff --git a/src/lib/serialization/abnf.pl b/src/lib/serialization/abnf.pl index d5c1c31b8..037e7aa0a 100644 --- a/src/lib/serialization/abnf.pl +++ b/src/lib/serialization/abnf.pl @@ -9,26 +9,26 @@ syntaxes. The DCGs are presented in the order they appear in the RFC. While some DCGs below use `char_type/2`, the most common ones are defined manually in order to take advantage of Prolog's first-argument indexing. - + BSD 3-Clause License - + Copyright (c) 2021, Aram Panasenco All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE diff --git a/src/lib/serialization/json.pl b/src/lib/serialization/json.pl index e1bebe114..dac278826 100644 --- a/src/lib/serialization/json.pl +++ b/src/lib/serialization/json.pl @@ -1,29 +1,29 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu) Part of Scryer Prolog. - + `json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl) or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html). - + BSD 3-Clause License - + Copyright (c) 2021, Aram Panasenco All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -44,7 +44,7 @@ :- use_module(library(dif)). :- use_module(library(lists)). -/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html +/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */ json_chars(Internal) --> json_element(Internal). diff --git a/src/lib/uuid.pl b/src/lib/uuid.pl index affa3b68c..3f89db4b2 100644 --- a/src/lib/uuid.pl +++ b/src/lib/uuid.pl @@ -4,9 +4,9 @@ This library provides reasoning about UUID (only version 4 right now). There are three predicates: * uuidv4/1, to generate a new UUIDv4 - * uuidv4_string/1, to generate a new UUIDv4 in string hex representation + * uuidv4_string/1, to generate a new UUIDv4 in string hex representation * uuid_string/2, to converte between UUID list of bytes and UUID hex representation - + Examples: ?- uuidv4(X). X = [42,147,248,242,117,196,79,2,129,159|...]. @@ -30,7 +30,7 @@ :- use_module(library(dcgs)). :- use_module(library(lists)). -/* +/* An UUID is made of 16 bytes, composed of 5 sections: time_low - 4 time_mid - 2 diff --git a/src/loader.pl b/src/loader.pl index 531730cc5..722d413a9 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -1,4 +1,3 @@ - :- module(loader, [consult/1, expand_goal/3, expand_term/2, @@ -508,7 +507,8 @@ ; catch(open(Path, read, Stream), error(existence_error(source_sink, _), _), ( atom_concat(Path, '.pl', ExtendedPath), - open(ExtendedPath, read, Stream) ) + open(ExtendedPath, read, Stream) + ) ) ). diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 4e3f832af..85b6cbc37 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1,37 +1,98 @@ use divrem::*; -use prolog_parser::ast::*; -use prolog_parser::clause_name; - +use crate::arena::*; use crate::arithmetic::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::rug::{Integer, Rational}; +use crate::parser::ast::*; +use crate::parser::rug::{Integer, Rational}; +use crate::types::*; + +use crate::fixnum; + use ordered_float::*; use std::cmp; use std::convert::TryFrom; use std::f64; use std::mem; -use std::rc::Rc; #[macro_export] macro_rules! try_numeric_result { - ($s: ident, $e: expr, $caller: expr) => { + ($e: expr, $stub_gen: expr) => { match $e { Ok(val) => Ok(val), - Err(e) => { - let caller_copy = $caller.iter().map(|v| v.context_free_clone()).collect(); + Err(e) => Err(Box::new(move |machine_st: &mut MachineState| { + let stub = $stub_gen(); + let evaluation_error = machine_st.evaluation_error(e); + + machine_st.error_form(evaluation_error, stub) + }) as Box MachineStub>), + } + }; +} - Err($s.error_form(MachineError::evaluation_error(e), caller_copy)) +macro_rules! drop_iter_on_err { + ($self:expr, $iter: expr, $result: expr) => { + match $result { + Ok(val) => val, + Err(stub_gen) => { + std::mem::drop($iter); + return Err(stub_gen($self)); } } }; } +fn zero_divisor_eval_error( + stub_gen: impl Fn() -> FunctorStub + 'static, +) -> MachineStubGen { + Box::new(move |machine_st| { + let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor); + let stub = stub_gen(); + + machine_st.error_form(eval_error, stub) + }) +} + +fn undefined_eval_error( + stub_gen: impl Fn() -> FunctorStub + 'static, +) -> MachineStubGen { + Box::new(move |machine_st| { + let eval_error = machine_st.evaluation_error(EvalError::Undefined); + let stub = stub_gen(); + + machine_st.error_form(eval_error, stub) + }) +} + +fn numerical_type_error( + valid_type: ValidType, + n: Number, + stub_gen: impl Fn() -> FunctorStub + 'static, +) -> MachineStubGen { + Box::new(move |machine_st| { + let type_error = machine_st.type_error(valid_type, n); + let stub = stub_gen(); + + machine_st.error_form(type_error, stub) + }) +} + +pub(crate) fn sign(n: Number) -> Number { + if n.is_positive() { + Number::Fixnum(Fixnum::build_with(1)) + } else if n.is_negative() { + Number::Fixnum(Fixnum::build_with(-1)) + } else { + Number::Fixnum(Fixnum::build_with(0)) + } +} + fn isize_gcd(n1: isize, n2: isize) -> Option { if n1 == 0 { return n2.checked_abs().map(|n| n as isize); @@ -80,935 +141,1290 @@ fn isize_gcd(n1: isize, n2: isize) -> Option { Some(n1 << shift as isize) } -impl MachineState { - pub(crate) fn get_number(&mut self, at: &ArithmeticTerm) -> Result { - match at { - &ArithmeticTerm::Reg(r) => self.arith_eval_by_metacall(r), - &ArithmeticTerm::Interm(i) => { - Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(0))) - } - &ArithmeticTerm::Number(ref n) => Ok(n.clone()), +pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result { + match (lhs, rhs) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok( + if let Some(result) = n1.get_num().checked_add(n2.get_num()) { + fixnum!(Number, result, arena) + } else { + Number::arena_from( + Integer::from(n1.get_num()) + Integer::from(n2.get_num()), + arena, + ) + }, + ), + (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Integer::from(n1.get_num()) + &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Rational::from(n1.get_num()) + &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { + Ok(Number::Float(add_f(float_fn_to_f(n1.get_num())?, n2)?)) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1) + &*n2, arena)) // add_i + } + (Number::Integer(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { + Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?)) + } + (Number::Integer(n1), Number::Rational(n2)) + | (Number::Rational(n2), Number::Integer(n1)) => { + Ok(Number::arena_from(Rational::from(&*n1) + &*n2, arena)) + } + (Number::Rational(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { + Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?)) + } + (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { + Ok(Number::Float(add_f(f1, f2)?)) + } + (Number::Rational(r1), Number::Rational(r2)) => { + Ok(Number::arena_from(Rational::from(&*r1) + &*r2, arena)) } } +} - pub(super) fn rational_from_number(&self, n: Number) -> Result, MachineError> { - match n { - Number::Fixnum(n) => Ok(Rc::new(Rational::from(n))), - Number::Rational(r) => Ok(r), - Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) { - Some(r) => Ok(Rc::new(r)), - None => Err(MachineError::instantiation_error()), - }, - Number::Integer(n) => Ok(Rc::new(Rational::from(&*n))), +pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number { + match n { + Number::Fixnum(n) => { + if let Some(n) = n.get_num().checked_neg() { + fixnum!(Number, n, arena) + } else { + Number::arena_from(-Integer::from(n.get_num()), arena) + } } + Number::Integer(n) => Number::arena_from(-Integer::from(&*n), arena), + Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), + Number::Rational(r) => Number::arena_from(-Rational::from(&*r), arena), } +} - pub(crate) fn get_rational( - &mut self, - at: &ArithmeticTerm, - caller: MachineStub, - ) -> Result<(Rc, MachineStub), MachineStub> { - let n = self.get_number(at)?; - - match self.rational_from_number(n) { - Ok(r) => Ok((r, caller)), - Err(e) => Err(self.error_form(e, caller)), - } - } - - pub(crate) fn arith_eval_by_metacall(&self, r: RegType) -> Result { - let caller = MachineError::functor_stub(clause_name!("is"), 2); - let mut interms: Vec = Vec::with_capacity(64); - - for addr in self.post_order_iter(self[r]) { - match self.heap.index_addr(&addr).as_ref() { - &HeapCellValue::NamedStr(2, ref name, _) => { - let a2 = interms.pop().unwrap(); - let a1 = interms.pop().unwrap(); - - match name.as_str() { - "+" => interms.push(try_numeric_result!(self, a1 + a2, caller)?), - "-" => interms.push(try_numeric_result!(self, a1 - a2, caller)?), - "*" => interms.push(try_numeric_result!(self, a1 * a2, caller)?), - "/" => interms.push(self.div(a1, a2)?), - "**" => interms.push(self.pow(a1, a2, "is")?), - "^" => interms.push(self.int_pow(a1, a2)?), - "max" => interms.push(self.max(a1, a2)?), - "min" => interms.push(self.min(a1, a2)?), - "rdiv" => { - let r1 = self.rational_from_number(a1); - let r2 = - r1.and_then(|r1| self.rational_from_number(a2).map(|r2| (r1, r2))); - - match r2 { - Ok((r1, r2)) => { - let result = Number::Rational(Rc::new(self.rdiv(r1, r2)?)); - interms.push(result); - } - Err(e) => { - return Err(self.error_form(e, caller)); - } - } - } - "//" => interms.push(self.idiv(a1, a2)?), - "div" => interms.push(self.int_floor_div(a1, a2)?), - ">>" => interms.push(self.shr(a1, a2)?), - "<<" => interms.push(self.shl(a1, a2)?), - "/\\" => interms.push(self.and(a1, a2)?), - "\\/" => interms.push(self.or(a1, a2)?), - "xor" => interms.push(self.xor(a1, a2)?), - "mod" => interms.push(self.modulus(a1, a2)?), - "rem" => interms.push(self.remainder(a1, a2)?), - "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))), - "gcd" => interms.push(self.gcd(a1, a2)?), - _ => { - let evaluable_stub = MachineError::functor_stub(name.clone(), 2); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - } - } - &HeapCellValue::NamedStr(1, ref name, _) => { - let a1 = interms.pop().unwrap(); - - match name.as_str() { - "-" => interms.push(-a1), - "+" => interms.push(a1), - "cos" => interms.push(Number::Float(OrderedFloat(self.cos(a1)?))), - "sin" => interms.push(Number::Float(OrderedFloat(self.sin(a1)?))), - "tan" => interms.push(Number::Float(OrderedFloat(self.tan(a1)?))), - "sqrt" => interms.push(Number::Float(OrderedFloat(self.sqrt(a1)?))), - "log" => interms.push(Number::Float(OrderedFloat(self.log(a1)?))), - "exp" => interms.push(Number::Float(OrderedFloat(self.exp(a1)?))), - "acos" => interms.push(Number::Float(OrderedFloat(self.acos(a1)?))), - "asin" => interms.push(Number::Float(OrderedFloat(self.asin(a1)?))), - "atan" => interms.push(Number::Float(OrderedFloat(self.atan(a1)?))), - "abs" => interms.push(a1.abs()), - "float" => interms.push(Number::Float(OrderedFloat(self.float(a1)?))), - "truncate" => interms.push(self.truncate(a1)), - "round" => interms.push(self.round(a1)?), - "ceiling" => interms.push(self.ceiling(a1)), - "floor" => interms.push(self.floor(a1)), - "\\" => interms.push(self.bitwise_complement(a1)?), - "sign" => interms.push(self.sign(a1)), - _ => { - let evaluable_stub = MachineError::functor_stub(name.clone(), 1); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - } - } - &HeapCellValue::Addr(Addr::Fixnum(n)) => { - interms.push(Number::Fixnum(n)); - } - &HeapCellValue::Addr(Addr::Float(n)) => interms.push(Number::Float(n)), - &HeapCellValue::Integer(ref n) => interms.push(Number::Integer(n.clone())), - &HeapCellValue::Addr(Addr::Usize(n)) => { - interms.push(Number::Integer(Rc::new(Integer::from(n)))); - } - &HeapCellValue::Rational(ref n) => interms.push(Number::Rational(n.clone())), - &HeapCellValue::Atom(ref name, _) if name.as_str() == "pi" => { - interms.push(Number::Float(OrderedFloat(f64::consts::PI))) - } - &HeapCellValue::Atom(ref name, _) if name.as_str() == "e" => { - interms.push(Number::Float(OrderedFloat(f64::consts::E))) - } - &HeapCellValue::Atom(ref name, _) if name.as_str() == "epsilon" => { - interms.push(Number::Float(OrderedFloat(f64::EPSILON))) - } - &HeapCellValue::NamedStr(arity, ref name, _) => { - let evaluable_stub = MachineError::functor_stub(name.clone(), arity); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - &HeapCellValue::Atom(ref name, _) => { - let evaluable_stub = MachineError::functor_stub(name.clone(), 0); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - &HeapCellValue::Addr(addr) if addr.is_ref() => { - return Err(self.error_form(MachineError::instantiation_error(), caller)); - } - val => { - return Err(self.type_error( - ValidType::Number, - val.context_free_clone(), - clause_name!("is"), - 2, - )); - } +pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number { + match n { + Number::Fixnum(n) => { + if let Some(n) = n.get_num().checked_abs() { + fixnum!(Number, n, arena) + } else { + Number::arena_from(Integer::from(n.get_num()).abs(), arena) } } - - Ok(interms.pop().unwrap()) + Number::Integer(n) => Number::arena_from(Integer::from(n.abs_ref()), arena), + Number::Float(f) => Number::Float(f.abs()), + Number::Rational(r) => Number::arena_from(Rational::from(r.abs_ref()), arena), } +} + +#[inline] +pub(crate) fn sub(lhs: Number, rhs: Number, arena: &mut Arena) -> Result { + let neg_result = neg(rhs, arena); + add(lhs, neg_result, arena) +} - pub(crate) fn rdiv(&self, r1: Rc, r2: Rc) -> Result { - if &*r2 == &0 { - let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Rational::from(&*r1 / &*r2)) +pub(crate) fn mul(lhs: Number, rhs: Number, arena: &mut Arena) -> Result { + match (lhs, rhs) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok( + if let Some(result) = n1.get_num().checked_mul(n2.get_num()) { + fixnum!(Number, result, arena) + } else { + Number::arena_from( + Integer::from(n1.get_num()) * Integer::from(n2.get_num()), + arena, + ) + }, + ), + (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Integer::from(n1.get_num()) * &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Rational::from(n1.get_num()) * &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { + Ok(Number::Float(mul_f(float_fn_to_f(n1.get_num())?, n2)?)) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1) * &*n2, arena)) // mul_i + } + (Number::Integer(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { + Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?)) + } + (Number::Integer(n1), Number::Rational(n2)) + | (Number::Rational(n2), Number::Integer(n1)) => { + Ok(Number::arena_from(Rational::from(&*n1) * &*n2, arena)) + } + (Number::Rational(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { + Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?)) + } + (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { + Ok(Number::Float(mul_f(f1, f2)?)) + } + (Number::Rational(r1), Number::Rational(r2)) => { + Ok(Number::arena_from(Rational::from(&*r1) * &*r2, arena)) } } +} - pub(crate) fn int_floor_div(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(div)"), 2); - let modulus = self.modulus(n1.clone(), n2.clone())?; +pub(crate) fn div(n1: Number, n2: Number) -> Result { + let stub_gen = || functor_stub(atom!("/"), 2); - self.idiv(try_numeric_result!(self, n1 - modulus, stub)?, n2) + if n2.is_zero() { + Err(zero_divisor_eval_error(stub_gen)) + } else { + try_numeric_result!(n1 / n2, stub_gen) } +} - pub(crate) fn idiv(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); +pub(crate) fn float_pow(n1: Number, n2: Number) -> Result { + let f1 = result_f(&n1, rnd_f); + let f2 = result_f(&n2, rnd_f); - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - if let Some(result) = n1.checked_div(n2) { - Ok(Number::from(result)) - } else { - let n1 = Integer::from(n1); - let n2 = Integer::from(n2); + let stub_gen = || { + let pow_atom = atom!("**"); + functor_stub(pow_atom, 2) + }; + + let f1 = try_numeric_result!(f1, stub_gen)?; + let f2 = try_numeric_result!(f2, stub_gen)?; - Ok(Number::from(n1 / n2)) + let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); + + Ok(Number::Float(OrderedFloat(try_numeric_result!( + result, stub_gen + )?))) +} + +pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result { + if n1.is_zero() && n2.is_negative() { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; + + return Err(undefined_eval_error(stub_gen)); + } + + let stub_gen = || { + let caret_atom = atom!("^"); + functor_stub(caret_atom, 2) + }; + + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num(); + let n2_i = n2.get_num(); + + if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && n2_i < 0 { + let n = Number::Fixnum(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + if let Ok(n2_u) = u32::try_from(n2_i) { + if let Some(result) = n1_i.checked_pow(n2_u) { + return Ok(Number::arena_from(result, arena)); } } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(Integer::from(n1) / &*n2)) - } - } - (Number::Integer(n2), Number::Fixnum(n1)) => { - if n1 == 0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); + let n1 = Integer::from(n1_i); + let n2 = Integer::from(n2_i); - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(&*n2 / Integer::from(n1))) - } + Ok(Number::arena_from(binary_pow(n1, &n2), arena)) } - (Number::Integer(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from( - <(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0, - )) - } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1_i = n1.get_num(); + + if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && &*n2 < &0 { + let n = Number::Fixnum(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + let n1 = Integer::from(n1_i); + Ok(Number::arena_from(binary_pow(n1, &*n2), arena)) } - (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); + + if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2_i < 0 { + let n = Number::Integer(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + let n2 = Integer::from(n2_i); + Ok(Number::arena_from(binary_pow((*n1).clone(), &n2), arena)) } - (n1, _) => { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )) + } + (Number::Integer(n1), Number::Integer(n2)) => { + if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 { + let n = Number::Integer(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + Ok(Number::arena_from(binary_pow((*n1).clone(), &*n2), arena)) } } - } + (n1, Number::Integer(n2)) => { + let f1 = float(n1)?; + let f2 = float(Number::Integer(n2))?; - pub(crate) fn div(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(/)"), 2); - - if n2.is_zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - try_numeric_result!(self, n1 / n2, stub) + unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) } - } + (n1, n2) => { + let f2 = float(n2)?; - pub(crate) fn atan2(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("is"), 2); + if n1.is_negative() && f2 != f2.floor() { + return Err(undefined_eval_error(stub_gen)); + } - if n1.is_zero() && n2.is_zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)) - } else { - let f1 = self.float(n1)?; - let f2 = self.float(n2)?; + let f1 = float(n1)?; - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2)) + unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) } } +} - pub(crate) fn int_pow(&self, n1: Number, n2: Number) -> Result { - if n1.is_zero() && n2.is_negative() { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); - } +pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result { + if n2.is_negative() && n1.is_zero() { + let stub_gen = move || functor_stub(culprit, 2); - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if !(n1 == 1 || n1 == 0 || n1 == -1) && n2 < 0 { - let n = Number::from(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + return Err(undefined_eval_error(stub_gen)); + } - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - if let Ok(n2) = u32::try_from(n2) { - if let Some(result) = n1.checked_pow(n2) { - return Ok(Number::from(result)); - } - } + float_pow(n1, n2) +} - let n1 = Integer::from(n1); - let n2 = Integer::from(n2); +#[inline] +pub(crate) fn float(n: Number) -> Result { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; - Ok(Number::from(binary_pow(n1, &n2))) - } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if !(n1 == 1 || n1 == 0 || n1 == -1) && &*n2 < &0 { - let n = Number::from(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + try_numeric_result!(result_f(&n, rnd_f), stub_gen) +} - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - let n1 = Integer::from(n1); - Ok(Number::from(binary_pow(n1, n2.as_ref()))) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2 < 0 { - let n = Number::Integer(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); +#[inline] +pub(crate) fn unary_float_fn_template( + n1: Number, + f: FloatFn, +) -> Result +where + FloatFn: Fn(f64) -> f64, +{ + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - let n2 = Integer::from(n2); - Ok(Number::from(binary_pow(n1.as_ref().clone(), &n2))) - } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 { - let n = Number::Integer(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; + let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f); - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - Ok(Number::from(binary_pow(n1.as_ref().clone(), n2.as_ref()))) - } - } - (n1, Number::Integer(n2)) => { - let f1 = self.float(n1)?; - let f2 = self.float(Number::Integer(n2))?; + try_numeric_result!(f1, stub_gen) +} - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) - .map(|f| Number::Float(OrderedFloat(f))) +pub(crate) fn max(n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n1.get_num() > n2.get_num() { + Ok(Number::Fixnum(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 > &n1.get_num() { + Ok(Number::Integer(n2)) + } else { + Ok(Number::Fixnum(n1)) } - (n1, n2) => { - let f2 = self.float(n2)?; + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if &*n1 > &n2.get_num() { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } + (Number::Integer(n1), Number::Integer(n2)) => { + if n1 > n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Integer(n2)) + } + } + (n1, n2) => { + let stub_gen = || { + let max_atom = atom!("max"); + functor_stub(max_atom, 2) + }; - if n1.is_negative() && f2 != f2.floor() { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - return Err( - self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub) - ); - } + let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; + let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?; - let f1 = self.float(n1)?; - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) - .map(|f| Number::Float(OrderedFloat(f))) - } + Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2)))) } } +} - pub(crate) fn gcd(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if let Some(result) = isize_gcd(n1, n2) { - Ok(Number::Fixnum(result)) - } else { - Ok(Number::from(Integer::from(n1).gcd(&Integer::from(n2)))) - } +pub(crate) fn min(n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n1.get_num() < n2.get_num() { + Ok(Number::Fixnum(n1)) + } else { + Ok(Number::Fixnum(n2)) } - (Number::Fixnum(n1), Number::Integer(n2)) - | (Number::Integer(n2), Number::Fixnum(n1)) => { - let n1 = Integer::from(n1); - Ok(Number::from(Integer::from(n2.gcd_ref(&n1)))) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 < &n1.get_num() { + Ok(Number::Integer(n2)) + } else { + Ok(Number::Fixnum(n1)) } - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(n1.gcd_ref(&n2)))) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if &*n1 < &n2.get_num() { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Fixnum(n2)) } - (Number::Float(f), _) | (_, Number::Float(f)) => { - let n = Number::Float(f); - let stub = MachineError::functor_stub(clause_name!("gcd"), 2); - - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n), - stub, - )) + } + (Number::Integer(n1), Number::Integer(n2)) => { + if n1 < n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Integer(n2)) } - (Number::Rational(r), _) | (_, Number::Rational(r)) => { - let n = Number::Rational(r); - let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + } + (n1, n2) => { + let stub_gen = || { + let min_atom = atom!("min"); + functor_stub(min_atom, 2) + }; - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n), - stub, - )) - } + let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; + let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?; + + Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2)))) } } +} - pub(crate) fn float_pow(&self, n1: Number, n2: Number) -> Result { - let f1 = result_f(&n1, rnd_f); - let f2 = result_f(&n2, rnd_f); - - let stub = MachineError::functor_stub(clause_name!("(**)"), 2); +pub fn rational_from_number( + n: Number, + stub_gen: impl Fn() -> FunctorStub + 'static, + arena: &mut Arena, +) -> Result, MachineStubGen> { + match n { + Number::Fixnum(n) => Ok(arena_alloc!(Rational::from(n.get_num()), arena)), + Number::Rational(r) => Ok(r), + Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) { + Some(r) => Ok(arena_alloc!(r, arena)), + None => Err(Box::new(move |machine_st| { + let instantiation_error = machine_st.instantiation_error(); + let stub = stub_gen(); + + machine_st.error_form(instantiation_error, stub) + })), + }, + Number::Integer(n) => Ok(arena_alloc!(Rational::from(&*n), arena)), + } +} - let f1 = try_numeric_result!(self, f1, stub)?; - let f2 = try_numeric_result!(self, f2, stub)?; +pub(crate) fn rdiv( + r1: TypedArenaPtr, + r2: TypedArenaPtr, +) -> Result { + if &*r2 == &0 { + let stub_gen = || { + let rdiv_atom = atom!("rdiv"); + functor_stub(rdiv_atom, 2) + }; + + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Rational::from(&*r1 / &*r2)) + } +} - let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); +pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let idiv_atom = atom!("//"); + functor_stub(idiv_atom, 2) + }; - Ok(Number::Float(OrderedFloat(try_numeric_result!( - self, result, stub - )?))) - } + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n2.get_num() == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + if let Some(result) = n1.get_num().checked_div(n2.get_num()) { + Ok(Number::arena_from(result, arena)) + } else { + let n1 = Integer::from(n1.get_num()); + let n2 = Integer::from(n2.get_num()); - pub(crate) fn pow( - &self, - n1: Number, - n2: Number, - culprit: &'static str, - ) -> Result { - if n2.is_negative() && n1.is_zero() { - let stub = MachineError::functor_stub(clause_name!(culprit), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + Ok(Number::arena_from(n1 / n2, arena)) + } + } } - - self.float_pow(n1, n2) + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from(Integer::from(n1) / &*n2, arena)) + } + } + (Number::Integer(n2), Number::Fixnum(n1)) => { + if n1.get_num() == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from(&*n2 / Integer::from(n1), arena)) + } + } + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from( + <(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0, + arena, + )) + } + } + (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn unary_float_fn_template( - &self, - n1: Number, - f: FloatFn, - ) -> Result - where - FloatFn: Fn(f64) -> f64, - { - let stub = MachineError::functor_stub(clause_name!("is"), 2); +pub(crate) fn int_floor_div( + n1: Number, + n2: Number, + arena: &mut Arena, +) -> Result { + let stub_gen = || { + let div_atom = atom!("div"); + functor_stub(div_atom, 2) + }; - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; - let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f); + let modulus = modulus(n1, n2, arena)?; + let n1 = try_numeric_result!(sub(n1, modulus, arena), stub_gen)?; - try_numeric_result!(self, f1, stub) - } + idiv(n1, n2, arena) +} - #[inline] - pub(crate) fn sin(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.sin()) - } +pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let shr_atom = atom!(">>"); + functor_stub(shr_atom, 2) + }; - #[inline] - pub(crate) fn cos(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.cos()) - } + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num(); + let n2_i = n2.get_num(); - #[inline] - pub(crate) fn tan(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.tan()) - } + let n1 = Integer::from(n1_i); - #[inline] - pub(crate) fn log(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.log(f64::consts::E)) - } + if let Ok(n2) = u32::try_from(n2_i) { + return Ok(Number::arena_from(n1 >> n2, arena)); + } else { + return Ok(Number::arena_from(n1 >> u32::max_value(), arena)); + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); - #[inline] - pub(crate) fn exp(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.exp()) + match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(n1 >> n2, arena)), + _ => Ok(Number::arena_from(n1 >> u32::max_value(), arena)), + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) { + Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 >> u32::max_value()), + arena, + )), + }, + (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 >> u32::max_value()), + arena, + )), + }, + (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn asin(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.asin()) - } +pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let shl_atom = atom!(">>"); + functor_stub(shl_atom, 2) + }; - #[inline] - pub(crate) fn acos(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.acos()) - } + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num(); + let n2_i = n2.get_num(); - #[inline] - pub(crate) fn atan(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.atan()) - } + let n1 = Integer::from(n1_i); - #[inline] - pub(crate) fn sqrt(&self, n1: Number) -> Result { - if n1.is_negative() { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + if let Ok(n2) = u32::try_from(n2_i) { + return Ok(Number::arena_from(n1 << n2, arena)); + } else { + return Ok(Number::arena_from(n1 << u32::max_value(), arena)); + } } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); - self.unary_float_fn_template(n1, |f| f.sqrt()) + match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(n1 << n2, arena)), + _ => Ok(Number::arena_from(n1 << u32::max_value(), arena)), + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) { + Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 << u32::max_value()), + arena, + )), + }, + (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 << u32::max_value()), + arena, + )), + }, + (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn float(&self, n: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - try_numeric_result!(self, result_f(&n, rnd_f), stub) - } +pub(crate) fn and(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let and_atom = atom!("/\\"); + functor_stub(and_atom, 2) + }; - #[inline] - pub(crate) fn floor(&self, n1: Number) -> Number { - rnd_i(&n1).to_owned() + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::arena_from(n1.get_num() & n2.get_num(), arena)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 & &*n2, arena)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from( + &*n1 & Integer::from(n2.get_num()), + arena, + )), + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1 & &*n2), arena)) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn ceiling(&self, n1: Number) -> Number { - -self.floor(-n1) - } +pub(crate) fn or(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let or_atom = atom!("\\/"); + functor_stub(or_atom, 2) + }; - #[inline] - pub(crate) fn truncate(&self, n: Number) -> Number { - if n.is_negative() { - -self.floor(n.abs()) - } else { - self.floor(n) + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::arena_from(n1.get_num() | n2.get_num(), arena)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 | &*n2, arena)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from( + &*n1 | Integer::from(n2.get_num()), + arena, + )), + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1 | &*n2), arena)) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - pub(crate) fn round(&self, n: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - - let result = n + Number::Float(OrderedFloat(0.5f64)); - let result = try_numeric_result!(self, result, stub)?; +pub(crate) fn xor(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let xor_atom = atom!("xor"); + functor_stub(xor_atom, 2) + }; - Ok(self.floor(result)) + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::arena_from(n1.get_num() ^ n2.get_num(), arena)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 ^ &*n2, arena)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from( + &*n1 ^ Integer::from(n2.get_num()), + arena, + )), + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1 ^ &*n2), arena)) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + _ => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), } +} - pub(crate) fn shr(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); +pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let mod_atom = atom!("mod"); + functor_stub(mod_atom, 2) + }; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - let n1 = Integer::from(n1); + match (x, y) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); - if let Ok(n2) = u32::try_from(n2) { - return Ok(Number::from(n1 >> n2)); - } else { - return Ok(Number::from(n1 >> u32::max_value())); - } + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1_i = n1.get_num(); + Ok(Number::arena_from(n1_i.rem_floor(n2_i), arena)) } - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - - match n2.to_u32() { - Some(n2) => Ok(Number::from(n1 >> n2)), - _ => Ok(Number::from(n1 >> u32::max_value())), - } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from( + <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1, + arena, + )) } - (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) { - Ok(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), - _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), - }, - (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), - _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), - }, - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), } + (Number::Integer(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); + + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n2 = Integer::from(n2_i); + Ok(Number::arena_from( + <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1, + arena, + )) + } + } + (Number::Integer(x), Number::Integer(y)) => { + if &*y == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from( + <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1, + arena, + )) + } + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - pub(crate) fn shl(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(<<)"), 2); +pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let rem_atom = atom!("rem"); + functor_stub(rem_atom, 2) + }; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - let n1 = Integer::from(n1); + match (x, y) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); - if let Ok(n2) = u32::try_from(n2) { - return Ok(Number::from(n1 << n2)); - } else { - return Ok(Number::from(n1 << u32::max_value())); - } + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1_i = n1.get_num(); + Ok(Number::arena_from(n1_i % n2_i, arena)) } - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - - match n2.to_u32() { - Some(n2) => Ok(Number::from(n1 << n2)), - _ => Ok(Number::from(n1 << u32::max_value())), - } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 % &*n2, arena)) } - (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) { - Ok(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), - _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), - }, - (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), - _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), - }, - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), } + (Number::Integer(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); + + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n2 = Integer::from(n2_i); + Ok(Number::arena_from(&*n1 % n2, arena)) + } + } + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from(Integer::from(&*n1 % &*n2), arena)) + } + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - pub(crate) fn bitwise_complement(&self, n1: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(\\)"), 2); +pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let gcd_atom = atom!("gcd"); + functor_stub(gcd_atom, 2) + }; - match n1 { - Number::Fixnum(n) => Ok(Number::Fixnum(!n)), - Number::Integer(n1) => Ok(Number::from(Integer::from(!&*n1))), - _ => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num() as isize; + let n2_i = n2.get_num() as isize; + + if let Some(result) = isize_gcd(n1_i, n2_i) { + Ok(Number::arena_from(result, arena)) + } else { + Ok(Number::arena_from( + Integer::from(n1_i).gcd(&Integer::from(n2_i)), + arena, + )) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(Integer::from(n2.gcd_ref(&n1)), arena)) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(n1.gcd_ref(&n2)), arena)) + } + (Number::Float(f), _) | (_, Number::Float(f)) => { + let n = Number::Float(f); + Err(numerical_type_error(ValidType::Integer, n, stub_gen)) + } + (Number::Rational(r), _) | (_, Number::Rational(r)) => { + let n = Number::Rational(r); + Err(numerical_type_error(ValidType::Integer, n, stub_gen)) } } +} - pub(crate) fn xor(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(xor)"), 2); +pub(crate) fn atan2(n1: Number, n2: Number) -> Result { + if n1.is_zero() && n2.is_zero() { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 ^ n2)), - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - Ok(Number::from(n1 ^ &*n2)) - } - (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 ^ Integer::from(n2))), - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1 ^ &*n2))) - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), - } + Err(undefined_eval_error(stub_gen)) + } else { + let f1 = float(n1)?; + let f2 = float(n2)?; + + unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2)) } +} - pub(crate) fn and(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2); +#[inline] +pub(crate) fn sin(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.sin()) +} - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 & n2)), - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - Ok(Number::from(n1 & &*n2)) - } - (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 & Integer::from(n2))), - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1 & &*n2))) - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), - } +#[inline] +pub(crate) fn cos(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.cos()) +} + +#[inline] +pub(crate) fn tan(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.tan()) +} + +#[inline] +pub(crate) fn log(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.log(f64::consts::E)) +} + +#[inline] +pub(crate) fn exp(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.exp()) +} + +#[inline] +pub(crate) fn asin(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.asin()) +} + +#[inline] +pub(crate) fn acos(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.acos()) +} + +#[inline] +pub(crate) fn atan(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.atan()) +} + +#[inline] +pub(crate) fn sqrt(n1: Number) -> Result { + if n1.is_negative() { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; + + return Err(undefined_eval_error(stub_gen)); } - pub(crate) fn or(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2); + unary_float_fn_template(n1, |f| f.sqrt()) +} - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 | n2)), - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - Ok(Number::from(n1 | &*n2)) - } - (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 | Integer::from(n2))), - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1 | &*n2))) - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), +#[inline] +pub(crate) fn floor(n1: Number, arena: &mut Arena) -> Number { + rnd_i(&n1, arena) +} + +#[inline] +pub(crate) fn ceiling(n1: Number, arena: &mut Arena) -> Number { + let n1 = neg(n1, arena); + let n1 = floor(n1, arena); + + neg(n1, arena) +} + +#[inline] +pub(crate) fn truncate(n: Number, arena: &mut Arena) -> Number { + if n.is_negative() { + let n = abs(n, arena); + let n = floor(n, arena); + + neg(n, arena) + } else { + floor(n, arena) + } +} + +pub(crate) fn round(n: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; + + let result = add(n, Number::Float(OrderedFloat(0.5f64)), arena); + let result = try_numeric_result!(result, stub_gen)?; + + Ok(floor(result, arena)) +} + +pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result { + match n1 { + Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))), + Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)), + _ => { + let stub_gen = || { + let bitwise_atom = atom!("\\"); + functor_stub(bitwise_atom, 2) + }; + + Err(numerical_type_error(ValidType::Integer, n1, stub_gen)) } } +} - pub(crate) fn modulus(&self, x: Number, y: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(mod)"), 2); +impl MachineState { + #[inline] + pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result { + match at { + &ArithmeticTerm::Reg(r) => { + let value = self.store(self.deref(self[r])); - match (x, y) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(n1.rem_floor(n2))) + match Number::try_from(value) { + Ok(n) => Ok(n), + Err(_) => self.arith_eval_by_metacall(value), } } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n1 = Integer::from(n1); - Ok(Number::from( - <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1, - )) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n2 = Integer::from(n2); - Ok(Number::from( - <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1, - )) - } - } - (Number::Integer(x), Number::Integer(y)) => { - if &*y == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from( - <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1, - )) - } + &ArithmeticTerm::Interm(i) => { + Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(Fixnum::build_with(0)))) } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), + &ArithmeticTerm::Number(n) => Ok(n), } } - pub(crate) fn remainder(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(rem)"), 2); + pub fn get_rational( + &mut self, + at: &ArithmeticTerm, + caller: impl Fn() -> FunctorStub + 'static, + ) -> Result, MachineStub> { + let n = self.get_number(at)?; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(n1 % n2)) - } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n1 = Integer::from(n1); - Ok(Number::from(n1 % &*n2)) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n2 = Integer::from(n2); - Ok(Number::from(&*n1 % n2)) - } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(Integer::from(&*n1 % &*n2))) - } - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), + match rational_from_number(n, caller, &mut self.arena) { + Ok(r) => Ok(r), + Err(e_gen) => Err(e_gen(self)) } } - pub(crate) fn max(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n1 > n2 { - Ok(Number::Fixnum(n1)) - } else { - Ok(Number::Fixnum(n2)) - } + pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result { + let stub_gen = || functor_stub(atom!("is"), 2); + let mut iter = stackless_post_order_iter(&mut self.heap, value); + + while let Some(value) = iter.next() { + if value.is_forwarded() { + let (name, arity) = read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + (name, arity) + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStr) => { + (atom!("."), 2) + } + _ => { + unreachable!() + } + ); + + std::mem::drop(iter); + + let evaluable_error = self.evaluable_error(name, arity); + let stub = stub_gen(); + + return Err(self.error_form(evaluable_error, stub)); } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 > &n1 { - Ok(Number::Integer(n2)) - } else { - Ok(Number::Fixnum(n1)) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if &*n1 > &n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Fixnum(n2)) - } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if n1 > n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Integer(n2)) - } - } - (n1, n2) => { - let stub = MachineError::functor_stub(clause_name!("max"), 2); - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; - let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 2 { + let a1 = self.interms.pop().unwrap(); + let a2 = self.interms.pop().unwrap(); + + match name { + atom!("+") => self.interms.push(drop_iter_on_err!( + self, + iter, + try_numeric_result!(add(a1, a2, &mut self.arena), stub_gen) + )), + atom!("-") => self.interms.push(drop_iter_on_err!( + self, + iter, + try_numeric_result!(sub(a1, a2, &mut self.arena), stub_gen) + )), + atom!("*") => self.interms.push(drop_iter_on_err!( + self, + iter, + try_numeric_result!(mul(a1, a2, &mut self.arena), stub_gen) + )), + atom!("/") => self.interms.push( + drop_iter_on_err!(self, iter, div(a1, a2)) + ), + atom!("**") => self.interms.push( + drop_iter_on_err!(self, iter, pow(a1, a2, atom!("is"))) + ), + atom!("^") => self.interms.push( + drop_iter_on_err!(self, iter, int_pow(a1, a2, &mut self.arena)) + ), + atom!("max") => self.interms.push( + drop_iter_on_err!(self, iter, max(a1, a2)) + ), + atom!("min") => self.interms.push( + drop_iter_on_err!(self, iter, min(a1, a2)) + ), + atom!("rdiv") => { + let r1 = drop_iter_on_err!( + self, + iter, + rational_from_number(a1, stub_gen, &mut self.arena) + ); + + let r2 = drop_iter_on_err!( + self, + iter, + rational_from_number(a2, stub_gen, &mut self.arena) + ); + + let result = arena_alloc!( + drop_iter_on_err!(self, iter, rdiv(r1, r2)), + self.arena + ); + + self.interms.push(Number::Rational(result)); + } + atom!("//") => self.interms.push( + drop_iter_on_err!(self, iter, idiv(a1, a2, &mut self.arena)) + ), + atom!("div") => self.interms.push( + drop_iter_on_err!(self, iter, int_floor_div(a1, a2, &mut self.arena)) + ), + atom!(">>") => self.interms.push( + drop_iter_on_err!(self, iter, shr(a1, a2, &mut self.arena)) + ), + atom!("<<") => self.interms.push( + drop_iter_on_err!(self, iter, shl(a1, a2, &mut self.arena)) + ), + atom!("/\\") => self.interms.push( + drop_iter_on_err!(self, iter, and(a1, a2, &mut self.arena)) + ), + atom!("\\/") => self.interms.push( + drop_iter_on_err!(self, iter, or(a1, a2, &mut self.arena)) + ), + atom!("xor") => self.interms.push( + drop_iter_on_err!(self, iter, xor(a1, a2, &mut self.arena)) + ), + atom!("mod") => self.interms.push( + drop_iter_on_err!(self, iter, modulus(a1, a2, &mut self.arena)) + ), + atom!("rem") => self.interms.push( + drop_iter_on_err!(self, iter, remainder(a1, a2, &mut self.arena)) + ), + atom!("atan2") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, atan2(a1, a2)) + ))), + atom!("gcd") => self.interms.push( + drop_iter_on_err!(self, iter, gcd(a1, a2, &mut self.arena)) + ), + _ => { + let evaluable_stub = functor_stub(name, 2); + let stub = stub_gen(); + + std::mem::drop(iter); + + let type_error = self.type_error(ValidType::Evaluable, evaluable_stub); + return Err(self.error_form(type_error, stub)); + } + } - Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2)))) - } - } - } + continue; + } else if arity == 1 { + let a1 = self.interms.pop().unwrap(); + + match name { + atom!("-") => self.interms.push(neg(a1, &mut self.arena)), + atom!("+") => self.interms.push(a1), + atom!("cos") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, cos(a1)) + ))), + atom!("sin") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, sin(a1)) + ))), + atom!("tan") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, tan(a1)) + ))), + atom!("sqrt") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, sqrt(a1)) + ))), + atom!("log") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, log(a1)) + ))), + atom!("exp") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, exp(a1)) + ))), + atom!("acos") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, acos(a1)) + ))), + atom!("asin") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, asin(a1)) + ))), + atom!("atan") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, atan(a1)) + ))), + atom!("abs") => self.interms.push(abs(a1, &mut self.arena)), + atom!("float") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, float(a1)) + ))), + atom!("truncate") => self.interms.push(truncate(a1, &mut self.arena)), + atom!("round") => self.interms.push(drop_iter_on_err!(self, iter, round(a1, &mut self.arena))), + atom!("ceiling") => self.interms.push(ceiling(a1, &mut self.arena)), + atom!("floor") => self.interms.push(floor(a1, &mut self.arena)), + atom!("\\") => self.interms.push( + drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena)) + ), + atom!("sign") => self.interms.push(sign(a1)), + _ => { + let evaluable_stub = functor_stub(name, 1); + std::mem::drop(iter); + + let type_error = self.type_error( + ValidType::Evaluable, + evaluable_stub, + ); - pub(crate) fn min(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n1 < n2 { - Ok(Number::Fixnum(n1)) - } else { - Ok(Number::Fixnum(n2)) + let stub = stub_gen(); + return Err(self.error_form(type_error, stub)); + } + } + + continue; + } else if arity == 0 { + match name { + atom!("pi") => { + self.interms.push(Number::Float(OrderedFloat(f64::consts::PI))); + continue; + } + atom!("e") => { + self.interms.push(Number::Float(OrderedFloat(f64::consts::E))); + continue; + } + atom!("epsilon") => { + self.interms.push(Number::Float(OrderedFloat(f64::EPSILON))); + continue; + } + _ => { + } + } + } + + std::mem::drop(iter); + + let evaluable_error = self.evaluable_error(name, arity); + let stub = stub_gen(); + + return Err(self.error_form(evaluable_error, stub)); } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 < &n1 { - Ok(Number::Integer(n2)) - } else { - Ok(Number::Fixnum(n1)) + (HeapCellValueTag::Fixnum, n) => { + self.interms.push(Number::Fixnum(n)); } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if &*n1 < &n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Fixnum(n2)) + (HeapCellValueTag::F64, fl) => { + self.interms.push(Number::Float(**fl)); } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if n1 < n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Integer(n2)) + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, n) => { + self.interms.push(Number::Integer(n)); + } + (ArenaHeaderTag::Rational, r) => { + self.interms.push(Number::Rational(r)); + } + _ => { + std::mem::drop(iter); + + let type_error = self.type_error(ValidType::Evaluable, value); + let stub = stub_gen(); + + return Err(self.error_form(type_error, stub)); + } + ) } - } - (n1, n2) => { - let stub = MachineError::functor_stub(clause_name!("max"), 2); + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => { + std::mem::drop(iter); - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; - let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; + let instantiation_error = self.instantiation_error(); + let stub = stub_gen(); - Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2)))) - } + return Err(self.error_form(instantiation_error, stub)); + } + _ => { + std::mem::drop(iter); + + let type_error = self.type_error(ValidType::Evaluable, value); + let stub = stub_gen(); + + return Err(self.error_form(type_error, stub)); + } + ) } + + Ok(self.interms.pop().unwrap()) } +} - pub(crate) fn sign(&self, n: Number) -> Number { - if n.is_positive() { - Number::from(1) - } else if n.is_negative() { - Number::from(-1) - } else { - Number::from(0) - } +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn arith_eval_by_metacall_tests() { + let mut wam = MachineState::new(); + let mut op_dir = default_op_dir(); + + op_dir.insert( + (atom!("+"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::Pre), + OpDesc::build_with(200, FY as u8), + ); + op_dir.insert( + (atom!("*"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + op_dir.insert( + (atom!("/"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + + let term_write_result = + parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap(); + + assert_eq!( + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + Ok(Number::Fixnum(Fixnum::build_with(8))), + ); + + wam.heap.clear(); + + let term_write_result = + parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap(); + + assert_eq!( + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + Ok(Number::Fixnum(Fixnum::build_with(19))), + ); + + wam.heap.clear(); + + let term_write_result = + parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap(); + + assert_eq!( + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + Ok(Number::Fixnum(Fixnum::build_with(-1))) + ); } } diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index f39a2ac8f..34cdd12ef 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -1,13 +1,15 @@ use crate::heap_iter::*; use crate::machine::*; -use prolog_parser::temp_v; +use crate::parser::ast::*; +use crate::temp_v; +use crate::types::*; use indexmap::IndexSet; use std::cmp::Ordering; use std::vec::IntoIter; -pub(super) type Bindings = Vec<(usize, Addr)>; +pub(super) type Bindings = Vec<(usize, HeapCellValue)>; #[derive(Debug)] pub(super) struct AttrVarInitializer { @@ -37,7 +39,7 @@ impl AttrVarInitializer { } impl MachineState { - pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) { + pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) { if self.attr_var_init.bindings.is_empty() { self.attr_var_init.instigating_p = self.p.local(); @@ -53,28 +55,24 @@ impl MachineState { self.attr_var_init.bindings.push((h, addr)); } - fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) { + fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) { let iter = self .attr_var_init .bindings .iter() - .map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h))); + .map(|(ref h, _)| attr_var_as_cell!(*h)); - let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); + let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter)); - let iter = self - .attr_var_init - .bindings - .drain(0..) - .map(|(_, addr)| HeapCellValue::Addr(addr)); + let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v); - let value_list_addr = Addr::HeapCell(self.heap.to_list(iter)); + let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter)); (var_list_addr, value_list_addr) } fn verify_attributes(&mut self) { for (h, _) in &self.attr_var_init.bindings { - self.heap[*h] = HeapCellValue::Addr(Addr::AttrVar(*h)); + self.heap[*h] = attr_var_as_cell!(*h); } let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists(); @@ -83,19 +81,26 @@ impl MachineState { self[temp_v!(2)] = value_list_addr; } - pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter { + pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter { let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..] .iter() - .filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) { - Addr::AttrVar(h) => Some(Addr::AttrVar(h)), - _ => None, + .filter_map(|h| { + read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))), //Addr::HeapCell(*h))) { + (HeapCellValueTag::AttrVar, h) => { + Some(attr_var_as_cell!(h)) + } + _ => { + None + } + ) }) .collect(); - attr_vars - .sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)); + attr_vars.sort_unstable_by(|a1, a2| { + compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less) + }); - self.term_dedup(&mut attr_vars); + attr_vars.dedup(); attr_vars.into_iter() } @@ -109,8 +114,10 @@ impl MachineState { self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)]; } - self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0); - self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args); + self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.b0 as i64)); + self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = + fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); self.verify_attributes(); @@ -119,33 +126,51 @@ impl MachineState { self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); } - pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec { + pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec { let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; - let mut iter = self.acyclic_pre_order_iter(addr); - - while let Some(addr) = iter.next() { - if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() { - if seen_set.contains(h) { - continue; - } - - seen_vars.push(addr); - seen_set.insert(*h); - - let mut l = h + 1; - let mut list_elements = vec![]; - - while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) { - list_elements.push(self.heap[elem].as_addr(elem)); - l = elem + 1; + let mut iter = stackful_preorder_iter(&mut self.heap, cell); + + while let Some(value) = iter.next() { + read_heap_cell!(value, + (HeapCellValueTag::AttrVar, h) => { + if seen_set.contains(&h) { + continue; + } + + seen_vars.push(value); + seen_set.insert(h); + + let mut l = h + 1; + // let mut list_elements = vec![]; + // let iter_stack_len = iter.stack_len(); + + loop { + read_heap_cell!(iter.heap[l], + (HeapCellValueTag::Lis) => { + iter.push_stack(l); + // l = elem + 1; + break; + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + if h == l { + break; + } else { + l = h; + } + } + _ => { + break; + } + ) + } + + // iter.stack_slice_from(iter_stack_len ..).reverse(); } - - for element in list_elements.into_iter().rev() { - iter.stack().push(element); + _ => { } - } + ); } seen_vars diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs index bb21462e2..54db570f6 100644 --- a/src/machine/code_repo.rs +++ b/src/machine/code_repo.rs @@ -3,7 +3,7 @@ use crate::instructions::*; use crate::machine::machine_indices::*; #[derive(Debug)] -pub(crate) struct CodeRepo { +pub struct CodeRepo { pub(super) code: Code, } diff --git a/src/machine/compile.rs b/src/machine/compile.rs index ef99df341..72ec57c4d 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1,18 +1,22 @@ -use prolog_parser::clause_name; - +use crate::atom_table::*; use crate::codegen::*; use crate::debray_allocator::*; -use crate::indexing::{merge_clause_index, remove_index, IndexingCodePtr}; +use crate::forms::*; +use crate::indexing::{merge_clause_index, remove_index}; +use crate::instructions::*; use crate::machine::load_state::*; use crate::machine::loader::*; +use crate::machine::machine_errors::*; use crate::machine::preprocessor::*; use crate::machine::term_stream::*; use crate::machine::*; +use crate::parser::ast::*; use slice_deque::{sdeq, SliceDeque}; use std::cell::Cell; use std::collections::VecDeque; +use std::mem; use std::ops::Range; struct StandaloneCompileResult { @@ -25,17 +29,21 @@ pub(super) fn bootstrapping_compile( wam: &mut Machine, listing_src: ListingSource, ) -> Result<(), SessionError> { - let stream = &mut parsing_stream(stream)?; - let term_stream = BootstrappingTermStream::from_prolog_stream( + let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st(); + + let term_stream = BootstrappingTermStream::from_char_reader( stream, - wam.machine_st.atom_tbl.clone(), - wam.machine_st.flags, + machine_st, listing_src, ); - let loader = Loader::new(term_stream, wam); - loader.load()?; + let payload = BootstrappingLoadState( + LoadStatePayload::new(wam_prelude.code_repo.code.len(), term_stream) + ); + let loader: Loader<'_, BootstrappingLoadState> = Loader { payload, wam_prelude }; + + loader.load()?; Ok(()) } @@ -57,7 +65,7 @@ pub(super) fn compile_appendix( mut queue: VecDeque, jmp_by_locs: Vec, non_counted_bt: bool, - atom_tbl: TabledData, + atom_tbl: &mut AtomTable, ) -> Result<(), CompilationError> { let mut jmp_by_locs = VecDeque::from(jmp_by_locs); @@ -80,7 +88,7 @@ pub(super) fn compile_appendix( non_counted_bt, }; - let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + let mut cg = CodeGenerator::::new(atom_tbl, settings); let tl = queue.pop_front().unwrap(); let decl_code = compile_relation(&mut cg, &tl)?; @@ -164,6 +172,7 @@ fn merge_indices( target_index_loc: usize, index_range: Range, skeleton: &mut [ClauseIndexInfo], + retracted_dynamic_clauses: &Option>, retraction_info: &mut RetractionInfo, ) { for clause_index in index_range { @@ -183,6 +192,7 @@ fn merge_indices( merge_clause_index( target_indexing_line, &mut skeleton[0..clause_index + 1], + retracted_dynamic_clauses, clause_loc, AppendOrPrepend::Append, ); @@ -422,13 +432,24 @@ fn delete_from_skeleton( skeleton.core.clause_assert_margin -= 1; } - retraction_info.push_record(RetractionRecord::RemovedSkeletonClause( - compilation_target, - key, - target_pos, - clause_index_info, - clause_clause_loc, - )); + if skeleton.core.is_dynamic { + skeleton.core.add_retracted_dynamic_clause_info(clause_index_info); + + retraction_info.push_record(RetractionRecord::RemovedDynamicSkeletonClause( + compilation_target, + key, + target_pos, + clause_clause_loc, + )); + } else { + retraction_info.push_record(RetractionRecord::RemovedSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + )); + } clause_clause_loc } @@ -617,7 +638,6 @@ fn internalize_choice_instr_at( } Line::Choice(ChoiceInstruction::TryMeElse(0)) => { retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0)); - code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); } Line::Choice(ChoiceInstruction::TryMeElse(o)) => { @@ -804,8 +824,8 @@ fn finalize_retract( retraction_info: &mut RetractionInfo, ) -> usize { let clause_clause_loc = delete_from_skeleton( - compilation_target.clone(), - key.clone(), + compilation_target, + key, skeleton, target_pos, retraction_info, @@ -920,7 +940,7 @@ fn prepend_compiled_clause( retraction_info.push_record(RetractionRecord::SkeletonClauseStartReplaced( compilation_target, - key.clone(), + key, 1, skeleton.clauses[1].clause_start, )); @@ -999,6 +1019,7 @@ fn prepend_compiled_clause( merge_clause_index( target_indexing_line, &mut skeleton.clauses, + &skeleton.core.retracted_dynamic_clauses, clause_loc + 2, // == skeleton.clauses[0].clause_start AppendOrPrepend::Prepend, ); @@ -1202,6 +1223,7 @@ fn append_compiled_clause( merge_clause_index( target_indexing_line, &mut skeleton.clauses[lower_bound..], + &skeleton.core.retracted_dynamic_clauses, clause_loc, AppendOrPrepend::Append, ); @@ -1322,21 +1344,20 @@ fn print_overwrite_warning( _ => {} } - println!("Warning: overwriting {}/{}", key.0, key.1); + println!("Warning: overwriting {}/{}", key.0.as_str(), key.1); } -impl<'a> LoadState<'a> { - pub(super) fn listing_src_file_name(&self) -> Option { - if let Some(load_context) = self.wam.load_contexts.last() { +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { + pub(super) fn listing_src_file_name(&mut self) -> Option { + if let Some(load_context) = self.wam_prelude.load_contexts.last() { if !load_context.path.is_file() { return None; } if let Some(path_str) = load_context.path.to_str() { if !path_str.is_empty() { - return Some(clause_name!( - path_str.to_string(), - self.wam.machine_st.atom_tbl + return Some(LS::machine_st(&mut self.payload).atom_tbl.build_with( + path_str )); } } @@ -1349,14 +1370,13 @@ impl<'a> LoadState<'a> { &mut self, term: Term, settings: CodeGenSettings, - atom_tbl: TabledData, ) -> Result { - let mut preprocessor = Preprocessor::new(); - let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags); let clause = self.try_term_to_tl(term, &mut preprocessor)?; let queue = preprocessor.parse_queue(self)?; + let mut cg = CodeGenerator::::new(&mut LS::machine_st(&mut self.payload).atom_tbl, settings); let mut clause_code = cg.compile_predicate(&vec![clause])?; compile_appendix( @@ -1364,7 +1384,7 @@ impl<'a> LoadState<'a> { queue, cg.jmp_by_locs, settings.non_counted_bt, - atom_tbl, + cg.atom_tbl, )?; Ok(StandaloneCompileResult { @@ -1376,26 +1396,28 @@ impl<'a> LoadState<'a> { fn compile( &mut self, key: PredicateKey, - predicates: &mut PredicateQueue, + mut predicates: PredicateQueue, settings: CodeGenSettings, ) -> Result { - let code_index = - self.get_or_insert_code_index(key.clone(), predicates.compilation_target.clone()); + let code_index = self.get_or_insert_code_index(key, predicates.compilation_target); - let code_len = self.wam.code_repo.code.len(); + let code_len = self.wam_prelude.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 clauses = vec![]; - let mut preprocessor = Preprocessor::new(); + let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags); for term in predicates.predicates.drain(0..) { clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); } let queue = preprocessor.parse_queue(self)?; + + let mut cg = CodeGenerator::::new( + &mut LS::machine_st(&mut self.payload).atom_tbl, + settings, + ); + let mut code = cg.compile_predicate(&clauses)?; compile_appendix( @@ -1403,7 +1425,7 @@ impl<'a> LoadState<'a> { queue, cg.jmp_by_locs, settings.non_counted_bt, - self.wam.machine_st.atom_tbl.clone(), + cg.atom_tbl, )?; if settings.is_extensible { @@ -1424,34 +1446,38 @@ impl<'a> LoadState<'a> { } match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&predicates.compilation_target, &key) { Some(skeleton) => { - self.retraction_info - .push_record(RetractionRecord::SkeletonClauseTruncateBack( - predicates.compilation_target.clone(), - key.clone(), - skeleton.clauses.len(), - )); + let skeleton_clause_len = skeleton.clauses.len(); skeleton.clauses.extend(cg.skeleton.clauses.into_iter()); skeleton .core .clause_clause_locs .extend_from_slice(&clause_clause_locs[0..]); + + self.payload.retraction_info + .push_record(RetractionRecord::SkeletonClauseTruncateBack( + predicates.compilation_target, + key, + skeleton_clause_len, + )); } None => { cg.skeleton - .core - .clause_clause_locs - .extend_from_slice(&clause_clause_locs[0..]); + .core + .clause_clause_locs + .extend_from_slice(&clause_clause_locs[0..]); + + let skeleton = cg.skeleton; self.add_extensible_predicate( - key.clone(), - cg.skeleton, - predicates.compilation_target.clone(), + key, + skeleton, + predicates.compilation_target, ); } }; @@ -1477,14 +1503,14 @@ impl<'a> LoadState<'a> { }; set_code_index( - &mut self.retraction_info, + &mut self.payload.retraction_info, &predicates.compilation_target, key, &code_index, index_ptr, ); - self.wam.code_repo.code.extend(code.into_iter()); + self.wam_prelude.code_repo.code.extend(code.into_iter()); Ok(code_index) } @@ -1494,18 +1520,22 @@ impl<'a> LoadState<'a> { key: &PredicateKey, clause_clause_locs: SliceDeque, ) { - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + *compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::SkeletonLocalClauseTruncateBack( - self.compilation_target.clone(), - compilation_target.clone(), - key.clone(), + payload_compilation_target, + *compilation_target, + *key, skeleton.clause_clause_locs.len(), ), ); @@ -1519,8 +1549,8 @@ impl<'a> LoadState<'a> { skeleton.clause_clause_locs = clause_clause_locs; self.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + *compilation_target, + *key, skeleton, ); } @@ -1533,18 +1563,22 @@ impl<'a> LoadState<'a> { key: &PredicateKey, code_len: usize, ) { - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + *compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::SkeletonLocalClauseClausePopFront( - self.compilation_target.clone(), - compilation_target.clone(), - key.clone(), + payload_compilation_target, + *compilation_target, + *key, ), ); @@ -1555,8 +1589,8 @@ impl<'a> LoadState<'a> { skeleton.clause_clause_locs.push_front(code_len); self.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + *compilation_target, + *key, skeleton, ); } @@ -1569,18 +1603,22 @@ impl<'a> LoadState<'a> { key: &PredicateKey, code_len: usize, ) { - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + *compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::SkeletonLocalClauseClausePopBack( - self.compilation_target.clone(), - compilation_target.clone(), - key.clone(), + payload_compilation_target, + *compilation_target, + *key, ), ); @@ -1591,8 +1629,8 @@ impl<'a> LoadState<'a> { skeleton.clause_clause_locs.push_back(code_len); self.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + *compilation_target, + *key, skeleton, ); } @@ -1608,13 +1646,13 @@ impl<'a> LoadState<'a> { append_or_prepend: AppendOrPrepend, ) -> Result { let settings = match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { Some(skeleton) if !skeleton.clauses.is_empty() => CodeGenSettings { global_clock_tick: if skeleton.core.is_dynamic { - Some(self.wam.machine_st.global_clock) + Some(LS::machine_st(&mut self.payload).global_clock) } else { None }, @@ -1625,7 +1663,7 @@ impl<'a> LoadState<'a> { let settings = CodeGenSettings { global_clock_tick: if let Some(skeleton) = skeleton_opt { if skeleton.core.is_dynamic { - Some(self.wam.machine_st.global_clock) + Some(LS::machine_st(&mut self.payload).global_clock) } else { None } @@ -1639,21 +1677,19 @@ impl<'a> LoadState<'a> { let mut predicate_queue = predicate_queue![clause]; predicate_queue.compilation_target = compilation_target; - return self.compile(key, &mut predicate_queue, settings); + return self.compile(key, predicate_queue, settings); } }; - let atom_tbl = self.wam.machine_st.atom_tbl.clone(); - let StandaloneCompileResult { clause_code, mut standalone_skeleton, - } = self.compile_standalone_clause(clause, settings, atom_tbl)?; + } = self.compile_standalone_clause(clause, settings)?; - let code_len = self.wam.code_repo.code.len(); + let code_len = self.wam_prelude.code_repo.code.len(); let skeleton = match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -1668,28 +1704,30 @@ impl<'a> LoadState<'a> { skeleton.core.clause_clause_locs.push_back(code_len); - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::SkeletonClausePopBack( - compilation_target.clone(), - key.clone(), + compilation_target, + key, )); + let global_clock = LS::machine_st(&mut self.payload).global_clock; + let result = append_compiled_clause( - &mut self.wam.code_repo.code, + &mut self.wam_prelude.code_repo.code, clause_code, skeleton, - &mut self.retraction_info, - self.wam.machine_st.global_clock, + &mut self.payload.retraction_info, + global_clock, ); self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len); let code_index = - self.get_or_insert_code_index(key.clone(), compilation_target.clone()); + self.get_or_insert_code_index(key, compilation_target); if let Some(new_code_ptr) = result { set_code_index( - &mut self.retraction_info, + &mut self.payload.retraction_info, &compilation_target, key, &code_index, @@ -1706,29 +1744,31 @@ impl<'a> LoadState<'a> { skeleton.core.clause_clause_locs.push_front(code_len); skeleton.core.clause_assert_margin += 1; - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::SkeletonClausePopFront( - compilation_target.clone(), - key.clone(), + compilation_target, + key, )); + let global_clock = LS::machine_st(&mut self.payload).global_clock; + let new_code_ptr = prepend_compiled_clause( - &mut self.wam.code_repo.code, - compilation_target.clone(), - key.clone(), + &mut self.wam_prelude.code_repo.code, + compilation_target, + key, clause_code, skeleton, - &mut self.retraction_info, - self.wam.machine_st.global_clock, + &mut self.payload.retraction_info, + global_clock, ); self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len); let code_index = - self.get_or_insert_code_index(key.clone(), compilation_target.clone()); + self.get_or_insert_code_index(key, compilation_target); set_code_index( - &mut self.retraction_info, + &mut self.payload.retraction_info, &compilation_target, key, &code_index, @@ -1742,9 +1782,9 @@ impl<'a> LoadState<'a> { pub(super) fn retract_dynamic_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { let skeleton = match self - .wam + .wam_prelude .indices - .get_predicate_skeleton_mut(&self.compilation_target, &key) + .get_predicate_skeleton_mut(&self.payload.compilation_target, &key) { Some(skeleton) => skeleton, None => { @@ -1757,38 +1797,38 @@ impl<'a> LoadState<'a> { .switch_on_term_loc() { Some(index_loc) => find_inner_choice_instr( - &self.wam.code_repo.code, + &self.wam_prelude.code_repo.code, skeleton.clauses[target_pos].clause_start, index_loc, ), None => skeleton.clauses[target_pos].clause_start, }; - match &mut self.wam.code_repo.code[clause_loc] { + match &mut self.wam_prelude.code_repo.code[clause_loc] { Line::Choice(ChoiceInstruction::DynamicElse(_, ref mut d, _)) | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, ref mut d, _)) => { - *d = Death::Finite(self.wam.machine_st.global_clock); + *d = Death::Finite(LS::machine_st(&mut self.payload).global_clock); } _ => unreachable!(), } delete_from_skeleton( - self.compilation_target.clone(), + self.payload.compilation_target, key, skeleton, target_pos, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { - let code_index = - self.get_or_insert_code_index(key.clone(), self.compilation_target.clone()); + let payload_compilation_target = self.payload.compilation_target; + let code_index = self.get_or_insert_code_index(key, payload_compilation_target); let skeleton = match self - .wam + .wam_prelude .indices - .get_predicate_skeleton_mut(&self.compilation_target, &key) + .get_predicate_skeleton_mut(&payload_compilation_target, &key) { Some(skeleton) => skeleton, None => { @@ -1796,7 +1836,7 @@ impl<'a> LoadState<'a> { } }; - let code = &mut self.wam.code_repo.code; + let code = &mut self.wam_prelude.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(); @@ -1818,13 +1858,13 @@ impl<'a> LoadState<'a> { code, &skeleton.clauses[target_pos].opt_arg_index_key, inner_clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); match derelictize_try_me_else( code, inner_clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) { Some(offset) => { let instr_loc = find_inner_choice_instr( @@ -1836,20 +1876,20 @@ impl<'a> LoadState<'a> { let clause_loc = blunt_leading_choice_instr( code, instr_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); set_switch_var_offset( code, index_loc, clause_loc - index_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); - self.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::SkeletonClauseStartReplaced( - self.compilation_target.clone(), - key.clone(), + payload_compilation_target, + key, target_pos + 1, skeleton.clauses[target_pos + 1].clause_start, ), @@ -1866,12 +1906,12 @@ impl<'a> LoadState<'a> { return finalize_retract( key, - self.compilation_target.clone(), + payload_compilation_target, skeleton, code_index, target_pos, index_ptr_opt, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } None => { @@ -1883,24 +1923,24 @@ impl<'a> LoadState<'a> { code, preceding_choice_instr_loc, skeleton.clauses[target_pos].clause_start - 2, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } else { remove_leading_unindexed_clause( code, skeleton.clauses[target_pos].clause_start - 2, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) }; return finalize_retract( key, - self.compilation_target.clone(), + payload_compilation_target, skeleton, code_index, target_pos, index_ptr_opt, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } } @@ -1938,7 +1978,7 @@ impl<'a> LoadState<'a> { match target_indexing_line { Line::IndexingCode(indexing_code) => { - self.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::ReplacedIndexingLine( target_indexing_loc, indexing_code, @@ -1953,7 +1993,7 @@ impl<'a> LoadState<'a> { skeleton, lower_bound, target_pos + 1, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); merge_indices( @@ -1961,14 +2001,15 @@ impl<'a> LoadState<'a> { later_indexing_loc, 0..target_pos - lower_bound, &mut skeleton.clauses[lower_bound..], - &mut self.retraction_info, + &skeleton.core.retracted_dynamic_clauses, + &mut self.payload.retraction_info, ); set_switch_var_offset( code, later_indexing_loc, lower_bound_clause_start - later_indexing_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } _ => { @@ -1977,7 +2018,7 @@ impl<'a> LoadState<'a> { skeleton, lower_bound, target_pos + 1, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); merge_indices( @@ -1985,14 +2026,15 @@ impl<'a> LoadState<'a> { target_indexing_loc, target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound, &mut skeleton.clauses[lower_bound..], - &mut self.retraction_info, + &skeleton.core.retracted_dynamic_clauses, + &mut self.payload.retraction_info, ); set_switch_var_offset_to_choice_instr( code, target_indexing_loc, lower_bound_clause_start - target_indexing_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } }; @@ -2005,7 +2047,7 @@ impl<'a> LoadState<'a> { code, &skeleton.clauses[target_pos].opt_arg_index_key, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); match skeleton.clauses[target_pos] @@ -2023,7 +2065,7 @@ impl<'a> LoadState<'a> { code, preceding_choice_instr_loc, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); match &mut code[preceding_choice_instr_loc] { @@ -2032,7 +2074,7 @@ impl<'a> LoadState<'a> { code, index_loc, preceding_choice_instr_loc + 1 - index_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } _ => {} @@ -2052,7 +2094,7 @@ impl<'a> LoadState<'a> { code, preceding_choice_instr_loc, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } } @@ -2060,7 +2102,7 @@ impl<'a> LoadState<'a> { remove_leading_unindexed_clause( code, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } } @@ -2068,17 +2110,17 @@ impl<'a> LoadState<'a> { finalize_retract( key, - self.compilation_target.clone(), + payload_compilation_target, skeleton, code_index, target_pos, index_ptr_opt, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } } -impl<'a, TS: TermStream> Loader<'a, TS> { +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn compile_clause_clauses>( &mut self, key: PredicateKey, @@ -2089,24 +2131,23 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let clause_predicates = clause_clauses.map(|(head, body)| { Term::Clause( Cell::default(), - clause_name!("$clause"), - vec![Box::new(head), Box::new(body)], - None, + atom!("$clause"), + vec![head, body], ) }); let clause_clause_compilation_target = match compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - _ => compilation_target.clone(), + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + _ => compilation_target, }; let mut num_clause_predicates = 0; for clause_term in clause_predicates { - self.load_state.incremental_compile_clause( - (clause_name!("$clause"), 2), + self.incremental_compile_clause( + (atom!("$clause"), 2), clause_term, - clause_clause_compilation_target.clone(), + clause_clause_compilation_target, false, // non_counted_bt is false. append_or_prepend, )?; @@ -2115,8 +2156,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } let locs_vec: Vec<_> = match self - .load_state - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -2136,9 +2176,9 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } }; - match self.load_state.wam.indices.get_predicate_skeleton_mut( + match self.wam_prelude.indices.get_predicate_skeleton_mut( &clause_clause_compilation_target, - &(clause_name!("$clause"), 2), + &(atom!("$clause"), 2), ) { Some(skeleton) if append_or_prepend.is_append() => { for _ in 0..num_clause_predicates { @@ -2168,6 +2208,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { let key = self + .payload .predicates .first() .and_then(|cl| { @@ -2176,23 +2217,24 @@ impl<'a, TS: TermStream> Loader<'a, TS> { }) .ok_or(SessionError::NamelessEntry)?; + let listing_src_file_name = self.listing_src_file_name(); + let payload_compilation_target = self.payload.compilation_target; + let mut predicate_info = self - .load_state - .wam + .wam_prelude .indices - .get_predicate_skeleton(&self.predicates.compilation_target, &key) + .get_predicate_skeleton(&self.payload.predicates.compilation_target, &key) .map(|skeleton| skeleton.predicate_info()) .unwrap_or_default(); let local_predicate_info = self - .load_state - .wam + .wam_prelude .indices .get_local_predicate_skeleton( - self.load_state.compilation_target.clone(), - self.predicates.compilation_target.clone(), - self.load_state.listing_src_file_name(), - key.clone(), + payload_compilation_target, + self.payload.predicates.compilation_target, + listing_src_file_name, + key, ) .map(|skeleton| skeleton.predicate_info()) .unwrap_or_default(); @@ -2202,54 +2244,55 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } let do_incremental_compile = - if self.load_state.compilation_target == self.predicates.compilation_target { + if payload_compilation_target == self.payload.predicates.compilation_target { predicate_info.compile_incrementally() } else { local_predicate_info.is_multifile && predicate_info.compile_incrementally() }; - let predicates_len = self.predicates.len(); - let non_counted_bt = self.non_counted_bt_preds.contains(&key); + let predicates_len = self.payload.predicates.len(); + let non_counted_bt = self.payload.non_counted_bt_preds.contains(&key); if do_incremental_compile { - for term in self.predicates.predicates.drain(0..) { - self.load_state.incremental_compile_clause( - key.clone(), + let predicates = self.payload.predicates.take(); + + for term in predicates.predicates { + self.incremental_compile_clause( + key, term, - self.predicates.compilation_target.clone(), + payload_compilation_target, non_counted_bt, AppendOrPrepend::Append, )?; } } else { - if self.load_state.compilation_target != self.predicates.compilation_target { + if payload_compilation_target != self.payload.predicates.compilation_target { if !local_predicate_info.is_extensible { if predicate_info.is_multifile { println!( "Warning: overwriting multifile predicate {}:{}/{} because \ it was not locally declared multifile.", - self.predicates.compilation_target, key.0, key.1 + self.payload.predicates.compilation_target, key.0.as_str(), key.1 ); } if let Some(skeleton) = self - .load_state - .wam + .wam_prelude .indices - .remove_predicate_skeleton(&self.predicates.compilation_target, &key) + .remove_predicate_skeleton(&self.payload.predicates.compilation_target, &key) { if predicate_info.is_dynamic { let clause_clause_compilation_target = - match &self.predicates.compilation_target { + match self.payload.predicates.compilation_target { CompilationTarget::User => { - CompilationTarget::Module(clause_name!("builtins")) + CompilationTarget::Module(atom!("builtins")) } - module => module.clone(), + module => module, }; - self.load_state.retract_local_clauses_by_locs( + self.retract_local_clauses_by_locs( clause_clause_compilation_target, - (clause_name!("$clause"), 2), + (atom!("$clause"), 2), (0..skeleton.clauses.len()).map(Some).collect(), false, // the builtin M:'$clause'/2 is never dynamic. ); @@ -2257,10 +2300,10 @@ impl<'a, TS: TermStream> Loader<'a, TS> { predicate_info.is_dynamic = false; } - self.load_state.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::RemovedSkeleton( - self.predicates.compilation_target.clone(), - key.clone(), + payload_compilation_target, + key, skeleton, ), ); @@ -2270,7 +2313,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let settings = CodeGenSettings { global_clock_tick: if predicate_info.is_dynamic { - Some(self.load_state.wam.machine_st.global_clock) + Some(LS::machine_st(&mut self.payload).global_clock) } else { None }, @@ -2278,20 +2321,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { non_counted_bt, }; - let code_index = - self.load_state - .compile(key.clone(), &mut self.predicates, settings)?; + let predicates = self.payload.predicates.take(); + let code_index = self.compile(key, predicates, settings)?; - if let Some(filename) = self.load_state.listing_src_file_name() { - match self.load_state.wam.indices.modules.get_mut(&filename) { + if let Some(filename) = self.listing_src_file_name() { + match self.wam_prelude.indices.modules.get_mut(&filename) { Some(ref mut module) => { let index_ptr = code_index.get(); - let code_index = module.code_dir.entry(key.clone()).or_insert(code_index); + let code_index = module.code_dir.entry(key).or_insert(code_index); set_code_index( - &mut self.load_state.retraction_info, + &mut self.payload.retraction_info, &CompilationTarget::Module(filename), - key.clone(), + key, &code_index, index_ptr, ); @@ -2302,13 +2344,14 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } if predicate_info.is_dynamic { - self.load_state.wam.machine_st.global_clock += 1; + LS::machine_st(&mut self.payload).global_clock += 1; - let clauses_vec: Vec<_> = self.clause_clauses.drain(0..predicates_len).collect(); + let clauses_vec: Vec<_> = self.payload + .clause_clauses.drain(0..predicates_len).collect(); self.compile_clause_clauses( key, - self.predicates.compilation_target.clone(), + payload_compilation_target, clauses_vec.into_iter(), AppendOrPrepend::Append, )?; diff --git a/src/machine/copier.rs b/src/machine/copier.rs index fdd52c96d..bab1d110b 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -1,5 +1,6 @@ -use crate::machine::machine_indices::*; +use crate::atom_table::*; use crate::machine::stack::*; +use crate::types::*; use std::mem; use std::ops::IndexMut; @@ -7,20 +8,24 @@ use std::ops::IndexMut; type Trail = Vec<(Ref, HeapCellValue)>; #[derive(Debug, Clone, Copy)] -pub(crate) enum AttrVarPolicy { +pub enum AttrVarPolicy { DeepCopy, StripAttributes, } -pub(crate) trait CopierTarget: IndexMut { - fn deref(&self, val: Addr) -> Addr; - fn push(&mut self, val: HeapCellValue); +pub trait CopierTarget: IndexMut { + fn store(&self, value: HeapCellValue) -> HeapCellValue; + fn deref(&self, value: HeapCellValue) -> HeapCellValue; + fn push(&mut self, value: HeapCellValue); fn stack(&mut self) -> &mut Stack; - fn store(&self, val: Addr) -> Addr; fn threshold(&self) -> usize; } -pub(crate) fn copy_term(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) { +pub(crate) fn copy_term( + target: T, + addr: HeapCellValue, + attr_var_policy: AttrVarPolicy, +) { let mut copy_term_state = CopyTermState::new(target, attr_var_policy); copy_term_state.copy_term_impl(addr); } @@ -47,50 +52,51 @@ impl CopyTermState { #[inline] fn value_at_scan(&mut self) -> &mut HeapCellValue { - let scan = self.scan; - &mut self.target[scan] + &mut self.target[self.scan] } fn trail_list_cell(&mut self, addr: usize, threshold: usize) { - let trail_item = mem::replace( - &mut self.target[addr], - HeapCellValue::Addr(Addr::Lis(threshold)), - ); - - self.trail.push((Ref::HeapCell(addr), trail_item)); + let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold)); + self.trail.push((Ref::heap_cell(addr), trail_item)); } fn copy_list(&mut self, addr: usize) { for offset in 0..2 { - if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) { - if h >= self.old_h { - *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h)); - self.scan += 1; + read_heap_cell!(self.target[addr + offset], + (HeapCellValueTag::Lis, h) => { + if h >= self.old_h { + *self.value_at_scan() = list_loc_as_cell!(h); + self.scan += 1; - return; + return; + } } - } + _ => { + } + ) } let threshold = self.target.threshold(); - *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); + *self.value_at_scan() = list_loc_as_cell!(threshold); for i in 0..2 { - let hcv = self.target[addr + i].context_free_clone(); + let hcv = self.target[addr + i]; self.target.push(hcv); } let cdr = self .target - .store(self.target.deref(Addr::HeapCell(addr + 1))); + .store(self.target.deref(heap_loc_as_cell!(addr + 1))); - if !cdr.is_ref() { + if !cdr.is_var() { self.trail_list_cell(addr + 1, threshold); } else { - let car = self.target.store(self.target.deref(Addr::HeapCell(addr))); + let car = self + .target + .store(self.target.deref(heap_loc_as_cell!(addr))); - if !car.is_ref() { + if !car.is_var() { self.trail_list_cell(addr, threshold); } } @@ -98,187 +104,208 @@ impl CopyTermState { self.scan += 1; } - fn copy_partial_string(&mut self, addr: usize, n: usize) { - if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] { - if h >= self.old_h { - *self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n)); - self.scan += 1; + fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) { + read_heap_cell!(self.target[pstr_loc], + (HeapCellValueTag::PStrLoc, h) => { + if h >= self.old_h { + *self.value_at_scan() = match scan_tag { + HeapCellValueTag::PStrLoc => { + pstr_loc_as_cell!(h) + } + tag => { + debug_assert!(tag == HeapCellValueTag::PStrOffset); + pstr_offset_as_cell!(h) + } + }; - return; + self.scan += 1; + return; + } } - } + _ => {} + ); let threshold = self.target.threshold(); - *self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n)); - + *self.value_at_scan() = pstr_loc_as_cell!(threshold); self.scan += 1; - let (pstr, has_tail) = match &self.target[addr] { - &HeapCellValue::PartialString(ref pstr, has_tail) => { - (pstr.clone_from_offset(0), has_tail) - } - _ => { - unreachable!() - } - }; - - self.target - .push(HeapCellValue::PartialString(pstr, has_tail)); - - let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n)); - - let trail_item = mem::replace(&mut self.target[addr], replacement); + self.target.push(self.target[pstr_loc]); - self.trail.push((Ref::HeapCell(addr), trail_item)); + let replacement = pstr_loc_as_cell!(threshold); + let trail_item = mem::replace(&mut self.target[pstr_loc], replacement); - if has_tail { - let tail_addr = self.target[addr + 1].as_addr(addr + 1); - self.target.push(HeapCellValue::Addr(tail_addr)); - } + self.trail.push((Ref::heap_cell(pstr_loc), trail_item)); + self.target.push(self.target[pstr_loc + 1]); } - fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) { - match addr { - Addr::HeapCell(h) => { - self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); - self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier)); + fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) { + read_heap_cell!(addr, + (HeapCellValueTag::Var, h) => { + self.target[frontier] = heap_loc_as_cell!(frontier); + self.target[h] = heap_loc_as_cell!(frontier); - self.trail - .push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h)))); + self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h))); } - Addr::StackCell(fr, sc) => { - self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); - self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier); - - self.trail.push(( - Ref::StackCell(fr, sc), - HeapCellValue::Addr(Addr::StackCell(fr, sc)), - )); + (HeapCellValueTag::StackVar, s) => { + self.target[frontier] = heap_loc_as_cell!(frontier); + self.target.stack()[s] = heap_loc_as_cell!(frontier); + + self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s))); } - Addr::AttrVar(h) => { + (HeapCellValueTag::AttrVar, h) => { let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy { self.target.threshold() } else { frontier }; - self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold)); - self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + self.target[frontier] = heap_loc_as_cell!(threshold); + self.target[h] = heap_loc_as_cell!(threshold); - self.trail - .push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h)))); + self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h))); if let AttrVarPolicy::DeepCopy = self.attr_var_policy { self.target - .push(HeapCellValue::Addr(Addr::AttrVar(threshold))); + .push(attr_var_as_cell!(threshold)); - let list_val = self.target[h + 1].context_free_clone(); + let list_val = self.target[h + 1]; self.target.push(list_val); } } _ => { unreachable!() } + ); + } + + fn copy_var(&mut self, addr: HeapCellValue) { + let rd = self.target.deref(addr); + let ra = self.target.store(rd); + + read_heap_cell!(ra, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h >= self.old_h { + *self.value_at_scan() = rd; + self.scan += 1; + + return; + } + } + _ => {} + ); + + if addr == ra { + self.reinstantiate_var(addr, self.scan); + self.scan += 1; + } else { + *self.value_at_scan() = ra; + // self.copy_compound(rd, ra); } } - fn copy_var(&mut self, addr: Addr) { - let rd = self.target.store(self.target.deref(addr)); + /* + fn copy_compound(&mut self, rd: HeapCellValue, ra: HeapCellValue) { + let h = rd.get_value(); + let trail_item = self.target[h]; + let threshold = self.target.threshold(); + + self.trail.push((Ref::heap_cell(h), trail_item)); + self.target[self.scan].set_value(threshold); + + read_heap_cell!(ra, + (HeapCellValueTag::Atom, (_name, arity)) => { + self.target.push(ra); + + for i in 0..arity { + self.target.push(self.target[h + 1 + i]); + } + + self.target[h] = str_loc_as_cell!(self.scan + 1); + } + (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + self.target.push(ra); + self.target.push(self.target[h + 1]); - match rd { - Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { - *self.value_at_scan() = HeapCellValue::Addr(rd); - self.scan += 1; + self.target[h] = pstr_loc_as_cell!(self.scan + 1); } - _ if addr == rd => { - self.reinstantiate_var(addr, self.scan); - self.scan += 1; + (HeapCellValueTag::CStr, cstr_atom) => { + self.target[h] = atom_as_cstr_cell!(cstr_atom); + } + (HeapCellValueTag::Str, s) => { + self.copy_structure(s); + return; } _ => { - *self.value_at_scan() = HeapCellValue::Addr(rd); + *self.value_at_scan() = rd; + self.trail.pop(); + return; } - } + ); + + self.scan += 1; } + */ fn copy_structure(&mut self, addr: usize) { - match self.target[addr].context_free_clone() { - HeapCellValue::NamedStr(arity, name, fixity) => { + read_heap_cell!(self.target[addr], + (HeapCellValueTag::Atom, (name, arity)) => { let threshold = self.target.threshold(); - *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold)); + *self.value_at_scan() = str_loc_as_cell!(threshold); let trail_item = mem::replace( &mut self.target[addr], - HeapCellValue::Addr(Addr::Str(threshold)), + str_loc_as_cell!(threshold), ); - self.trail.push((Ref::HeapCell(addr), trail_item)); - - self.target - .push(HeapCellValue::NamedStr(arity, name, fixity)); + self.trail.push((Ref::heap_cell(addr), trail_item)); + self.target.push(atom_as_cell!(name, arity)); for i in 0..arity { - let hcv = self.target[addr + 1 + i].context_free_clone(); + let hcv = self.target[addr + 1 + i]; self.target.push(hcv); } } - HeapCellValue::Addr(Addr::Str(addr)) => { - *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr)) + (HeapCellValueTag::Str, h) => { + *self.value_at_scan() = str_loc_as_cell!(h); } _ => { unreachable!() } - } + ); self.scan += 1; } - fn copy_term_impl(&mut self, addr: Addr) { + fn copy_term_impl(&mut self, addr: HeapCellValue) { self.scan = self.target.threshold(); - self.target.push(HeapCellValue::Addr(addr)); + self.target.push(addr); while self.scan < self.target.threshold() { - match self.value_at_scan() { - &mut HeapCellValue::Addr(addr) => match addr { - Addr::Con(h) => { - let addr = self.target[h].as_addr(h); - - if addr == Addr::Con(h) { - *self.value_at_scan() = self.target[h].context_free_clone(); - } else { - *self.value_at_scan() = HeapCellValue::Addr(addr); - } - } - Addr::Lis(h) => { - if h >= self.old_h { - self.scan += 1; - } else { - self.copy_list(h); - } - } - addr @ Addr::AttrVar(_) - | addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) => { - self.copy_var(addr); - } - Addr::Str(addr) => { - self.copy_structure(addr); - } - Addr::PStrLocation(addr, n) => { - self.copy_partial_string(addr, n); - } - Addr::Stream(h) => { - *self.value_at_scan() = self.target[h].context_free_clone(); - } - _ => { + let addr = *self.value_at_scan(); + + read_heap_cell!(addr, + (HeapCellValueTag::Lis, h) => { + if h >= self.old_h { self.scan += 1; + } else { + self.copy_list(h); } - }, + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => { + self.copy_var(addr); + } + (HeapCellValueTag::Str, h) => { + self.copy_structure(h); + } + (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => { + self.copy_partial_string(addr.get_tag(), pstr_loc); + } _ => { self.scan += 1; } - } + ); } self.unwind_trail(); @@ -286,12 +313,117 @@ impl CopyTermState { fn unwind_trail(&mut self) { for (r, value) in self.trail.drain(0..) { - match r { - Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value, - Ref::StackCell(fr, sc) => { - self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0) - } + let index = r.get_value() as usize; + + match r.get_tag() { + RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value, + RefTag::StackCell => self.target.stack()[index] = value, } } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn copier_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom)); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + } + + // check that the original heap state is still intact. + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom)); + + assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(4)); + assert_eq!(wam.machine_st.heap[4], atom_as_cell!(f_atom, 2)); + assert_eq!(wam.machine_st.heap[5], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[6], atom_as_cell!(b_atom)); + + wam.machine_st.heap.clear(); + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + } + + print_heap_terms(wam.machine_st.heap[6..].iter(), 6); + + assert_eq!(wam.machine_st.heap[0], pstr_cell); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[2], pstr_second_cell); + assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4)); + assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0)); + assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(0i64))); + + assert_eq!(wam.machine_st.heap[7], pstr_cell); + assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9)); + assert_eq!(wam.machine_st.heap[9], pstr_second_cell); + assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11)); + assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7)); + assert_eq!(wam.machine_st.heap[12], fixnum_as_cell!(Fixnum::build_with(0i64))); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + } + + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6)); + assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4)); + assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[8], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[9], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[10], str_loc_as_cell!(6)); + } +} diff --git a/src/machine/gc.rs b/src/machine/gc.rs new file mode 100644 index 000000000..1b7f83fee --- /dev/null +++ b/src/machine/gc.rs @@ -0,0 +1,1101 @@ +use crate::atom_table::*; +use crate::machine::heap::*; +use crate::types::*; + +use core::marker::PhantomData; + +// TODO: rename to 'unmark_if_iter', 'mark_if_gc' +pub(crate) trait UnmarkPolicy { + fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool; + fn mark(heap: &mut [HeapCellValue], current: usize); + fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option + where + Self: Sized; +} + +pub(crate) struct IteratorUMP; + +impl UnmarkPolicy for IteratorUMP { + #[inline(always)] + fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool { + heap[current].set_mark_bit(false); + false + } + + #[inline(always)] + fn mark(_heap: &mut [HeapCellValue], _current: usize) {} + + #[inline(always)] + fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { + iter.forward_var() + } +} + +struct MarkerUMP {} + +impl UnmarkPolicy for MarkerUMP { + #[inline(always)] + fn unmark(_heap: &mut [HeapCellValue], _current: usize) -> bool { true } + + #[inline(always)] + fn mark(heap: &mut [HeapCellValue], current: usize) { + heap[current].set_mark_bit(true); + } + + #[inline(always)] + fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { + if iter.heap[iter.current + 1].get_mark_bit() { + return iter.forward_var(); + } + + let temp = iter.heap[iter.current].get_value(); + + iter.heap[iter.current].set_value(iter.next); + iter.current += 1; + + iter.next = iter.heap[iter.current].get_value(); + + iter.heap[iter.current].set_value(temp); + iter.heap[iter.current].set_mark_bit(true); + + None + } +} + +#[derive(Debug)] +pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> { + pub(crate) heap: &'a mut Vec, + orig_heap_len: usize, + start: usize, + current: usize, + next: usize, + _marker: PhantomData, +} + +impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { + fn drop(&mut self) { + if self.current == self.start { + self.heap.truncate(self.orig_heap_len); + return; + } + + while !self.backward() {} + + self.heap.truncate(self.orig_heap_len); + } +} + +impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { + pub(crate) fn new(heap: &'a mut Vec, cell: HeapCellValue) -> Self { + let orig_heap_len = heap.len(); + let start = orig_heap_len + 1; + + heap.push(cell); + heap.push(heap_loc_as_cell!(orig_heap_len)); + + heap[start].set_mark_bit(true); + let next = heap[start].get_value(); + + Self { + heap, + orig_heap_len, + start, + current: start, + next, + _marker: PhantomData, + } + } + + fn backward_and_return(&mut self) -> Option { + let current = self.current; + + if self.backward() { + self.heap[self.current].set_forwarding_bit(true); + self.heap[self.current].set_mark_bit(true); + } + + Some(self.heap[current]) + } + + fn forward_var(&mut self) -> Option { + if self.heap[self.next].get_mark_bit() { + return self.backward_and_return(); + } + + self.heap[self.current].set_forwarding_bit(true); + + if self.heap[self.next].get_forwarding_bit() == Some(true) { + return self.backward_and_return(); + } + + let temp = self.heap[self.next].get_value(); + + self.heap[self.next].set_value(self.current); + self.current = self.next; + self.next = temp; + + None + } + + fn forward(&mut self) -> Option { + loop { + if self.heap[self.current].get_forwarding_bit() != Some(true) { + match self.heap[self.current].get_tag() { + HeapCellValueTag::AttrVar => { + if let Some(cell) = UMP::forward_attr_var(self) { return Some(cell); } + } + HeapCellValueTag::Var => { + if let Some(cell) = self.forward_var() { return Some(cell); } + } + HeapCellValueTag::Str => { + if self.heap[self.next + 1].get_mark_bit() { + return self.backward_and_return(); + } + + let h = self.next; + let cell = self.heap[h]; + + self.heap[h].set_forwarding_bit(true); + self.heap[self.current].set_forwarding_bit(true); + + let arity = cell_as_atom_cell!(self.heap[h]).get_arity(); + + for cell in &mut self.heap[h + 1 .. h + arity + 1] { + cell.set_mark_bit(true); + } + + let last_cell_loc = h + arity; + + self.next = self.heap[last_cell_loc].get_value(); + self.heap[last_cell_loc].set_value(self.current); + self.current = last_cell_loc; + + return Some(cell); + } + HeapCellValueTag::Lis => { + if self.heap[self.next + 1].get_mark_bit() { + return self.backward_and_return(); + } + + self.heap[self.current].set_forwarding_bit(true); + self.heap[self.next+1].set_mark_bit(true); + + let last_cell_loc = self.next + 1; + + self.next = self.heap[last_cell_loc].get_value(); + self.heap[last_cell_loc].set_value(self.current); + self.current = last_cell_loc; + + return Some(list_loc_as_cell!(last_cell_loc - 1)); + } + HeapCellValueTag::PStrLoc => { + let h = self.next; + let cell = self.heap[h]; + + self.heap[self.current].set_forwarding_bit(true); + + if self.heap[h+1].get_mark_bit() { + return self.backward_and_return(); + } + + if self.heap[h].get_tag() == HeapCellValueTag::PStr { + self.heap[h+1].set_mark_bit(true); + + self.next = self.heap[h+1].get_value(); + self.heap[h+1].set_value(self.current); + self.heap[h].set_forwarding_bit(true); + + self.current = h+1; + } else { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + + self.next = self.heap[h].get_value(); + self.heap[h].set_value(self.current); + self.current = h; + + if self.heap[h].get_forwarding_bit() == Some(true) { + continue; + } + } + + return Some(cell); + } + HeapCellValueTag::PStrOffset => { + let h = self.next; + + UMP::mark(self.heap, self.current+1); + + if self.heap[h].get_tag() == HeapCellValueTag::PStr { + if self.heap[h+1].get_mark_bit() { + return self.backward_and_return(); + } + + self.heap[h+1].set_mark_bit(true); + self.heap[self.current].set_forwarding_bit(true); + + self.next = self.heap[h+1].get_value(); + self.heap[h+1].set_value(self.current); + self.current = h+1; + } else { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr); + + self.next = self.heap[h].get_value(); + self.heap[h].set_value(self.current); + self.current = h; + } + } + HeapCellValueTag::StackVar => { + let cell = self.heap[self.current]; + self.heap[self.current].set_forwarding_bit(true); + return Some(cell); + } + _ => { + if self.heap[self.current].get_mark_bit() { + let current = self.current; + + if self.backward() { + return None; + } + + return Some(self.heap[current]); + } + + return self.backward_and_return(); + } + } + } else { + if self.backward() { + return None; + } + } + } + } + + fn backward(&mut self) -> bool { + while !self.heap[self.current].get_mark_bit() { + let temp = self.heap[self.current].get_value(); + + UMP::mark(self.heap, self.current); + + self.heap[self.current].set_forwarding_bit(false); + self.heap[self.current].set_value(self.next); + + self.next = self.current; + self.current = temp; + } + + self.heap[self.current].set_forwarding_bit(false); + + let unmark_is_no_op = UMP::unmark(self.heap, self.current); + + if self.current == self.start { + return true; + } + + if unmark_is_no_op { // if true, the marker is running. + let cell = self.heap[self.current]; + + // a cyclic root must be handled specially when marking. + if self.next >= self.orig_heap_len && cell.is_ref() { + debug_assert!(cell.get_tag() != HeapCellValueTag::PStrOffset); + + self.heap[self.current].set_mark_bit(false); + let prev_current = self.heap[self.current].get_value(); + + if !self.heap[prev_current].is_forwarded() { + return self.backward(); + } + } + } + + self.current -= 1; + + let temp = self.heap[self.current+1].get_value(); + + self.heap[self.current+1].set_value(self.next); + self.next = self.heap[self.current].get_value(); + self.heap[self.current].set_value(temp); + + false + } +} + +impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> { + type Item = HeapCellValue; + + #[inline] + fn next(&mut self) -> Option { + self.forward() + } +} + +pub fn mark_cells(heap: &mut Heap, cell: HeapCellValue) { + let mut iter = StacklessPreOrderHeapIter::::new(heap, cell); + while let Some(_) = iter.forward() {} +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn heap_marking_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st + .heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom)); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(0)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + // make the structure doubly cyclic. + wam.machine_st.heap[2] = str_loc_as_cell!(0); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(1)) + ] + )); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(f_atom, 4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), str_loc_as_cell!(1)); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!()); + + wam.machine_st.heap.pop(); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), heap_loc_as_cell!(0)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + // make the list doubly cyclic. + wam.machine_st.heap[3] = heap_loc_as_cell!(0); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + // term is: [a, ] + let stream = Stream::from_static_string("test", &mut wam.machine_st.arena); + let stream_cell = + HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons)); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(stream_cell); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), stream_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + // now a cycle of variables. + + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + + wam.machine_st.heap.pop(); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(4)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(4)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(3)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(2)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(1)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap.truncate(4); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap[3] = pstr_loc_as_cell!(5); + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(5)); + + assert!(wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(wam.machine_st.heap[3].get_mark_bit()); + assert!(!wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(wam.machine_st.heap[6].get_mark_bit()); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(4)); + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_second_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(7)); + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_offset_as_cell!(1)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(7)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(5)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(4)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(2)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(1)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.clear(); + + // embedded cyclic partial string. + + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(4)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(3))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), list_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap.push(heap_loc_as_cell!(4)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(4)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(3))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), list_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(4)); + + wam.machine_st.heap.clear(); + + // a chain of variables, ending in a self-referential variable. + + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3)); + + wam.machine_st.heap.clear(); + + // print L = [L|L]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(1)); + + wam.machine_st.heap.clear(); + + // term is [X,f(Y),Z]. + // Z is an attributed variable, but has a variable attributes list. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 + wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 + wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 + wam.machine_st.heap.push(heap_loc_as_cell!(8)); + wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 + wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 + wam.machine_st.heap.push(list_loc_as_cell!(9)); + wam.machine_st.heap.push(heap_loc_as_cell!(9)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. + wam.machine_st.heap.push(heap_loc_as_cell!(12)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(12)); + + // now populate the attributes list. + let clpz_atom = atom!("clpz"); + let p_atom = atom!("p"); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + cell.set_forwarding_bit(false); + } + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 + wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 + wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 + wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 + wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 + wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 + wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 + wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 + wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 + wam.machine_st.heap.push(empty_list_as_cell!()); // 21 + wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 + wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + cell.set_forwarding_bit(false); + } + + // push some unrelated nonsense cells to the heap and check that they + // are unmarked after the marker has finished at 0. + wam.machine_st.heap.push(heap_loc_as_cell!(5)); + wam.machine_st.heap.push(heap_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&mut wam.machine_st.heap[0..24]); + + for cell in &wam.machine_st.heap[24..] { + assert_eq!(cell.get_mark_bit(), false); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[24]), heap_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[25]), heap_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[26]), list_loc_as_cell!(5)); + + wam.machine_st.heap.clear(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap.len(), 1); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(list_loc_as_cell!(8)); + wam.machine_st.heap.push(str_loc_as_cell!(4)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(7)); + + assert_eq!(wam.machine_st.heap.len(), 10); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(atom!("g"), 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("y"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("="), 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), atom_as_cell!(atom!("X"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), list_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), str_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("f"), 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(1)); + } +} diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 067bfa939..462aacbce 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1,140 +1,282 @@ -use core::marker::PhantomData; - -use prolog_parser::ast::Constant; - +use crate::arena::*; +use crate::atom_table::*; +use crate::forms::*; use crate::machine::machine_indices::*; use crate::machine::partial_string::*; -use crate::machine::raw_block::*; +use crate::parser::ast::*; +use crate::types::*; + +use ordered_float::OrderedFloat; +use rug::{Integer, Rational}; use std::convert::TryFrom; -use std::mem; -use std::ops::{Index, IndexMut}; -use std::ptr; -#[derive(Debug)] -pub(crate) struct StandardHeapTraits {} +pub(crate) type Heap = Vec; -impl RawBlockTraits for StandardHeapTraits { +impl From for HeapCellValue { #[inline] - fn init_size() -> usize { - 256 * mem::size_of::() + fn from(literal: Literal) -> Self { + match literal { + Literal::Atom(name) => atom_as_cell!(name), + Literal::Char(c) => char_as_cell!(c), + Literal::Fixnum(n) => fixnum_as_cell!(n), + Literal::Integer(bigint_ptr) => { + typed_arena_ptr_as_cell!(bigint_ptr) + } + Literal::Rational(bigint_ptr) => { + typed_arena_ptr_as_cell!(bigint_ptr) + } + Literal::Float(f) => HeapCellValue::from(f), + Literal::String(s) => { + if s == atom!("") { + empty_list_as_cell!() + } else { + string_as_cstr_cell!(s) + } + } + } } +} - #[inline] - fn align() -> usize { - mem::align_of::() +impl TryFrom for Literal { + type Error = (); + + fn try_from(value: HeapCellValue) -> Result { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + Ok(Literal::Atom(name)) + } else { + Err(()) + } + } + (HeapCellValueTag::Char, c) => { + Ok(Literal::Char(c)) + } + (HeapCellValueTag::Fixnum, n) => { + Ok(Literal::Fixnum(n)) + } + (HeapCellValueTag::F64, f) => { + Ok(Literal::Float(f)) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Integer, n) => { + Ok(Literal::Integer(n)) + } + (ArenaHeaderTag::Rational, n) => { + Ok(Literal::Rational(n)) + } + _ => { + Err(()) + } + ) + } + (HeapCellValueTag::CStr, cstr_atom) => { + Ok(Literal::String(cstr_atom)) + } + _ => { + Err(()) + } + ) } } -#[derive(Debug)] -pub(crate) struct HeapTemplate { - buf: RawBlock, - _marker: PhantomData, -} +// sometimes we need to dereference variables that are found only in +// the heap without access to the full WAM (e.g., while detecting +// cycles in terms), and which therefore may only point other cells in +// the heap (thanks to the design of the WAM). +pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue { + loop { + let new_value = read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + heap[h] + } + _ => { + value + } + ); -pub(crate) type Heap = HeapTemplate; + if new_value != value && new_value.is_var() { + value = new_value; + continue; + } -impl Drop for HeapTemplate { - fn drop(&mut self) { - self.clear(); - self.buf.deallocate(); + return value; } } -#[derive(Debug)] -pub(crate) struct HeapIntoIter { - offset: usize, - buf: RawBlock, +pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue { + read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + heap[h] + } + _ => { + value + } + ) } -impl Drop for HeapIntoIter { - fn drop(&mut self) { - let mut heap = HeapTemplate { - buf: self.buf.take(), - _marker: PhantomData, - }; - - heap.truncate(self.offset / mem::size_of::()); - heap.buf.deallocate(); +#[allow(dead_code)] +pub fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { + for (index, term) in heap.enumerate() { + println!("{} : {:?}", h + index, term); } } -impl Iterator for HeapIntoIter { - type Item = HeapCellValue; - - fn next(&mut self) -> Option { - let ptr = self.buf.base as usize + self.offset; - self.offset += mem::size_of::(); - - if ptr < self.buf.top as usize { - unsafe { Some(ptr::read(ptr as *const HeapCellValue)) } - } else { - None +#[inline] +pub(crate) fn put_complete_string( + heap: &mut Heap, + s: &str, + atom_tbl: &mut AtomTable, +) -> HeapCellValue { + match allocate_pstr(heap, s, atom_tbl) { + Some(h) => { + heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr. + + if heap.len() == h + 1 { + let pstr_atom = cell_as_atom!(heap[h]); + heap[h] = atom_as_cstr_cell!(pstr_atom); + heap_loc_as_cell!(h) + } else { + heap.push(empty_list_as_cell!()); + pstr_loc_as_cell!(h) + } + } + None => { + empty_list_as_cell!() } } } -#[derive(Debug)] -pub(crate) struct HeapIter<'a, T: RawBlockTraits> { - offset: usize, - buf: &'a RawBlock, -} - -impl<'a, T: RawBlockTraits> HeapIter<'a, T> { - pub(crate) fn new(buf: &'a RawBlock, offset: usize) -> Self { - HeapIter { buf, offset } +#[inline] +pub(crate) fn put_partial_string( + heap: &mut Heap, + s: &str, + atom_tbl: &mut AtomTable, +) -> HeapCellValue { + match allocate_pstr(heap, s, atom_tbl) { + Some(h) => { + pstr_loc_as_cell!(h) + } + None => { + empty_list_as_cell!() + } } } -impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> { - type Item = &'a HeapCellValue; +#[inline] +pub(crate) fn allocate_pstr( + heap: &mut Heap, + mut src: &str, + atom_tbl: &mut AtomTable, +) -> Option { + let orig_h = heap.len(); + + loop { + if src == "" { + return if orig_h == heap.len() { + None + } else { + let tail_h = heap.len() - 1; + heap[tail_h] = heap_loc_as_cell!(tail_h); + + Some(orig_h) + }; + } + + let h = heap.len(); + + let (pstr, rest_src) = match PartialString::new(src, atom_tbl) { + Some(tuple) => tuple, + None => { + if src.len() > '\u{0}'.len_utf8() { + src = &src['\u{0}'.len_utf8()..]; + continue; + } else if orig_h == h { + return None; + } else { + heap[h - 1] = heap_loc_as_cell!(h - 1); + return Some(orig_h); + } + } + }; - fn next(&mut self) -> Option { - let ptr = self.buf.base as usize + self.offset; - self.offset += mem::size_of::(); + heap.push(string_as_pstr_cell!(pstr)); - if ptr < self.buf.top as usize { - unsafe { Some(&*(ptr as *const _)) } + if rest_src != "" { + heap.push(pstr_loc_as_cell!(h + 2)); + src = rest_src; } else { - None + heap.push(heap_loc_as_cell!(h + 1)); + return Some(orig_h); } } } -#[allow(dead_code)] -pub(crate) fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { - for (index, term) in heap.enumerate() { - println!("{} : {}", h + index, term); +pub fn filtered_iter_to_heap_list>( + heap: &mut Heap, + values: impl Iterator, + filter_fn: impl Fn(&Heap, HeapCellValue) -> bool, +) -> usize { + let head_addr = heap.len(); + let mut h = head_addr; + + for value in values { + let value = value.into(); + + if filter_fn(heap, value) { + heap.push(list_loc_as_cell!(h + 1)); + heap.push(value); + + h += 2; + } } -} -#[derive(Debug)] -pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> { - offset: usize, - buf: &'a mut RawBlock, + heap.push(empty_list_as_cell!()); + + head_addr } -impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> { - pub(crate) fn new(buf: &'a mut RawBlock, offset: usize) -> Self { - HeapIterMut { buf, offset } - } +#[inline(always)] +pub fn iter_to_heap_list(heap: &mut Heap, values: Iter) -> usize +where + Iter: Iterator, + SrcT: Into, +{ + filtered_iter_to_heap_list(heap, values, |_, _| true) } -impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> { - type Item = &'a mut HeapCellValue; +pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { + let extract_integer = |s: usize| -> Option { + match Number::try_from(heap[s]) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + Ok(Number::Integer(n)) => n.to_usize(), + _ => None, + } + }; - fn next(&mut self) -> Option { - let ptr = self.buf.base as usize + self.offset; - self.offset += mem::size_of::(); + read_heap_cell!(addr, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); - if ptr < self.buf.top as usize { - unsafe { Some(&mut *(ptr as *mut _)) } - } else { + if name == atom!("dir_entry") && arity == 1 { + extract_integer(s+1).map(LocalCodePtr::DirEntry) + } else { + panic!( + "to_local_code_ptr crashed with p.i. {}/{}", + name.as_str(), + arity, + ); + } + } + _ => { None } - } + ) } +/* impl HeapTemplate { #[inline] pub(crate) fn new() -> Self { @@ -144,67 +286,40 @@ impl HeapTemplate { } } - #[inline] - pub(crate) fn clone(&self, h: usize) -> HeapCellValue { - match &self[h] { - &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr), - &HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()), - &HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()), - &HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()), - &HeapCellValue::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)), - &HeapCellValue::NamedStr(arity, ref name, ref op) => { - HeapCellValue::NamedStr(arity, name.clone(), op.clone()) - } - &HeapCellValue::PartialString(..) => HeapCellValue::Addr(Addr::PStrLocation(h, 0)), - &HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()), - &HeapCellValue::Stream(_) => HeapCellValue::Addr(Addr::Stream(h)), - &HeapCellValue::TcpListener(_) => HeapCellValue::Addr(Addr::TcpListener(h)), - } - } - - #[inline] - pub(crate) fn put_complete_string(&mut self, s: &str) -> Addr { - if s.is_empty() { - return Addr::EmptyList; - } - - let addr = self.allocate_pstr(s); - self.pop(); - - let h = self.h(); - - match &mut self[h - 1] { - &mut HeapCellValue::PartialString(_, ref mut has_tail) => { - *has_tail = false; - } - _ => { - unreachable!() - } - } - - addr - } - - #[inline] - pub(crate) fn put_constant(&mut self, c: Constant) -> Addr { - match c { - Constant::Atom(name, op) => Addr::Con(self.push(HeapCellValue::Atom(name, op))), - Constant::Char(c) => Addr::Char(c), - Constant::EmptyList => Addr::EmptyList, - Constant::Fixnum(n) => Addr::Fixnum(n), - Constant::Integer(n) => Addr::Con(self.push(HeapCellValue::Integer(n))), - Constant::Rational(r) => Addr::Con(self.push(HeapCellValue::Rational(r))), - Constant::Float(f) => Addr::Float(f), - Constant::String(s) => { - if s.is_empty() { - Addr::EmptyList - } else { - self.put_complete_string(&s) + /* + // TODO: move this to the WAM, then remove the temporary (and by + // then, unnecessary and impossible) "arena" argument. OR, remove + // this thing totally! if we can. by that I mean, just convert a + // little to a HeapCellValue. don't bother writing to the + // heap at all. Each of these data is either already inlinable in a + // HeapCellValue or a pointer to an GC'ed location in memory. + #[inline] + pub(crate) fn put_literal(&mut self, literal: Literal) -> HeapCellValue { + match literal { + Literal::Atom(name) => atom_as_cell!(name), + Literal::Char(c) => char_as_cell!(c), + Literal::EmptyList => empty_list_as_cell!(), + Literal::Fixnum(n) => fixnum_as_cell!(n), + Literal::Integer(bigint_ptr) => { + let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr)); + self[h] + } + Literal::Rational(bigint_ptr) => { + let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr)); + self[h] } + Literal::Float(f) => typed_arena_ptr_as_cell!(f), + Literal::String(s) => { + if s.as_str().is_empty() { + empty_list_as_cell!() + } else { + // TODO: how do we know where the tail is located?? well, there is no tail. separate tag? + untyped_arena_ptr_as_cell!(s) // self.put_complete_string(arena, &s) + } + } // Literal::Usize(n) => Addr::Usize(n), } - Constant::Usize(n) => Addr::Usize(n), } - } + */ #[inline] pub(crate) fn is_empty(&self) -> bool { @@ -225,14 +340,14 @@ impl HeapTemplate { let h = self.h(); unsafe { - let new_top = self.buf.new_block(mem::size_of::()); - ptr::write(self.buf.top as *mut _, val); - self.buf.top = new_top; + let new_ptr = self.buf.alloc(mem::size_of::()); + ptr::write(new_ptr as *mut _, val); } h } + /* #[inline] pub(crate) fn atom_at(&self, h: usize) -> bool { if let HeapCellValue::Atom(..) = &self[h] { @@ -265,76 +380,17 @@ impl HeapTemplate { val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)), } } - - #[inline] - pub(crate) fn allocate_pstr(&mut self, src: &str) -> Addr { - self.write_pstr(src).unwrap_or_else(|| Addr::EmptyList) - } - - #[inline] - fn write_pstr(&mut self, mut src: &str) -> Option { - let orig_h = self.h(); - - loop { - if src == "" { - return if orig_h == self.h() { - None - } else { - let tail_h = self.h() - 1; - self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h)); - - Some(Addr::PStrLocation(orig_h, 0)) - }; - } - - let h = self.h(); - - let (pstr, rest_src) = match PartialString::new(src) { - Some(tuple) => tuple, - None => { - if src.len() > '\u{0}'.len_utf8() { - src = &src['\u{0}'.len_utf8()..]; - continue; - } else if orig_h == h { - return None; - } else { - self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1)); - return Some(Addr::PStrLocation(orig_h, 0)); - } - } - }; - - self.push(HeapCellValue::PartialString(pstr, true)); - - if rest_src != "" { - self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0))); - src = rest_src; - } else { - self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); - return Some(Addr::PStrLocation(orig_h, 0)); - } - } - } + */ #[inline] pub(crate) fn truncate(&mut self, h: usize) { - let new_top = h * mem::size_of::() + self.buf.base as usize; - let mut h = new_top; - - unsafe { - while h as *const _ < self.buf.top { - let val = h as *mut HeapCellValue; - ptr::drop_in_place(val); - h += mem::size_of::(); - } - } - - self.buf.top = new_top as *const _; + let new_ptr = self.buf.top as usize - h * mem::size_of::(); + self.buf.ptr = new_ptr as *mut _; } #[inline] pub(crate) fn h(&self) -> usize { - (self.buf.top as usize - self.buf.base as usize) / mem::size_of::() + (self.buf.top as usize - self.buf.ptr as usize) / mem::size_of::() } pub(crate) fn append(&mut self, vals: Vec) { @@ -350,84 +406,7 @@ impl HeapTemplate { } } - pub(crate) fn to_list(&mut self, values: Iter) -> usize - where - Iter: Iterator, - SrcT: Into, - { - let head_addr = self.h(); - let mut h = head_addr; - - for value in values.map(|v| v.into()) { - self.push(HeapCellValue::Addr(Addr::Lis(h + 1))); - self.push(value); - - h += 2; - } - - self.push(HeapCellValue::Addr(Addr::EmptyList)); - - head_addr - } - - /* Create an iterator starting from the passed offset. */ - pub(crate) fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> { - HeapIter::new(&self.buf, offset * mem::size_of::()) - } - - pub(crate) fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> { - HeapIterMut::new(&mut self.buf, offset * mem::size_of::()) - } - - pub(crate) fn into_iter(mut self) -> HeapIntoIter { - HeapIntoIter { - buf: self.buf.take(), - offset: 0, - } - } - - pub(crate) fn extend>(&mut self, iter: Iter) { - for hcv in iter { - self.push(hcv); - } - } - - pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option { - let extract_integer = |s: usize| -> Option { - match &self[s] { - &HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(), - &HeapCellValue::Integer(ref n) => n.to_usize(), - _ => None, - } - }; - - match addr { - Addr::Str(s) => { - match &self[*s] { - HeapCellValue::NamedStr(arity, ref name, _) => { - match (name.as_str(), *arity) { - ("dir_entry", 1) => extract_integer(s + 1).map(LocalCodePtr::DirEntry), - /* - ("top_level", 2) => { - if let Some(chunk_num) = extract_integer(s+1) { - if let Some(p) = extract_integer(s+2) { - return Some(LocalCodePtr::TopLevel(chunk_num, p)); - } - } - - None - } - */ - _ => None, - } - } - _ => unreachable!(), - } - } - _ => None, - } - } - + /* TODO: get rid of this!! #[inline] pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> { match addr { @@ -437,6 +416,20 @@ impl HeapTemplate { addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)), } } + */ +} + +impl Index for HeapTemplate { + type Output = HeapCellValue; + + #[inline] + fn index(&self, index: u64) -> &Self::Output { + unsafe { + let ptr = + self.buf.top as usize - (index as usize + 1) * mem::size_of::(); + &*(ptr as *const HeapCellValue) + } + } } impl Index for HeapTemplate { @@ -445,7 +438,7 @@ impl Index for HeapTemplate { #[inline] fn index(&self, index: usize) -> &Self::Output { unsafe { - let ptr = self.buf.base as usize + index * mem::size_of::(); + let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); &*(ptr as *const HeapCellValue) } } @@ -455,8 +448,9 @@ impl IndexMut for HeapTemplate { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { unsafe { - let ptr = self.buf.base as usize + index * mem::size_of::(); + let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); &mut *(ptr as *mut HeapCellValue) } } } +*/ diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index d0a0d1264..2b8c0fb51 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -1,26 +1,21 @@ +use crate::clause_types::*; +use crate::forms::*; +use crate::machine::loader::*; +use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::preprocessor::*; use crate::machine::term_stream::*; use crate::machine::*; - -use prolog_parser::clause_name; +use crate::parser::ast::*; use indexmap::IndexSet; use ref_thread_local::RefThreadLocal; use slice_deque::{sdeq, SliceDeque}; -type ModuleOpExports = Vec<(OpDecl, Option<(usize, Specifier)>)>; - -/* - * We will want to borrow these fields from Loader separately, without - * restricting access to other fields by borrowing them mutably. - */ -pub(super) struct LoadState<'a> { - pub(super) compilation_target: CompilationTarget, - pub(super) module_op_exports: ModuleOpExports, - pub(super) retraction_info: RetractionInfo, - pub(super) wam: &'a mut Machine, -} +use std::fs::File; +use std::mem; + +pub(super) type ModuleOpExports = Vec<(OpDecl, Option)>; pub(super) fn set_code_index( retraction_info: &mut RetractionInfo, @@ -42,10 +37,10 @@ pub(super) fn set_code_index( CompilationTarget::Module(ref module_name) => { if IndexPtr::Undefined == code_index.get() { code_index.set(code_ptr); - RetractionRecord::AddedModulePredicate(module_name.clone(), key) + RetractionRecord::AddedModulePredicate(*module_name, key) } else { let replaced = code_index.replace(code_ptr); - RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, replaced) + RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced) } } }; @@ -69,18 +64,17 @@ fn add_op_decl_as_module_export( */ match op_decl.insert_into_op_dir(wam_op_dir) { - Some((prec, spec)) => { + Some(op_desc) => { retraction_info.push_record(RetractionRecord::ReplacedUserOp( - op_decl.clone(), - prec, - spec, + *op_decl, + op_desc, )); - module_op_exports.push((op_decl.clone(), Some((prec, spec)))); + module_op_exports.push((*op_decl, Some(op_desc))); } None => { - retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone())); - module_op_exports.push((op_decl.clone(), None)); + retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); + module_op_exports.push((*op_decl, None)); } } @@ -94,31 +88,29 @@ pub(super) fn add_op_decl( op_decl: &OpDecl, ) { match op_decl.insert_into_op_dir(op_dir) { - Some((prec, spec)) => match &compilation_target { + Some(op_desc) => match &compilation_target { CompilationTarget::User => { retraction_info.push_record(RetractionRecord::ReplacedUserOp( - op_decl.clone(), - prec, - spec, + *op_decl, + op_desc, )); } CompilationTarget::Module(ref module_name) => { retraction_info.push_record(RetractionRecord::ReplacedModuleOp( - module_name.clone(), - op_decl.clone(), - prec, - spec, + *module_name, + *op_decl, + op_desc, )); } }, None => match &compilation_target { CompilationTarget::User => { - retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone())); + retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); } CompilationTarget::Module(ref module_name) => { retraction_info.push_record(RetractionRecord::AddedModuleOp( - module_name.clone(), - op_decl.clone(), + *module_name, + *op_decl, )); } }, @@ -135,16 +127,16 @@ pub(super) fn import_module_exports( ) -> Result<(), SessionError> { for export in imported_module.module_decl.exports.iter() { match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { - meta_predicates.insert(key.clone(), meta_specs.clone()); + meta_predicates.insert(key, meta_specs.clone()); } if let Some(src_code_index) = imported_module.code_dir.get(&key) { let target_code_index = code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(); @@ -157,8 +149,8 @@ pub(super) fn import_module_exports( ); } else { return Err(SessionError::ModuleDoesNotContainExport( - imported_module.module_decl.name.clone(), - (name.clone(), *arity), + imported_module.module_decl.name, + key, )); } } @@ -183,8 +175,8 @@ fn import_module_exports_into_module( ) -> Result<(), SessionError> { for export in imported_module.module_decl.exports.iter() { match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { meta_predicates.insert(key.clone(), meta_specs.clone()); @@ -192,7 +184,7 @@ fn import_module_exports_into_module( if let Some(src_code_index) = imported_module.code_dir.get(&key) { let target_code_index = code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(); @@ -206,7 +198,7 @@ fn import_module_exports_into_module( } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), - (name.clone(), *arity), + (*name, *arity), )); } } @@ -241,8 +233,8 @@ fn import_qualified_module_exports( } match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { meta_predicates.insert(key.clone(), meta_specs.clone()); @@ -264,7 +256,7 @@ fn import_qualified_module_exports( } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), - (name.clone(), *arity), + (*name, *arity), )); } } @@ -294,16 +286,16 @@ fn import_qualified_module_exports_into_module( } match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { - meta_predicates.insert(key.clone(), meta_specs.clone()); + meta_predicates.insert(key, meta_specs.clone()); } if let Some(src_code_index) = imported_module.code_dir.get(&key) { let target_code_index = code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(); @@ -317,7 +309,7 @@ fn import_qualified_module_exports_into_module( } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), - (name.clone(), *arity), + (*name, *arity), )); } } @@ -337,15 +329,15 @@ fn import_qualified_module_exports_into_module( Ok(()) } -impl<'a> LoadState<'a> { - pub(super) fn retract_local_clauses( +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { + pub(super) fn retract_local_clauses_impl( &mut self, compilation_target: CompilationTarget, key: PredicateKey, clause_locs: &SliceDeque, ) { let result_opt = self - .wam + .wam_prelude .indices .get_predicate_skeleton(&compilation_target, &key) .map(|skeleton| { @@ -377,15 +369,18 @@ impl<'a> LoadState<'a> { mut clause_target_poses: Vec>, is_dynamic: bool, ) { - let old_compilation_target = mem::replace(&mut self.compilation_target, compilation_target); + let old_compilation_target = mem::replace( + &mut self.payload.compilation_target, + compilation_target, + ); while let Some(target_pos_opt) = clause_target_poses.pop() { match target_pos_opt { Some(target_pos) if is_dynamic => { - self.retract_dynamic_clause(key.clone(), target_pos); + self.retract_dynamic_clause(key, target_pos); } Some(target_pos) => { - self.retract_clause(key.clone(), target_pos); + self.retract_clause(key, target_pos); } None => { // Here because the clause was been removed @@ -395,7 +390,7 @@ impl<'a> LoadState<'a> { } } - self.compilation_target = old_compilation_target; + self.payload.compilation_target = old_compilation_target; } pub(super) fn retract_local_clause_clauses( @@ -403,20 +398,23 @@ impl<'a> LoadState<'a> { clause_clause_compilation_target: CompilationTarget, clause_locs: &SliceDeque, ) { - let key = (clause_name!("$clause"), 2); - - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - clause_clause_compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let key = (atom!("$clause"), 2); + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + clause_clause_compilation_target, + listing_src_file_name, + key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::RemovedLocalSkeletonClauseLocations( - self.compilation_target.clone(), - clause_clause_compilation_target.clone(), - key.clone(), + payload_compilation_target, + clause_clause_compilation_target, + key, mem::replace(&mut skeleton.clause_clause_locs, sdeq![]), ), ); @@ -430,7 +428,7 @@ impl<'a> LoadState<'a> { } }; - self.retract_local_clauses(clause_clause_compilation_target, key, &clause_locs); + self.retract_local_clauses_impl(clause_clause_compilation_target, key, &clause_locs); } pub(super) fn try_term_to_tl( @@ -450,19 +448,18 @@ impl<'a> LoadState<'a> { #[inline] pub(super) fn remove_module_op_exports(&mut self) { - for (mut op_decl, record) in self.module_op_exports.drain(0..) { - op_decl.remove(&mut self.wam.indices.op_dir); + for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) { + op_decl.remove(&mut self.wam_prelude.indices.op_dir); - if let Some((prec, spec)) = record { - op_decl.prec = prec; - op_decl.spec = spec; - op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir); + if let Some(op_desc) = record { + op_decl.op_desc = op_desc; + op_decl.insert_into_op_dir(&mut self.wam_prelude.indices.op_dir); } } } - pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: ClauseName) { - let removed_module = match self.wam.indices.modules.remove(&module_name) { + pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: Atom) { + let removed_module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(module) => module, None => return, }; @@ -479,7 +476,7 @@ impl<'a> LoadState<'a> { if code_index.get() != IndexPtr::Undefined { let old_index_ptr = code_index.replace(IndexPtr::Undefined); - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::ReplacedModulePredicate( module_name.clone(), key.clone(), @@ -488,11 +485,11 @@ impl<'a> LoadState<'a> { } } - self.wam.indices.modules.insert(module_name, removed_module); + self.wam_prelude.indices.modules.insert(module_name, removed_module); } - pub(super) fn remove_module_exports(&mut self, module_name: ClauseName) { - let removed_module = match self.wam.indices.modules.remove(&module_name) { + pub(super) fn remove_module_exports(&mut self, module_name: Atom) { + let removed_module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(module) => module, None => return, }; @@ -503,7 +500,7 @@ impl<'a> LoadState<'a> { op_dir: &mut OpDir, retraction_info: &mut RetractionInfo, predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord, - op_retractor: impl Fn(OpDecl, usize, Specifier) -> RetractionRecord, + op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord, ) { for export in removed_module.module_decl.exports.iter() { match export { @@ -513,55 +510,51 @@ impl<'a> LoadState<'a> { if module_code_index.get() == target_code_index.get() => { let old_index_ptr = target_code_index.replace(IndexPtr::Undefined); - - retraction_info - .push_record(predicate_retractor(key.clone(), old_index_ptr)); + retraction_info.push_record(predicate_retractor(*key, old_index_ptr)); } _ => {} } } ModuleExport::OpDecl(op_decl) => { let op_dir_value_opt = - op_dir.remove(&(op_decl.name.clone(), op_decl.fixity())); - - if let Some(op_dir_value) = op_dir_value_opt { - let (prec, spec) = op_dir_value.shared_op_desc().get(); + op_dir.remove(&(op_decl.name, fixity(op_decl.op_desc.get_spec() as u32))); - retraction_info.push_record(op_retractor(op_decl.clone(), prec, spec)); + if let Some(op_desc) = op_dir_value_opt { + retraction_info.push_record(op_retractor(*op_decl, op_desc)); } } } } } - match &self.compilation_target { + match self.payload.compilation_target { CompilationTarget::User => { remove_module_exports( &removed_module, - &mut self.wam.indices.code_dir, - &mut self.wam.indices.op_dir, - &mut self.retraction_info, + &mut self.wam_prelude.indices.code_dir, + &mut self.wam_prelude.indices.op_dir, + &mut self.payload.retraction_info, RetractionRecord::ReplacedUserPredicate, RetractionRecord::ReplacedUserOp, ); } - CompilationTarget::Module(ref target_module_name) - if target_module_name.as_str() != module_name.as_str() => + CompilationTarget::Module(target_module_name) + if target_module_name != module_name => { let predicate_retractor = |key, index_ptr| { - RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, index_ptr) + RetractionRecord::ReplacedModulePredicate(module_name, key, index_ptr) }; - let op_retractor = |op_decl, prec, spec| { - RetractionRecord::ReplacedModuleOp(module_name.clone(), op_decl, prec, spec) + let op_retractor = |op_decl, op_desc| { + RetractionRecord::ReplacedModuleOp(module_name, op_decl, op_desc) }; - if let Some(module) = self.wam.indices.modules.get_mut(target_module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&target_module_name) { remove_module_exports( &removed_module, &mut module.code_dir, &mut module.op_dir, - &mut self.retraction_info, + &mut self.payload.retraction_info, predicate_retractor, op_retractor, ); @@ -572,24 +565,24 @@ impl<'a> LoadState<'a> { CompilationTarget::Module(_) => {} }; - self.wam.indices.modules.insert(module_name, removed_module); + self.wam_prelude.indices.modules.insert(module_name, removed_module); } fn get_or_insert_local_code_index( &mut self, - module_name: ClauseName, + module_name: Atom, key: PredicateKey, ) -> CodeIndex { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => module .code_dir .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(), None => { - self.add_dynamically_generated_module(&module_name); + self.add_dynamically_generated_module(module_name); - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => module .code_dir .entry(key) @@ -610,7 +603,7 @@ impl<'a> LoadState<'a> { ) -> CodeIndex { match compilation_target { CompilationTarget::User => self - .wam + .wam_prelude .indices .code_dir .entry(key) @@ -624,12 +617,12 @@ impl<'a> LoadState<'a> { pub(super) fn get_or_insert_qualified_code_index( &mut self, - module_name: ClauseName, + module_name: Atom, key: PredicateKey, ) -> CodeIndex { - if module_name.as_str() == "user" { + if module_name == atom!("user") { return self - .wam + .wam_prelude .indices .code_dir .entry(key) @@ -649,18 +642,18 @@ impl<'a> LoadState<'a> { ) { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates - .insert(key.clone(), skeleton); + .insert(key, skeleton); let record = RetractionRecord::AddedExtensiblePredicate(CompilationTarget::User, key); - self.retraction_info.push_record(record); + self.payload.retraction_info.push_record(record); } CompilationTarget::Module(module_name) => { - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { module.extensible_predicates.insert(key.clone(), skeleton); let record = RetractionRecord::AddedExtensiblePredicate( @@ -668,7 +661,7 @@ impl<'a> LoadState<'a> { key, ); - self.retraction_info.push_record(record); + self.payload.retraction_info.push_record(record); } else { unreachable!() } @@ -685,21 +678,21 @@ impl<'a> LoadState<'a> { ) { let src_compilation_target = match self.listing_src_file_name() { Some(filename) => CompilationTarget::Module(filename), - None => self.compilation_target.clone(), + None => self.payload.compilation_target, }; match src_compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .local_extensible_predicates - .insert((local_compilation_target.clone(), key.clone()), skeleton); + .insert((local_compilation_target, key), skeleton); } CompilationTarget::Module(module_name) => { - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { module .local_extensible_predicates - .insert((local_compilation_target.clone(), key.clone()), skeleton); + .insert((local_compilation_target, key), skeleton); } else { unreachable!() } @@ -708,10 +701,13 @@ impl<'a> LoadState<'a> { } pub(super) fn add_op_decl(&mut self, op_decl: &OpDecl) { - match &self.compilation_target { + let listing_src_file_name = self.listing_src_file_name(); + let payload_compilation_target = self.payload.compilation_target; + + match payload_compilation_target { CompilationTarget::User => { - if let Some(filename) = self.listing_src_file_name() { - match self.wam.indices.modules.get_mut(&filename) { + if let Some(filename) = listing_src_file_name { + match self.wam_prelude.indices.modules.get_mut(&filename) { Some(ref mut module) => { op_decl.insert_into_op_dir(&mut module.op_dir); } @@ -720,21 +716,23 @@ impl<'a> LoadState<'a> { } add_op_decl( - &mut self.retraction_info, - &self.compilation_target, - &mut self.wam.indices.op_dir, + &mut self.payload.retraction_info, + &payload_compilation_target, + &mut self.wam_prelude.indices.op_dir, op_decl, ); } CompilationTarget::Module(ref module_name) => { - match self.wam.indices.modules.get_mut(module_name) { + match self.wam_prelude.indices.modules.get_mut(module_name) { Some(ref mut module) => { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + add_op_decl_as_module_export( &mut module.op_dir, - &self.compilation_target, - &mut self.retraction_info, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &payload.compilation_target, + &mut payload.retraction_info, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, op_decl, ); } @@ -746,28 +744,17 @@ impl<'a> LoadState<'a> { } } - pub(super) fn get_clause_type( - &mut self, - name: ClauseName, - arity: usize, - fixity: Option, - ) -> ClauseType { - match ClauseType::from(name, arity, fixity) { + pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType { + match ClauseType::from(name, arity) { ClauseType::Named(name, arity, _) => { - let idx = self.get_or_insert_code_index( - (name.clone(), arity), - self.compilation_target.clone(), - ); + let payload_compilation_target = self.payload.compilation_target; - ClauseType::Named(name, arity, idx) - } - ClauseType::Op(name, fixity, _) => { let idx = self.get_or_insert_code_index( - (name.clone(), arity), - self.compilation_target.clone(), + (name, arity), + payload_compilation_target, ); - ClauseType::Op(name, fixity, idx) + ClauseType::Named(name, arity, idx) } ct => ct, } @@ -775,92 +762,85 @@ impl<'a> LoadState<'a> { pub(super) fn get_qualified_clause_type( &mut self, - module_name: ClauseName, - name: ClauseName, + module_name: Atom, + name: Atom, arity: usize, - fixity: Option, ) -> ClauseType { - match ClauseType::from(name, arity, fixity) { + match ClauseType::from(name, arity) { ClauseType::Named(name, arity, _) => { - let key = (name.clone(), arity); + let key = (name, 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, } } pub(super) fn add_meta_predicate_record( &mut self, - module_name: ClauseName, - name: ClauseName, + module_name: Atom, + name: Atom, meta_specs: Vec, ) { let arity = meta_specs.len(); let key = (name, arity); - match module_name.as_str() { - "user" => { + match module_name { + atom!("user") => { match self - .wam + .wam_prelude .indices .meta_predicates - .insert(key.clone(), meta_specs) + .insert(key, meta_specs) { Some(old_meta_specs) => { - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::ReplacedMetaPredicate( - module_name.clone(), + module_name, key.0, old_meta_specs, )); } None => { - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::AddedMetaPredicate( - module_name.clone(), + module_name, key, )); } } } _ => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { match module.meta_predicates.insert(key.clone(), meta_specs) { Some(old_meta_specs) => { - self.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::ReplacedMetaPredicate( - module_name.clone(), + module_name, key.0, old_meta_specs, ), ); } None => { - self.retraction_info.push_record( - RetractionRecord::AddedMetaPredicate(module_name.clone(), key), + self.payload.retraction_info.push_record( + RetractionRecord::AddedMetaPredicate(module_name, key), ); } } } None => { - self.add_dynamically_generated_module(&module_name); + self.add_dynamically_generated_module(module_name); - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { module.meta_predicates.insert(key.clone(), meta_specs); } else { unreachable!() } - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::AddedMetaPredicate( module_name.clone(), key, @@ -871,7 +851,7 @@ impl<'a> LoadState<'a> { } } - pub(super) fn add_dynamically_generated_module(&mut self, module_name: &ClauseName) { + pub(super) fn add_dynamically_generated_module(&mut self, module_name: Atom) { let module_decl = ModuleDecl { name: module_name.clone(), exports: vec![], @@ -887,28 +867,28 @@ impl<'a> LoadState<'a> { &mut module.meta_predicates, ); - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::AddedModule(module_name.clone())); - self.wam.indices.modules.insert(module_name.clone(), module); + self.wam_prelude.indices.modules.insert(module_name.clone(), module); } fn import_builtins_in_module( &mut self, - module_name: ClauseName, + module_name: Atom, code_dir: &mut CodeDir, op_dir: &mut OpDir, meta_predicates: &mut MetaPredicateDir, ) { - if let Some(builtins) = self.wam.indices.modules.get(&clause_name!("builtins")) { + if let Some(builtins) = self.wam_prelude.indices.modules.get(&atom!("builtins")) { let module_compilation_target = CompilationTarget::Module(module_name); - if CompilationTarget::Module(clause_name!("builtins")) == self.compilation_target { + if CompilationTarget::Module(atom!("builtins")) == self.payload.compilation_target { return; } import_module_exports( - &mut self.retraction_info, + &mut self.payload.retraction_info, &module_compilation_target, builtins, code_dir, @@ -929,7 +909,7 @@ impl<'a> LoadState<'a> { self.remove_module_exports(module_name.clone()); self.remove_replaced_in_situ_module(module_name.clone()); - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(module) => { let old_module_decl = mem::replace(&mut module.module_decl, module_decl.clone()); @@ -939,14 +919,14 @@ impl<'a> LoadState<'a> { ); for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() { - self.retract_local_clauses( - compilation_target.clone(), - key.clone(), + self.retract_local_clauses_impl( + *compilation_target, + *key, &skeleton.clause_clause_locs, ); let is_dynamic = self - .wam + .wam_prelude .indices .get_predicate_skeleton(compilation_target, key) .map(|skeleton| skeleton.core.is_dynamic) @@ -955,7 +935,7 @@ impl<'a> LoadState<'a> { if is_dynamic { let clause_clause_compilation_target = match compilation_target { CompilationTarget::User => { - CompilationTarget::Module(clause_name!("builtins")) + CompilationTarget::Module(atom!("builtins")) } module => module.clone(), }; @@ -967,7 +947,7 @@ impl<'a> LoadState<'a> { } } - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::ReplacedModule( old_module_decl, listing_src.clone(), @@ -980,15 +960,16 @@ impl<'a> LoadState<'a> { pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) { self.reset_in_situ_module(module_decl.clone(), &listing_src); - let module_name = module_decl.name.clone(); + let module_name = module_decl.name; - let mut module = match self.wam.indices.modules.remove(&module_name) { + let mut module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(mut module) => { module.listing_src = listing_src; module } None => { - self.retraction_info + self.payload + .retraction_info .push_record(RetractionRecord::AddedModule(module_name.clone())); Module::new(module_decl, listing_src) @@ -996,7 +977,7 @@ impl<'a> LoadState<'a> { }; self.import_builtins_in_module( - module_name.clone(), + module_name, &mut module.code_dir, &mut module.op_dir, &mut module.meta_predicates, @@ -1004,62 +985,68 @@ impl<'a> LoadState<'a> { for export in &module.module_decl.exports { if let ModuleExport::OpDecl(ref op_decl) = export { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + add_op_decl_as_module_export( &mut module.op_dir, - &self.compilation_target, // this is a Module. - &mut self.retraction_info, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &payload.compilation_target, // this is a Module. + &mut payload.retraction_info, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, op_decl, ); } } - if let Some(load_context) = self.wam.load_contexts.last_mut() { - load_context.module = module_name.clone(); + if let Some(load_context) = self.wam_prelude.load_contexts.last_mut() { + load_context.module = module_name; } - self.wam.indices.modules.insert(module_name, module); + self.wam_prelude.indices.modules.insert(module_name, module); } - pub(super) fn import_module(&mut self, module_name: ClauseName) -> Result<(), SessionError> { - if let Some(module) = self.wam.indices.modules.remove(&module_name) { - match &self.compilation_target { + pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> { + if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) { + let payload_compilation_target = self.payload.compilation_target; + + match &payload_compilation_target { CompilationTarget::User => { import_module_exports( - &mut self.retraction_info, - &self.compilation_target, + &mut self.payload.retraction_info, + &payload_compilation_target, &module, - &mut self.wam.indices.code_dir, - &mut self.wam.indices.op_dir, - &mut self.wam.indices.meta_predicates, + &mut self.wam_prelude.indices.code_dir, + &mut self.wam_prelude.indices.op_dir, + &mut self.wam_prelude.indices.meta_predicates, )?; } CompilationTarget::Module(ref defining_module_name) => { - match self.wam.indices.modules.get_mut(defining_module_name) { + match self.wam_prelude.indices.modules.get_mut(defining_module_name) { Some(ref mut target_module) => { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + import_module_exports_into_module( - &mut self.retraction_info, - &self.compilation_target, + &mut payload.retraction_info, + &payload_compilation_target, &module, &mut target_module.code_dir, &mut target_module.op_dir, &mut target_module.meta_predicates, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, )?; } None => { // we find ourselves here because we're trying to import // a module into itself as it is being defined. - self.wam.indices.modules.insert(module_name.clone(), module); + self.wam_prelude.indices.modules.insert(module_name, module); return Err(SessionError::ModuleCannotImportSelf(module_name)); } } } } - self.wam.indices.modules.insert(module_name, module); + self.wam_prelude.indices.modules.insert(module_name, module); Ok(()) } else { Err(SessionError::ExistenceError(ExistenceError::Module( @@ -1070,53 +1057,55 @@ impl<'a> LoadState<'a> { pub(super) fn import_qualified_module( &mut self, - module_name: ClauseName, + module_name: Atom, exports: IndexSet, ) -> Result<(), SessionError> { - if let Some(module) = self.wam.indices.modules.remove(&module_name) { - match &self.compilation_target { + if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) { + let payload_compilation_target = self.payload.compilation_target; + + match &payload_compilation_target { CompilationTarget::User => { import_qualified_module_exports( - &mut self.retraction_info, - &self.compilation_target, + &mut self.payload.retraction_info, + &payload_compilation_target, &module, &exports, - &mut self.wam.indices.code_dir, - &mut self.wam.indices.op_dir, - &mut self.wam.indices.meta_predicates, + &mut self.wam_prelude.indices.code_dir, + &mut self.wam_prelude.indices.op_dir, + &mut self.wam_prelude.indices.meta_predicates, )?; } CompilationTarget::Module(ref defining_module_name) => { - match self.wam.indices.modules.get_mut(defining_module_name) { + match self.wam_prelude.indices.modules.get_mut(defining_module_name) { Some(ref mut target_module) => { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + import_qualified_module_exports_into_module( - &mut self.retraction_info, - &self.compilation_target, + &mut payload.retraction_info, + &payload_compilation_target, &module, &exports, &mut target_module.code_dir, &mut target_module.op_dir, &mut target_module.meta_predicates, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, )?; } None => { // we find ourselves here because we're trying to import // a module into itself as it is being defined. - self.wam.indices.modules.insert(module_name.clone(), module); + self.wam_prelude.indices.modules.insert(module_name, module); return Err(SessionError::ModuleCannotImportSelf(module_name)); } } } } - self.wam.indices.modules.insert(module_name, module); + self.wam_prelude.indices.modules.insert(module_name, module); Ok(()) } else { - Err(SessionError::ExistenceError(ExistenceError::Module( - module_name, - ))) + Err(SessionError::ExistenceError(ExistenceError::Module(module_name))) } } @@ -1125,23 +1114,30 @@ impl<'a> LoadState<'a> { ModuleSource::File(filename) => { let mut path_buf = PathBuf::from(filename.as_str()); path_buf.set_extension("pl"); + let file = File::open(&path_buf)?; ( - Stream::from_file_as_input(filename.clone(), file), + Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena), ListingSource::File(filename, path_buf), ) } ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { Some(code) => { - if let Some(ref module) = self.wam.indices.modules.get(&library) { + if let Some(ref module) = self.wam_prelude.indices.modules.get(&library) { if let ListingSource::DynamicallyGenerated = &module.listing_src { - (Stream::from(*code), ListingSource::User) + ( + Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), + ListingSource::User, + ) } else { return self.import_module(library); } } else { - (Stream::from(*code), ListingSource::User) + ( + Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), + ListingSource::User, + ) } } None => { @@ -1151,16 +1147,23 @@ impl<'a> LoadState<'a> { }; let compilation_target = { - let stream = &mut parsing_stream(stream)?; - - let ts = BootstrappingTermStream::from_prolog_stream( + let term_stream = BootstrappingTermStream::from_char_reader( stream, - self.wam.machine_st.atom_tbl.clone(), - self.wam.machine_st.flags, + LS::machine_st(&mut self.payload), listing_src, ); - let subloader = Loader::new(ts, self.wam); + let subloader: Loader<'_, BootstrappingLoadState> = Loader { + payload: BootstrappingLoadState( + LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream) + ), + wam_prelude: MachinePreludeView { + indices: self.wam_prelude.indices, + code_repo: self.wam_prelude.code_repo, + load_contexts: self.wam_prelude.load_contexts, + } + }; + subloader.load()? }; @@ -1185,16 +1188,19 @@ impl<'a> LoadState<'a> { let file = File::open(&path_buf)?; ( - Stream::from_file_as_input(filename.clone(), file), + Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena), ListingSource::File(filename, path_buf), ) } ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { Some(code) => { - if self.wam.indices.modules.contains_key(&library) { + if self.wam_prelude.indices.modules.contains_key(&library) { return self.import_qualified_module(library, exports); } else { - (Stream::from(*code), ListingSource::User) + ( + Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), + ListingSource::User, + ) } } None => { @@ -1204,16 +1210,23 @@ impl<'a> LoadState<'a> { }; let compilation_target = { - let stream = &mut parsing_stream(stream)?; - - let ts = BootstrappingTermStream::from_prolog_stream( + let term_stream = BootstrappingTermStream::from_char_reader( stream, - self.wam.machine_st.atom_tbl.clone(), - self.wam.machine_st.flags, + LS::machine_st(&mut self.payload), listing_src, ); - let subloader = Loader::new(ts, self.wam); + let subloader: Loader<'_, BootstrappingLoadState> = Loader { + payload: BootstrappingLoadState( + LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream), + ), + wam_prelude: MachinePreludeView { + indices: self.wam_prelude.indices, + code_repo: self.wam_prelude.code_repo, + load_contexts: self.wam_prelude.load_contexts, + } + }; + subloader.load()? }; @@ -1227,21 +1240,4 @@ impl<'a> LoadState<'a> { } } } - - #[inline] - pub(super) fn composite_op_dir(&self) -> CompositeOpDir { - match &self.compilation_target { - CompilationTarget::User => CompositeOpDir::new(&self.wam.indices.op_dir, None), - CompilationTarget::Module(ref module_name) => { - match self.wam.indices.modules.get(module_name) { - Some(ref module) => { - CompositeOpDir::new(&self.wam.indices.op_dir, Some(&module.op_dir)) - } - None => { - unreachable!() - } - } - } - } - } } diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 6f48b1d9d..b2f43e543 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1,18 +1,26 @@ -use prolog_parser::ast::*; -use prolog_parser::{clause_name, temp_v}; - +use crate::arena::*; +use crate::atom_table::*; +use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::indexing::*; +use crate::instructions::*; use crate::machine::load_state::*; +use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::preprocessor::*; +use crate::machine::term_stream::*; use crate::machine::*; +use crate::parser::ast::*; +use crate::types::*; use indexmap::IndexSet; use slice_deque::{sdeq, SliceDeque}; use std::cell::Cell; use std::convert::TryFrom; +use std::mem; +use std::ops::{Deref, DerefMut}; use std::rc::Rc; /* @@ -44,19 +52,19 @@ use std::rc::Rc; #[derive(Debug)] pub(crate) enum RetractionRecord { - AddedMetaPredicate(ClauseName, PredicateKey), - ReplacedMetaPredicate(ClauseName, ClauseName, Vec), - AddedModule(ClauseName), + AddedMetaPredicate(Atom, PredicateKey), + ReplacedMetaPredicate(Atom, Atom, Vec), + AddedModule(Atom), ReplacedModule(ModuleDecl, ListingSource, LocalExtensiblePredicates), - AddedModuleOp(ClauseName, OpDecl), - ReplacedModuleOp(ClauseName, OpDecl, usize, Specifier), - AddedModulePredicate(ClauseName, PredicateKey), - ReplacedModulePredicate(ClauseName, PredicateKey, IndexPtr), + AddedModuleOp(Atom, OpDecl), + ReplacedModuleOp(Atom, OpDecl, OpDesc), + AddedModulePredicate(Atom, PredicateKey), + ReplacedModulePredicate(Atom, PredicateKey, IndexPtr), AddedDiscontiguousPredicate(CompilationTarget, PredicateKey), AddedDynamicPredicate(CompilationTarget, PredicateKey), AddedMultifilePredicate(CompilationTarget, PredicateKey), AddedUserOp(OpDecl), - ReplacedUserOp(OpDecl, usize, Specifier), + ReplacedUserOp(OpDecl, OpDesc), AddedExtensiblePredicate(CompilationTarget, PredicateKey), AddedUserPredicate(PredicateKey), ReplacedUserPredicate(PredicateKey, IndexPtr), @@ -75,6 +83,7 @@ pub(crate) enum RetractionRecord { SkeletonLocalClauseTruncateBack(CompilationTarget, CompilationTarget, PredicateKey, usize), SkeletonClauseTruncateBack(CompilationTarget, PredicateKey, usize), SkeletonClauseStartReplaced(CompilationTarget, PredicateKey, usize, usize), + RemovedDynamicSkeletonClause(CompilationTarget, PredicateKey, usize, usize), RemovedSkeletonClause( CompilationTarget, PredicateKey, @@ -113,7 +122,7 @@ impl RetractionInfo { pub(super) fn new(orig_code_extent: usize) -> Self { Self { orig_code_extent, - records: vec![], //BTreeMap::new(), + records: vec![], } } @@ -134,16 +143,397 @@ impl RetractionInfo { } } -impl<'a> Drop for LoadState<'a> { +impl<'a, LS: LoadState<'a>> Drop for Loader<'a, LS> { fn drop(&mut self) { - while let Some(record) = self.retraction_info.records.pop() { + if LS::should_drop_load_state(self) { + LS::reset_machine(self); + } + } +} + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum CompilationTarget { + Module(Atom), + User, +} + +impl Default for CompilationTarget { + #[inline] + fn default() -> Self { + CompilationTarget::User + } +} + +impl CompilationTarget { + #[inline] + pub(crate) fn module_name(&self) -> Atom { + match self { + CompilationTarget::User => { + atom!("user") + } + CompilationTarget::Module(module_name) => *module_name, + } + } +} + +pub struct PredicateQueue { + pub(super) predicates: Vec, + pub(super) compilation_target: CompilationTarget, +} + +impl PredicateQueue { + #[inline] + pub(super) fn push(&mut self, clause: Term) { + self.predicates.push(clause); + } + + #[inline] + pub(crate) fn first(&self) -> Option<&Term> { + self.predicates.first() + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.predicates.is_empty() + } + + #[inline] + pub(super) fn take(&mut self) -> Self { + Self { + predicates: mem::replace(&mut self.predicates, vec![]), + compilation_target: self.compilation_target.clone(), + } + } + + #[inline] + pub(super) fn len(&self) -> usize { + self.predicates.len() + } +} + +#[macro_export] +macro_rules! predicate_queue { + [$($v:expr),*] => ( + PredicateQueue { + predicates: vec![$($v,)*], + compilation_target: CompilationTarget::default(), + } + ) +} + +pub type LiveLoadState = LoadStatePayload; + +pub struct BootstrappingLoadState<'a>( + pub LoadStatePayload> +); + +impl<'a> Deref for BootstrappingLoadState<'a> { + type Target = LoadStatePayload>; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a> DerefMut for BootstrappingLoadState<'a> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub trait LoadState<'a>: Sized { + type Evacuable; + type TS: TermStream; + type LoaderFieldType: DerefMut>; + + fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload) -> Self::LoaderFieldType; + fn evacuate(loader: Loader<'a, Self>) -> Result; + fn should_drop_load_state(loader: &Loader<'a, Self>) -> bool; + fn reset_machine(loader: &mut Loader<'a, Self>); + fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState; +} + +pub struct LiveLoadAndMachineState<'a> { + load_state: TypedArenaPtr, + machine_st: &'a mut MachineState, +} + +impl<'a> Deref for LiveLoadAndMachineState<'a> { + type Target = LiveLoadState; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.load_state + } +} + +impl<'a> DerefMut for LiveLoadAndMachineState<'a> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.load_state + } +} + +impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> { + type TS = LiveTermStream; + type LoaderFieldType = LiveLoadAndMachineState<'a>; + type Evacuable = TypedArenaPtr; + + #[inline(always)] + fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload) -> Self::LoaderFieldType { + let load_state = arena_alloc!(payload, &mut machine_st.arena); + LiveLoadAndMachineState { load_state, machine_st } + } + + #[inline(always)] + fn evacuate(mut loader: Loader<'a, Self>) -> Result { + loader.payload.load_state.set_tag(ArenaHeaderTag::InactiveLoadState); + Ok(loader.payload.load_state) + } + + #[inline(always)] + fn should_drop_load_state(loader: &Loader<'a, Self>) -> bool { + loader.payload.load_state.get_tag() == ArenaHeaderTag::LiveLoadState + } + + #[inline(always)] + fn reset_machine(loader: &mut Loader<'a, Self>) { + if loader.payload.load_state.get_tag() != ArenaHeaderTag::Dropped { + loader.payload.load_state.set_tag(ArenaHeaderTag::Dropped); + loader.reset_machine(); + } + } + + #[inline(always)] + fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { + loader.machine_st + } +} + +impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { + type TS = BootstrappingTermStream<'a>; + type LoaderFieldType = BootstrappingLoadState<'a>; + type Evacuable = CompilationTarget; + + #[inline(always)] + fn new(_: &'a mut MachineState, payload: LoadStatePayload) -> Self::LoaderFieldType { + BootstrappingLoadState(payload) + } + + fn evacuate(mut loader: Loader<'a, Self>) -> Result { + if !loader.payload.predicates.is_empty() { + loader.compile_and_submit()?; + } + + let repo_len = loader.wam_prelude.code_repo.code.len(); + + loader + .payload + .retraction_info + .reset(repo_len); + + loader.remove_module_op_exports(); + + Ok(loader.payload.compilation_target) + } + + #[inline(always)] + fn should_drop_load_state(_loader: &Loader<'a, Self>) -> bool { + true + } + + #[inline(always)] + fn reset_machine(loader: &mut Loader<'a, Self>) { + loader.reset_machine(); + } + + #[inline(always)] + fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { + &mut loader.term_stream.parser.lexer.machine_st + } +} + +pub struct Loader<'a, LS: LoadState<'a>> { + pub(super) payload: LS::LoaderFieldType, + pub(super) wam_prelude: MachinePreludeView<'a>, +} + +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { + #[inline] + pub(super) fn new(wam: &'a mut Machine, term_stream: >::TS) -> Self { + let payload = LoadStatePayload::new(wam.code_repo.code.len(), term_stream); + let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st(); + + Self { + payload: LS::new(machine_st, payload), + wam_prelude, + } + } + + pub(crate) fn load(mut self) -> Result { + while let Some(decl) = self.dequeue_terms()? { + self.load_decl(decl)?; + } + + LS::evacuate(self) + } + + /* + #[inline(always)] + pub(crate) fn load_state(&mut self) -> &mut LoadStatePayload<>::TS> { + self.payload.as_mut() + } + */ + + fn dequeue_terms(&mut self) -> Result, SessionError> { + while !self.payload.term_stream.eof()? { + let load_state = &mut self.payload; + let compilation_target = &load_state.compilation_target; + let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target); + + let term = load_state.term_stream.next(&composite_op_dir)?; + + // if is_consistent is false, self.predicates is not empty. + if !term.is_consistent(&load_state.predicates) { + self.compile_and_submit()?; + } + + let term = match term { + Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => { + return Ok(Some(setup_declaration(self, terms)?)); + } + term => term, + }; + + self.payload.predicates.push(term); + } + + Ok(None) + } + + pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> { + match decl { + Declaration::Dynamic(name, arity) => { + let compilation_target = self.payload.compilation_target; + self.add_dynamic_predicate(compilation_target, name, arity)?; + } + Declaration::MetaPredicate(module_name, name, meta_specs) => { + self.add_meta_predicate_record(module_name, name, meta_specs); + } + Declaration::Module(module_decl) => { + self.payload.compilation_target = CompilationTarget::Module(module_decl.name); + self.payload.predicates.compilation_target = self.payload.compilation_target; + + let listing_src = self.payload.term_stream.listing_src().clone(); + self.add_module(module_decl, listing_src); + } + Declaration::NonCountedBacktracking(name, arity) => { + self.payload.non_counted_bt_preds.insert((name, arity)); + } + Declaration::Op(op_decl) => { + self.add_op_decl(&op_decl); + } + Declaration::UseModule(module_src) => { + self.use_module(module_src)?; + } + Declaration::UseQualifiedModule(module_src, exports) => { + self.use_qualified_module(module_src, exports)?; + } + } + + Ok(()) + } + + pub(super) fn read_term_from_heap(&mut self, heap_term_loc: RegType) -> Result { + let machine_st = LS::machine_st(&mut self.payload); + let term_addr = machine_st[heap_term_loc]; + + /* + if let Ok(lit) = Literal::try_from(term_addr) { + return Ok(Term::Literal(Cell::default(), lit)); + } else if machine_st.is_cyclic_term(term_addr) { + return Err(SessionError::from(CompilationError::CannotParseCyclicTerm)); + } + */ + + let mut term_stack = vec![]; + let mut iter = stackful_post_order_iter(&mut machine_st.heap, term_addr); + + while let Some(addr) = iter.next() { + read_heap_cell!(addr, + (HeapCellValueTag::Lis) => { + let tail = term_stack.pop().unwrap(); + let head = term_stack.pop().unwrap(); + + term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => { + let offset_string = format!("_{}", h); + term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string))); + } + (HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | HeapCellValueTag::F64) => { + let addr = unmark_cell_bits!(addr); + term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); + } else { + let subterms = term_stack + .drain(term_stack.len() - arity ..) + .collect(); + + term_stack.push(Term::Clause(Cell::default(), name, subterms)); + } + } + (HeapCellValueTag::PStr, string) => { + let tail = term_stack.pop().unwrap(); + + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail { + term_stack.push(Term::PartialString( + Cell::default(), + string, + None, + )); + } else { + term_stack.push(Term::PartialString( + Cell::default(), + string, + Some(Box::new(tail)), + )); + } + } + (HeapCellValueTag::PStrOffset, h) => { + let string = cell_as_atom_cell!(iter.heap[h]).get_name(); + let tail = term_stack.pop().unwrap(); + + term_stack.push(Term::PartialString( + Cell::default(), + string, + Some(Box::new(tail)), + )); + } + _ => { + } + ); + } + + debug_assert!(term_stack.len() == 1); + Ok(term_stack.pop().unwrap()) + } + + fn reset_machine(&mut self) { + while let Some(record) = self.payload.retraction_info.records.pop() { match record { RetractionRecord::AddedMetaPredicate(target_module_name, key) => { - match target_module_name.as_str() { - "user" => { - self.wam.indices.meta_predicates.remove(&key); + match target_module_name { + atom!("user") => { + self.wam_prelude.indices.meta_predicates.remove(&key); } - _ => match self.wam.indices.modules.get_mut(&target_module_name) { + _ => match self.wam_prelude.indices.modules.get_mut(&target_module_name) { Some(ref mut module) => { module.meta_predicates.remove(&key); } @@ -154,14 +544,14 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ReplacedMetaPredicate(target_module_name, name, meta_specs) => { - match target_module_name.as_str() { - "user" => { - self.wam + match target_module_name { + atom!("user") => { + self.wam_prelude .indices .meta_predicates .insert((name, meta_specs.len()), meta_specs); } - _ => match self.wam.indices.modules.get_mut(&target_module_name) { + _ => match self.wam_prelude.indices.modules.get_mut(&target_module_name) { Some(ref mut module) => { module .meta_predicates @@ -174,13 +564,13 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AddedModule(module_name) => { - self.wam.indices.modules.remove(&module_name); + self.wam_prelude.indices.modules.remove(&module_name); } RetractionRecord::ReplacedModule( module_decl, listing_src, local_extensible_predicates, - ) => match self.wam.indices.modules.get_mut(&module_decl.name) { + ) => match self.wam_prelude.indices.modules.get_mut(&module_decl.name) { Some(ref mut module) => { module.module_decl = module_decl; module.listing_src = listing_src; @@ -193,7 +583,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedDiscontiguousPredicate(compilation_target, key) => { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -202,7 +592,7 @@ impl<'a> Drop for LoadState<'a> { }); } CompilationTarget::Module(module_name) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.extensible_predicates.get_mut(&key).map(|skeleton| { skeleton.core.is_discontiguous = false; @@ -216,7 +606,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedDynamicPredicate(compilation_target, key) => { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -225,10 +615,11 @@ impl<'a> Drop for LoadState<'a> { }); } CompilationTarget::Module(module_name) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.extensible_predicates.get_mut(&key).map(|skeleton| { skeleton.core.is_dynamic = false; + skeleton.core.retracted_dynamic_clauses = None; }); } None => {} @@ -239,7 +630,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedMultifilePredicate(compilation_target, key) => { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -248,7 +639,7 @@ impl<'a> Drop for LoadState<'a> { }); } CompilationTarget::Module(module_name) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.extensible_predicates.get_mut(&key).map(|skeleton| { skeleton.core.is_multifile = false; @@ -260,25 +651,24 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AddedModuleOp(module_name, mut op_decl) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { op_decl.remove(&mut module.op_dir); } None => {} } } - RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, prec, spec) => { - match self.wam.indices.modules.get_mut(&module_name) { + RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, op_desc) => { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { - op_decl.prec = prec; - op_decl.spec = spec; + op_decl.op_desc = op_desc; op_decl.insert_into_op_dir(&mut module.op_dir); } None => {} } } RetractionRecord::AddedModulePredicate(module_name, key) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.code_dir.remove(&key); } @@ -286,7 +676,7 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ReplacedModulePredicate(module_name, key, old_code_idx) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module .code_dir @@ -297,23 +687,22 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AddedExtensiblePredicate(compilation_target, key) => { - self.wam + self.wam_prelude .indices .remove_predicate_skeleton(&compilation_target, &key); } RetractionRecord::AddedUserOp(mut op_decl) => { - op_decl.remove(&mut self.wam.indices.op_dir); + op_decl.remove(&mut self.wam_prelude.indices.op_dir); } - RetractionRecord::ReplacedUserOp(mut op_decl, prec, spec) => { - op_decl.prec = prec; - op_decl.spec = spec; - op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir); + RetractionRecord::ReplacedUserOp(mut op_decl, op_desc) => { + op_decl.op_desc = op_desc; + op_decl.insert_into_op_dir(&mut self.wam_prelude.indices.op_dir); } RetractionRecord::AddedUserPredicate(key) => { - self.wam.indices.code_dir.remove(&key); + self.wam_prelude.indices.code_dir.remove(&key); } RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => { - self.wam + self.wam_prelude .indices .code_dir .get_mut(&key) @@ -322,7 +711,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedIndex(index_key, clause_loc) => { // WAS: inner_index_locs) => { if let Some(index_loc) = index_key.switch_on_term_loc() { - let indexing_code = match &mut self.wam.code_repo.code[index_loc] { + let indexing_code = match &mut self.wam_prelude.code_repo.code[index_loc] { Line::IndexingCode(indexing_code) => indexing_code, _ => { unreachable!() @@ -330,14 +719,14 @@ impl<'a> Drop for LoadState<'a> { }; match index_key { - OptArgIndexKey::Constant( + OptArgIndexKey::Literal( _, index_loc, constant, overlapping_constants, ) => { remove_constant_indices( - &constant, + constant, &overlapping_constants, indexing_code, clause_loc - index_loc, // WAS: &inner_index_locs, @@ -345,7 +734,7 @@ impl<'a> Drop for LoadState<'a> { } OptArgIndexKey::Structure(_, index_loc, name, arity) => { remove_structure_index( - &name, + name, arity, indexing_code, clause_loc - index_loc, // WAS: &inner_index_locs, @@ -369,7 +758,7 @@ impl<'a> Drop for LoadState<'a> { // write the retraction logic of this arm. } RetractionRecord::ReplacedChoiceOffset(instr_loc, offset) => { - match &mut self.wam.code_repo.code[instr_loc] { + match self.wam_prelude.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)) => { @@ -381,7 +770,7 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AppendedTrustMe(instr_loc, offset, is_default) => { - match &mut self.wam.code_repo.code[instr_loc] { + match self.wam_prelude.code_repo.code[instr_loc] { Line::Choice(ref mut choice_instr) => { *choice_instr = if is_default { ChoiceInstruction::DefaultTrustMe(offset) @@ -395,7 +784,7 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v) => { - match &mut self.wam.code_repo.code[index_loc] { + match self.wam_prelude.code_repo.code[index_loc] { Line::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( _, @@ -410,20 +799,20 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ModifiedTryMeElse(instr_loc, o) => { - self.wam.code_repo.code[instr_loc] = + self.wam_prelude.code_repo.code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(o)); } RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => { - self.wam.code_repo.code[instr_loc] = + self.wam_prelude.code_repo.code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o)); } RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => { - self.wam.code_repo.code[instr_loc] = + self.wam_prelude.code_repo.code[instr_loc] = Line::Control(ControlInstruction::RevJmpBy(o)); } RetractionRecord::SkeletonClausePopBack(compilation_target, key) => { match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -436,7 +825,7 @@ impl<'a> Drop for LoadState<'a> { } RetractionRecord::SkeletonClausePopFront(compilation_target, key) => { match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -453,10 +842,12 @@ impl<'a> Drop for LoadState<'a> { local_compilation_target, key, ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( src_compilation_target, local_compilation_target, - self.listing_src_file_name(), + listing_src_file_name, key, ) { Some(skeleton) => { @@ -470,10 +861,12 @@ impl<'a> Drop for LoadState<'a> { local_compilation_target, key, ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( src_compilation_target, local_compilation_target, - self.listing_src_file_name(), + listing_src_file_name, key, ) { Some(skeleton) => { @@ -488,401 +881,175 @@ impl<'a> Drop for LoadState<'a> { key, len, ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( - src_compilation_target, - local_compilation_target, - self.listing_src_file_name(), - key, - ) { - Some(skeleton) => { - skeleton.clause_clause_locs.truncate_back(len); - } - None => {} - } - } - RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => { - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - { - Some(skeleton) => { - skeleton.clauses.truncate_back(len); - skeleton.core.clause_clause_locs.truncate_back(len); - } - None => {} - } - } - RetractionRecord::SkeletonClauseStartReplaced( - compilation_target, - key, - target_pos, - clause_start, - ) => { - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - { - Some(skeleton) => { - skeleton.clauses[target_pos].clause_start = clause_start; - } - None => {} - } - } - RetractionRecord::RemovedSkeletonClause( - compilation_target, - key, - target_pos, - clause_index_info, - clause_clause_loc, - ) => { - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - { - Some(skeleton) => { - skeleton - .core - .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); - } - RetractionRecord::RemovedLocalSkeletonClauseLocations( - compilation_target, - local_compilation_target, - key, - clause_locs, - ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( - compilation_target, - local_compilation_target, - self.listing_src_file_name(), - key, - ) { - Some(skeleton) => skeleton.clause_clause_locs = clause_locs, - None => {} - } - } - RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton) => { - match compilation_target { - CompilationTarget::User => { - self.wam.indices.extensible_predicates.insert(key, skeleton); - } - CompilationTarget::Module(module_name) => { - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { - module.extensible_predicates.insert(key, skeleton); - } - } - } - } - RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => { - match &mut self.wam.code_repo.code[instr_loc] { - Line::Choice(ChoiceInstruction::DynamicElse( - _, - _, - NextOrFail::Next(ref mut o), - )) - | Line::Choice(ChoiceInstruction::DynamicInternalElse( - _, - _, - NextOrFail::Next(ref mut o), - )) => { - *o = next; - } - _ => {} - } - } - RetractionRecord::AppendedNextOrFail(instr_loc, fail) => { - match &mut self.wam.code_repo.code[instr_loc] { - Line::Choice(ChoiceInstruction::DynamicElse( - _, - _, - ref mut next_or_fail, - )) - | Line::Choice(ChoiceInstruction::DynamicInternalElse( - _, - _, - ref mut next_or_fail, - )) => { - *next_or_fail = fail; - } - _ => {} - } - } - } - } - - // TODO: necessary? unnecessary? - // self.wam.code_repo.code.truncate(self.retraction_info.orig_code_extent); - } -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub(crate) enum CompilationTarget { - Module(ClauseName), - User, -} - -impl Default for CompilationTarget { - #[inline] - fn default() -> Self { - CompilationTarget::User - } -} - -impl CompilationTarget { - #[inline] - pub(super) fn take(&mut self) -> CompilationTarget { - mem::replace(self, CompilationTarget::User) - } + let listing_src_file_name = self.listing_src_file_name(); - #[inline] - pub(crate) fn module_name(&self) -> ClauseName { - match self { - CompilationTarget::User => { - clause_name!("user") - } - CompilationTarget::Module(ref module_name) => module_name.clone(), - } - } -} - -pub(crate) struct PredicateQueue { - pub(super) predicates: Vec, - pub(super) compilation_target: CompilationTarget, -} - -impl PredicateQueue { - #[inline] - pub(super) fn push(&mut self, clause: Term) { - self.predicates.push(clause); - } - - #[inline] - pub(crate) fn first(&self) -> Option<&Term> { - self.predicates.first() - } - - #[inline] - pub(crate) fn is_empty(&self) -> bool { - self.predicates.is_empty() - } - - #[inline] - pub(super) fn take(&mut self) -> Self { - Self { - predicates: mem::replace(&mut self.predicates, vec![]), - compilation_target: self.compilation_target.take(), - } - } - - #[inline] - pub(super) fn len(&self) -> usize { - self.predicates.len() - } -} - -macro_rules! predicate_queue { - [$($v:expr),*] => ( - PredicateQueue { - predicates: vec![$($v,)*], - compilation_target: CompilationTarget::default(), - } - ) -} - -pub(crate) struct Loader<'a, TermStream> { - pub(super) load_state: LoadState<'a>, - pub(super) predicates: PredicateQueue, - pub(super) clause_clauses: Vec<(Term, Term)>, - pub(super) term_stream: TermStream, - pub(super) non_counted_bt_preds: IndexSet, -} - -impl<'a, TS: TermStream> Loader<'a, TS> { - #[inline] - pub(super) fn new(term_stream: TS, wam: &'a mut Machine) -> Self { - let load_state = LoadState { - compilation_target: CompilationTarget::User, - module_op_exports: vec![], - retraction_info: RetractionInfo::new(wam.code_repo.code.len()), - wam, - }; - - Self { - load_state, - term_stream, - non_counted_bt_preds: IndexSet::new(), - predicates: predicate_queue![], - clause_clauses: vec![], - } - } - - pub(crate) fn load(mut self) -> Result { - 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 term = match term { - Term::Clause(_, name, terms, _) if name.as_str() == ":-" && terms.len() == 1 => { - return Ok(Some(setup_declaration(&self.load_state, terms)?)); - } - term => term, - }; - - self.predicates.push(term); - } - - Ok(None) - } - - pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> { - match decl { - Declaration::Dynamic(name, arity) => { - let compilation_target = self.load_state.compilation_target.clone(); - self.add_dynamic_predicate(compilation_target, name, arity)?; - } - Declaration::MetaPredicate(module_name, name, meta_specs) => { - self.load_state - .add_meta_predicate_record(module_name, name, meta_specs); - } - Declaration::Module(module_decl) => { - self.load_state.compilation_target = - CompilationTarget::Module(module_decl.name.clone()); - - self.predicates.compilation_target = self.load_state.compilation_target.clone(); - - self.load_state - .add_module(module_decl, self.term_stream.listing_src().clone()); - } - Declaration::NonCountedBacktracking(name, arity) => { - self.non_counted_bt_preds.insert((name, arity)); - } - Declaration::Op(op_decl) => { - self.load_state.add_op_decl(&op_decl); - } - Declaration::UseModule(module_src) => { - self.load_state.use_module(module_src)?; - } - Declaration::UseQualifiedModule(module_src, exports) => { - self.load_state.use_qualified_module(module_src, exports)?; - } - } - - Ok(()) - } - - pub(super) fn read_term_from_heap(&self, heap_term_loc: RegType) -> Result { - 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))); + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + src_compilation_target, + local_compilation_target, + listing_src_file_name, + key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.truncate_back(len); + } + None => {} + } } - 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), - }; + RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses.truncate_back(len); + skeleton.core.clause_clause_locs.truncate_back(len); + } + None => {} + } + } + RetractionRecord::SkeletonClauseStartReplaced( + compilation_target, + key, + target_pos, + clause_start, + ) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses[target_pos].clause_start = clause_start; + } + None => {} + } + } + RetractionRecord::RemovedDynamicSkeletonClause( + compilation_target, + key, + target_pos, + clause_clause_loc, + ) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + if let Some(removed_clauses) = &mut skeleton.core.retracted_dynamic_clauses { + let clause_index_info = removed_clauses.pop().unwrap(); - 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)); + skeleton + .core + .clause_clause_locs + .insert(target_pos, clause_clause_loc); + + skeleton.clauses.insert(target_pos, clause_index_info); } } + None => {} } } - HeapCellValue::Atom(ref name, ref shared_op_desc) => { - term_stack.push(Term::Constant( - Cell::default(), - Constant::Atom(name.clone(), shared_op_desc.clone()), - )); + RetractionRecord::RemovedSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + ) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton + .core + .clause_clause_locs + .insert(target_pos, clause_clause_loc); + skeleton.clauses.insert(target_pos, clause_index_info); + } + None => {} + } } - HeapCellValue::Integer(ref integer) => { - term_stack.push(Term::Constant( - Cell::default(), - Constant::Integer(integer.clone()), - )); + RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => { + self.wam_prelude.code_repo.code[index_loc] = Line::IndexingCode(indexing_code); } - HeapCellValue::NamedStr(arity, ref name, ref shared_op_desc) => { - let subterms = term_stack - .drain(term_stack.len() - arity..) - .map(Box::new) - .collect(); + RetractionRecord::RemovedLocalSkeletonClauseLocations( + compilation_target, + local_compilation_target, + key, + clause_locs, + ) => { + let listing_src_file_name = self.listing_src_file_name(); - term_stack.push(Term::Clause( - Cell::default(), - name.clone(), - subterms, - shared_op_desc.clone(), - )); + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + compilation_target, + local_compilation_target, + listing_src_file_name, + key, + ) { + Some(skeleton) => skeleton.clause_clause_locs = clause_locs, + None => {} + } } - HeapCellValue::PartialString(..) => { - let string = machine_st.heap_pstr_iter(addr).to_string(); - term_stack.push(Term::Constant( - Cell::default(), - Constant::String(Rc::new(string)), - )); + RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton) => { + match compilation_target { + CompilationTarget::User => { + self.wam_prelude.indices.extensible_predicates.insert(key, skeleton); + } + CompilationTarget::Module(module_name) => { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { + module.extensible_predicates.insert(key, skeleton); + } + } + } } - HeapCellValue::Rational(ref rational) => { - term_stack.push(Term::Constant( - Cell::default(), - Constant::Rational(rational.clone()), - )); + RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => { + match self.wam_prelude.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::DynamicElse( + _, + _, + NextOrFail::Next(ref mut o), + )) + | Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, + _, + NextOrFail::Next(ref mut o), + )) => { + *o = next; + } + _ => {} + } } - _ => { - return Err(SessionError::from(CompilationError::UnreadableTerm)); + RetractionRecord::AppendedNextOrFail(instr_loc, fail) => { + match self.wam_prelude.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::DynamicElse( + _, + _, + ref mut next_or_fail, + )) + | Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, + _, + ref mut next_or_fail, + )) => { + *next_or_fail = fail; + } + _ => {} + } } } } - - debug_assert!(term_stack.len() == 1); - Ok(term_stack.pop().unwrap()) } fn extract_module_export_list_from_heap( - &self, + &mut 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 atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl; let export_list = setup_module_export_list(export_list, atom_tbl)?; Ok(export_list.into_iter().collect()) @@ -890,19 +1057,16 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> { match term { - Term::Clause(_, turnstile, mut terms, _) - if turnstile.as_str() == ":-" && terms.len() == 2 => + Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => { - let body = *terms.pop().unwrap(); - let head = *terms.pop().unwrap(); + let body = terms.pop().unwrap(); + let head = terms.pop().unwrap(); - self.clause_clauses.push((head, body)); + self.payload.clause_clauses.push((head, body)); } - head @ Term::Constant(_, Constant::Atom(..)) | head @ Term::Clause(..) => { - let body = - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)); - - self.clause_clauses.push((head, body)); + head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => { + let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true"))); + self.payload.clause_clauses.push((head, body)); } _ => { return Err(CompilationError::InadmissibleFact); @@ -915,7 +1079,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_extensible_predicate_declaration( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, flag_accessor: impl Fn(&mut LocalPredicateSkeleton) -> &mut bool, retraction_fn: impl Fn(CompilationTarget, PredicateKey) -> RetractionRecord, @@ -926,8 +1090,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { match &compilation_target { CompilationTarget::User => { match self - .load_state - .wam + .wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -936,19 +1099,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { if !*flag_accessor(&mut skeleton.core) { *flag_accessor(&mut skeleton.core) = true; - self.load_state.retraction_info.push_record(retraction_fn( - compilation_target.clone(), - key.clone(), + self.payload.retraction_info.push_record(retraction_fn( + compilation_target, + key, )); } } None => { - if self.load_state.compilation_target == compilation_target { + if self.payload.compilation_target == compilation_target { let mut skeleton = PredicateSkeleton::new(); *flag_accessor(&mut skeleton.core) = true; - self.load_state.add_extensible_predicate( - key.clone(), + self.add_extensible_predicate( + key, skeleton, CompilationTarget::User, ); @@ -959,27 +1122,27 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } } CompilationTarget::Module(ref module_name) => { - match self.load_state.wam.indices.modules.get_mut(module_name) { + match self.wam_prelude.indices.modules.get_mut(module_name) { Some(ref mut module) => match module.extensible_predicates.get_mut(&key) { Some(ref mut skeleton) => { if !*flag_accessor(&mut skeleton.core) { *flag_accessor(&mut skeleton.core) = true; - self.load_state.retraction_info.push_record(retraction_fn( - compilation_target.clone(), - key.clone(), + self.payload.retraction_info.push_record(retraction_fn( + compilation_target, + key, )); } } None => { - if self.load_state.compilation_target == compilation_target { + if self.payload.compilation_target == compilation_target { let mut skeleton = PredicateSkeleton::new(); *flag_accessor(&mut skeleton.core) = true; - self.load_state.add_extensible_predicate( - key.clone(), + self.add_extensible_predicate( + key, skeleton, - compilation_target.clone(), + compilation_target, ); } else { throw_permission_error = true; @@ -987,16 +1150,15 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } }, None => { - self.load_state - .add_dynamically_generated_module(module_name); + self.add_dynamically_generated_module(*module_name); let mut skeleton = PredicateSkeleton::new(); *flag_accessor(&mut skeleton.core) = true; - self.load_state.add_extensible_predicate( - key.clone(), + self.add_extensible_predicate( + key, skeleton, - compilation_target.clone(), + compilation_target, ); } } @@ -1004,17 +1166,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } if !throw_permission_error { - match self.load_state.compilation_target.clone() { + let listing_src_file_name = self.listing_src_file_name(); + let payload_compilation_target = self.payload.compilation_target; + + match payload_compilation_target { CompilationTarget::User => { match self - .load_state - .wam + .wam_prelude .indices .get_local_predicate_skeleton_mut( - self.load_state.compilation_target.clone(), - compilation_target.clone(), - self.load_state.listing_src_file_name(), - key.clone(), + payload_compilation_target, + compilation_target, + listing_src_file_name, + key, ) { Some(skeleton) => { if !*flag_accessor(skeleton) { @@ -1025,19 +1189,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let mut skeleton = LocalPredicateSkeleton::new(); *flag_accessor(&mut skeleton) = true; - self.load_state.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + self.add_local_extensible_predicate( + compilation_target, + key, skeleton, ); } } } CompilationTarget::Module(ref module_name) => { - match self.load_state.wam.indices.modules.get_mut(module_name) { + match self.wam_prelude.indices.modules.get_mut(module_name) { Some(module) => match module .local_extensible_predicates - .get_mut(&(compilation_target.clone(), key.clone())) + .get_mut(&(compilation_target, key)) { Some(skeleton) => { if !*flag_accessor(skeleton) { @@ -1048,23 +1212,22 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let mut skeleton = LocalPredicateSkeleton::new(); *flag_accessor(&mut skeleton) = true; - self.load_state.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + self.add_local_extensible_predicate( + compilation_target, + key, skeleton, ); } }, None => { - self.load_state - .add_dynamically_generated_module(module_name); + self.add_dynamically_generated_module(*module_name); let mut skeleton = LocalPredicateSkeleton::new(); *flag_accessor(&mut skeleton) = true; - self.load_state.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + self.add_local_extensible_predicate( + compilation_target, + key, skeleton, ); } @@ -1072,7 +1235,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } } - self.fail_on_undefined(&compilation_target, key); + self.fail_on_undefined(compilation_target, key); Ok(()) } else { @@ -1083,20 +1246,18 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } } - fn fail_on_undefined(&mut self, compilation_target: &CompilationTarget, key: PredicateKey) { + fn fail_on_undefined(&mut self, compilation_target: CompilationTarget, key: PredicateKey) { /* * DynamicUndefined isn't only applied to dynamic predicates * but to multifile and discontiguous predicates as well. */ - let code_index = self - .load_state - .get_or_insert_code_index(key.clone(), compilation_target.clone()); + let code_index = self.get_or_insert_code_index(key, compilation_target); if let IndexPtr::Undefined = code_index.get() { set_code_index( - &mut self.load_state.retraction_info, - compilation_target, + &mut self.payload.retraction_info, + &compilation_target, key, &code_index, IndexPtr::DynamicUndefined, @@ -1107,7 +1268,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_discontiguous_predicate( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, ) -> Result<(), SessionError> { self.add_extensible_predicate_declaration( @@ -1122,12 +1283,12 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_dynamic_predicate( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, ) -> Result<(), SessionError> { self.add_extensible_predicate_declaration( - compilation_target.clone(), - name.clone(), + compilation_target, + name, arity, |skeleton| &mut skeleton.is_dynamic, RetractionRecord::AddedDynamicPredicate, @@ -1137,7 +1298,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_multifile_predicate( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, ) -> Result<(), SessionError> { self.add_extensible_predicate_declaration( @@ -1152,13 +1313,13 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> { if let Some(predicate_name) = ClauseInfo::name(term) { let arity = ClauseInfo::arity(term); + let predicates_compilation_target = self.payload.predicates.compilation_target; let is_dynamic = self - .load_state - .wam + .wam_prelude .indices .get_predicate_skeleton( - &self.predicates.compilation_target, + &predicates_compilation_target, &(predicate_name, arity), ) .map(|skeleton| skeleton.core.is_dynamic) @@ -1173,15 +1334,18 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } pub(super) fn retract_local_clauses(&mut self, key: &PredicateKey, is_dynamic: bool) { + let payload_compilation_target = self.payload.compilation_target; + let predicates_compilation_target = self.payload.predicates.compilation_target; + let listing_src_file_name = self.listing_src_file_name(); + let clause_locs = match self - .load_state - .wam + .wam_prelude .indices .get_local_predicate_skeleton_mut( - self.load_state.compilation_target.clone(), - self.predicates.compilation_target.clone(), - self.load_state.listing_src_file_name(), - key.clone(), + payload_compilation_target, + predicates_compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => { mem::replace(&mut skeleton.clause_clause_locs, sdeq![]) @@ -1189,29 +1353,47 @@ impl<'a, TS: TermStream> Loader<'a, TS> { _ => return, }; - self.load_state.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::RemovedLocalSkeletonClauseLocations( - self.load_state.compilation_target.clone(), - self.predicates.compilation_target.clone(), - key.clone(), + payload_compilation_target, + predicates_compilation_target, + *key, clause_locs.clone(), ), ); - self.load_state.retract_local_clauses( - self.predicates.compilation_target.clone(), - key.clone(), + self.retract_local_clauses_impl( + predicates_compilation_target, + *key, &clause_locs, ); if is_dynamic { - let clause_clause_compilation_target = match &self.predicates.compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - module_name => module_name.clone(), + let clause_clause_compilation_target = match predicates_compilation_target { + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + module_name => module_name, }; - self.load_state - .retract_local_clause_clauses(clause_clause_compilation_target, &clause_locs); + self.retract_local_clause_clauses(clause_clause_compilation_target, &clause_locs); + } + } +} + +impl<'a> MachinePreludeView<'a> { + #[inline] + pub(super) fn composite_op_dir(&self, compilation_target: &CompilationTarget) -> CompositeOpDir { + match compilation_target { + CompilationTarget::User => CompositeOpDir::new(&self.indices.op_dir, None), + CompilationTarget::Module(ref module_name) => { + match self.indices.modules.get(module_name) { + Some(ref module) => { + CompositeOpDir::new(&self.indices.op_dir, Some(&module.op_dir)) + } + None => { + unreachable!() + } + } + } } } } @@ -1220,50 +1402,40 @@ 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!() + .store(self.machine_st.deref(self.machine_st.registers[2])); + + let module_src = ModuleSource::Library({ + let payload = cell_as_load_state_payload!(subevacuable_addr); + + match payload.compilation_target { + CompilationTarget::Module(module_name) => module_name, + CompilationTarget::User => { + return; } - }, - _ => { - unreachable!() } }); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let use_module = || { let export_list = loader.extract_module_export_list_from_heap(temp_v!(3))?; if export_list.is_empty() { - loader.load_state.use_module(module_src)?; + loader.use_module(module_src)?; } else { - loader - .load_state - .use_qualified_module(module_src, export_list)?; + loader.use_qualified_module(module_src, export_list)?; } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = use_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn load_compiled_library(&mut self) { - let library = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let library = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); if let Some(module) = self.indices.modules.get(&library) { @@ -1272,38 +1444,33 @@ impl Machine { return; } - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); let import_module = || { let export_list = loader.extract_module_export_list_from_heap(temp_v!(2))?; if export_list.is_empty() { - loader.load_state.import_module(library)?; + loader.import_module(library)?; } else { - loader - .load_state - .import_qualified_module(library, export_list)?; + loader.import_qualified_module(library, export_list)?; } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = import_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } else { self.machine_st.fail = true; } } 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 module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - // let export_list = self.machine_st.extract_module_export_list(temp_v!(2)); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); let declare_module = || { // let export_list = export_list?; @@ -1315,11 +1482,11 @@ impl Machine { }; loader.load_decl(Declaration::Module(module_decl))?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = declare_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } #[inline] @@ -1351,145 +1518,135 @@ impl Machine { fn add_extensible_predicate_declaration( &mut self, - decl_adder: impl Fn( - &mut Loader, + decl_adder: impl for<'a> Fn( + &mut Loader<'a, LiveLoadAndMachineState<'a>>, CompilationTarget, - ClauseName, + Atom, usize, ) -> Result<(), SessionError>, ) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let predicate_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(2)])) + let predicate_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) ); let arity = self .machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); + .store(self.machine_st.deref(self.machine_st.registers[3])); - let arity = match Number::try_from((arity, &self.machine_st.heap)) { + let arity = match Number::try_from(arity) { Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => Ok(n.to_usize().unwrap()), - Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => { - Ok(usize::try_from(n).unwrap()) + Ok(Number::Fixnum(n)) if n.get_num() >= 0 && n.get_num() <= MAX_ARITY as i64 => { + Ok(usize::try_from(n.get_num()).unwrap()) } _ => Err(SessionError::from(CompilationError::InvalidRuleHead)), }; - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); - let add_predicate_decl = || { + let add_predicate_decl = move || { decl_adder(&mut loader, compilation_target, predicate_name, arity?)?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_predicate_decl(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_term_expansion_clause(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { let term = loader.read_term_from_heap(temp_v!(1))?; - loader.load_state.incremental_compile_clause( - (clause_name!("term_expansion"), 2), + loader.incremental_compile_clause( + (atom!("term_expansion"), 2), term, CompilationTarget::User, false, AppendOrPrepend::Append, )?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_clause(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_goal_expansion_clause(&mut self) { - let target_module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let target_module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); - let compilation_target = match target_module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match target_module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(target_module_name), }; let add_clause = || { let term = loader.read_term_from_heap(temp_v!(2))?; - loader.load_state.incremental_compile_clause( - (clause_name!("goal_expansion"), 2), + loader.incremental_compile_clause( + (atom!("goal_expansion"), 2), term, compilation_target, false, // backtracking inferences are counted by call_with_inference_limit. AppendOrPrepend::Append, )?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_clause(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_in_situ_filename_module(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let add_in_situ_filename_module = || { - if let Some(filename) = loader.load_state.listing_src_file_name() { + if let Some(filename) = loader.listing_src_file_name() { let module_decl = ModuleDecl { name: filename, exports: vec![], }; - let module_name = module_decl.name.clone(); + let module_name = module_decl.name; if !loader - .load_state - .wam + .wam_prelude .indices .modules .contains_key(&module_decl.name) { let module = Module::new_in_situ(module_decl); loader - .load_state - .wam + .wam_prelude .indices .modules .insert(module_name, module); } else { - loader.load_state.reset_in_situ_module( + loader.reset_in_situ_module( module_decl.clone(), &ListingSource::DynamicallyGenerated, ); - match loader.load_state.wam.indices.modules.get_mut(&module_name) { + match loader.wam_prelude.indices.modules.get_mut(&module_name) { Some(module) => { for (key, value) in module.op_dir.drain(0..) { - let (prec, spec) = value.shared_op_desc().get(); - let mut op_decl = OpDecl::new(prec, spec, key.0); - - op_decl.remove(&mut loader.load_state.wam.indices.op_dir); + let mut op_decl = OpDecl::new(value, key.0); + op_decl.remove(&mut loader.wam_prelude.indices.op_dir); } } None => {} @@ -1497,83 +1654,78 @@ impl Machine { } } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_in_situ_filename_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } - pub(crate) fn loader_from_heap_evacuable( - &mut self, + pub(crate) fn loader_from_heap_evacuable<'a>( + &'a mut self, r: RegType, - ) -> (Loader, usize) { - let (load_state_payload, evacuable_h) = match self - .machine_st - .store(self.machine_st.deref(self.machine_st[r])) - { - Addr::LoadStatePayload(h) => ( - mem::replace( - &mut self.machine_st.heap[h], - HeapCellValue::Addr(Addr::EmptyList), - ), - h, - ), - _ => { - unreachable!() - } - }; + ) -> Loader<'a, LiveLoadAndMachineState<'a>> { + let mut load_state = cell_as_load_state_payload!( + self.machine_st.store(self.machine_st.deref(self.machine_st[r])) + ); - match load_state_payload { - HeapCellValue::LoadStatePayload(payload) => { - (Loader::from_load_state_payload(self, payload), evacuable_h) - } - _ => { - unreachable!() - } + load_state.set_tag(ArenaHeaderTag::LiveLoadState); + + let (wam_prelude, machine_st) = self.prelude_view_and_machine_st(); + + Loader { + payload: LiveLoadAndMachineState { load_state, machine_st }, + wam_prelude, } } #[inline] pub(crate) fn push_load_state_payload(&mut self) { - let payload = Box::new(LoadStatePayload::new(self)); - let addr = Addr::LoadStatePayload( - self.machine_st - .heap - .push(HeapCellValue::LoadStatePayload(payload)), + let payload = arena_alloc!( + LoadStatePayload::new( + self.code_repo.code.len(), + LiveTermStream::new(ListingSource::User), + ), + &mut self.machine_st.arena ); - self.machine_st - .bind(self.machine_st[temp_v!(1)].as_var().unwrap(), addr); + let var = self.machine_st.deref( + self.machine_st.registers[1] + ); + + self.machine_st.bind( + var.as_var().unwrap(), + typed_arena_ptr_as_cell!(payload), + ); } #[inline] pub(crate) fn pop_load_state_payload(&mut self) { - let load_state_payload = match self - .machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) - { - Addr::LoadStatePayload(h) => mem::replace( - &mut self.machine_st.heap[h], - HeapCellValue::Addr(Addr::EmptyList), - ), - _ => { - unreachable!() - } - }; + let load_state_payload = self.machine_st.store( + self.machine_st.deref(self.machine_st.registers[1]) + ); - match load_state_payload { - HeapCellValue::LoadStatePayload(payload) => { - Loader::from_load_state_payload(self, payload); - } - _ => { - // unlike in loader_from_heap_evacuable, - // pop_load_state_payload is allowed to fail to find a - // LoadStatePayload in the heap, as a Rust-side - // top-level command may have failed to write the - // load state payload back to the heap. + // unlike in loader_from_heap_evacuable, + // pop_load_state_payload is allowed to fail to find a + // LoadStatePayload in the heap, as a Rust-side + // top-level command may have failed to write the + // load state payload back to the heap. + + read_heap_cell!(load_state_payload, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::LiveLoadState, payload) => { + unsafe { + std::ptr::drop_in_place( + payload.as_ptr() as *mut LiveLoadState, + ); + } + } + _ => {} + ); } - } + _ => {} + ); } #[inline] @@ -1585,94 +1737,79 @@ impl Machine { let stream = try_or_fail!( self.machine_st, self.machine_st.get_stream_or_alias( - self.machine_st[temp_v!(1)], + self.machine_st.registers[1], &self.indices.stream_aliases, - "$push_load_context", + atom!("$push_load_context"), 2, ) ); - let path = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(2)])) + let path = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) ); - self.load_contexts - .push(LoadContext::new(path.as_str(), stream)); + self.load_contexts.push(LoadContext::new(path.as_str(), stream)); } pub(crate) fn restore_load_state_payload( &mut self, - result: Result, - evacuable_h: usize, + result: Result, SessionError>, ) { match result { - Ok(payload) => { - self.machine_st.heap[evacuable_h] = - HeapCellValue::LoadStatePayload(Box::new(payload)); + Ok(_payload) => { } Err(e) => { - self.throw_session_error(e, (clause_name!("load"), 1)); + self.throw_session_error(e, (atom!("load"), 1)); } } } pub(crate) fn scoped_clause_to_evacuable(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let loader = self.loader_from_heap_evacuable(temp_v!(3)); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; let result = loader.read_and_enqueue_term(temp_v!(2), compilation_target); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn clause_to_evacuable(&mut self) { - let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); - let compilation_target = loader.load_state.compilation_target.clone(); + let loader = self.loader_from_heap_evacuable(temp_v!(2)); + let compilation_target = loader.payload.compilation_target; let result = loader.read_and_enqueue_term(temp_v!(1), compilation_target); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn conclude_load(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let compile_final_terms = || { - if !loader.predicates.is_empty() { + if !loader.payload.predicates.is_empty() { loader.compile_and_submit()?; } - loader.load_state.remove_module_op_exports(); - LiveTermStream::evacuate(loader) + loader.remove_module_op_exports(); + LiveLoadAndMachineState::evacuate(loader) }; let result = compile_final_terms(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn load_context_source(&mut self) { if let Some(load_context) = self.load_contexts.last() { let path_str = load_context.path.to_str().unwrap(); - let path_atom = clause_name!(path_str.to_string(), self.machine_st.atom_tbl); - - let path_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(path_atom, None)), - ); + let path_atom = self.machine_st.atom_tbl.build_with(path_str); - self.machine_st - .unify(path_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(path_atom, self.machine_st.registers[1]); } else { self.machine_st.fail = true; } @@ -1683,17 +1820,9 @@ impl Machine { match load_context.path.file_name() { Some(file_name) if load_context.path.is_file() => { let file_name_str = file_name.to_str().unwrap(); - let file_name_atom = - clause_name!(file_name_str.to_string(), self.machine_st.atom_tbl); - - let file_name_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(file_name_atom, None)), - ); + let file_name_atom = self.machine_st.atom_tbl.build_with(file_name_str); - self.machine_st - .unify(file_name_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(file_name_atom, self.machine_st.registers[1]); return; } _ => { @@ -1709,18 +1838,9 @@ impl Machine { if let Some(load_context) = self.load_contexts.last() { if let Some(directory) = load_context.path.parent() { let directory_str = directory.to_str().unwrap(); + let directory_atom = self.machine_st.atom_tbl.build_with(directory_str); - let directory_atom = - clause_name!(directory_str.to_string(), self.machine_st.atom_tbl); - - let directory_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(directory_atom, None)), - ); - - self.machine_st - .unify(directory_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(directory_atom, self.machine_st.registers[1]); return; } } @@ -1730,14 +1850,7 @@ impl Machine { pub(crate) fn load_context_module(&mut self) { if let Some(load_context) = self.load_contexts.last() { - let module_name_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(load_context.module.clone(), None)), - ); - - self.machine_st - .unify(module_name_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(load_context.module, self.machine_st.registers[1]); } else { self.machine_st.fail = true; } @@ -1745,63 +1858,57 @@ impl Machine { pub(crate) fn load_context_stream(&mut self) { if let Some(load_context) = self.load_contexts.last() { - let stream_addr = Addr::Stream( - self.machine_st - .heap - .push(HeapCellValue::Stream(load_context.stream.clone())), + self.machine_st.unify_constant( + UntypedArenaPtr::from(load_context.stream.as_ptr()), + self.machine_st.registers[1], ); - - self.machine_st - .unify(stream_addr, self.machine_st[temp_v!(1)]); } else { self.machine_st.fail = true; } } - pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) { + pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) { let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]); - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(5)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[5])) ); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let compile_assert = || { - let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); + let mut compile_assert = || { + let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = + Loader::new(self, LiveTermStream::new(ListingSource::User)); - loader.load_state.compilation_target = compilation_target.clone(); + loader.payload.compilation_target = compilation_target; let head = loader.read_term_from_heap(temp_v!(1))?; let body = loader.read_term_from_heap(temp_v!(2))?; let asserted_clause = Term::Clause( Cell::default(), - clause_name!(":-"), - vec![Box::new(head.clone()), Box::new(body.clone())], - fetch_op_spec(clause_name!(":-"), 2, &loader.load_state.wam.indices.op_dir), + atom!(":-"), + vec![head.clone(), body.clone()], ); // if a new predicate was just created, make it dynamic. - loader.add_dynamic_predicate(compilation_target.clone(), key.0.clone(), key.1)?; + loader.add_dynamic_predicate(compilation_target, key.0, key.1)?; - loader.load_state.incremental_compile_clause( - key.clone(), + loader.incremental_compile_clause( + key, asserted_clause, - compilation_target.clone(), + compilation_target, false, append_or_prepend, )?; // the global clock is incremented after each assertion. - loader.load_state.wam.machine_st.global_clock += 1; + LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; loader.compile_clause_clauses( key, @@ -1810,15 +1917,15 @@ impl Machine { append_or_prepend, )?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; match compile_assert() { Ok(_) => {} Err(e) => { let error_pi = match append_or_prepend { - AppendOrPrepend::Append => (clause_name!("assertz"), 1), - AppendOrPrepend::Prepend => (clause_name!("asserta"), 1), + AppendOrPrepend::Append => (atom!("assertz"), 1), + AppendOrPrepend::Prepend => (atom!("asserta"), 1), }; self.throw_session_error(e, error_pi); @@ -1827,43 +1934,41 @@ impl Machine { } pub(crate) fn abolish_clause(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let abolish_clause = || { - let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); - loader.load_state.compilation_target = compilation_target; + let mut abolish_clause = || { + let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> + = Loader::new(self, LiveTermStream::new(ListingSource::User)); + + loader.payload.compilation_target = compilation_target; - let clause_clause_compilation_target = match &loader.load_state.compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - module => module.clone(), + let clause_clause_compilation_target = match compilation_target { + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + module => module, }; let mut clause_clause_target_poses: Vec<_> = loader - .load_state - .wam + .wam_prelude .indices - .get_predicate_skeleton(&loader.load_state.compilation_target, &key) + .get_predicate_skeleton(&compilation_target, &key) .map(|skeleton| { loader - .load_state - .wam + .wam_prelude .indices .get_predicate_skeleton( &clause_clause_compilation_target, - &(clause_name!("$clause"), 2), + &(atom!("$clause"), 2), ) .map(|clause_clause_skeleton| { skeleton @@ -1882,33 +1987,29 @@ impl Machine { .unwrap(); loader - .load_state - .wam + .wam_prelude .indices - .get_predicate_skeleton_mut(&loader.load_state.compilation_target, &key) + .get_predicate_skeleton_mut(&compilation_target, &key) .map(|skeleton| skeleton.reset()); let code_index = loader - .load_state - .get_or_insert_code_index(key, loader.load_state.compilation_target.clone()); + .get_or_insert_code_index(key, compilation_target); code_index.set(IndexPtr::DynamicUndefined); - loader.load_state.compilation_target = clause_clause_compilation_target; + loader.payload.compilation_target = clause_clause_compilation_target; while let Some(target_pos) = clause_clause_target_poses.pop() { - loader - .load_state - .retract_clause((clause_name!("$clause"), 2), target_pos); + loader.retract_clause((atom!("$clause"), 2), target_pos); } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; match abolish_clause() { Ok(_) => {} Err(e) => { - self.throw_session_error(e, (clause_name!("abolish"), 1)); + self.throw_session_error(e, (atom!("abolish"), 1)); } } } @@ -1922,40 +2023,40 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); - let target_pos = match Number::try_from((target_pos, &self.machine_st.heap)) { + let target_pos = match Number::try_from(target_pos) { Ok(Number::Integer(n)) => n.to_usize().unwrap(), - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), _ => unreachable!(), }; - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(4)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])) ); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let clause_clause_compilation_target = match &compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - _ => compilation_target.clone(), + let clause_clause_compilation_target = match compilation_target { + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + _ => compilation_target, }; - let retract_clause = || { - let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); - loader.load_state.compilation_target = compilation_target; + let mut retract_clause = || { + let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = + Loader::new(self, LiveTermStream::new(ListingSource::User)); + + loader.payload.compilation_target = compilation_target; - let clause_clause_loc = loader.load_state.retract_dynamic_clause(key, target_pos); + let clause_clause_loc = loader.retract_dynamic_clause(key, target_pos); // the global clock is incremented after each retraction. - loader.load_state.wam.machine_st.global_clock += 1; + LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; - let target_pos = match loader.load_state.wam.indices.get_predicate_skeleton( + let target_pos = match loader.wam_prelude.indices.get_predicate_skeleton( &clause_clause_compilation_target, - &(clause_name!("$clause"), 2), + &(atom!("$clause"), 2), ) { Some(skeleton) => skeleton .target_pos_of_clause_clause_loc(clause_clause_loc) @@ -1965,79 +2066,74 @@ impl Machine { } }; - loader.load_state.compilation_target = clause_clause_compilation_target; - loader - .load_state - .retract_clause((clause_name!("$clause"), 2), target_pos); + loader.payload.compilation_target = clause_clause_compilation_target; + loader.retract_clause((atom!("$clause"), 2), target_pos); - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; match retract_clause() { Ok(_) => {} Err(e) => { - self.throw_session_error(e, (clause_name!("retract"), 1)); + self.throw_session_error(e, (atom!("retract"), 1)); } } } pub(crate) fn is_consistent_with_term_queue(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); - loader.load_state.wam.machine_st.fail = (!loader.predicates.is_empty() - && loader.predicates.compilation_target != compilation_target) - || !key.is_consistent(&loader.predicates); + LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = + (!loader.payload.predicates.is_empty() + && loader.payload.predicates.compilation_target != compilation_target) + || !key.is_consistent(&loader.payload.predicates); - let result = LiveTermStream::evacuate(loader); - self.restore_load_state_payload(result, evacuable_h); + let result = LiveLoadAndMachineState::evacuate(loader); + self.restore_load_state_payload(result); } pub(crate) fn flush_term_queue(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let flush_term_queue = || { - if !loader.predicates.is_empty() { + if !loader.payload.predicates.is_empty() { loader.compile_and_submit()?; } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = flush_term_queue(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn remove_module_exports(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let remove_module_exports = || { - loader.load_state.remove_module_exports(module_name); - LiveTermStream::evacuate(loader) + loader.remove_module_exports(module_name); + LiveLoadAndMachineState::evacuate(loader) }; let result = remove_module_exports(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_non_counted_backtracking(&mut self) { @@ -2045,26 +2141,24 @@ impl Machine { .machine_st .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); - loader.non_counted_bt_preds.insert(key); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); + loader.payload.non_counted_bt_preds.insert(key); - let result = LiveTermStream::evacuate(loader); - self.restore_load_state_payload(result, evacuable_h); + let result = LiveLoadAndMachineState::evacuate(loader); + self.restore_load_state_payload(result); } pub(crate) fn meta_predicate_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let (predicate_name, arity) = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2073,30 +2167,23 @@ impl Machine { .get_meta_predicate_spec(predicate_name, arity, &compilation_target) { Some(meta_specs) => { - let list_loc = self - .machine_st - .heap - .to_list(meta_specs.iter().map(|meta_spec| match meta_spec { - MetaSpec::Minus => HeapCellValue::Atom(clause_name!("+"), None), - MetaSpec::Plus => HeapCellValue::Atom(clause_name!("-"), None), - MetaSpec::Either => HeapCellValue::Atom(clause_name!("?"), None), + let list_loc = iter_to_heap_list( + &mut self.machine_st.heap, + meta_specs.iter().map(|meta_spec| match meta_spec { + MetaSpec::Minus => atom_as_cell!(atom!("+")), + MetaSpec::Plus => atom_as_cell!(atom!("-")), + MetaSpec::Either => atom_as_cell!(atom!("?")), MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { - HeapCellValue::Addr(Addr::Usize(*arg_num)) + fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) } })); - let heap_loc = self.machine_st.heap.push(HeapCellValue::NamedStr( - 1, - clause_name!("meta_predicate"), - None, - )); + let heap_loc = self.machine_st.heap.len(); - self.machine_st - .heap - .push(HeapCellValue::Addr(Addr::HeapCell(list_loc))); + self.machine_st.heap.push(atom_as_cell!(atom!("meta_predicate"), 1)); + self.machine_st.heap.push(heap_loc_as_cell!(list_loc)); - self.machine_st - .unify(Addr::HeapCell(heap_loc), self.machine_st[temp_v!(4)]); + unify!(self.machine_st, str_loc_as_cell!(heap_loc), self.machine_st.registers[4]); } None => { self.machine_st.fail = true; @@ -2105,18 +2192,16 @@ impl Machine { } pub(crate) fn dynamic_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2134,18 +2219,16 @@ impl Machine { } pub(crate) fn multifile_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2163,18 +2246,16 @@ impl Machine { } pub(crate) fn discontiguous_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2194,24 +2275,15 @@ impl Machine { pub(crate) fn builtin_property(&mut self) { let key = self .machine_st - .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); + .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]); - match ClauseType::from(key.0, key.1, None) { + match ClauseType::from(key.0, key.1) { ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN => { return; } - ClauseType::Named(ref name, arity, _) => { - if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { - self.machine_st.fail = !module.code_dir.contains_key(&(name.clone(), arity)); - - return; - } - } - ClauseType::Op(ref name, ref op_desc, _) => { - if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { - self.machine_st.fail = !module - .code_dir - .contains_key(&(name.clone(), op_desc.arity())); + ClauseType::Named(name, arity, _) => { + if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) { + self.machine_st.fail = !module.code_dir.contains_key(&(name, arity)); return; } @@ -2223,63 +2295,24 @@ impl Machine { } } -impl<'a> Loader<'a, LiveTermStream> { - pub(super) fn to_load_state_payload(mut self) -> LoadStatePayload { - LoadStatePayload { - term_stream: mem::replace( - &mut self.term_stream, - LiveTermStream::new(ListingSource::User), - ), - non_counted_bt_preds: mem::replace(&mut self.non_counted_bt_preds, IndexSet::new()), - compilation_target: self.load_state.compilation_target.take(), - retraction_info: mem::replace( - &mut self.load_state.retraction_info, - RetractionInfo::new(self.load_state.wam.code_repo.code.len()), - ), - predicates: self.predicates.take(), - clause_clauses: mem::replace(&mut self.clause_clauses, vec![]), - module_op_exports: mem::replace(&mut self.load_state.module_op_exports, vec![]), - } - } - - pub(super) fn from_load_state_payload( - wam: &'a mut Machine, - mut payload: Box, - ) -> Self { - Loader { - term_stream: mem::replace( - &mut payload.term_stream, - LiveTermStream::new(ListingSource::User), - ), - non_counted_bt_preds: mem::replace(&mut payload.non_counted_bt_preds, IndexSet::new()), - clause_clauses: mem::replace(&mut payload.clause_clauses, vec![]), - predicates: payload.predicates.take(), - load_state: LoadState { - compilation_target: payload.compilation_target.take(), - module_op_exports: mem::replace(&mut payload.module_op_exports, vec![]), - retraction_info: mem::replace(&mut payload.retraction_info, RetractionInfo::new(0)), - wam, - }, - } - } - +impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { fn read_and_enqueue_term( mut self, term_reg: RegType, compilation_target: CompilationTarget, - ) -> Result { - if self.predicates.compilation_target != compilation_target { - if !self.predicates.is_empty() { + ) -> Result>, SessionError> { + if self.payload.predicates.compilation_target != compilation_target { + if !self.payload.predicates.is_empty() { self.compile_and_submit()?; } - self.predicates.compilation_target = compilation_target; + self.payload.predicates.compilation_target = compilation_target; } let term = self.read_term_from_heap(term_reg)?; self.add_clause_clause_if_dynamic(&term)?; - self.term_stream.term_queue.push_back(term); + self.payload.term_stream.term_queue.push_back(term); self.load() } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index fbfb1bcf5..d62e5b5b1 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -1,17 +1,14 @@ -use prolog_parser::ast::*; -use prolog_parser::{clause_name, temp_v}; +use crate::atom_table::*; +use crate::parser::ast::*; -use crate::forms::{ModuleSource, Number}; //, PredicateKey}; +use crate::forms::*; use crate::machine::heap::*; use crate::machine::loader::CompilationTarget; -use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::machine::PredicateKey; -use crate::rug::Integer; +use crate::types::*; -use std::rc::Rc; - -pub(crate) type MachineStub = Vec; +pub type MachineStub = Vec; +pub type MachineStubGen = Box MachineStub>; #[derive(Debug, Clone, Copy)] enum ErrorProvenance { @@ -26,13 +23,64 @@ pub(crate) struct MachineError { from: ErrorProvenance, } +// from 7.12.2 b) of 13211-1:1995 +#[derive(Debug, Clone, Copy)] +pub(crate) enum ValidType { + Atom, + Atomic, + // Boolean, + Byte, + Callable, + Character, + Compound, + Evaluable, + Float, + InByte, + InCharacter, + Integer, + List, + #[allow(unused)] Number, + Pair, + // PredicateIndicator, + // Variable + TcpListener, +} + +impl ValidType { + pub(crate) fn as_atom(self) -> Atom { + match self { + ValidType::Atom => atom!("atom"), + ValidType::Atomic => atom!("atomic"), + // ValidType::Boolean => atom!("boolean"), + ValidType::Byte => atom!("byte"), + ValidType::Callable => atom!("callable"), + ValidType::Character => atom!("character"), + ValidType::Compound => atom!("compound"), + ValidType::Evaluable => atom!("evaluable"), + ValidType::Float => atom!("float"), + ValidType::InByte => atom!("in_byte"), + ValidType::InCharacter => atom!("in_character"), + ValidType::Integer => atom!("integer"), + ValidType::List => atom!("list"), + ValidType::Number => atom!("number"), + ValidType::Pair => atom!("pair"), + // ValidType::PredicateIndicator => atom!("predicate_indicator"), + // ValidType::Variable => atom!("variable") + ValidType::TcpListener => atom!("tcp_listener"), + } + } +} + pub(crate) trait TypeError { - fn type_error(self, h: usize, valid_type: ValidType) -> MachineError; + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError; } -impl TypeError for Addr { - fn type_error(self, _: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), addr(self)]); +impl TypeError for HeapCellValue { + fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [atom(valid_type.as_atom()), cell(self)] + ); MachineError { stub, @@ -42,21 +90,29 @@ impl TypeError for Addr { } } -impl TypeError for HeapCellValue { - fn type_error(self, _: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), value(self)]); +impl TypeError for MachineStub { + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)], + [self] + ); MachineError { stub, location: None, - from: ErrorProvenance::Received, + from: ErrorProvenance::Constructed, } } } -impl TypeError for MachineStub { - fn type_error(self, h: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), aux(h, 0)], [self]); +impl TypeError for FunctorStub { + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)], + [self] + ); MachineError { stub, @@ -67,8 +123,14 @@ impl TypeError for MachineStub { } impl TypeError for Number { - fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), number(self)]); + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [ + atom(valid_type.as_atom()), + number(&mut machine_st.arena, self) + ] + ); MachineError { stub, @@ -79,14 +141,24 @@ impl TypeError for Number { } pub(crate) trait PermissionError { - fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError; -} - -impl PermissionError for Addr { - fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError { + fn permission_error( + self, + machine_st: &mut MachineState, + index_atom: Atom, + perm: Permission, + ) -> MachineError; +} + +impl PermissionError for HeapCellValue { + fn permission_error( + self, + _machine_st: &mut MachineState, + index_atom: Atom, + perm: Permission, + ) -> MachineError { let stub = functor!( - "permission_error", - [atom(perm.as_str()), atom(index_str), addr(self)] + atom!("permission_error"), + [atom(perm.as_atom()), atom(index_atom), cell(self)] ); MachineError { @@ -98,10 +170,19 @@ impl PermissionError for Addr { } impl PermissionError for MachineStub { - fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError { + fn permission_error( + self, + machine_st: &mut MachineState, + index_atom: Atom, + perm: Permission, + ) -> MachineError { let stub = functor!( - "permission_error", - [atom(perm.as_str()), atom(index_str), aux(h, 0)], + atom!("permission_error"), + [ + atom(perm.as_atom()), + atom(index_atom), + str(machine_st.heap.len(), 0) + ], [self] ); @@ -114,12 +195,12 @@ impl PermissionError for MachineStub { } pub(super) trait DomainError { - fn domain_error(self, error: DomainErrorType) -> MachineError; + fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError; } -impl DomainError for Addr { - fn domain_error(self, error: DomainErrorType) -> MachineError { - let stub = functor!("domain_error", [atom(error.as_str()), addr(self)]); +impl DomainError for HeapCellValue { + fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { + let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]); MachineError { stub, @@ -130,8 +211,11 @@ impl DomainError for Addr { } impl DomainError for Number { - fn domain_error(self, error: DomainErrorType) -> MachineError { - let stub = functor!("domain_error", [atom(error.as_str()), number(self)]); + fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { + let stub = functor!( + atom!("domain_error"), + [atom(error.as_atom()), number(&mut machine_st.arena, self)] + ); MachineError { stub, @@ -141,18 +225,19 @@ impl DomainError for Number { } } -impl MachineError { - pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { - functor!( - "/", - SharedOpDesc::new(400, YFX), - [clause_name(name), integer(arity)] - ) - } +pub(super) type FunctorStub = [HeapCellValue; 3]; +#[inline(always)] +pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub { + [atom_as_cell!(atom!("/"), 2), + atom_as_cell!(name), + fixnum_as_cell!(Fixnum::build_with(arity as i64))] +} + +impl MachineState { #[inline] - pub(super) fn interrupt_error() -> Self { - let stub = functor!("$interrupt_thrown"); + pub(super) fn interrupt_error(&mut self) -> MachineError { + let stub = functor!(atom!("$interrupt_thrown")); MachineError { stub, @@ -161,8 +246,8 @@ impl MachineError { } } - pub(super) fn evaluation_error(eval_error: EvalError) -> Self { - let stub = functor!("evaluation_error", [atom(eval_error.as_str())]); + pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError { + let stub = functor!(atom!("evaluation_error"), [atom(eval_error.as_atom())]); MachineError { stub, @@ -171,30 +256,26 @@ impl MachineError { } } - pub(super) fn type_error(h: usize, valid_type: ValidType, culprit: T) -> Self { - culprit.type_error(h, valid_type) + pub(super) fn type_error( + &mut self, + valid_type: ValidType, + culprit: T, + ) -> MachineError { + culprit.type_error(self, valid_type) } pub(super) fn module_resolution_error( - h: usize, - mod_name: ClauseName, - name: ClauseName, + &mut self, + mod_name: Atom, + name: Atom, arity: usize, - ) -> Self { - let res_stub = functor!( - ":", - SharedOpDesc::new(600, XFY), - [clause_name(mod_name), clause_name(name)] - ); + ) -> MachineError { + let h = self.heap.len(); - let ind_stub = functor!( - "/", - SharedOpDesc::new(400, YFX), - [aux(h + 2, 0), integer(arity)], - [res_stub] - ); + let res_stub = functor!(atom!(":"), [atom(mod_name), atom(name)]); + let ind_stub = functor!(atom!("/"), [str(h + 2, 0), fixnum(arity)], [res_stub]); - let stub = functor!("evaluation_error", [aux(h, 0)], [ind_stub]); + let stub = functor!(atom!("evaluation_error"), [str(h, 0)], [ind_stub]); MachineError { stub, @@ -203,10 +284,13 @@ impl MachineError { } } - pub(super) fn existence_error(h: usize, err: ExistenceError) -> Self { + pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError { match err { ExistenceError::Module(name) => { - let stub = functor!("existence_error", [atom("source_sink"), clause_name(name)]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("source_sink")), atom(name)] + ); MachineError { stub, @@ -215,13 +299,13 @@ impl MachineError { } } ExistenceError::Procedure(name, arity) => { - let culprit = functor!( - "/", - SharedOpDesc::new(400, YFX), - [clause_name(name), integer(arity)] - ); + let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]); - let stub = functor!("existence_error", [atom("procedure"), aux(h, 0)], [culprit]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("procedure")), str(self.heap.len(), 0)], + [culprit] + ); MachineError { stub, @@ -233,8 +317,8 @@ impl MachineError { let source_stub = source.as_functor_stub(); let stub = functor!( - "existence_error", - [atom("source_sink"), aux(h, 0)], + atom!("existence_error"), + [atom(atom!("source_sink")), str(self.heap.len(), 0)], [source_stub] ); @@ -245,7 +329,10 @@ impl MachineError { } } ExistenceError::SourceSink(culprit) => { - let stub = functor!("existence_error", [atom("source_sink"), addr(culprit)]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("source_sink")), cell(culprit)] + ); MachineError { stub, @@ -254,7 +341,10 @@ impl MachineError { } } ExistenceError::Stream(culprit) => { - let stub = functor!("existence_error", [atom("stream"), addr(culprit)]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("stream")), cell(culprit)] + ); MachineError { stub, @@ -266,36 +356,41 @@ impl MachineError { } pub(super) fn permission_error( - h: usize, + &mut self, err: Permission, - index_str: &'static str, + index_atom: Atom, culprit: T, - ) -> Self { - culprit.permission_error(h, index_str, err) + ) -> MachineError { + culprit.permission_error(self, index_atom, err) } - fn arithmetic_error(h: usize, err: ArithmeticError) -> Self { + pub(super) fn evaluable_error(&mut self, name: Atom, arity: usize) -> MachineError { + let evaluable_stub = functor_stub(name, arity); + evaluable_stub.type_error(self, ValidType::Evaluable) + } + + fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError { match err { - ArithmeticError::UninstantiatedVar => Self::instantiation_error(), - ArithmeticError::NonEvaluableFunctor(name, arity) => { - let culprit = functor!( - "/", - SharedOpDesc::new(400, YFX), - [constant(h, &name), integer(arity)] - ); + ArithmeticError::UninstantiatedVar => self.instantiation_error(), + ArithmeticError::NonEvaluableFunctor(literal, arity) => { + let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]); - Self::type_error(h, ValidType::Evaluable, culprit) + self.type_error(ValidType::Evaluable, culprit) } } } #[inline] - pub(super) fn domain_error(error: DomainErrorType, culprit: T) -> Self { - culprit.domain_error(error) + pub(super) fn domain_error( + &mut self, + error: DomainErrorType, + culprit: T, + ) -> MachineError { + culprit.domain_error(self, error) } - pub(super) fn instantiation_error() -> Self { - let stub = functor!("instantiation_error"); + pub(super) fn instantiation_error(&mut self) -> MachineError { + let stub = functor!(atom!("instantiation_error")); MachineError { stub, @@ -304,81 +399,91 @@ impl MachineError { } } - pub(super) fn session_error(h: usize, err: SessionError) -> Self { + pub(super) fn session_error(&mut self, err: SessionError) -> MachineError { match err { // SessionError::CannotOverwriteBuiltIn(pred_str) | /* SessionError::CannotOverwriteImport(pred_str) => { Self::permission_error( + atom_tbl, h, Permission::Modify, - "private_procedure", - functor!(clause_name(pred_str)), + atom!("private_procedure"), + functor!(atom(pred_str)), ) } */ - SessionError::ExistenceError(err) => Self::existence_error(h, err), + SessionError::ExistenceError(err) => self.existence_error(err), // SessionError::InvalidFileName(filename) => { // Self::existence_error(h, ExistenceError::Module(filename)) // } - SessionError::ModuleDoesNotContainExport(..) => Self::permission_error( - h, - Permission::Access, - "private_procedure", - functor!("module_does_not_contain_claimed_export"), - ), - SessionError::ModuleCannotImportSelf(module_name) => Self::permission_error( - h, - Permission::Modify, - "module", - functor!("module_cannot_import_self", [clause_name(module_name)]), - ), - SessionError::NamelessEntry => Self::permission_error( - h, - Permission::Create, - "static_procedure", - functor!("nameless_procedure"), - ), + SessionError::ModuleDoesNotContainExport(..) => { + let error_atom = atom!("module_does_not_contain_claimed_export"); + + self.permission_error( + Permission::Access, + atom!("private_procedure"), + functor!(error_atom), + ) + } + SessionError::ModuleCannotImportSelf(module_name) => { + let error_atom = atom!("module_cannot_import_self"); + + self.permission_error( + Permission::Modify, + atom!("module"), + functor!(error_atom, [atom(module_name)]), + ) + } + SessionError::NamelessEntry => { + let error_atom = atom!("nameless_procedure"); + self.permission_error(Permission::Create, atom!("static_procedure"), functor!(error_atom)) + } SessionError::OpIsInfixAndPostFix(op) => { - Self::permission_error(h, Permission::Create, "operator", functor!(clause_name(op))) + self.permission_error(Permission::Create, atom!("operator"), functor!(op)) } - SessionError::CompilationError(err) => Self::syntax_error(h, err), + SessionError::CompilationError(err) => self.syntax_error(err), SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => { - let functor_stub = Self::functor_stub(key.0, key.1); + let functor_stub = functor_stub(key.0, key.1); + let stub = functor!( - ":", - SharedOpDesc::new(600, XFY), - [clause_name(compilation_target.module_name()), aux(h + 4, 0)], + atom!(":"), + [ + atom(compilation_target.module_name()), + str(self.heap.len() + 4, 0) + ], [functor_stub] ); - Self::permission_error( - h, + self.permission_error( Permission::Modify, - "not_declared_multifile_or_discontiguous", + atom!("not_declared_multifile_or_discontiguous"), stub, ) } - SessionError::QueryCannotBeDefinedAsFact => Self::permission_error( - h, - Permission::Create, - "static_procedure", - functor!("query_cannot_be_defined_as_fact"), - ), + SessionError::QueryCannotBeDefinedAsFact => { + let error_atom = atom!("query_cannot_be_defined_as_fact"); + + self.permission_error( + Permission::Create, + atom!("static_procedure"), + functor!(error_atom), + ) + } } } - pub(super) fn syntax_error>(h: usize, err: E) -> Self { + pub(super) fn syntax_error>(&mut self, err: E) -> MachineError { let err = err.into(); if let CompilationError::Arithmetic(err) = err { - return Self::arithmetic_error(h, err); + return self.arithmetic_error(err); } let location = err.line_and_col_num(); - let stub = err.as_functor(h); + let stub = err.as_functor(); - let stub = functor!("syntax_error", [aux(h, 0)], [stub]); + let stub = functor!(atom!("syntax_error"), [str(self.heap.len(), 0)], [stub]); MachineError { stub, @@ -387,8 +492,8 @@ impl MachineError { } } - pub(super) fn representation_error(flag: RepFlag) -> Self { - let stub = functor!("representation_error", [atom(flag.as_str())]); + pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError { + let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]); MachineError { stub, @@ -397,13 +502,53 @@ impl MachineError { } } + pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub { + let location = err.location; + let err_len = err.len(); + + let h = self.heap.len(); + + let mut stub = vec![ + atom_as_cell!(atom!("error"), 2), + str_loc_as_cell!(h + 3), + str_loc_as_cell!(h + 3 + err_len), + ]; + + stub.extend(err.into_iter(3)); + + if let Some((line_num, _)) = location { + stub.push(atom_as_cell!(atom!(":"), 2)); + stub.push(str_loc_as_cell!(h + 6 + err_len)); + stub.push(integer_as_cell!(Number::arena_from( + line_num, + &mut self.arena + ))); + } + + stub.extend(src.iter()); + stub + } + + pub(super) fn throw_exception(&mut self, err: MachineStub) { + let h = self.heap.len(); + + self.ball.boundary = 0; + self.ball.stub.truncate(0); + + self.heap.extend(err.into_iter()); + + self.registers[1] = str_loc_as_cell!(h); + + self.set_ball(); + self.unwind_stack(); + } +} + +impl MachineError { fn into_iter(self, offset: usize) -> Box> { match self.from { ErrorProvenance::Constructed => { - Box::new(self.stub.into_iter().map(move |hcv| match hcv { - HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr + offset), - hcv => hcv, - })) + Box::new(self.stub.into_iter().map(move |hcv| hcv + offset)) } ErrorProvenance::Received => Box::new(self.stub.into_iter()), } @@ -415,7 +560,7 @@ impl MachineError { } #[derive(Debug)] -pub(crate) enum CompilationError { +pub enum CompilationError { Arithmetic(ArithmeticError), ParserError(ParserError), // BadPendingByte, @@ -433,7 +578,7 @@ pub(crate) enum CompilationError { InvalidModuleExport, InvalidRuleHead, InvalidUseModuleDecl, - InvalidModuleResolution(ClauseName), + InvalidModuleResolution(Atom), UnreadableTerm, } @@ -459,34 +604,60 @@ impl CompilationError { } } - pub(crate) fn as_functor(&self, _h: usize) -> MachineStub { + pub(crate) fn as_functor(&self) -> MachineStub { match self { - &CompilationError::Arithmetic(..) => functor!("arithmetic_error"), + &CompilationError::Arithmetic(..) => { + functor!(atom!("arithmetic_error")) + } // &CompilationError::BadPendingByte => - // functor!("bad_pending_byte"), - &CompilationError::CannotParseCyclicTerm => functor!("cannot_parse_cyclic_term"), + // functor!(atom_from_ss!("bad_pending_byte"), atom_tbl), + &CompilationError::CannotParseCyclicTerm => { + functor!(atom!("cannot_parse_cyclic_term")) + } // &CompilationError::ExpandedTermsListNotAList => - // functor!("expanded_terms_list_is_not_a_list"), - &CompilationError::ExpectedRel => functor!("expected_relation"), + // functor!(atom_tbl.build_with_static_str("expanded_terms_list_is_not_a_list")), + &CompilationError::ExpectedRel => { + functor!(atom!("expected_relation")) + } // &CompilationError::ExpectedTopLevelTerm => - // functor!("expected_atom_or_cons_or_clause"), - &CompilationError::InadmissibleFact => functor!("inadmissible_fact"), - &CompilationError::InadmissibleQueryTerm => functor!("inadmissible_query_term"), - &CompilationError::InconsistentEntry => functor!("inconsistent_entry"), + // functor!(atom_from_ss!("expected_atom_or_cons_or_clause"), atom_tbl), + &CompilationError::InadmissibleFact => { + functor!(atom!("inadmissible_fact")) + } + &CompilationError::InadmissibleQueryTerm => { + functor!(atom!("inadmissible_query_term")) + } + &CompilationError::InconsistentEntry => { + functor!(atom!("inconsistent_entry")) + } // &CompilationError::InvalidDoubleQuotesDecl => - // functor!("invalid_double_quotes_declaration"), + // functor!(atom_from_ss!("invalid_double_quotes_declaration"), atom_tbl), // &CompilationError::InvalidHook => - // functor!("invalid_hook"), - &CompilationError::InvalidMetaPredicateDecl => functor!("invalid_meta_predicate_decl"), - &CompilationError::InvalidModuleDecl => functor!("invalid_module_declaration"), - &CompilationError::InvalidModuleExport => functor!("invalid_module_export"), + // functor!(atom_from_ss!("invalid_hook"), atom_tbl), + &CompilationError::InvalidMetaPredicateDecl => { + functor!(atom!("invalid_meta_predicate_decl")) + } + &CompilationError::InvalidModuleDecl => { + functor!(atom!("invalid_module_declaration")) + } + &CompilationError::InvalidModuleExport => { + functor!(atom!("invalid_module_export")) + } &CompilationError::InvalidModuleResolution(ref module_name) => { - functor!("no_such_module", [clause_name(module_name.clone())]) + functor!(atom!("no_such_module"), [atom(module_name)]) + } + &CompilationError::InvalidRuleHead => { + functor!(atom!("invalid_head_of_rule")) + } + &CompilationError::InvalidUseModuleDecl => { + functor!(atom!("invalid_use_module_declaration")) + } + &CompilationError::ParserError(ref err) => { + functor!(err.as_atom()) + } + &CompilationError::UnreadableTerm => { + functor!(atom!("unreadable_term")) } - &CompilationError::InvalidRuleHead => functor!("invalid_head_of_rule"), - &CompilationError::InvalidUseModuleDecl => functor!("invalid_use_module_declaration"), - &CompilationError::ParserError(ref err) => functor!(err.as_str()), - &CompilationError::UnreadableTerm => functor!("unreadable_term"), } } } @@ -504,63 +675,15 @@ pub(crate) enum Permission { impl Permission { #[inline] - pub(crate) fn as_str(self) -> &'static str { - match self { - Permission::Access => "access", - Permission::Create => "create", - Permission::InputStream => "input", - Permission::Modify => "modify", - Permission::Open => "open", - Permission::OutputStream => "output", - Permission::Reposition => "reposition", - } - } -} - -// from 7.12.2 b) of 13211-1:1995 -#[derive(Debug, Clone, Copy)] -pub(crate) enum ValidType { - Atom, - Atomic, - // Boolean, - Byte, - Callable, - Character, - Compound, - Evaluable, - Float, - InByte, - InCharacter, - Integer, - List, - Number, - Pair, - // PredicateIndicator, - // Variable - TcpListener, -} - -impl ValidType { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - ValidType::Atom => "atom", - ValidType::Atomic => "atomic", - // ValidType::Boolean => "boolean", - ValidType::Byte => "byte", - ValidType::Callable => "callable", - ValidType::Character => "character", - ValidType::Compound => "compound", - ValidType::Evaluable => "evaluable", - ValidType::Float => "float", - ValidType::InByte => "in_byte", - ValidType::InCharacter => "in_character", - ValidType::Integer => "integer", - ValidType::List => "list", - ValidType::Number => "number", - ValidType::Pair => "pair", - // ValidType::PredicateIndicator => "predicate_indicator", - // ValidType::Variable => "variable" - ValidType::TcpListener => "tcp_listener", + Permission::Access => atom!("access"), + Permission::Create => atom!("create"), + Permission::InputStream => atom!("input"), + Permission::Modify => atom!("modify"), + Permission::Open => atom!("open"), + Permission::OutputStream => atom!("output"), + Permission::Reposition => atom!("reposition"), } } } @@ -576,14 +699,14 @@ pub(crate) enum DomainErrorType { } impl DomainErrorType { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - DomainErrorType::IOMode => "io_mode", - DomainErrorType::NotLessThanZero => "not_less_than_zero", - DomainErrorType::Order => "order", - DomainErrorType::SourceSink => "source_sink", - DomainErrorType::Stream => "stream", - DomainErrorType::StreamOrAlias => "stream_or_alias", + DomainErrorType::IOMode => atom!("io_mode"), + DomainErrorType::NotLessThanZero => atom!("not_less_than_zero"), + DomainErrorType::Order => atom!("order"), + DomainErrorType::SourceSink => atom!("source_sink"), + DomainErrorType::Stream => atom!("stream"), + DomainErrorType::StreamOrAlias => atom!("stream_or_alias"), } } } @@ -601,22 +724,22 @@ pub(crate) enum RepFlag { } impl RepFlag { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - RepFlag::Character => "character", - RepFlag::CharacterCode => "character_code", - RepFlag::InCharacterCode => "in_character_code", - RepFlag::MaxArity => "max_arity", - RepFlag::Term => "term", - // RepFlag::MaxInteger => "max_integer", - // RepFlag::MinInteger => "min_integer" + RepFlag::Character => atom!("character"), + RepFlag::CharacterCode => atom!("character_code"), + RepFlag::InCharacterCode => atom!("in_character_code"), + RepFlag::MaxArity => atom!("max_arity"), + RepFlag::Term => atom!("term"), + // RepFlag::MaxInteger => atom!("max_integer"), + // RepFlag::MinInteger => atom!("min_integer") } } } // from 7.12.2 g) of 13211-1:1995 #[derive(Debug, Clone, Copy)] -pub(crate) enum EvalError { +pub enum EvalError { FloatOverflow, Undefined, // Underflow, @@ -624,93 +747,108 @@ pub(crate) enum EvalError { } impl EvalError { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - EvalError::FloatOverflow => "float_overflow", - EvalError::Undefined => "undefined", - // EvalError::FloatUnderflow => "underflow", - EvalError::ZeroDivisor => "zero_divisor", + EvalError::FloatOverflow => atom!("float_overflow"), + EvalError::Undefined => atom!("undefined"), + // EvalError::FloatUnderflow => atom!("underflow"), + EvalError::ZeroDivisor => atom!("zero_divisor"), } } } // used by '$skip_max_list'. -#[derive(Debug, Clone, Copy)] -pub(super) enum CycleSearchResult { +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CycleSearchResult { EmptyList, NotList, PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. ProperList(usize), // the list length. - PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string. - UntouchedList(usize), // the address of an uniterated Addr::Lis(address). + PStrLocation(usize, usize), // list length (up to max), the heap address of the PStrOffset + UntouchedList(usize), // the address of an uniterated Addr::Lis(address). + UntouchedCStr(Atom, usize), } impl MachineState { // see 8.4.3 of Draft Technical Corrigendum 2. - pub(super) fn check_sort_errors(&self) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("sort"), 2); - let list = self.store(self.deref(self[temp_v!(1)].clone())); - let sorted = self.store(self.deref(self[temp_v!(2)].clone())); + pub(super) fn check_sort_errors(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("sort"), 2); - match self.detect_cycles(list.clone()) { + let list = self.registers[1]; + let sorted = self.registers[2]; + + match self.detect_cycles(list) { CycleSearchResult::PartialList(..) => { - return Err(self.error_form(MachineError::instantiation_error(), stub)) + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())) } CycleSearchResult::NotList => { - return Err( - self.error_form(MachineError::type_error(0, ValidType::List, list), stub) - ) + let err = self.type_error(ValidType::List, list); + return Err(self.error_form(err, stub_gen())); } _ => {} }; - match self.detect_cycles(sorted.clone()) { - CycleSearchResult::NotList if !sorted.is_ref() => { - Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub)) + match self.detect_cycles(sorted) { + CycleSearchResult::NotList if !sorted.is_var() => { + let err = self.type_error(ValidType::List, sorted); + Err(self.error_form(err, stub_gen())) } _ => Ok(()), } } - fn check_for_list_pairs(&self, list: Addr) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); + fn check_for_list_pairs(&mut self, mut list: HeapCellValue) -> CallResult { + let stub_gen = || functor_stub(atom!("keysort"), 2); - match self.detect_cycles(list.clone()) { - CycleSearchResult::NotList if !list.is_ref() => { - Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub)) + match self.detect_cycles(list) { + CycleSearchResult::NotList if !list.is_var() => { + let err = self.type_error(ValidType::List, list); + Err(self.error_form(err, stub_gen())) } _ => { - let mut addr = list; - - while let Addr::Lis(l) = self.store(self.deref(addr)) { - let mut new_l = l; - - loop { - match self.heap.clone(new_l) { - HeapCellValue::Addr(Addr::Str(l)) => { - new_l = l; - } - HeapCellValue::NamedStr(2, ref name, Some(_)) - if name.as_str() == "-" => - { - break; - } - HeapCellValue::Addr(Addr::HeapCell(_)) => { - break; + loop { + read_heap_cell!(self.store(self.deref(list)), + (HeapCellValueTag::Lis, l) => { + let mut new_l = l; + + loop { + read_heap_cell!(self.heap[new_l], + (HeapCellValueTag::Str, s) => { + new_l = s; + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("-") && arity == 2 { + break; + } else { + let err = self.type_error( + ValidType::Pair, + list_loc_as_cell!(l), + ); + + return Err(self.error_form(err, stub_gen())); + } + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => { + break; + } + _ => { + let err = self.type_error( + ValidType::Pair, + list_loc_as_cell!(l), + ); + + return Err(self.error_form(err, stub_gen())); + } + ); } - HeapCellValue::Addr(Addr::StackCell(..)) => { - break; - } - _ => { - return Err(self.error_form( - MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)), - stub, - )) - } - }; - } - addr = Addr::HeapCell(l + 1); + list = heap_loc_as_cell!(l+1); + } + _ => { + break; + } + ); } Ok(()) @@ -719,112 +857,48 @@ impl MachineState { } // see 8.4.4 of Draft Technical Corrigendum 2. - pub(super) fn check_keysort_errors(&self) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); + pub(super) fn check_keysort_errors(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("keysort"), 2); - let pairs = self.store(self.deref(self[temp_v!(1)].clone())); - let sorted = self.store(self.deref(self[temp_v!(2)].clone())); + let pairs = self.store(self.deref(self[temp_v!(1)])); + let sorted = self.store(self.deref(self[temp_v!(2)])); - match self.detect_cycles(pairs.clone()) { + match self.detect_cycles(pairs) { CycleSearchResult::PartialList(..) => { - Err(self.error_form(MachineError::instantiation_error(), stub)) + let err = self.instantiation_error(); + Err(self.error_form(err, stub_gen())) } CycleSearchResult::NotList => { - Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub)) + let err = self.type_error(ValidType::List, pairs); + Err(self.error_form(err, stub_gen())) } _ => Ok(()), }?; self.check_for_list_pairs(sorted) } - - #[inline] - pub(crate) fn type_error( - &self, - valid_type: ValidType, - culprit: T, - caller: ClauseName, - arity: usize, - ) -> MachineStub { - let stub = MachineError::functor_stub(caller, arity); - let err = MachineError::type_error(self.heap.h(), valid_type, culprit); - - return self.error_form(err, stub); - } - - #[inline] - pub(crate) fn representation_error( - &self, - rep_flag: RepFlag, - caller: ClauseName, - arity: usize, - ) -> MachineStub { - let stub = MachineError::functor_stub(caller, arity); - let err = MachineError::representation_error(rep_flag); - - return self.error_form(err, stub); - } - - pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub { - let location = err.location; - let err_len = err.len(); - - let h = self.heap.h(); - let mut stub = vec![ - HeapCellValue::NamedStr(2, clause_name!("error"), None), - HeapCellValue::Addr(Addr::HeapCell(h + 3)), - HeapCellValue::Addr(Addr::HeapCell(h + 3 + err_len)), - ]; - - stub.extend(err.into_iter(3)); - - if let Some((line_num, _)) = location { - let colon_op_desc = Some(SharedOpDesc::new(600, XFY)); - - stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc)); - stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len))); - stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num)))); - } - - stub.extend(src.into_iter()); - stub - } - - pub(super) fn throw_exception(&mut self, err: MachineStub) { - let h = self.heap.h(); - - self.ball.boundary = 0; - self.ball.stub.truncate(0); - - self.heap.append(err); - - self.registers[1] = Addr::HeapCell(h); - - self.set_ball(); - self.unwind_stack(); - } } #[derive(Debug)] -pub(crate) enum ExistenceError { - Module(ClauseName), +pub enum ExistenceError { + Module(Atom), ModuleSource(ModuleSource), - Procedure(ClauseName, usize), - SourceSink(Addr), - Stream(Addr), + Procedure(Atom, usize), + SourceSink(HeapCellValue), + Stream(HeapCellValue), } #[derive(Debug)] -pub(crate) enum SessionError { +pub enum SessionError { CompilationError(CompilationError), - // CannotOverwriteBuiltIn(ClauseName), - // CannotOverwriteImport(ClauseName), + // CannotOverwriteBuiltIn(Atom), + // CannotOverwriteImport(Atom), ExistenceError(ExistenceError), - // InvalidFileName(ClauseName), - ModuleDoesNotContainExport(ClauseName, PredicateKey), - ModuleCannotImportSelf(ClauseName), + // InvalidFileName(Atom), + ModuleDoesNotContainExport(Atom, PredicateKey), + ModuleCannotImportSelf(Atom), NamelessEntry, - OpIsInfixAndPostFix(ClauseName), + OpIsInfixAndPostFix(Atom), PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey), QueryCannotBeDefinedAsFact, } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index e66a87138..6d5be8c14 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -1,53 +1,43 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; +use crate::parser::ast::*; +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; + use crate::machine::code_repo::CodeRepo; use crate::machine::heap::*; +use crate::machine::loader::*; +use crate::machine::machine_errors::MachineStub; use crate::machine::machine_state::*; -use crate::machine::partial_string::*; -use crate::machine::raw_block::RawBlockTraits; use crate::machine::streams::Stream; -use crate::machine::term_stream::LoadStatePayload; -use crate::machine::CompilationTarget; -use crate::rug::{Integer, Rational}; -use ordered_float::OrderedFloat; use indexmap::IndexMap; use std::cell::Cell; use std::cmp::Ordering; -use std::collections::{BTreeMap, BTreeSet}; -use std::convert::TryFrom; +use std::collections::BTreeSet; use std::fmt; -// use std::mem; -use std::net::TcpListener; use std::ops::{Add, AddAssign, Deref, Sub, SubAssign}; use std::rc::Rc; +use crate::types::*; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct OrderedOpDirKey(pub(crate) ClauseName, pub(crate) Fixity); +pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity); -pub(crate) type OssifiedOpDir = BTreeMap; +pub(crate) type OssifiedOpDir = IndexMap<(Atom, Fixity), (usize, Specifier)>; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) enum DBRef { - NamedPred(ClauseName, usize, Option), - Op( - usize, - Specifier, - ClauseName, - Rc, - SharedOpDesc, - ), +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DBRef { + NamedPred(Atom, usize), + Op(Atom, Fixity, TypedArenaPtr), } // 7.2 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum TermOrderCategory { +pub enum TermOrderCategory { Variable, FloatingPoint, Integer, @@ -55,43 +45,95 @@ pub(crate) enum TermOrderCategory { Compound, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum Addr { - AttrVar(usize), - Char(char), - Con(usize), - CutPoint(usize), - EmptyList, - Fixnum(isize), - Float(OrderedFloat), - Lis(usize), - LoadStatePayload(usize), - HeapCell(usize), - PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes. - StackCell(usize, usize), - Str(usize), - Stream(usize), - TcpListener(usize), - Usize(usize), -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)] -pub(crate) enum Ref { - AttrVar(usize), - HeapCell(usize), - StackCell(usize, usize), -} - -impl Ref { - pub(crate) fn as_addr(self) -> Addr { - match self { - Ref::AttrVar(h) => Addr::AttrVar(h), - Ref::HeapCell(h) => Addr::HeapCell(h), - Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc), - } +// the position-dependent heap template: + +/* + read_heap_cell!( + (HeapCellValueTag::AttrVar, n) => { + } + (HeapCellValueTag::Lis, n) => { + } + (HeapCellValueTag::Var, n) => { + } + (HeapCellValueTag::Str, n) => { + } + (HeapCellValueTag::PStrOffset, n) => { + } + _ => { + } + ) +*/ + +impl PartialEq for HeapCellValue { + fn eq(&self, r: &Ref) -> bool { + self.as_var() == Some(*r) } } +impl PartialOrd for HeapCellValue { + fn partial_cmp(&self, r: &Ref) -> Option { + read_heap_cell!(*self, + (HeapCellValueTag::StackVar, s1) => { + match r.get_tag() { + RefTag::StackCell => { + let s2 = r.get_value() as usize; + s1.partial_cmp(&s2) + } + _ => Some(Ordering::Greater), + } + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h1) => { + match r.get_tag() { + RefTag::StackCell => Some(Ordering::Less), + _ => { + let h2 = r.get_value() as usize; + h1.partial_cmp(&h2) + } + } + } + _ => { + None + } + ) + } +} +/* +impl HeapCellValue { + #[inline] + pub fn as_constant_index(self, machine_st: &MachineState) -> Option { + read_heap_cell!(self, + (HeapCellValueTag::Char, c) => Some(Literal::Char(c)), + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + Some(Literal::Atom(name)) + } else { + None + } + } + (HeapCellValueTag::Fixnum, n) => { + Some(Literal::Fixnum(n)) + } + (HeapCellValueTag::F64, f) => { + Some(Literal::Float(f)) + } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, n) => { + Some(Literal::Integer(n)) + } + (ArenaHeaderTag::Rational, r) => { + Some(Literal::Rational(r)) + } + _ => { + None + } + ) + } + ) + } +} +*/ +/* impl Ord for Ref { fn cmp(&self, other: &Ref) -> Ordering { match (self, other) { @@ -114,31 +156,6 @@ impl PartialEq for Addr { } } -// for use crate::in MachineState::bind. -impl PartialOrd for Addr { - fn partial_cmp(&self, r: &Ref) -> Option { - match self { - &Addr::StackCell(fr, sc) => match *r { - Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater), - Ref::StackCell(fr1, sc1) => { - if fr1 < fr || (fr1 == fr && sc1 < sc) { - Some(Ordering::Greater) - } else if fr1 == fr && sc1 == sc { - Some(Ordering::Equal) - } else { - Some(Ordering::Less) - } - } - }, - &Addr::HeapCell(h) | &Addr::AttrVar(h) => match r { - Ref::StackCell(..) => Some(Ordering::Less), - Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1), - }, - _ => None, - } - } -} - impl Addr { #[inline] pub(crate) fn is_heap_bound(&self) -> bool { @@ -171,57 +188,6 @@ impl Addr { } } - pub(super) fn order_category(&self, heap: &Heap) -> Option { - match Number::try_from((*self, heap)) { - Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => { - Some(TermOrderCategory::Integer) - } - Ok(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), - _ => match self { - Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => { - Some(TermOrderCategory::Variable) - } - Addr::Float(_) => Some(TermOrderCategory::FloatingPoint), - &Addr::Con(h) => match &heap[h] { - HeapCellValue::Atom(..) => Some(TermOrderCategory::Atom), - HeapCellValue::DBRef(_) => None, - _ => { - unreachable!() - } - }, - Addr::Char(_) | Addr::EmptyList => Some(TermOrderCategory::Atom), - Addr::Fixnum(_) | Addr::Usize(_) => Some(TermOrderCategory::Integer), - Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { - Some(TermOrderCategory::Compound) - } - Addr::CutPoint(_) - | Addr::LoadStatePayload(_) - | Addr::Stream(_) - | Addr::TcpListener(_) => None, - }, - } - } - - pub(crate) fn as_constant_index(&self, machine_st: &MachineState) -> Option { - match self { - &Addr::Char(c) => Some(Constant::Char(c)), - &Addr::Con(h) => match &machine_st.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - Some(Constant::Char(name.as_str().chars().next().unwrap())) - } - &HeapCellValue::Atom(ref name, _) => Some(Constant::Atom(name.clone(), None)), - &HeapCellValue::Integer(ref n) => Some(Constant::Integer(n.clone())), - &HeapCellValue::Rational(ref n) => Some(Constant::Rational(n.clone())), - _ => None, - }, - &Addr::EmptyList => Some(Constant::EmptyList), - &Addr::Fixnum(n) => Some(Constant::Fixnum(n)), - &Addr::Float(f) => Some(Constant::Float(f)), - &Addr::Usize(n) => Some(Constant::Usize(n)), - _ => None, - } - } - pub(crate) fn is_protected(&self, e: usize) -> bool { match self { &Addr::StackCell(addr, _) if addr >= e => false, @@ -230,61 +196,6 @@ impl Addr { } } -impl Add for Addr { - type Output = Addr; - - fn add(self, rhs: usize) -> Self::Output { - match self { - Addr::Stream(h) => Addr::Stream(h + rhs), - Addr::Con(h) => Addr::Con(h + rhs), - Addr::Lis(a) => Addr::Lis(a + rhs), - Addr::AttrVar(h) => Addr::AttrVar(h + rhs), - Addr::HeapCell(h) => Addr::HeapCell(h + rhs), - Addr::Str(s) => Addr::Str(s + rhs), - Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n), - _ => self, - } - } -} - -impl Sub for Addr { - type Output = Addr; - - fn sub(self, rhs: i64) -> Self::Output { - if rhs < 0 { - match self { - Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize), - Addr::Con(h) => Addr::Con(h + rhs.abs() as usize), - Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize), - Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize), - Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize), - Addr::Str(s) => Addr::Str(s + rhs.abs() as usize), - Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n), - _ => self, - } - } else { - self.sub(rhs as usize) - } - } -} - -impl Sub for Addr { - type Output = Addr; - - fn sub(self, rhs: usize) -> Self::Output { - match self { - Addr::Stream(h) => Addr::Stream(h - rhs), - Addr::Con(h) => Addr::Con(h - rhs), - Addr::Lis(a) => Addr::Lis(a - rhs), - Addr::AttrVar(h) => Addr::AttrVar(h - rhs), - Addr::HeapCell(h) => Addr::HeapCell(h - rhs), - Addr::Str(s) => Addr::Str(s - rhs), - Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n), - _ => self, - } - } -} - impl SubAssign for Addr { fn sub_assign(&mut self, rhs: usize) { *self = self.clone() - rhs; @@ -305,72 +216,9 @@ impl From for TrailRef { TrailRef::Ref(r) } } - -#[derive(Debug)] -pub(crate) enum HeapCellValue { - Addr(Addr), - Atom(ClauseName, Option), - DBRef(DBRef), - Integer(Rc), - LoadStatePayload(Box), - 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. - Stream(Stream), - TcpListener(TcpListener), -} - -impl HeapCellValue { - #[inline] - pub(crate) fn as_addr(&self, focus: usize) -> Addr { - match self { - HeapCellValue::Addr(ref a) => *a, - HeapCellValue::Atom(..) - | HeapCellValue::DBRef(..) - | HeapCellValue::Integer(..) - | HeapCellValue::Rational(..) => Addr::Con(focus), - HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus), - HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus), - HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0), - HeapCellValue::Stream(_) => Addr::Stream(focus), - HeapCellValue::TcpListener(_) => Addr::TcpListener(focus), - } - } - - #[inline] - pub(crate) fn context_free_clone(&self) -> HeapCellValue { - match self { - &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr), - &HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()), - &HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()), - &HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()), - &HeapCellValue::LoadStatePayload(_) => { - HeapCellValue::Atom(clause_name!("$live_term_stream"), None) - } - &HeapCellValue::NamedStr(arity, ref name, ref op) => { - HeapCellValue::NamedStr(arity, name.clone(), op.clone()) - } - &HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()), - &HeapCellValue::PartialString(ref pstr, has_tail) => { - HeapCellValue::PartialString(pstr.clone(), has_tail) - } - &HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()), - &HeapCellValue::TcpListener(_) => { - HeapCellValue::Atom(clause_name!("$tcp_listener"), None) - } - } - } -} - -impl From for HeapCellValue { - #[inline] - fn from(value: Addr) -> HeapCellValue { - HeapCellValue::Addr(value) - } -} - +*/ #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub(crate) enum IndexPtr { +pub enum IndexPtr { DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. DynamicIndex(usize), Index(usize), @@ -378,7 +226,7 @@ pub(crate) enum IndexPtr { } #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub(crate) struct CodeIndex(pub(crate) Rc>); +pub struct CodeIndex(pub(crate) Rc>); impl Deref for CodeIndex { type Target = Cell; @@ -419,7 +267,7 @@ impl Default for CodeIndex { } #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] -pub(crate) enum REPLCodePtr { +pub enum REPLCodePtr { AddDiscontiguousPredicate, AddDynamicPredicate, AddMultifilePredicate, @@ -456,12 +304,11 @@ pub(crate) enum REPLCodePtr { AddNonCountedBacktracking, } -#[derive(Debug, Clone, PartialEq)] -pub(crate) enum CodePtr { +#[derive(Debug, Clone, Copy, PartialEq)] +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. REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. } @@ -488,7 +335,7 @@ impl CodePtr { } #[derive(Copy, Clone, Debug, PartialEq)] -pub(crate) enum LocalCodePtr { +pub enum LocalCodePtr { DirEntry(usize), // offset Halt, IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset @@ -496,7 +343,7 @@ pub(crate) enum LocalCodePtr { } impl LocalCodePtr { - pub(crate) fn assign_if_local(&mut self, cp: CodePtr) { + pub fn assign_if_local(&mut self, cp: CodePtr) { match cp { CodePtr::Local(local) => *self = local, _ => {} @@ -504,7 +351,7 @@ impl LocalCodePtr { } #[inline] - pub(crate) fn abs_loc(&self) -> usize { + pub fn abs_loc(&self) -> usize { match self { LocalCodePtr::DirEntry(ref p) => *p, LocalCodePtr::IndexingBuf(ref p, ..) => *p, @@ -528,33 +375,21 @@ impl LocalCodePtr { false } - pub(crate) fn as_functor(&self, heap: &mut HeapTemplate) -> Addr { - let addr = Addr::HeapCell(heap.h()); - + pub(crate) fn as_functor(&self) -> MachineStub { match self { LocalCodePtr::DirEntry(p) => { - heap.append(functor!("dir_entry", [integer(*p)])); + functor!(atom!("dir_entry"), [fixnum(*p)]) } LocalCodePtr::Halt => { - heap.append(functor!("halt")); + functor!(atom!("halt")) } - /* - LocalCodePtr::TopLevel(chunk_num, offset) => { - heap.append(functor!( - "top_level", - [integer(*chunk_num), integer(*offset)] - )); - } - */ LocalCodePtr::IndexingBuf(p, o, i) => { - heap.append(functor!( - "indexed_buf", - [integer(*p), integer(*o), integer(*i)] - )); + functor!( + atom!("indexed_buf"), + [fixnum(*p), fixnum(*o), fixnum(*i)] + ) } } - - addr } } @@ -614,9 +449,8 @@ impl AddAssign for LocalCodePtr { #[inline] fn add_assign(&mut self, rhs: usize) { match self { - &mut LocalCodePtr::DirEntry(ref mut p) /* | - &mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs, - &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, + &mut LocalCodePtr::DirEntry(ref mut i) + | &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, &mut LocalCodePtr::Halt => unreachable!(), } } @@ -627,11 +461,7 @@ impl Add for CodePtr { fn add(self, rhs: usize) -> Self::Output { match self { - p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => { - // | - // p @ CodePtr::DynamicTransaction(..) => { - p - } + p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => p, CodePtr::Local(local) => CodePtr::Local(local + rhs), CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => { CodePtr::Local(local + rhs) @@ -660,12 +490,12 @@ impl SubAssign for CodePtr { } } -pub(crate) type HeapVarDict = IndexMap, Addr>; -pub(crate) type AllocVarDict = IndexMap, VarData>; +pub(crate) type HeapVarDict = IndexMap, HeapCellValue>; +pub(crate) type AllocVarDict = IndexMap, VarData>; -pub(crate) type GlobalVarDir = IndexMap)>; +pub(crate) type GlobalVarDir = IndexMap)>; -pub(crate) type StreamAliasDir = IndexMap; +pub(crate) type StreamAliasDir = IndexMap; pub(crate) type StreamDir = BTreeSet; pub(crate) type MetaPredicateDir = IndexMap>; @@ -676,7 +506,7 @@ pub(crate) type LocalExtensiblePredicates = IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>; #[derive(Debug)] -pub(crate) struct IndexStore { +pub struct IndexStore { pub(super) code_dir: CodeDir, pub(super) extensible_predicates: ExtensiblePredicates, pub(super) local_extensible_predicates: LocalExtensiblePredicates, @@ -688,31 +518,21 @@ pub(crate) struct IndexStore { pub(super) stream_aliases: StreamAliasDir, } -impl Default for IndexStore { - #[inline] - fn default() -> Self { - index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) - } -} - impl IndexStore { pub(crate) fn get_predicate_skeleton_mut( &mut self, compilation_target: &CompilationTarget, key: &PredicateKey, ) -> Option<&mut PredicateSkeleton> { - match (key.0.as_str(), key.1) { - // ("term_expansion", 2) => self.extensible_predicates.get_mut(key), - _ => match compilation_target { - CompilationTarget::User => self.extensible_predicates.get_mut(key), - CompilationTarget::Module(ref module_name) => { - if let Some(module) = self.modules.get_mut(module_name) { - module.extensible_predicates.get_mut(key) - } else { - None - } + match compilation_target { + CompilationTarget::User => self.extensible_predicates.get_mut(key), + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get_mut(module_name) { + module.extensible_predicates.get_mut(key) + } else { + None } - }, + } } } @@ -737,7 +557,7 @@ impl IndexStore { &mut self, mut src_compilation_target: CompilationTarget, local_compilation_target: CompilationTarget, - listing_src_file_name: Option, + listing_src_file_name: Option, key: PredicateKey, ) -> Option<&mut LocalPredicateSkeleton> { if let Some(filename) = listing_src_file_name { @@ -748,8 +568,8 @@ impl IndexStore { CompilationTarget::User => self .local_extensible_predicates .get_mut(&(local_compilation_target, key)), - CompilationTarget::Module(ref module_name) => { - if let Some(module) = self.modules.get_mut(module_name) { + CompilationTarget::Module(module_name) => { + if let Some(module) = self.modules.get_mut(&module_name) { module .local_extensible_predicates .get_mut(&(local_compilation_target, key)) @@ -764,7 +584,7 @@ impl IndexStore { &self, mut src_compilation_target: CompilationTarget, local_compilation_target: CompilationTarget, - listing_src_file_name: Option, + listing_src_file_name: Option, key: PredicateKey, ) -> Option<&LocalPredicateSkeleton> { if let Some(filename) = listing_src_file_name { @@ -775,8 +595,8 @@ impl IndexStore { CompilationTarget::User => self .local_extensible_predicates .get(&(local_compilation_target, key)), - CompilationTarget::Module(ref module_name) => { - if let Some(module) = self.modules.get(module_name) { + CompilationTarget::Module(module_name) => { + if let Some(module) = self.modules.get(&module_name) { module .local_extensible_predicates .get(&(local_compilation_target, key)) @@ -806,35 +626,30 @@ impl IndexStore { pub(crate) fn get_predicate_code_index( &self, - name: ClauseName, + name: Atom, arity: usize, - module: ClauseName, - op_spec: Option, + module: Atom, ) -> Option { - if module.as_str() == "user" { - match ClauseType::from(name, arity, op_spec) { + if module == atom!("user") { + match ClauseType::from(name, arity) { ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(), - ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(), _ => None, } } else { - self.modules.get(&module).and_then(|module| { - match ClauseType::from(name, arity, op_spec) { + self.modules + .get(&module) + .and_then(|module| match ClauseType::from(name, arity) { 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(crate) fn get_meta_predicate_spec( &self, - name: ClauseName, + name: Atom, arity: usize, compilation_target: &CompilationTarget, ) -> Option<&Vec> { @@ -850,9 +665,13 @@ impl IndexStore { } } - pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool { - match module_name.as_str() { - "user" => self + pub(crate) fn is_dynamic_predicate( + &self, + module_name: Atom, + key: PredicateKey, + ) -> bool { + match module_name { + atom!("user") => self .extensible_predicates .get(&key) .map(|skeleton| skeleton.core.is_dynamic) @@ -870,19 +689,19 @@ impl IndexStore { #[inline] pub(super) fn new() -> Self { - IndexStore::default() + index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) } 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 = atom!("run_cleaners_with_handling"); + let r_wo_h = atom!("run_cleaners_without_handling"); + let iso_ext = atom!("iso_ext"); let r_w_h = self - .get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None) + .get_predicate_code_index(r_w_h, 0, iso_ext) .and_then(|item| item.local()); let r_wo_h = self - .get_predicate_code_index(r_wo_h, 1, iso_ext, None) + .get_predicate_code_index(r_wo_h, 1, iso_ext) .and_then(|item| item.local()); if let Some(r_w_h) = r_w_h { @@ -895,7 +714,7 @@ impl IndexStore { } } -pub(crate) type CodeDir = BTreeMap; +pub(crate) type CodeDir = IndexMap; pub(crate) enum RefOrOwned<'a, T: 'a> { Borrowed(&'a T), @@ -918,14 +737,4 @@ impl<'a, T> RefOrOwned<'a, T> { &RefOrOwned::Owned(ref r) => r, } } - - pub(crate) fn to_owned(self) -> T - where - T: Clone, - { - match self { - RefOrOwned::Borrowed(item) => item.clone(), - RefOrOwned::Owned(item) => item, - } - } } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 9e845f04a..8d39edcdd 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1,19 +1,22 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{clause_name, temp_v}; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::temp_v; use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::heap_print::*; use crate::machine::attributed_variables::*; use crate::machine::copier::*; use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::machine::partial_string::HeapPStrIter; use crate::machine::stack::*; use crate::machine::streams::*; -use crate::rug::Integer; +use crate::types::*; + +use crate::parser::rug::Integer; use downcast::{ downcast, downcast_methods, downcast_methods_core, downcast_methods_std, impl_downcast, Any, @@ -28,203 +31,7 @@ use std::mem; use std::ops::{Index, IndexMut}; use std::rc::Rc; -#[derive(Debug)] -pub(crate) struct Ball { - pub(super) boundary: usize, - pub(super) stub: Heap, -} - -impl Ball { - pub(super) fn new() -> Self { - Ball { - boundary: 0, - stub: Heap::new(), - } - } - - pub(super) fn reset(&mut self) { - self.boundary = 0; - self.stub.clear(); - } - - pub(super) fn copy_and_align(&self, h: usize) -> Heap { - let diff = self.boundary as i64 - h as i64; - let mut stub = Heap::new(); - - for heap_value in self.stub.iter_from(0) { - stub.push(match heap_value { - &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff), - heap_value => heap_value.context_free_clone(), - }); - } - - stub - } -} - -#[derive(Debug)] -pub(super) struct CopyTerm<'a> { - state: &'a mut MachineState, -} - -impl<'a> CopyTerm<'a> { - pub(super) fn new(state: &'a mut MachineState) -> Self { - CopyTerm { state: state } - } -} - -impl<'a> Index for CopyTerm<'a> { - type Output = HeapCellValue; - - fn index(&self, index: usize) -> &Self::Output { - &self.state.heap[index] - } -} - -impl<'a> IndexMut for CopyTerm<'a> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.state.heap[index] - } -} - -// the ordinary, heap term copier, used by duplicate_term. -impl<'a> CopierTarget for CopyTerm<'a> { - fn threshold(&self) -> usize { - self.state.heap.h() - } - - fn push(&mut self, hcv: HeapCellValue) { - self.state.heap.push(hcv); - } - - fn store(&self, a: Addr) -> Addr { - self.state.store(a) - } - - fn deref(&self, a: Addr) -> Addr { - self.state.deref(a) - } - - fn stack(&mut self) -> &mut Stack { - &mut self.state.stack - } -} - -#[derive(Debug)] -pub(super) struct CopyBallTerm<'a> { - stack: &'a mut Stack, - heap: &'a mut Heap, - heap_boundary: usize, - stub: &'a mut Heap, -} - -impl<'a> CopyBallTerm<'a> { - pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self { - let hb = heap.h(); - - CopyBallTerm { - stack, - heap, - heap_boundary: hb, - stub, - } - } -} - -impl<'a> Index for CopyBallTerm<'a> { - type Output = HeapCellValue; - - fn index(&self, index: usize) -> &Self::Output { - if index < self.heap_boundary { - &self.heap[index] - } else { - let index = index - self.heap_boundary; - &self.stub[index] - } - } -} - -impl<'a> IndexMut for CopyBallTerm<'a> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - if index < self.heap_boundary { - &mut self.heap[index] - } else { - let index = index - self.heap_boundary; - &mut self.stub[index] - } - } -} - -// the ordinary, heap term copier, used by duplicate_term. -impl<'a> CopierTarget for CopyBallTerm<'a> { - fn threshold(&self) -> usize { - self.heap_boundary + self.stub.h() - } - - fn push(&mut self, value: HeapCellValue) { - self.stub.push(value); - } - - fn store(&self, addr: Addr) -> Addr { - match addr { - Addr::HeapCell(h) | Addr::AttrVar(h) if h < self.heap_boundary => { - self.heap[h].as_addr(h) - } - Addr::HeapCell(h) | Addr::AttrVar(h) => { - let index = h - self.heap_boundary; - self.stub[index].as_addr(h) - } - Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc], - addr => addr, - } - } - - fn deref(&self, mut addr: Addr) -> Addr { - loop { - let value = self.store(addr); - - if value.is_ref() && value != addr { - addr = value; - continue; - } - - return addr; - } - } - - fn stack(&mut self) -> &mut Stack { - self.stack - } -} - -impl Index for MachineState { - type Output = Addr; - - fn index(&self, reg: RegType) -> &Self::Output { - match reg { - RegType::Temp(temp) => &self.registers[temp], - RegType::Perm(perm) => { - let e = self.e; - &self.stack.index_and_frame(e)[perm] - } - } - } -} - -impl IndexMut for MachineState { - fn index_mut(&mut self, reg: RegType) -> &mut Self::Output { - match reg { - RegType::Temp(temp) => &mut self.registers[temp], - RegType::Perm(perm) => { - let e = self.e; - - &mut self.stack.index_and_frame_mut(e)[perm] - } - } - } -} - -pub(crate) type Registers = Vec; +pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; #[derive(Debug, Clone, Copy)] pub(super) enum MachineMode { @@ -239,29 +46,6 @@ pub(super) enum HeapPtr { PStrLocation(usize, usize), } -impl HeapPtr { - #[inline] - pub(super) fn read(&self, heap: &Heap) -> Addr { - match self { - &HeapPtr::HeapCell(h) => Addr::HeapCell(h), - &HeapPtr::PStrChar(h, n) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &heap[h] { - if let Some(c) = pstr.range_from(n..).next() { - Addr::Char(c) - } else if has_tail { - Addr::HeapCell(h + 1) - } else { - Addr::EmptyList - } - } else { - unreachable!() - } - } - &HeapPtr::PStrLocation(h, n) => Addr::PStrLocation(h, n), - } - } -} - impl Default for HeapPtr { fn default() -> Self { HeapPtr::HeapCell(0) @@ -274,9 +58,10 @@ pub enum FirstOrNext { Next, } -// #[derive(Debug)] -pub(crate) struct MachineState { - pub(crate) atom_tbl: TabledData, +pub struct MachineState { + pub atom_tbl: AtomTable, + pub arena: Arena, + pub(super) pdl: Vec, pub(super) s: HeapPtr, pub(super) p: CodePtr, pub(super) b: usize, @@ -286,11 +71,11 @@ pub(crate) struct MachineState { pub(super) cp: LocalCodePtr, pub(super) attr_var_init: AttrVarInitializer, pub(super) fail: bool, - pub(crate) heap: Heap, + pub heap: Heap, pub(super) mode: MachineMode, pub(crate) stack: Stack, pub(super) registers: Registers, - pub(super) trail: Vec, + pub(super) trail: Vec, pub(super) tr: usize, pub(super) hb: usize, pub(super) block: usize, // an offset into the OR stack. @@ -302,14 +87,15 @@ pub(crate) struct MachineState { pub(crate) cc: usize, pub(crate) global_clock: usize, pub(crate) dynamic_mode: FirstOrNext, - pub(crate) unify_fn: fn(&mut MachineState, Addr, Addr), - pub(crate) bind_fn: fn(&mut MachineState, Ref, Addr), + pub(crate) unify_fn: fn(&mut MachineState), + pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue), } impl fmt::Debug for MachineState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MachineState") .field("atom_tbl", &self.atom_tbl) + .field("arena", &self.arena) .field("s", &self.s) .field("p", &self.p) .field("b", &self.b) @@ -361,403 +147,73 @@ impl fmt::Debug for MachineState { } } -impl MachineState { - pub(crate) fn read_term(&mut self, mut stream: Stream, indices: &mut IndexStore) -> CallResult { - fn push_var_eq_functors<'a>( - heap: &mut Heap, - iter: impl Iterator, &'a Addr)>, - op_dir: &OpDir, - atom_tbl: TabledData, - ) -> Vec { - let mut list_of_var_eqs = vec![]; +impl Index for MachineState { + type Output = HeapCellValue; - for (var, binding) in iter { - let var_atom = clause_name!(var.to_string(), atom_tbl); + #[inline(always)] + fn index(&self, reg: RegType) -> &Self::Output { + match reg { + RegType::Temp(temp) => &self.registers[temp], + RegType::Perm(perm) => { + let e = self.e; + &self.stack[stack_loc!(AndFrame, e, perm)] + } + } + } +} - let h = heap.h(); - let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir); +impl IndexMut for MachineState { + #[inline(always)] + fn index_mut(&mut self, reg: RegType) -> &mut Self::Output { + match reg { + RegType::Temp(temp) => &mut self.registers[temp], + RegType::Perm(perm) => { + let e = self.e; + &mut self.stack[stack_loc!(AndFrame, e, perm)] + } + } + } +} - heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); - heap.push(HeapCellValue::Atom(var_atom, None)); - heap.push(HeapCellValue::Addr(*binding)); +pub type CallResult = Result<(), Vec>; - list_of_var_eqs.push(Addr::Str(h)); - } +pub trait CutPolicy: Any + fmt::Debug { + // returns true iff we fail or cut redirected the MachineState's p itself + fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool; +} - list_of_var_eqs - } +downcast!(dyn CutPolicy); - self.check_stream_properties( - &mut stream, - StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("read_term"), - 3, - )?; +pub trait CallPolicy: Any + fmt::Debug { + fn retry_me_else( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { + let b = machine_st.b; + let n = machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; - if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { - return return_from_clause!(self.last_call, self); - } else if self.fail { - return Ok(()); - } + for i in 1..n + 1 { + machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; } - let mut orig_stream = stream.clone(); - - loop { - match self.read(stream.clone(), self.atom_tbl.clone(), &indices.op_dir) { - Ok(term_write_result) => { - let term = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::HeapCell(term_write_result.heap_loc), term); + machine_st.num_of_args = n; + machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; + machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; - if self.fail { - return Ok(()); - } + machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset; - let mut singleton_var_set: IndexMap = IndexMap::new(); + let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; + let curr_tr = machine_st.tr; - for addr in self.acyclic_pre_order_iter(term) { - if let Some(var) = addr.as_var() { - if !singleton_var_set.contains_key(&var) { - singleton_var_set.insert(var, true); - } else { - singleton_var_set.insert(var, false); - } - } - } - - let singleton_var_list = push_var_eq_functors( - &mut self.heap, - term_write_result.var_dict.iter().filter(|(_, binding)| { - if let Some(r) = binding.as_var() { - *singleton_var_set.get(&r).unwrap_or(&false) - } else { - false - } - }), - &indices.op_dir, - self.atom_tbl.clone(), - ); - - let mut var_list = Vec::with_capacity(singleton_var_set.len()); - - for (var_name, addr) in term_write_result.var_dict { - if let Some(var) = addr.as_var() { - let idx = singleton_var_set.get_index_of(&var).unwrap(); - var_list.push((var_name, addr, idx)); - } - } - - var_list.sort_by(|(_,_,idx_1),(_,_,idx_2)| idx_1.cmp(idx_2)); - - let list_of_var_eqs = push_var_eq_functors( - &mut self.heap, - var_list.iter().map(|(var_name, var,_)| (var_name,var)), - &indices.op_dir, - self.atom_tbl.clone(), - ); - - let singleton_addr = self[temp_v!(3)]; - let singletons_offset = Addr::HeapCell(self.heap.to_list( - singleton_var_list.into_iter() - )); - - (self.unify_fn)(self, singletons_offset, singleton_addr); - - if self.fail { - return Ok(()); - } - - let vars_addr = self[temp_v!(4)]; - let vars_offset = Addr::HeapCell(self.heap.to_list( - var_list.into_iter().map(|(_,var,_)| var) - )); - - (self.unify_fn)(self, vars_offset, vars_addr); - - if self.fail { - return Ok(()); - } - - let var_names_addr = self[temp_v!(5)]; - let var_names_offset = - Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); - - return Ok((self.unify_fn)(self, var_names_offset, var_names_addr)); - } - Err(err) => { - if let ParserError::UnexpectedEOF = err { - self.eof_action( - self[temp_v!(2)], - &mut orig_stream, - clause_name!("read_term"), - 3, - )?; - - if orig_stream.options().eof_action == EOFAction::Reset { - if self.fail == false { - continue; - } - } - - return Ok(()); - } - - let stub = MachineError::functor_stub(clause_name!("read_term"), 3); - let err = MachineError::syntax_error(self.heap.h(), err); - - return Err(self.error_form(err, stub)); - } - } - } - } - - pub(crate) fn write_term<'a>( - &'a self, - op_dir: &'a OpDir, - ) -> Result>, MachineStub> { - let ignore_ops = self.store(self.deref(self[temp_v!(3)])); - let numbervars = self.store(self.deref(self[temp_v!(4)])); - let quoted = self.store(self.deref(self[temp_v!(5)])); - let max_depth = self.store(self.deref(self[temp_v!(7)])); - - let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new()); - - if let &Addr::Con(h) = &ignore_ops { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - printer.ignore_ops = name.as_str() == "true"; - } else { - unreachable!() - } - } - - if let &Addr::Con(h) = &numbervars { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - printer.numbervars = name.as_str() == "true"; - } else { - unreachable!() - } - } - - if let &Addr::Con(h) = "ed { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - printer.quoted = name.as_str() == "true"; - } else { - unreachable!() - } - } - - match Number::try_from((max_depth, &self.heap)) { - Ok(Number::Fixnum(n)) => { - if let Ok(n) = usize::try_from(n) { - printer.max_depth = n; - } else { - return Ok(None); - } - } - Ok(Number::Integer(n)) => { - if let Some(n) = n.to_usize() { - printer.max_depth = n; - } else { - return Ok(None); - } - } - _ => { - unreachable!(); - } - } - - let stub = MachineError::functor_stub(clause_name!("write_term"), 2); - - match self.try_from_list(temp_v!(6), stub) { - Ok(addrs) => { - let mut var_names: IndexMap = IndexMap::new(); - - for addr in addrs { - match addr { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(2, ref name, _) if name.as_str() == "=" => { - let atom = self.heap[s + 1].as_addr(s + 1); - let var = self.heap[s + 2].as_addr(s + 2); - - let atom = match self.store(self.deref(atom)) { - Addr::Con(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.to_string() - } else { - unreachable!() - } - } - Addr::Char(c) => c.to_string(), - _ => unreachable!(), - }; - - let var = self.store(self.deref(var)); - - if var_names.contains_key(&var) { - continue; - } - - var_names.insert(var, atom); - } - _ => {} - }, - _ => {} - } - } - - printer.var_names = var_names; - } - Err(err) => { - return Err(err); - } - } - - Ok(Some(printer)) - } - - pub(super) fn throw_undefined_error(&mut self, name: ClauseName, arity: usize) -> MachineStub { - let stub = MachineError::functor_stub(name.clone(), arity); - let h = self.heap.h(); - let key = ExistenceError::Procedure(name, arity); - - self.error_form(MachineError::existence_error(h, key), stub) - } - - #[inline] - pub(crate) fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> { - HeapPStrIter::new(self, focus) - } - - pub(super) fn try_char_list(&self, addrs: Vec) -> Result { - let mut chars = String::new(); - let mut iter = addrs.iter(); - - while let Some(addr) = iter.next() { - let addr = self.store(self.deref(*addr)); - - match addr { - Addr::Char(c) => { - chars.push(c); - continue; - } - Addr::Con(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - if name.is_char() { - chars += name.as_str(); - continue; - } - } - } - _ => {} - }; - - let h = self.heap.h(); - - return Err(MachineError::type_error(h, ValidType::Character, addr)); - } - - Ok(chars) - } - - pub(super) fn read_predicate_key(&self, name: Addr, arity: Addr) -> (ClauseName, usize) { - let predicate_name = atom_from!(self, self.store(self.deref(name))); - let arity = self.store(self.deref(arity)); - - let arity = match Number::try_from((arity, &self.heap)) { - Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => n.to_usize().unwrap(), - Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => { - usize::try_from(n).unwrap() - } - _ => unreachable!(), - }; - - (predicate_name, arity) - } - - pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { - self.cp.assign_if_local(self.p.clone() + 1); - self.num_of_args = arity; - self.b0 = self.b; - self.p = CodePtr::Local(p); - } - - pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) { - self.num_of_args = arity; - self.b0 = self.b; - self.p = CodePtr::Local(p); - } - - pub(super) fn module_lookup( - &mut self, - indices: &IndexStore, - call_policy: &mut Box, - key: PredicateKey, - module_name: ClauseName, - _last_call: bool, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - if module_name.as_str() == "user" { - return call_policy.call_clause_type( - self, - key, - &indices.code_dir, - &indices.op_dir, - stream_aliases, - ); - } else if let Some(module) = indices.modules.get(&module_name) { - return call_policy.call_clause_type( - self, - key, - &module.code_dir, - &module.op_dir, - stream_aliases, - ); - } - - let (name, arity) = key; - - let h = self.heap.h(); - let stub = MachineError::functor_stub(name.clone(), arity); - let err = MachineError::module_resolution_error(h, module_name, name, arity); - - return Err(self.error_form(err, stub)); - } -} - -pub(crate) type CallResult = Result<(), Vec>; - -pub(crate) trait CallPolicy: Any + fmt::Debug { - fn retry_me_else( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - let b = machine_st.b; - let n = machine_st - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; - } - - machine_st.num_of_args = n; - machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; - machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; - - machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset; - - let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; - let curr_tr = machine_st.tr; - - machine_st.unwind_trail(old_tr, curr_tr, global_variables); - machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; + machine_st.unwind_trail(old_tr, curr_tr, global_variables); + machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); machine_st @@ -765,8 +221,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p += 1; Ok(()) @@ -808,8 +263,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); Ok(()) @@ -830,7 +284,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .num_cells; for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; + machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; } machine_st.num_of_args = n; @@ -849,11 +303,10 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); Ok(()) @@ -873,7 +326,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .num_cells; for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; + machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; } machine_st.num_of_args = n; @@ -892,11 +345,10 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p += 1; Ok(()) @@ -905,7 +357,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { fn context_call( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { @@ -919,7 +371,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { fn try_call( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { @@ -946,7 +398,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { fn try_execute( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { @@ -980,7 +432,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { ) -> CallResult { match ct { &BuiltInClauseType::AcyclicTerm => { - let addr = machine_st[temp_v!(1)]; + let addr = machine_st.registers[1]; machine_st.fail = machine_st.is_cyclic_term(addr); return_from_clause!(machine_st.last_call, machine_st) } @@ -989,57 +441,47 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Compare => { - let a1 = machine_st.store(machine_st.deref(machine_st[temp_v!(1)])); - let a2 = machine_st[temp_v!(2)]; - let a3 = machine_st[temp_v!(3)]; - - match a1 { - Addr::Con(h) if machine_st.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &machine_st.heap[h] { - match atom.as_str() { - ">" | "<" | "=" => {} - _ => { - let stub = - MachineError::functor_stub(clause_name!("compare"), 3); - - let err = - MachineError::domain_error(DomainErrorType::Order, a1); - return Err(machine_st.error_form(err, stub)); - } + let stub_gen = || functor_stub(atom!("compare"), 3); + + let a1 = machine_st.store(machine_st.deref(machine_st.registers[1])); + let a2 = machine_st.registers[2]; + let a3 = machine_st.registers[3]; + + read_heap_cell!(a1, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) + .get_name_and_arity(); + + match name { + atom!(">") | atom!("<") | atom!("=") if arity == 2 => { + } + _ => { + let err = machine_st.domain_error(DomainErrorType::Order, a1); + return Err(machine_st.error_form(err, stub_gen())); } - } else { - unreachable!() } } - addr if !addr.is_ref() => { - let h = machine_st.heap.h(); - let stub = MachineError::functor_stub(clause_name!("compare"), 3); - let err = MachineError::type_error(h, ValidType::Atom, a1); - return Err(machine_st.error_form(err, stub)); + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { } - _ => {} - } + _ => { + let err = machine_st.type_error(ValidType::Atom, a1); + return Err(machine_st.error_form(err, stub_gen())); + } + ); - let atom = match machine_st.compare_term_test(&a2, &a3) { + let atom = match compare_term_test!(machine_st, a2, a3) { Some(Ordering::Greater) => { - let spec = fetch_atom_op_spec(clause_name!(">"), None, op_dir); - HeapCellValue::Atom(clause_name!(">"), spec) + atom!(">") } Some(Ordering::Equal) => { - let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir); - HeapCellValue::Atom(clause_name!("="), spec) + atom!("=") } None | Some(Ordering::Less) => { - let spec = fetch_atom_op_spec(clause_name!("<"), None, op_dir); - HeapCellValue::Atom(clause_name!("<"), spec) + atom!("<") } }; - let h = machine_st.heap.h(); - - machine_st.heap.push(atom); - (machine_st.unify_fn)(machine_st, a1, Addr::Con(h)); - + machine_st.unify_atom(atom, a1); return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::CompareTerm(qt) => { @@ -1050,31 +492,24 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let stream = machine_st.get_stream_or_alias( machine_st[temp_v!(1)], stream_aliases, - "read", + atom!("read"), 2, )?; - match machine_st.read(stream, machine_st.atom_tbl.clone(), op_dir) { + match machine_st.read(stream, op_dir) { Ok(offset) => { - let addr = machine_st[temp_v!(2)]; - (machine_st.unify_fn)(machine_st, addr, Addr::HeapCell(offset.heap_loc)); + let value = machine_st.registers[2]; + unify_fn!(machine_st, value, heap_loc_as_cell!(offset.heap_loc)); } Err(ParserError::UnexpectedEOF) => { - let addr = machine_st[temp_v!(2)]; - let eof = clause_name!("end_of_file".to_string(), machine_st.atom_tbl); - - let atom = machine_st.heap.to_unifiable(HeapCellValue::Atom(eof, None)); - - (machine_st.unify_fn)(machine_st, addr, atom); + let value = machine_st.registers[2]; + machine_st.unify_atom(atom!("end_of_file"), value); } Err(e) => { - let h = machine_st.heap.h(); - let stub = MachineError::functor_stub(clause_name!("read"), 2); - - let err = MachineError::syntax_error(h, e); - let err = machine_st.error_form(err, stub); + let stub = functor_stub(atom!("read"), 2); + let err = machine_st.syntax_error(e); - return Err(err); + return Err(machine_st.error_form(err, stub)); } }; @@ -1085,8 +520,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Eq => { - let a1 = machine_st[temp_v!(1)]; - let a2 = machine_st[temp_v!(2)]; + let a1 = machine_st.registers[1]; + let a2 = machine_st.registers[2]; machine_st.fail = machine_st.eq_test(a1, a2); return_from_clause!(machine_st.last_call, machine_st) @@ -1096,146 +531,757 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Functor => { - machine_st.try_functor(op_dir)?; + machine_st.try_functor()?; return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::NotEq => { - let a1 = machine_st[temp_v!(1)]; - let a2 = machine_st[temp_v!(2)]; + let a1 = machine_st.registers[1]; + let a2 = machine_st.registers[2]; + + machine_st.fail = + if let Some(Ordering::Equal) = compare_term_test!(machine_st, a1, a2) { + true + } else { + false + }; + + return_from_clause!(machine_st.last_call, machine_st) + } + &BuiltInClauseType::Sort => { + machine_st.check_sort_errors()?; + + let stub_gen = || functor_stub(atom!("sort"), 2); + let mut list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?; + + list.sort_unstable_by(|v1, v2| { + compare_term_test!(machine_st, *v1, *v2).unwrap_or(Ordering::Less) + }); + + list.dedup_by(|v1, v2| { + compare_term_test!(machine_st, *v1, *v2) == Some(Ordering::Equal) + }); + + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut machine_st.heap, list.into_iter()) + ); + + let r2 = machine_st.registers[2]; + unify_fn!(machine_st, r2, heap_addr); + + return_from_clause!(machine_st.last_call, machine_st) + } + &BuiltInClauseType::KeySort => { + machine_st.check_keysort_errors()?; + + let stub_gen = || functor_stub(atom!("keysort"), 2); + let list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?; + + let mut key_pairs = Vec::with_capacity(list.len()); + + for val in list { + let key = machine_st.project_onto_key(val)?; + key_pairs.push((key, val)); + } + + key_pairs.sort_by(|a1, a2| { + compare_term_test!(machine_st, a1.0, a2.0).unwrap_or(Ordering::Less) + }); + + let key_pairs = key_pairs.into_iter().map(|kp| kp.1); + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut machine_st.heap, key_pairs) + ); + + let r2 = machine_st.registers[2]; + unify_fn!(machine_st, r2, heap_addr); + + return_from_clause!(machine_st.last_call, machine_st) + } + &BuiltInClauseType::Is(r, ref at) => { + let n1 = machine_st[r]; + let n2 = machine_st.get_number(at)?; + + match n2 { + Number::Fixnum(n) => machine_st.unify_fixnum(n, n1), + Number::Float(n) => { + // TODO: argghh.. deal with it. + let n = arena_alloc!(n, &mut machine_st.arena); + machine_st.unify_f64(n, n1) + } + Number::Integer(n) => machine_st.unify_big_int(n, n1), + Number::Rational(n) => machine_st.unify_rational(n, n1), + } + + return_from_clause!(machine_st.last_call, machine_st) + } + } + } + + fn call_clause_type( + &mut self, + machine_st: &mut MachineState, + key: PredicateKey, + code_dir: &CodeDir, + op_dir: &OpDir, + stream_aliases: &StreamAliasDir, + ) -> CallResult { + let (name, arity) = key; + + match ClauseType::from(name, arity) { + ClauseType::BuiltIn(built_in) => { + machine_st.setup_built_in_call(built_in); + self.call_builtin(machine_st, &built_in, code_dir, op_dir, stream_aliases)?; + } + 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::Named(..) => { + if let Some(idx) = code_dir.get(&(name, arity)) { + self.context_call(machine_st, name, arity, idx)?; + } else { + return Err(machine_st.throw_undefined_error(name, arity)); + } + } + ClauseType::System(_) => { + let (name, arity) = key; + let name = functor!(name); + + let stub = functor_stub(atom!("call"), arity + 1); + let err = machine_st.type_error(ValidType::Callable, name); + + return Err(machine_st.error_form(err, stub)); + } + } + + Ok(()) + } + + fn call_n( + &mut self, + machine_st: &mut MachineState, + arity: usize, + code_dir: &CodeDir, + op_dir: &OpDir, + stream_aliases: &StreamAliasDir, + ) -> CallResult { + if let Some(key) = machine_st.setup_call_n(arity) { + self.call_clause_type(machine_st, key, code_dir, op_dir, stream_aliases)?; + } + + Ok(()) + } +} + +#[inline(always)] +pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) { + read_heap_cell!(heap[index], + (HeapCellValueTag::PStr | HeapCellValueTag::CStr) => { + (index, Fixnum::build_with(0)) + } + (HeapCellValueTag::PStrOffset, h) => { + (h, cell_as_fixnum!(heap[index+1])) + } + _ => { + unreachable!() + } + ) +} + +#[derive(Debug)] +pub struct Ball { + pub(super) boundary: usize, + pub(super) stub: Heap, +} + +impl Ball { + pub(super) fn new() -> Self { + Ball { + boundary: 0, + stub: Heap::new(), + } + } + + pub(super) fn reset(&mut self) { + self.boundary = 0; + self.stub.clear(); + } + + pub(super) fn copy_and_align(&self, h: usize) -> Heap { + let diff = self.boundary as i64 - h as i64; + + self.stub.iter().cloned().map(|heap_value| { + heap_value - diff + }).collect() + } +} + +#[derive(Debug)] +pub(super) struct CopyTerm<'a> { + state: &'a mut MachineState, +} + +impl<'a> CopyTerm<'a> { + pub(super) fn new(state: &'a mut MachineState) -> Self { + CopyTerm { state } + } +} + +impl<'a> Index for CopyTerm<'a> { + type Output = HeapCellValue; + + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + &self.state.heap[index] + } +} + +impl<'a> IndexMut for CopyTerm<'a> { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.state.heap[index] + } +} + +// the ordinary, heap term copier, used by duplicate_term. +impl<'a> CopierTarget for CopyTerm<'a> { + #[inline(always)] + fn threshold(&self) -> usize { + self.state.heap.len() + } + + #[inline(always)] + fn push(&mut self, hcv: HeapCellValue) { + self.state.heap.push(hcv); + } + + #[inline(always)] + fn store(&self, value: HeapCellValue) -> HeapCellValue { + self.state.store(value) + } + + #[inline(always)] + fn deref(&self, value: HeapCellValue) -> HeapCellValue { + self.state.deref(value) + } + + #[inline(always)] + fn stack(&mut self) -> &mut Stack { + &mut self.state.stack + } +} + +#[derive(Debug)] +pub(super) struct CopyBallTerm<'a> { + stack: &'a mut Stack, + heap: &'a mut Heap, + heap_boundary: usize, + stub: &'a mut Heap, +} + +impl<'a> CopyBallTerm<'a> { + pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self { + let hb = heap.len(); + + CopyBallTerm { + stack, + heap, + heap_boundary: hb, + stub, + } + } +} + +impl<'a> Index for CopyBallTerm<'a> { + type Output = HeapCellValue; + + fn index(&self, index: usize) -> &Self::Output { + if index < self.heap_boundary { + &self.heap[index] + } else { + let index = index - self.heap_boundary; + &self.stub[index] + } + } +} + +impl<'a> IndexMut for CopyBallTerm<'a> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + if index < self.heap_boundary { + &mut self.heap[index] + } else { + let index = index - self.heap_boundary; + &mut self.stub[index] + } + } +} + +// the ordinary, heap term copier, used by duplicate_term. +impl<'a> CopierTarget for CopyBallTerm<'a> { + fn threshold(&self) -> usize { + self.heap_boundary + self.stub.len() + } + + fn push(&mut self, value: HeapCellValue) { + self.stub.push(value); + } + + fn store(&self, value: HeapCellValue) -> HeapCellValue { + read_heap_cell!(value, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + if h < self.heap_boundary { + self.heap[h] + } else { + let index = h - self.heap_boundary; + self.stub[index] + } + } + (HeapCellValueTag::StackVar, s) => { + self.stack[s] + } + _ => { + value + } + ) + } + + fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue { + loop { + let value = self.store(addr); + + if value.is_var() && value != addr { + addr = value; + continue; + } + + return addr; + } + } + + fn stack(&mut self) -> &mut Stack { + self.stack + } +} + +impl MachineState { + #[allow(dead_code)] + pub(super) fn try_char_list(&mut self, addrs: Vec) -> Result { + let mut chars = String::new(); + + for addr in addrs { + let addr = self.store(self.deref(addr)); + + read_heap_cell!(addr, + (HeapCellValueTag::Char, c) => { + chars.push(c); + continue; + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + if let Some(c) = name.as_char() { + chars.push(c); + continue; + } + } + } + _ => { + } + ); + + return Err(self.type_error(ValidType::Character, addr)); + } + + Ok(chars) + } + + pub(super) fn throw_undefined_error(&mut self, name: Atom, arity: usize) -> MachineStub { + let stub = functor_stub(name, arity); + let err = self.existence_error(ExistenceError::Procedure(name, arity)); + + self.error_form(err, stub) + } + + pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { + self.cp.assign_if_local(self.p + 1); + self.num_of_args = arity; + self.b0 = self.b; + self.p = CodePtr::Local(p); + } + + pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) { + self.num_of_args = arity; + self.b0 = self.b; + self.p = CodePtr::Local(p); + } + + pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { + fn push_var_eq_functors<'a>( + heap: &mut Heap, + iter: impl Iterator, &'a HeapCellValue)>, + atom_tbl: &mut AtomTable, + ) -> Vec { + let mut list_of_var_eqs = vec![]; + + for (var, binding) in iter { + let var_atom = atom_tbl.build_with(&var); + let h = heap.len(); + + heap.push(atom_as_cell!(atom!("="), 2)); + heap.push(atom_as_cell!(var_atom)); + heap.push(*binding); + + list_of_var_eqs.push(str_loc_as_cell!(h)); + } + + list_of_var_eqs + } + + self.check_stream_properties( + stream, + StreamType::Text, + Some(self.registers[2]), + atom!("read_term"), + 3, + )?; + + if stream.past_end_of_stream() { + if EOFAction::Reset != stream.options().eof_action() { + return return_from_clause!(self.last_call, self); + } else if self.fail { + return Ok(()); + } + } + + loop { + match self.read(stream, &indices.op_dir) { + Ok(term_write_result) => { + let term = self.registers[2]; + unify_fn!(self, heap_loc_as_cell!(term_write_result.heap_loc), term); + let term = self.store(self.deref(term)); + + if self.fail { + return Ok(()); + } + + let mut singleton_var_set: IndexMap = IndexMap::new(); + let mut var_list = vec![]; + + let list_of_var_eqs = push_var_eq_functors( + &mut self.heap, + term_write_result.var_dict.iter(), + &mut self.atom_tbl, + ); + + for addr in stackful_preorder_iter(&mut self.heap, term) { + let addr = unmark_cell_bits!(addr); + + if let Some(var) = addr.as_var() { + if !singleton_var_set.contains_key(&var) { + singleton_var_set.insert(var, true); + var_list.push(addr); + } else { + singleton_var_set.insert(var, false); + } + } + } + + let singleton_var_list = push_var_eq_functors( + &mut self.heap, + term_write_result.var_dict.iter().filter(|(_, binding)| { + if let Some(r) = binding.as_var() { + *singleton_var_set.get(&r).unwrap_or(&false) + } else { + false + } + }), + &mut self.atom_tbl, + ); + + let singleton_addr = self.registers[3]; + let singletons_offset = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter()) + ); + + unify_fn!(self, singletons_offset, singleton_addr); + + if self.fail { + return Ok(()); + } + + let vars_addr = self.registers[4]; + let vars_offset = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, var_list.into_iter()) + ); + + unify_fn!(self, vars_offset, vars_addr); + + if self.fail { + return Ok(()); + } + + let var_names_addr = self.registers[5]; + let var_names_offset = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, list_of_var_eqs.into_iter()) + ); + + return Ok(unify_fn!(self, var_names_offset, var_names_addr)); + } + Err(err) => { + if let ParserError::UnexpectedEOF = err { + self.eof_action( + self.registers[2], + stream, + atom!("read_term"), + 3, + )?; + + if stream.options().eof_action() == EOFAction::Reset { + if self.fail == false { + continue; + } + } + + return Ok(()); + } - machine_st.fail = - if let Some(Ordering::Equal) = machine_st.compare_term_test(&a1, &a2) { - true - } else { - false - }; + let stub = functor_stub(atom!("read_term"), 3); + let err = self.syntax_error(err); - return_from_clause!(machine_st.last_call, machine_st) + return Err(self.error_form(err, stub)); + } } - &BuiltInClauseType::Sort => { - machine_st.check_sort_errors()?; + } + } - let stub = MachineError::functor_stub(clause_name!("sort"), 2); - let mut list = machine_st.try_from_list(temp_v!(1), stub)?; + pub(crate) fn write_term<'a>( + &'a mut self, + op_dir: &'a OpDir, + ) -> Result>, MachineStub> { + let ignore_ops = self.store(self.deref(self.registers[3])); + let numbervars = self.store(self.deref(self.registers[4])); + let quoted = self.store(self.deref(self.registers[5])); + let max_depth = self.store(self.deref(self.registers[7])); - list.sort_unstable_by(|a1, a2| { - machine_st - .compare_term_test(a1, a2) - .unwrap_or(Ordering::Less) - }); + let term_to_be_printed = self.store(self.deref(self.registers[2])); + let stub_gen = || functor_stub(atom!("write_term"), 2); - machine_st.term_dedup(&mut list); + let printer = match self.try_from_list(self.registers[6], stub_gen) { + Ok(addrs) => { + let mut var_names: IndexMap> = IndexMap::new(); - let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter())); + for addr in addrs { + read_heap_cell!(addr, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); - let r2 = machine_st[temp_v!(2)]; - (machine_st.unify_fn)(machine_st, r2, heap_addr); + if name == atom!("=") && arity == 2 { + let atom = self.store(self.deref(self.heap[s+1])); + let var = self.store(self.deref(self.heap[s+2])); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::KeySort => { - machine_st.check_keysort_errors()?; + if var_names.contains_key(&var) { + continue; + } - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); - let list = machine_st.try_from_list(temp_v!(1), stub)?; - let mut key_pairs = Vec::new(); + var_names.insert(var, Rc::new(cell_as_atom!(atom).as_str().to_owned())); + } + } + _ => { + } + ); + } - for val in list { - let key = machine_st.project_onto_key(val.clone())?; - key_pairs.push((key, val.clone())); + let mut printer = HCPrinter::new( + &mut self.heap, + &mut self.arena, + op_dir, + PrinterOutputter::new(), + term_to_be_printed, + ); + + if let HeapCellValueTag::Atom = ignore_ops.get_tag() { + let name = cell_as_atom!(ignore_ops); + printer.ignore_ops = name == atom!("true"); + } else { + unreachable!(); } - key_pairs.sort_by(|a1, a2| { - machine_st - .compare_term_test(&a1.0, &a2.0) - .unwrap_or(Ordering::Less) - }); + if let HeapCellValueTag::Atom = numbervars.get_tag() { + let name = cell_as_atom!(numbervars); + printer.numbervars = name == atom!("true"); + } else { + unreachable!(); + } - let key_pairs = key_pairs.into_iter().map(|kp| kp.1); - let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs)); + if let HeapCellValueTag::Atom = quoted.get_tag() { + let name = cell_as_atom!(quoted); + printer.quoted = name == atom!("true"); + } else { + unreachable!(); + } - let r2 = machine_st[temp_v!(2)]; - (machine_st.unify_fn)(machine_st, r2, heap_addr); + match Number::try_from(max_depth) { + Ok(Number::Fixnum(n)) => { + if let Ok(n) = usize::try_from(n.get_num()) { + printer.max_depth = n; + } else { + self.fail = true; + return Ok(None); + } + } + Ok(Number::Integer(n)) => { + if let Some(n) = n.to_usize() { + printer.max_depth = n; + } else { + self.fail = true; + return Ok(None); + } + } + _ => { + unreachable!(); + } + } - return_from_clause!(machine_st.last_call, machine_st) + printer.var_names = var_names; + + printer } - &BuiltInClauseType::Is(r, ref at) => { - let a1 = machine_st[r]; - let n2 = machine_st.get_number(at)?; + Err(err) => { + return Err(err); + } + }; - let n2 = machine_st.heap.put_constant(n2.into()); - (machine_st.unify_fn)(machine_st, a1, n2); + Ok(Some(printer)) + } - return_from_clause!(machine_st.last_call, machine_st) - } - } + pub(super) fn read_predicate_key(&self, name: HeapCellValue, arity: HeapCellValue) -> (Atom, usize) { + let name = cell_as_atom!(self.store(self.deref(name))); + let arity = cell_as_fixnum!(self.store(self.deref(arity))); + + (name, usize::try_from(arity.get_num()).unwrap()) } - fn call_clause_type( + pub(super) fn module_lookup( &mut self, - machine_st: &mut MachineState, + indices: &IndexStore, + call_policy: &mut Box, key: PredicateKey, - code_dir: &CodeDir, - op_dir: &OpDir, + module_name: Atom, + _last_call: bool, stream_aliases: &StreamAliasDir, ) -> CallResult { + if module_name == atom!("user") { + return call_policy.call_clause_type( + self, + key, + &indices.code_dir, + &indices.op_dir, + stream_aliases, + ); + } else if let Some(module) = indices.modules.get(&module_name) { + return call_policy.call_clause_type( + self, + key, + &module.code_dir, + &module.op_dir, + stream_aliases, + ); + } + let (name, arity) = key; - match ClauseType::from(name.clone(), arity, None) { - ClauseType::BuiltIn(built_in) => { - machine_st.setup_built_in_call(built_in.clone()); - self.call_builtin(machine_st, &built_in, code_dir, op_dir, stream_aliases)?; - } - ClauseType::CallN => { - machine_st.handle_internal_call_n(arity); + let stub = functor_stub(name, arity); + let err = self.module_resolution_error(module_name, name, arity); - if machine_st.fail { - return Ok(()); - } + return Err(self.error_form(err, stub)); + } +} - machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call); - } - ClauseType::Inlined(inlined) => { - machine_st.execute_inlined(&inlined); +#[derive(Debug)] +pub(crate) struct CWILCallPolicy { + pub(crate) prev_policy: Box, + count: Integer, + limits: Vec<(Integer, usize)>, + inference_limit_exceeded: bool, +} - 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); +impl CWILCallPolicy { + pub(crate) fn new_in_place(policy: &mut Box) { + let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); + mem::swap(&mut prev_policy, policy); + + let new_policy = CWILCallPolicy { + prev_policy, + count: Integer::from(0), + limits: vec![], + inference_limit_exceeded: false, + }; + + *policy = Box::new(new_policy); + } + + fn increment(&mut self, machine_st: &MachineState) -> CallResult { + if self.inference_limit_exceeded || machine_st.ball.stub.len() > 0 { + return Ok(()); + } + + if let Some(&(ref limit, bp)) = self.limits.last() { + if self.count == *limit { + self.inference_limit_exceeded = true; - return Err(machine_st.error_form( - MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name), - stub, - )); + return Err( + functor!(atom!("inference_limit_exceeded"), [fixnum(bp)]) + ); + } else { + self.count += 1; } } Ok(()) } - fn call_n( - &mut self, - machine_st: &mut MachineState, - arity: usize, - code_dir: &CodeDir, - op_dir: &OpDir, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - if let Some(key) = machine_st.setup_call_n(arity) { - self.call_clause_type(machine_st, key, code_dir, op_dir, stream_aliases)?; + pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer { + let mut limit = Integer::from(limit); + limit += &self.count; + + match self.limits.last() { + Some((ref inner_limit, _)) if *inner_limit <= limit => {} + _ => self.limits.push((limit, b)), + }; + + &self.count + } + + pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { + if let Some((_, bp)) = self.limits.last() { + if bp == &b { + self.limits.pop(); + } } - Ok(()) + &self.count + } + + pub(crate) fn is_empty(&self) -> bool { + self.limits.is_empty() + } + + pub(crate) fn into_inner(&mut self) -> Box { + let mut new_inner: Box = Box::new(DefaultCallPolicy {}); + mem::swap(&mut self.prev_policy, &mut new_inner); + new_inner } } @@ -1243,12 +1289,11 @@ impl CallPolicy for CWILCallPolicy { fn context_call( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { - self.prev_policy - .context_call(machine_st, name, arity, idx)?; //, indices)?; + self.prev_policy.context_call(machine_st, name, arity, idx)?; self.increment(machine_st) } @@ -1258,8 +1303,7 @@ impl CallPolicy for CWILCallPolicy { offset: usize, global_variables: &mut GlobalVarDir, ) -> CallResult { - self.prev_policy - .retry_me_else(machine_st, offset, global_variables)?; + self.prev_policy.retry_me_else(machine_st, offset, global_variables)?; self.increment(machine_st) } @@ -1269,8 +1313,7 @@ impl CallPolicy for CWILCallPolicy { offset: usize, global_variables: &mut GlobalVarDir, ) -> CallResult { - self.prev_policy - .retry(machine_st, offset, global_variables)?; + self.prev_policy.retry(machine_st, offset, global_variables)?; self.increment(machine_st) } @@ -1289,8 +1332,7 @@ impl CallPolicy for CWILCallPolicy { offset: usize, global_variables: &mut GlobalVarDir, ) -> CallResult { - self.prev_policy - .trust(machine_st, offset, global_variables)?; + self.prev_policy.trust(machine_st, offset, global_variables)?; self.increment(machine_st) } @@ -1302,9 +1344,7 @@ impl CallPolicy for CWILCallPolicy { op_dir: &OpDir, stream_aliases: &StreamAliasDir, ) -> CallResult { - self.prev_policy - .call_builtin(machine_st, ct, code_dir, op_dir, stream_aliases)?; - + self.prev_policy.call_builtin(machine_st, ct, code_dir, op_dir, stream_aliases)?; self.increment(machine_st) } @@ -1316,9 +1356,7 @@ impl CallPolicy for CWILCallPolicy { op_dir: &OpDir, stream_aliases: &StreamAliasDir, ) -> CallResult { - self.prev_policy - .call_n(machine_st, arity, code_dir, op_dir, stream_aliases)?; - + self.prev_policy.call_n(machine_st, arity, code_dir, op_dir, stream_aliases)?; self.increment(machine_st) } } @@ -1330,94 +1368,13 @@ pub(crate) struct DefaultCallPolicy {} impl CallPolicy for DefaultCallPolicy {} -#[derive(Debug)] -pub(crate) struct CWILCallPolicy { - pub(crate) prev_policy: Box, - count: Integer, - limits: Vec<(Integer, usize)>, - inference_limit_exceeded: bool, -} - -impl CWILCallPolicy { - pub(crate) fn new_in_place(policy: &mut Box) { - let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); - mem::swap(&mut prev_policy, policy); - - let new_policy = CWILCallPolicy { - prev_policy, - count: Integer::from(0), - limits: vec![], - inference_limit_exceeded: false, - }; - - *policy = Box::new(new_policy); - } - - fn increment(&mut self, machine_st: &MachineState) -> CallResult { - if self.inference_limit_exceeded || machine_st.ball.stub.h() > 0 { - return Ok(()); - } - - if let Some(&(ref limit, bp)) = self.limits.last() { - if self.count == *limit { - self.inference_limit_exceeded = true; - - return Err(functor!( - "inference_limit_exceeded", - [addr(Addr::Usize(bp))] - )); - } else { - self.count += 1; - } - } - - Ok(()) - } - - pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { - limit += &self.count; - - match self.limits.last().cloned() { - Some((ref inner_limit, _)) if *inner_limit <= limit => {} - _ => self.limits.push((limit, b)), - }; - - &self.count - } - - pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { - if let Some((_, bp)) = self.limits.last().cloned() { - if bp == b { - self.limits.pop(); - } - } - - &self.count - } - - pub(crate) fn is_empty(&self) -> bool { - self.limits.is_empty() - } - - pub(crate) fn into_inner(&mut self) -> Box { - let mut new_inner: Box = Box::new(DefaultCallPolicy {}); - mem::swap(&mut self.prev_policy, &mut new_inner); - new_inner - } -} - -pub(crate) trait CutPolicy: Any + fmt::Debug { - // returns true iff we fail or cut redirected the MachineState's p itself - fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool; -} - -downcast!(dyn CutPolicy); - -fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool { +fn cut_body(machine_st: &mut MachineState, addr: HeapCellValue) -> bool { let b = machine_st.b; - match addr { - &Addr::CutPoint(b0) | &Addr::Usize(b0) => { + read_heap_cell!(addr, + (HeapCellValueTag::Fixnum, b0) => { + let b0 = b0.get_num() as usize; + if b > b0 { machine_st.b = b0; } @@ -1426,7 +1383,7 @@ fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool { machine_st.fail = true; return true; } - }; + ); false } @@ -1436,20 +1393,20 @@ pub(crate) struct DefaultCutPolicy {} pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) { let addr = machine_st.store(machine_st.deref(machine_st[r])); - cut_body(machine_st, &addr); + cut_body(machine_st, addr); } impl CutPolicy for DefaultCutPolicy { fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { let addr = machine_st[r]; - cut_body(machine_st, &addr) + cut_body(machine_st, addr) } } #[derive(Debug)] pub(crate) struct SCCCutPolicy { // locations of cleaners, cut points, the previous block - cont_pts: Vec<(Addr, usize, usize)>, + cont_pts: Vec<(HeapCellValue, usize, usize)>, r_c_w_h: usize, r_c_wo_h: usize, } @@ -1467,21 +1424,21 @@ impl SCCCutPolicy { self.cont_pts.is_empty() } - pub(crate) fn push_cont_pt(&mut self, addr: Addr, b: usize, prev_b: usize) { + pub(crate) fn push_cont_pt(&mut self, addr: HeapCellValue, b: usize, prev_b: usize) { self.cont_pts.push((addr, b, prev_b)); } - pub(crate) fn pop_cont_pt(&mut self) -> Option<(Addr, usize, usize)> { + pub(crate) fn pop_cont_pt(&mut self) -> Option<(HeapCellValue, usize, usize)> { self.cont_pts.pop() } fn run_cleaners(&self, machine_st: &mut MachineState) -> bool { if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() { if machine_st.b < b_cutoff { - let (idx, arity) = if machine_st.block < prev_block { + let (idx, arity) = if machine_st.block > prev_block { (dir_entry!(self.r_c_w_h), 0) } else { - machine_st[temp_v!(1)] = Addr::Usize(b_cutoff); + machine_st.registers[1] = fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64)); (dir_entry!(self.r_c_wo_h), 1) }; @@ -1503,8 +1460,10 @@ impl CutPolicy for SCCCutPolicy { fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { let b = machine_st.b; - match machine_st[r] { - Addr::Usize(b0) | Addr::CutPoint(b0) => { + read_heap_cell!(machine_st[r], + (HeapCellValueTag::Fixnum, b0) => { + let b0 = b0.get_num() as usize; + if b > b0 { machine_st.b = b0; } @@ -1513,8 +1472,9 @@ impl CutPolicy for SCCCutPolicy { machine_st.fail = true; return true; } - } + ); self.run_cleaners(machine_st) } } + diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index c4929d2d5..8f4dc44dc 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1,12 +1,12 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{clause_name, perm_v, temp_v}; +use crate::arena::*; +use crate::atom_table::*; +use crate::types::*; use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; -use crate::indexing::*; use crate::instructions::*; +use crate::machine::arithmetic_ops::*; use crate::machine::attributed_variables::*; use crate::machine::code_repo::CodeRepo; use crate::machine::copier::*; @@ -18,19 +18,24 @@ use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::INTERRUPT; -use crate::rug::Integer; +use crate::parser::ast::*; +use crate::parser::rug::{Integer, Rational}; + +use crate::try_numeric_result; + use ordered_float::*; -use indexmap::{IndexMap, IndexSet}; +use indexmap::IndexSet; use std::cmp::Ordering; use std::convert::TryFrom; -use std::rc::Rc; impl MachineState { pub(crate) fn new() -> Self { MachineState { - atom_tbl: TabledData::new(Rc::new("".to_owned())), + arena: Arena::new(), + atom_tbl: AtomTable::new(), + pdl: Vec::with_capacity(1024), s: HeapPtr::default(), p: CodePtr::default(), b: 0, @@ -40,10 +45,10 @@ impl MachineState { cp: LocalCodePtr::default(), attr_var_init: AttrVarInitializer::new(0), fail: false, - heap: Heap::new(), + heap: Heap::with_capacity(256 * 256), mode: MachineMode::Write, stack: Stack::new(), - registers: vec![Addr::HeapCell(0); MAX_ARITY + 1], // self.registers[0] is never used. + registers: [heap_loc_as_cell!(0); MAX_ARITY + 1], // self.registers[0] is never used. trail: vec![], tr: 0, hb: 0, @@ -62,36 +67,25 @@ impl MachineState { } #[inline] - pub(crate) fn machine_flags(&self) -> MachineFlags { - self.flags - } - - pub(crate) fn store(&self, addr: Addr) -> Addr { - match addr { - Addr::AttrVar(h) | Addr::HeapCell(h) => self.heap[h].as_addr(h), - Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc], - Addr::PStrLocation(h, n) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] { - if !pstr.at_end(n) { - Addr::PStrLocation(h, n) - } else if has_tail { - Addr::HeapCell(h + 1) - } else { - Addr::EmptyList - } - } else { - unreachable!() - } + pub(crate) fn store(&self, value: HeapCellValue) -> HeapCellValue { + read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + self.heap[h] } - addr => addr, - } + (HeapCellValueTag::StackVar, s) => { + self.stack[s] + } + _ => { + value + } + ) } - pub(crate) fn deref(&self, mut addr: Addr) -> Addr { + pub fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue { loop { let value = self.store(addr); - if value.is_ref() && value != addr { + if value.is_var() && value != addr { addr = value; continue; } @@ -100,589 +94,1713 @@ impl MachineState { } } - fn bind_attr_var(&mut self, h: usize, addr: Addr) { - match addr.as_var() { - Some(Ref::HeapCell(hc)) => { - self.heap[hc] = HeapCellValue::Addr(Addr::AttrVar(h)); - self.trail(TrailRef::Ref(Ref::HeapCell(hc))); + pub fn trail(&mut self, r: TrailRef) { + match r { + TrailRef::Ref(r) => { + let h = r.get_value() as usize; + + match r.get_tag() { + RefTag::HeapCell => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedHeapVar, + h as u64, + )); + + self.tr += 1; + } + } + RefTag::StackCell => { + if h < self.b { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedStackVar, + h as u64, + )); + + self.tr += 1; + } + } + RefTag::AttrVar => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedAttrVar, + h as u64, + )); + + self.tr += 1; + } + } + } } - Some(Ref::StackCell(fr, sc)) => { - self.stack.index_and_frame_mut(fr)[sc] = Addr::AttrVar(h); - self.trail(TrailRef::Ref(Ref::StackCell(fr, sc))); + TrailRef::AttrVarHeapLink(h) => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedAttrVarHeapLink, + h as u64, + )); + + self.tr += 1; + } } - _ => { - self.push_attr_var_binding(h, addr); - self.heap[h] = HeapCellValue::Addr(addr); - self.trail(TrailRef::Ref(Ref::AttrVar(h))); + TrailRef::AttrVarListLink(h, l) => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedAttrVarListLink, + h as u64, + )); + + self.trail.push(TrailEntry::from_bytes( + list_loc_as_cell!(l).into_bytes() + )); + + self.tr += 2; + } + } + TrailRef::BlackboardEntry(key_atom) => { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedBlackboardEntry, + key_atom.index as u64, + )); + + self.tr += 1; + } + TrailRef::BlackboardOffset(key_atom, value_cell) => { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedBlackboardOffset, + key_atom.index as u64, + )); + + self.trail.push(TrailEntry::from_bytes( + value_cell.into_bytes(), + )); + + self.tr += 2; } } } - pub(super) fn bind(&mut self, r1: Ref, a2: Addr) { - let t1 = self.store(r1.as_addr()); + pub fn allocate(&mut self, num_cells: usize) { + let e = self.stack.allocate_and_frame(num_cells); + let and_frame = self.stack.index_and_frame_mut(e); + + and_frame.prelude.e = self.e; + and_frame.prelude.cp = self.cp; + + self.e = e; + self.p += 1; + } + + pub fn bind(&mut self, r1: Ref, a2: HeapCellValue) { + let t1 = self.store(r1.as_heap_cell_value()); let t2 = self.store(a2); - if t1.is_ref() && (!t2.is_ref() || a2 < r1) { - match r1 { - Ref::StackCell(fr, sc) => { - self.stack.index_and_frame_mut(fr)[sc] = t2; + if t1.is_var() && (!t2.is_var() || a2 < r1) { + match r1.get_tag() { + RefTag::StackCell => { + self.stack[r1.get_value() as usize] = t2; } - Ref::HeapCell(h) => { - self.heap[h] = HeapCellValue::Addr(t2); - } - Ref::AttrVar(h) => { - return self.bind_attr_var(h, t2); + RefTag::HeapCell => { + self.heap[r1.get_value() as usize] = t2; } + RefTag::AttrVar => { + self.bind_attr_var(r1.get_value() as usize, t2); + } }; - self.trail(TrailRef::from(r1)); + self.trail(TrailRef::Ref(r1)); } else { - match a2.as_var() { - Some(Ref::StackCell(fr, sc)) => { - self.stack.index_and_frame_mut(fr)[sc] = t1; - self.trail(TrailRef::Ref(Ref::StackCell(fr, sc))); + read_heap_cell!(a2, + (HeapCellValueTag::StackVar, s) => { + self.stack[s] = t1; + self.trail(TrailRef::Ref(Ref::stack_cell(s))); } - Some(Ref::HeapCell(h)) => { - self.heap[h] = HeapCellValue::Addr(t1); - self.trail(TrailRef::Ref(Ref::HeapCell(h))); + (HeapCellValueTag::Var, h) => { + self.heap[h] = t1; + self.trail(TrailRef::Ref(Ref::heap_cell(h))); } - Some(Ref::AttrVar(h)) => { + (HeapCellValueTag::AttrVar, h) => { self.bind_attr_var(h, t1); } - None => {} - } - } - } - - #[inline] - pub(super) fn bind_with_occurs_check_with_error_wrapper(&mut self, r: Ref, addr: Addr) { - if self.bind_with_occurs_check(r, addr) { - let err = self.representation_error( - RepFlag::Term, - clause_name!("unify_with_occurs_check"), - 2, + _ => { + unreachable!(); + } ); - - self.throw_exception(err); } } - #[inline] - pub(super) fn bind_with_occurs_check_wrapper(&mut self, r: Ref, addr: Addr) { - self.bind_with_occurs_check(r, addr); + pub fn bind_attr_var(&mut self, h: usize, addr: HeapCellValue) { + read_heap_cell!(addr, + (HeapCellValueTag::Var, hc) => { + self.heap[hc] = attr_var_as_cell!(h); + self.trail(TrailRef::Ref(Ref::heap_cell(hc))); + } + (HeapCellValueTag::StackVar, hc) => { + self.stack[hc] = attr_var_as_cell!(h); + self.trail(TrailRef::Ref(Ref::stack_cell(hc))); + } + _ => { + self.push_attr_var_binding(h, addr); + self.heap[h] = addr; + self.trail(TrailRef::Ref(Ref::attr_var(h))); + } + ) } - #[inline] - pub(super) fn bind_with_occurs_check(&mut self, r: Ref, addr: Addr) -> bool { - if let Ref::StackCell(..) = r { - // local variable optimization -- r cannot occur in the - // data structure bound to addr, so don't bother - // traversing it. - self.bind(r, addr); - return false; - } + fn unify_structure(&mut self, s1: usize, value: HeapCellValue) { + // s1 is the value of a STR cell. + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity(); - let mut occurs_triggered = false; + read_heap_cell!(value, + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); - for addr in self.acyclic_pre_order_iter(addr) { - if let Some(inner_r) = addr.as_var() { - if r == inner_r { - occurs_triggered = true; - break; + if n1 == n2 && a1 == a2 { + for idx in 0..a1 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; } } - } - - self.fail = occurs_triggered; - self.bind(r, addr); - - return occurs_triggered; + (HeapCellValueTag::Lis, l2) => { + if a1 == 2 && n1 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2+1+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::Atom, (n2, a2)) => { + if !(a1 == 0 && a2 == 0 && n1 == n2) { + self.fail = true; + } + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), str_loc_as_cell!(s1)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), str_loc_as_cell!(s1)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), str_loc_as_cell!(s1)); + } + _ => { + self.fail = true; + } + ) } - pub(super) fn unify_with_occurs_check_with_error(&mut self, a1: Addr, a2: Addr) { - let mut throw_error = false; - self.unify_with_occurs_check_loop(a1, a2, || throw_error = true); + fn unify_list(&mut self, l1: usize, d2: HeapCellValue) { + read_heap_cell!(d2, + (HeapCellValueTag::Lis, l2) => { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2 + idx)); + self.pdl.push(heap_loc_as_cell!(l1 + idx)); + } + } + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); - if throw_error { - let err = self.representation_error( - RepFlag::Term, - clause_name!("unify_with_occurs_check"), - 2, - ); + if a2 == 2 && n2 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(l1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => { + self.unify_partial_string(list_loc_as_cell!(l1), d2) + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), list_loc_as_cell!(l1)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), list_loc_as_cell!(l1)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), list_loc_as_cell!(l1)); + } + _ => { + self.fail = true; + } + ) + } - self.throw_exception(err); + pub fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, atom_as_cstr_cell!(atom)); + return; } - } - pub(super) fn unify_with_occurs_check(&mut self, a1: Addr, a2: Addr) { - self.unify_with_occurs_check_loop(a1, a2, || {}) + read_heap_cell!(value, + (HeapCellValueTag::CStr, cstr_atom) => { + self.fail = atom != cstr_atom; + } + _ => { + self.fail = true; + } + ); } - pub(super) fn unify_with_occurs_check_loop( - &mut self, - a1: Addr, - a2: Addr, - mut occurs_trigger: impl FnMut(), - ) { - let mut pdl = vec![a1, a2]; - let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new(); + // d1's tag is LIS, STR or PSTRLOC. + pub fn unify_partial_string(&mut self, d1: HeapCellValue, d2: HeapCellValue) { + if let Some(r) = d2.as_var() { + self.bind(r, d1); + return; + } - self.fail = false; + let s1 = self.heap.len(); - while !(pdl.is_empty() || self.fail) { - let d1 = self.deref(pdl.pop().unwrap()); - let d2 = self.deref(pdl.pop().unwrap()); + self.heap.push(d1); + self.heap.push(d2); - if d1 != d2 { - let d1 = self.store(d1); - let d2 = self.store(d2); + let mut pstr_iter1 = HeapPStrIter::new(&self.heap, s1); + let mut pstr_iter2 = HeapPStrIter::new(&self.heap, s1 + 1); - if tabu_list.contains(&(d1, d2)) { - continue; - } else { - tabu_list.insert((d1, d2)); + match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { + PStrCmpResult::Ordered(Ordering::Equal) => {} + PStrCmpResult::Ordered(Ordering::Less) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } + PStrCmpResult::Ordered(Ordering::Greater) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } + continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | + continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { + if continuable.is_second_iter() { + std::mem::swap(&mut pstr_iter1, &mut pstr_iter2); } - match (d1, d2) { - (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => { - if self.bind_with_occurs_check(Ref::AttrVar(h), addr) { - occurs_trigger(); - } - } - (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => { - if self.bind_with_occurs_check(Ref::HeapCell(h), addr) { - occurs_trigger(); - } - } - (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => { - if self.bind_with_occurs_check(Ref::StackCell(fr, sc), addr) { - occurs_trigger(); - } - } - (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] { - if f2.as_str() == "." && n2 == 2 { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2 + 1)); + let mut chars_iter = PStrCharsIter { + iter: pstr_iter1, + item: Some(iteratee), + }; - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 2)); + let mut focus = pstr_iter2.focus; - continue; - } - } + 'outer: loop { + while let Some(c) = chars_iter.peek() { + read_heap_cell!(focus, + (HeapCellValueTag::Lis, l) => { + let val = pstr_iter2.heap[l]; - self.fail = true; - } - (Addr::PStrLocation(h, n), Addr::Lis(l)) - | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { - if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(n..).next() { - pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); - pdl.push(Addr::HeapCell(l + 1)); + self.pdl.push(val); + self.pdl.push(char_as_cell!(c)); - pdl.push(Addr::Char(c)); - pdl.push(Addr::HeapCell(l)); - } else { - unreachable!() + focus = pstr_iter2.heap[l+1]; } - } else { - unreachable!() - } - } - (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { - if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] - { - if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = - &self.heap[h2] - { - let pstr1_s = pstr1.as_str_from(n1); - let pstr2_s = pstr2.as_str_from(n2); - - let m_len = if pstr1_s.starts_with(pstr2_s) { - pstr2_s.len() - } else if pstr2_s.starts_with(pstr1_s) { - pstr1_s.len() - } else { - self.fail = true; - return; - }; + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s]) + .get_name_and_arity(); - if pstr1.at_end(n1 + m_len) { - if has_tail_1 { - pdl.push(Addr::HeapCell(h1 + 1)); - } else { - pdl.push(Addr::EmptyList); - } + if name == atom!(".") && arity == 2 { + self.pdl.push(pstr_iter2.heap[s+1]); + self.pdl.push(char_as_cell!(c)); - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); - } - } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); - } + focus = pstr_iter2.heap[s+2]; } else { - pdl.push(Addr::PStrLocation(h1, n1 + m_len)); - - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); - } - } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); - } + self.fail = true; + break 'outer; } - } else { - unreachable!() } - } else { - unreachable!() - } - } - (Addr::Lis(a1), Addr::Lis(a2)) => { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2)); - - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 1)); - } - (Addr::Str(a1), Addr::Str(a2)) => { - let r1 = &self.heap[a1]; - let r2 = &self.heap[a2]; - - if let &HeapCellValue::NamedStr(n1, ref f1, _) = r1 { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = r2 { - if n1 == n2 && *f1 == *f2 { - for i in 1..n1 + 1 { - pdl.push(Addr::HeapCell(a1 + i)); - pdl.push(Addr::HeapCell(a2 + i)); + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + match chars_iter.item.unwrap() { + PStrIteratee::Char(focus, _) => { + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); } + PStrIteratee::PStrSegment(focus, _, n) => { + read_heap_cell!(self.heap[focus], + (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == 0 { + let target_cell = match self.heap[focus].get_tag() { + HeapCellValueTag::CStr => { + atom_as_cstr_cell!(pstr_atom) + } + HeapCellValueTag::PStr => { + pstr_loc_as_cell!(focus) + } + _ => { + unreachable!() + } + }; + + self.pdl.push(target_cell); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(focus)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + (HeapCellValueTag::PStrOffset, pstr_loc) => { + let n0 = cell_as_fixnum!(self.heap[focus+1]) + .get_num() as usize; + + if pstr_loc < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == n0 { + self.pdl.push(pstr_loc_as_cell!(focus)); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(pstr_loc)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + _ => { + } + ); - continue; - } - } - } + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } - self.fail = true; - } - (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) { - (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _)) - if n1.as_str() == n2.as_str() => {} - ( - &HeapCellValue::DBRef(ref db_ref_1), - &HeapCellValue::DBRef(ref db_ref_2), - ) if db_ref_1 == db_ref_2 => {} - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { - continue; + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); + + return; } } - } - self.fail = true; - } - }, - (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { - match &self.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - if name.as_str().chars().next() != Some(c) { - self.fail = true; - return; - } + break 'outer; } _ => { self.fail = true; - return; - } - } - } - (Addr::Stream(s1), Addr::Stream(s2)) => { - if s1 != s2 { - self.fail = true; - } - } - (v, Addr::Con(h)) | (Addr::Con(h), v) => { - if let Ok(n1) = Number::try_from(&self.heap[h]) { - if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) { - if n1 == v { - continue; - } - } - } - - self.fail = true; - } - (a1, a2) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) { - if n1 == n2 { - continue; - } + break 'outer; } - } + ); - if a1 != a2 { - self.fail = true; - } + chars_iter.next(); } - }; - } - } - } - - pub(super) fn unify(&mut self, a1: Addr, a2: Addr) { - let mut pdl = vec![a1, a2]; - let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new(); + chars_iter.iter.next(); - self.fail = false; + self.pdl.push(chars_iter.iter.focus); + self.pdl.push(focus); - while !(pdl.is_empty() || self.fail) { - let d1 = self.deref(pdl.pop().unwrap()); - let d2 = self.deref(pdl.pop().unwrap()); + break; + } + } + PStrCmpResult::Unordered => { + self.pdl.push(pstr_iter1.focus); + self.pdl.push(pstr_iter2.focus); + } + } - if d1 != d2 { - let d1 = self.store(d1); - let d2 = self.store(d2); + self.heap.pop(); + self.heap.pop(); + } - if tabu_list.contains(&(d1, d2)) { - continue; + pub fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + self.fail = !(arity == 0 && name == atom); + } + (HeapCellValueTag::Char, c1) => { + if let Some(c2) = atom.as_char() { + self.fail = c1 != c2; } else { - tabu_list.insert((d1, d2)); + self.fail = true; } + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), atom_as_cell!(atom)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), atom_as_cell!(atom)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), atom_as_cell!(atom)); + } + _ => { + self.fail = true; + } + ); + } - match (d1, d2) { - (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => { - self.bind(Ref::AttrVar(h), addr); - } - (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => { - self.bind(Ref::HeapCell(h), addr); - } - (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => { - self.bind(Ref::StackCell(fr, sc), addr); - } - (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] { - if f2.as_str() == "." && n2 == 2 { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2 + 1)); - - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 2)); + pub fn unify_char(&mut self, c: char, value: HeapCellValue) { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + if let Some(c2) = name.as_char() { + self.fail = !(c == c2 && arity == 0); + } else { + self.fail = true; + } + } + (HeapCellValueTag::Char, c2) => { + if c != c2 { + self.fail = true; + } + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), char_as_cell!(c)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), char_as_cell!(c)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), char_as_cell!(c)); + } + _ => { + self.fail = true; + } + ); + } - continue; - } - } + pub fn unify_fixnum(&mut self, n1: Fixnum, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, fixnum_as_cell!(n1)); + return; + } - self.fail = true; + match Number::try_from(value) { + Ok(n2) => match n2 { + Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {} + Number::Integer(n2) if n1.get_num() == *n2 => {} + Number::Rational(n2) if n1.get_num() == *n2 => {} + _ => { + self.fail = true; + } + }, + Err(_) => { + self.fail = true; + } + } + } + + pub fn unify_big_int(&mut self, n1: TypedArenaPtr, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, typed_arena_ptr_as_cell!(n1)); + return; + } + + match Number::try_from(value) { + Ok(n2) => match n2 { + Number::Fixnum(n2) if *n1 == n2.get_num() => {} + Number::Integer(n2) if *n1 == *n2 => {} + Number::Rational(n2) if *n1 == *n2 => {} + _ => { + self.fail = true; + } + }, + Err(_) => { + self.fail = true; + } + } + } + + pub fn unify_rational(&mut self, n1: TypedArenaPtr, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, typed_arena_ptr_as_cell!(n1)); + return; + } + + match Number::try_from(value) { + Ok(n2) => match n2 { + Number::Fixnum(n2) if *n1 == n2.get_num() => {} + Number::Integer(n2) if *n1 == *n2 => {} + Number::Rational(n2) if *n1 == *n2 => {} + _ => { + self.fail = true; + } + }, + Err(_) => { + self.fail = true; + } + } + } + + pub fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, typed_arena_ptr_as_cell!(f1)); + return; + } + + read_heap_cell!(value, + (HeapCellValueTag::F64, f2) => { + if *f1 != *f2 { + self.fail = true; + } + } + _ => { + self.fail = true; + } + ); + } + + pub fn unify_constant(&mut self, ptr: UntypedArenaPtr, value: HeapCellValue) { + if let Some(ptr2) = value.to_untyped_arena_ptr() { + if ptr.get_ptr() == ptr2.get_ptr() { + return; + } + } + + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, int_ptr) => { + self.unify_big_int(int_ptr, value); + } + (ArenaHeaderTag::Rational, rat_ptr) => { + self.unify_rational(rat_ptr, value); + } + _ => { + if let Some(r) = value.as_var() { + self.bind(r, untyped_arena_ptr_as_cell!(ptr)); + } else { + self.fail = true; + } + } + ); + } + + pub fn unify(&mut self) { + let mut tabu_list: IndexSet<(usize, usize)> = IndexSet::new(); + // self.fail = false; + + while !(self.pdl.is_empty() || self.fail) { + let s1 = self.pdl.pop().unwrap(); + let s1 = self.deref(s1); + + let s2 = self.pdl.pop().unwrap(); + let s2 = self.deref(s2); + + if s1 != s2 { + let d1 = self.store(s1); + let d2 = self.store(s2); + + read_heap_cell!(d1, + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), d2); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), d2); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), d2); + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert!(arity == 0); + self.unify_atom(name, d2); + } + (HeapCellValueTag::Str, s1) => { + if d2.is_constant() { + self.fail = true; + break; + } + + let s2 = s2.get_value() as usize; + + if tabu_list.contains(&(s1, s2)) { + continue; + } + + self.unify_structure(s1, d2); + + if !self.fail { + tabu_list.insert((s1, s2)); + } + } + (HeapCellValueTag::Lis, l1) => { + if d2.is_ref() { + let l2 = s2.get_value(); + + if tabu_list.contains(&(l1, l2)) { + continue; + } + + tabu_list.insert((l1, l2)); + } + + self.unify_list(l1, d2); + } + (HeapCellValueTag::PStrLoc, pstr1_loc) => { + read_heap_cell!(d2, + (HeapCellValueTag::PStrLoc | + HeapCellValueTag::Lis | + HeapCellValueTag::Str, + pstr2_loc) => { + if tabu_list.contains(&(pstr1_loc, pstr2_loc)) { + continue; + } + } + (HeapCellValueTag::CStr | + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar) => { + } + _ => { + self.fail = true; + break; + } + ); + + self.unify_partial_string(d1, d2); + + if !self.fail && !d2.is_constant() { + tabu_list.insert((pstr1_loc, d2.get_value())); + } + } + (HeapCellValueTag::CStr) => { + read_heap_cell!(d2, + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), d1); + continue; + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), d1); + continue; + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), d1); + continue; + } + (HeapCellValueTag::Str | + HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc) => { + } + (HeapCellValueTag::CStr) => { + self.fail = d1 != d2; + continue; + } + _ => { + self.fail = true; + return; + } + ); + + self.unify_partial_string(d2, d1); + } + (HeapCellValueTag::F64, f1) => { + self.unify_f64(f1, d2); + } + (HeapCellValueTag::Fixnum, n1) => { + self.unify_fixnum(n1, d2); + } + (HeapCellValueTag::Char, c1) => { + self.unify_char(c1, d2); + } + (HeapCellValueTag::Cons, ptr_1) => { + self.unify_constant(ptr_1, d2); + } + _ => { + unreachable!(); + } + ); + } + } + } + + pub(super) fn set_ball(&mut self) { + self.ball.reset(); + + let addr = self.registers[1]; + self.ball.boundary = self.heap.len(); + + copy_term( + CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub), + addr, + AttrVarPolicy::DeepCopy, + ); + } + + pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { + let old_h = self.heap.len(); + + let a1 = self.registers[1]; + let a2 = self.registers[2]; + + copy_term(CopyTerm::new(self), a1, attr_var_policy); + + unify_fn!(self, heap_loc_as_cell!(old_h), a2); + } + + pub(super) fn unwind_stack(&mut self) { + self.b = self.block; + self.fail = true; + } + + #[inline] + pub fn bind_with_occurs_check(&mut self, r: Ref, value: HeapCellValue) -> bool { + if let RefTag::StackCell = r.get_tag() { + // local variable optimization -- r cannot occur in the + // heap structure bound to value, so don't bother + // traversing value. + self.bind(r, value); + return false; + } + + let mut occurs_triggered = false; + + if !value.is_constant() { + for addr in stackful_preorder_iter(&mut self.heap, value) { + if let Some(inner_r) = addr.as_var() { + if r == inner_r { + occurs_triggered = true; + break; + } + } + } + } + + if occurs_triggered { + self.fail = true; + } else { + self.bind(r, value); + } + + return occurs_triggered; + } + + #[inline] + pub(super) fn bind_with_occurs_check_wrapper(&mut self, r: Ref, value: HeapCellValue) { + self.bind_with_occurs_check(r, value); + } + + #[inline] + pub(super) fn bind_with_occurs_check_with_error_wrapper( + &mut self, + r: Ref, + value: HeapCellValue, + ) { + if self.bind_with_occurs_check(r, value) { + let err = self.representation_error(RepFlag::Term); + let stub = functor_stub(atom!("unify_with_occurs_check"), 2); + let err = self.error_form(err, stub); + + self.throw_exception(err); + } + } + + pub(super) fn unify_with_occurs_check_with_error(&mut self) { + let mut throw_error = false; + self.unify_with_occurs_check_loop(|| throw_error = true); + + if throw_error { + let err = self.representation_error(RepFlag::Term); + let stub = functor_stub(atom!("unify_with_occurs_check"), 2); + let err = self.error_form(err, stub); + + self.throw_exception(err); + } + } + + pub(super) fn unify_with_occurs_check(&mut self) { + self.unify_with_occurs_check_loop(|| {}) + } + + fn unify_structure_with_occurs_check( + &mut self, + s1: usize, + value: HeapCellValue, + mut occurs_trigger: impl FnMut(), + ) { + // s1 is the value of a STR cell. + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity(); + + read_heap_cell!(value, + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + if n1 == n2 && a1 == a2 { + for idx in 0..a1 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::Lis, l2) => { + if a1 == 2 && n1 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::Atom, (n2, a2)) => { + if !(a1 == 0 && a2 == 0 && n1 == n2) { + self.fail = true; + } + } + (HeapCellValueTag::AttrVar, h) => { + if self.bind_with_occurs_check(Ref::attr_var(h), str_loc_as_cell!(s1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::Var, h) => { + if self.bind_with_occurs_check(Ref::heap_cell(h), str_loc_as_cell!(s1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::StackVar, s) => { + if self.bind_with_occurs_check(Ref::stack_cell(s), str_loc_as_cell!(s1)) { + occurs_trigger(); + } + } + _ => { + self.fail = true; + } + ) + } + + // the return value of unify_partial_string_with_occurs_check is + // interpreted as follows: + // + // Some(None) -- the strings are equal, nothing to unify + // Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1 + // None -- prefixes not equal, unification fails + // + // d1's tag is assumed to be one of LIS, STR or PSTRLOC. + pub fn unify_partial_string_with_occurs_check( + &mut self, + d1: HeapCellValue, + d2: HeapCellValue, + mut occurs_trigger: impl FnMut(), + ) { + if let Some(r) = d2.as_var() { + if self.bind_with_occurs_check(r, d1) { + occurs_trigger(); + } + + return; + } + + let s1 = self.heap.len(); + + self.heap.push(d1); + self.heap.push(d2); + + let mut pstr_iter1 = HeapPStrIter::new(&self.heap, s1); + let mut pstr_iter2 = HeapPStrIter::new(&self.heap, s1 + 1); + + match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { + PStrCmpResult::Ordered(Ordering::Equal) => {} + PStrCmpResult::Ordered(Ordering::Less) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } + PStrCmpResult::Ordered(Ordering::Greater) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } + continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | + continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { + if continuable.is_second_iter() { + std::mem::swap(&mut pstr_iter1, &mut pstr_iter2); + } + + let mut chars_iter = PStrCharsIter { + iter: pstr_iter1, + item: Some(iteratee), + }; + + let mut focus = pstr_iter2.focus; + + 'outer: loop { + while let Some(c) = chars_iter.peek() { + read_heap_cell!(focus, + (HeapCellValueTag::Lis, l) => { + let val = pstr_iter2.heap[l]; + + self.pdl.push(val); + self.pdl.push(char_as_cell!(c)); + + focus = pstr_iter2.heap[l+1]; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s]) + .get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + self.pdl.push(pstr_iter2.heap[s+1]); + self.pdl.push(char_as_cell!(c)); + + focus = pstr_iter2.heap[s+2]; + } else { + self.fail = true; + break 'outer; + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + match chars_iter.item.unwrap() { + PStrIteratee::Char(focus, _) => { + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); + } + PStrIteratee::PStrSegment(focus, _, n) => { + read_heap_cell!(self.heap[focus], + (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == 0 { + let target_cell = match self.heap[focus].get_tag() { + HeapCellValueTag::CStr => { + atom_as_cstr_cell!(pstr_atom) + } + HeapCellValueTag::PStr => { + pstr_loc_as_cell!(focus) + } + _ => { + unreachable!() + } + }; + + self.pdl.push(target_cell); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(focus)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + (HeapCellValueTag::PStrOffset, pstr_loc) => { + let n0 = cell_as_fixnum!(self.heap[focus+1]) + .get_num() as usize; + + if pstr_loc < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == n0 { + self.pdl.push(pstr_loc_as_cell!(focus)); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(pstr_loc)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + _ => { + } + ); + + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); + + return; + } + } + + break 'outer; + } + _ => { + self.fail = true; + break 'outer; + } + ); + + chars_iter.next(); + } + + chars_iter.iter.next(); + + self.pdl.push(chars_iter.iter.focus); + self.pdl.push(focus); + + break; + } + } + PStrCmpResult::Unordered => { + self.pdl.push(pstr_iter1.focus); + self.pdl.push(pstr_iter2.focus); + } + } + + self.heap.pop(); + self.heap.pop(); + } + + fn unify_list_with_occurs_trigger( + &mut self, + l1: usize, + d2: HeapCellValue, + mut occurs_trigger: impl FnMut(), + ) { + read_heap_cell!(d2, + (HeapCellValueTag::Lis, l2) => { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2+idx)); + self.pdl.push(heap_loc_as_cell!(l1+idx)); + } + } + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + if a2 == 2 && n2 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(l1+idx)); } - (Addr::PStrLocation(h, n), Addr::Lis(l)) - | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { - if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(n..).next() { - pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); - pdl.push(Addr::HeapCell(l + 1)); + } else { + self.fail = true; + } + } + (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => { + self.unify_partial_string_with_occurs_check( + list_loc_as_cell!(l1), + d2, + &mut occurs_trigger, + ) + } + (HeapCellValueTag::AttrVar, h) => { + if self.bind_with_occurs_check(Ref::attr_var(h), list_loc_as_cell!(l1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::Var, h) => { + if self.bind_with_occurs_check(Ref::heap_cell(h), list_loc_as_cell!(l1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::StackVar, s) => { + if self.bind_with_occurs_check(Ref::stack_cell(s), list_loc_as_cell!(l1)) { + occurs_trigger(); + } + } + _ => { + self.fail = true; + } + ) + } - pdl.push(Addr::Char(c)); - pdl.push(Addr::HeapCell(l)); - } else { - unreachable!() + pub(super) fn unify_with_occurs_check_loop(&mut self, mut occurs_trigger: impl FnMut()) { + let mut tabu_list: IndexSet<(usize, usize)> = IndexSet::new(); + + // self.fail = false; + + while !(self.pdl.is_empty() || self.fail) { + let s1 = self.pdl.pop().unwrap(); + let s1 = self.deref(s1); + + let s2 = self.pdl.pop().unwrap(); + let s2 = self.deref(s2); + + if s1 != s2 { + let d1 = self.store(s1); + let d2 = self.store(s2); + + read_heap_cell!(d1, + (HeapCellValueTag::AttrVar, h) => { + if self.bind_with_occurs_check(Ref::attr_var(h), d2) { + occurs_trigger(); + } + } + (HeapCellValueTag::Var, h) => { + if self.bind_with_occurs_check(Ref::heap_cell(h), d2) { + occurs_trigger(); + } + } + (HeapCellValueTag::StackVar, s) => { + if self.bind_with_occurs_check(Ref::stack_cell(s), d2) { + occurs_trigger(); + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert!(arity == 0); + self.unify_atom(name, d2); + } + (HeapCellValueTag::Str, s1) => { + if d2.is_constant() { + self.fail = true; + break; + } + + let s2 = s2.get_value() as usize; + + if tabu_list.contains(&(s1, s2)) { + continue; + } + + self.unify_structure_with_occurs_check(s1, d2, &mut occurs_trigger); + + if !self.fail { + tabu_list.insert((s1, s2)); + } + } + (HeapCellValueTag::Lis, l1) => { + if d2.is_ref() { + let l2 = s2.get_value() as usize; + + if tabu_list.contains(&(l1, l2)) { + continue; + } + + tabu_list.insert((l1, l2)); + } + + self.unify_list_with_occurs_trigger(l1, d2, &mut occurs_trigger); + } + (HeapCellValueTag::PStrLoc, pstr1_loc) => { + read_heap_cell!(d2, + (HeapCellValueTag::PStrLoc | + HeapCellValueTag::Lis | + HeapCellValueTag::Str, + pstr2_loc) => { + if tabu_list.contains(&(pstr1_loc, pstr2_loc)) { + continue; + } + } + (HeapCellValueTag::CStr | + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar) => { + } + _ => { + self.fail = true; + break; + } + ); + + self.unify_partial_string_with_occurs_check( + d1, + d2, + &mut occurs_trigger, + ); + + if !self.fail && !d2.is_constant() { + tabu_list.insert((pstr1_loc, d2.get_value())); + } + } + (HeapCellValueTag::CStr) => { + read_heap_cell!(d2, + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), d1); + continue; + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), d1); + continue; + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), d1); + continue; + } + (HeapCellValueTag::Str | + HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc) => { + } + _ => { + self.fail = true; + return; } + ); + + self.unify_partial_string(d2, d1); + } + (HeapCellValueTag::F64, f1) => { + self.unify_f64(f1, d2); + } + (HeapCellValueTag::Fixnum, n1) => { + self.unify_fixnum(n1, d2); + } + (HeapCellValueTag::Char, c1) => { + self.unify_char(c1, d2); + } + (HeapCellValueTag::Cons, ptr_1) => { + self.unify_constant(ptr_1, d2); + } + _ => { + unreachable!(); + } + ); + } + } + } + + fn read_s(&mut self) -> HeapCellValue { + match &self.s { + &HeapPtr::HeapCell(h) => self.deref(self.heap[h]), + &HeapPtr::PStrChar(h, n) => { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + if let Some(c) = pstr.as_str_from(n).chars().next() { + char_as_cell!(c) + } else { // if has_tail { + self.deref(self.heap[h+1]) // heap_loc_as_cell!(h+1) + } + // } else { + // empty_list_as_cell!() + // } + } + (HeapCellValueTag::CStr, cstr_atom) => { + let pstr = PartialString::from(cstr_atom); + + if let Some(c) = pstr.as_str_from(n).chars().next() { + char_as_cell!(c) + } else { // if has_tail { + empty_list_as_cell!() + } + } + _ => { + unreachable!() + } + ) + } + &HeapPtr::PStrLocation(h, n) => { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::PStr, pstr_atom) => { + if n < pstr_atom.len() { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(h)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(n as i64))); + + pstr_loc_as_cell!(h_len) } else { - unreachable!() + self.deref(self.heap[h+1]) } } - (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { - if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] - { - if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = - &self.heap[h2] - { - let pstr1_s = pstr1.as_str_from(n1); - let pstr2_s = pstr2.as_str_from(n2); + (HeapCellValueTag::CStr, cstr_atom) => { + if n < cstr_atom.len() { + let h_len = self.heap.len(); - let m_len = if pstr1_s.starts_with(pstr2_s) { - pstr2_s.len() - } else if pstr2_s.starts_with(pstr1_s) { - pstr1_s.len() - } else { - self.fail = true; - return; - }; + self.heap.push(pstr_offset_as_cell!(h)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(n as i64))); - if pstr1.at_end(n1 + m_len) { - if has_tail_1 { - pdl.push(Addr::HeapCell(h1 + 1)); - } else { - pdl.push(Addr::EmptyList); - } + pstr_loc_as_cell!(h_len) + } else { + empty_list_as_cell!() + } + } + _ => { + unreachable!() + } + ) + } + } + } + + pub fn compare_term_test(&mut self) -> Option { + let mut tabu_list = IndexSet::new(); + + while !self.pdl.is_empty() { + let s1 = self.pdl.pop().unwrap(); + let s1 = self.deref(s1); + + let s2 = self.pdl.pop().unwrap(); + let s2 = self.deref(s2); + + if s1 == s2 { + continue; + } + + let v1 = self.store(s1); + let v2 = self.store(s2); + + let order_cat_v1 = v1.order_category(); + let order_cat_v2 = v2.order_category(); + + if order_cat_v1 != order_cat_v2 { + self.pdl.clear(); + return Some(order_cat_v1.cmp(&order_cat_v2)); + } - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); + match order_cat_v1 { + Some(TermOrderCategory::Variable) => { + let v1 = v1.as_var().unwrap(); + let v2 = v2.as_var().unwrap(); + + if v1 != v2 { + self.pdl.clear(); + return Some(v1.cmp(&v2)); + } + } + Some(TermOrderCategory::FloatingPoint) => { + let v1 = cell_as_f64_ptr!(v1); + let v2 = cell_as_f64_ptr!(v2); + + if v1 != v2 { + self.pdl.clear(); + return Some(v1.cmp(&v2)); + } + } + Some(TermOrderCategory::Integer) => { + let v1 = Number::try_from(v1).unwrap(); + let v2 = Number::try_from(v2).unwrap(); + + if v1 != v2 { + self.pdl.clear(); + return Some(v1.cmp(&v2)); + } + } + Some(TermOrderCategory::Atom) => { + read_heap_cell!(v1, + (HeapCellValueTag::Atom, (n1, _a1)) => { + read_heap_cell!(v2, + (HeapCellValueTag::Atom, (n2, _a2)) => { + if n1 != n2 { + self.pdl.clear(); + return Some(n1.cmp(&n2)); + } + } + (HeapCellValueTag::Char, c2) => { + if let Some(c1) = n1.as_char() { + if c1 != c2 { + self.pdl.clear(); + return Some(c1.cmp(&c2)); } } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); + self.pdl.clear(); + return Some(Ordering::Greater); } - } else { - pdl.push(Addr::PStrLocation(h1, n1 + m_len)); - - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); + } + _ => { + unreachable!(); + } + ) + } + (HeapCellValueTag::Char, c1) => { + read_heap_cell!(v2, + (HeapCellValueTag::Atom, (n2, _a2)) => { + if let Some(c2) = n2.as_char() { + if c1 != c2 { + self.pdl.clear(); + return Some(c1.cmp(&c2)); } } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); + self.pdl.clear(); + return Some(Ordering::Less); } } - } + (HeapCellValueTag::Char, c2) => { + if c1 != c2 { + self.pdl.clear(); + return Some(c1.cmp(&c2)); + } + } + _ => { + unreachable!() + } + ) } - } - (Addr::Lis(a1), Addr::Lis(a2)) => { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2)); + _ => { + unreachable!() + } + ) + } + Some(TermOrderCategory::Compound) => { + fn stalled_pstr_iter_handler( + string_iter: HeapPStrIter, + stalled_iter: HeapPStrIter, + pdl: &mut Vec, + ) -> Option { + let l = read_heap_cell!(stalled_iter.focus, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(stalled_iter.heap[s]) + .get_name_and_arity(); + + if !(name == atom!(".") && arity == 2) { + pdl.clear(); + return Some((atom!("."),2).cmp(&(name,arity))); + } + + s+1 + } + (HeapCellValueTag::Lis, l) => { + l + } + _ => { + unreachable!() + } + ); + + let c2 = stalled_iter.heap[l]; + let c1 = string_iter.chars().next().unwrap(); - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 1)); + pdl.push(c2); + pdl.push(char_as_cell!(c1)); + + None } - (Addr::Str(a1), Addr::Str(a2)) => { - let r1 = &self.heap[a1]; - let r2 = &self.heap[a2]; - if let &HeapCellValue::NamedStr(n1, ref f1, _) = r1 { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = r2 { - if n1 == n2 && *f1 == *f2 { - for i in 1..n1 + 1 { - pdl.push(Addr::HeapCell(a1 + i)); - pdl.push(Addr::HeapCell(a2 + i)); - } + fn pstr_comparator( + heap: &[HeapCellValue], + pdl: &mut Vec, + s1: usize, + s2: usize, + ) -> Option { + let mut iter1 = HeapPStrIter::new(heap, s1); + let mut iter2 = HeapPStrIter::new(heap, s2); - continue; + match compare_pstr_prefixes(&mut iter1, &mut iter2) { + PStrCmpResult::Ordered(ordering) => Some(ordering), + _ => { + if iter1.num_steps() == 0 && iter2.num_steps() == 0 { + return match iter2.focus.get_tag() { + HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc => { + let result = stalled_pstr_iter_handler(iter2, iter1, pdl); + + if let Some(ordering) = result { + Some(ordering.reverse()) + } else { + let pdl_len = pdl.len(); + pdl.swap(pdl_len - 2, pdl_len - 1); + result + } + } + _ => { + stalled_pstr_iter_handler(iter1, iter2, pdl) + } + }; } + + pdl.push(iter2.focus); + pdl.push(iter1.focus); + + None } } - - self.fail = true; } - (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) { - (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _)) - if n1.as_str() == n2.as_str() => {} - ( - &HeapCellValue::DBRef(ref db_ref_1), - &HeapCellValue::DBRef(ref db_ref_2), - ) if db_ref_1 == db_ref_2 => {} - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { + + read_heap_cell!(v1, + (HeapCellValueTag::Lis, l1) => { + read_heap_cell!(v2, + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + let h = self.heap.len(); + + self.heap.push(v1); + self.heap.push(v2); + + if let Some(ordering) = pstr_comparator( + &self.heap, &mut self.pdl, h, h+1 + ) { + if ordering != Ordering::Equal { + self.heap.pop(); + self.heap.pop(); + + self.pdl.clear(); + + return Some(ordering); + } + } + + self.heap.pop(); + self.heap.pop(); + } + (HeapCellValueTag::Lis, l2) => { + if tabu_list.contains(&(l1, l2)) { continue; } + + tabu_list.insert((l1, l2)); + + self.pdl.push(self.heap[l2 + 1]); + self.pdl.push(self.heap[l1 + 1]); + + self.pdl.push(self.heap[l2]); + self.pdl.push(self.heap[l1]); } - } + (HeapCellValueTag::Str, s2) => { + if tabu_list.contains(&(l1, s2)) { + continue; + } - self.fail = true; - } - }, - (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { - match &self.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - if name.as_str().chars().next() != Some(c) { - self.fail = true; - return; + let (name, arity) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + match (atom!("."), 2).cmp(&(name, arity)) { + Ordering::Equal => { + tabu_list.insert((l1, s2)); + + self.pdl.push(self.heap[s2 + 2]); + self.pdl.push(self.heap[l1 + 1]); + + self.pdl.push(self.heap[s2 + 1]); + self.pdl.push(self.heap[l1]); + } + ordering => { + self.pdl.clear(); + return Some(ordering); + } + } } - } - _ => { - self.fail = true; - return; - } - } - } - (Addr::Stream(s1), Addr::Stream(s2)) => { - if s1 != s2 { - self.fail = true; + _ => { + unreachable!(); + } + ) } - } - (v, Addr::Con(h)) | (Addr::Con(h), v) => { - if let Ok(n1) = Number::try_from(&self.heap[h]) { - if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) { - if n1 == v { - continue; + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + let h = self.heap.len(); + + self.heap.push(v1); + self.heap.push(v2); + + if let Some(ordering) = pstr_comparator( + &self.heap, &mut self.pdl, h, h+1, + ) { + if ordering != Ordering::Equal { + self.heap.pop(); + self.heap.pop(); + + self.pdl.clear(); + + return Some(ordering); } } + + self.heap.pop(); + self.heap.pop(); } + (HeapCellValueTag::Str, s1) => { + read_heap_cell!(v2, + (HeapCellValueTag::Str, s2) => { + if tabu_list.contains(&(s1, s2)) { + continue; + } - self.fail = true; - } - (a1, a2) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) { - if n1 == n2 { - continue; + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]) + .get_name_and_arity(); + + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + match (n1,a1).cmp(&(n2,a2)) { + Ordering::Equal => { + tabu_list.insert((s1, s2)); + + for idx in (1 .. a1+1).rev() { + self.pdl.push(self.heap[s2+idx]); + self.pdl.push(self.heap[s1+idx]); + } + } + ordering => { + self.pdl.clear(); + return Some(ordering); + } + } + } + (HeapCellValueTag::Lis, l2) => { + if tabu_list.contains(&(s1, l2)) { + continue; + } + + tabu_list.insert((s1, l2)); + + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]) + .get_name_and_arity(); + + match (n1,a1).cmp(&(atom!("."), 2)) { + Ordering::Equal => { + self.pdl.push(self.heap[l2]); + self.pdl.push(self.heap[s1+1]); + + self.pdl.push(self.heap[l2+1]); + self.pdl.push(self.heap[s1+2]); + } + ordering => { + self.pdl.clear(); + return Some(ordering); + } + } + } + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + let h = self.heap.len(); + + self.heap.push(v1); + self.heap.push(v2); + + if let Some(ordering) = pstr_comparator( + &self.heap, &mut self.pdl, h, h+1, + ) { + if ordering != Ordering::Equal { + self.heap.pop(); + self.heap.pop(); + + self.pdl.clear(); + + return Some(ordering); + } + } + + self.heap.pop(); + self.heap.pop(); + } + _ => { + unreachable!() } - } + ) } - - if a1 != a2 { - self.fail = true; + _ => { + unreachable!() } - } - }; - } - } - } - - pub(super) fn trail(&mut self, r: TrailRef) { - match r { - TrailRef::Ref(Ref::HeapCell(h)) => { - if h < self.hb { - self.trail.push(TrailRef::Ref(Ref::HeapCell(h))); - self.tr += 1; - } - } - TrailRef::Ref(Ref::AttrVar(h)) => { - if h < self.hb { - self.trail.push(TrailRef::Ref(Ref::AttrVar(h))); - self.tr += 1; - } - } - TrailRef::AttrVarHeapLink(h) => { - if h < self.hb { - self.trail.push(TrailRef::AttrVarHeapLink(h)); - self.tr += 1; - } - } - TrailRef::AttrVarListLink(h, l) => { - if h < self.hb { - self.trail.push(TrailRef::AttrVarListLink(h, l)); - self.tr += 1; + ); } - } - TrailRef::Ref(Ref::StackCell(b, sc)) => { - if b < self.b { - self.trail.push(TrailRef::Ref(Ref::StackCell(b, sc))); - self.tr += 1; + None => { + if v1 != v2 { + self.pdl.clear(); + return None; + } } } - TrailRef::BlackboardOffset(key_h, value_h) => { - self.trail.push(TrailRef::BlackboardOffset(key_h, value_h)); - self.tr += 1; - } - TrailRef::BlackboardEntry(key_h) => { - self.trail.push(TrailRef::BlackboardEntry(key_h)); - self.tr += 1; - } } + + Some(Ordering::Equal) } fn increment_s_ptr(&mut self, rhs: usize) { @@ -691,16 +1809,20 @@ impl MachineState { *h += rhs; } &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => { - match &self.heap[h] { - &HeapCellValue::PartialString(ref pstr, _) => { - for c in pstr.range_from(*n..).take(rhs) { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + for c in pstr.as_str_from(*n).chars().take(rhs) { *n += c.len_utf8(); } self.s = HeapPtr::PStrLocation(h, *n); } - _ => {} - } + _ => { + unreachable!() + } + ) } } } @@ -715,425 +1837,409 @@ impl MachineState { // additions, now that deleted attributes can be undeleted by // backtracking. for i in (a1..a2).rev() { - match self.trail[i] { - TrailRef::Ref(Ref::HeapCell(h)) => { - self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h)) + let h = self.trail[i].get_value() as usize; + + match self.trail[i].get_tag() { + TrailEntryTag::TrailedHeapVar => { + self.heap[h] = heap_loc_as_cell!(h); } - TrailRef::Ref(Ref::AttrVar(h)) => { - self.heap[h] = HeapCellValue::Addr(Addr::AttrVar(h)) + TrailEntryTag::TrailedStackVar => { + self.stack[h] = stack_loc_as_cell!(h); } - TrailRef::Ref(Ref::StackCell(fr, sc)) => { - self.stack.index_and_frame_mut(fr)[sc] = Addr::StackCell(fr, sc) + TrailEntryTag::TrailedAttrVar => { + self.heap[h] = attr_var_as_cell!(h); } - TrailRef::AttrVarHeapLink(h) => { - self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h)); + TrailEntryTag::TrailedAttrVarHeapLink => { + self.heap[h] = heap_loc_as_cell!(h); } - TrailRef::AttrVarListLink(h, l) => { - self.heap[h] = HeapCellValue::Addr(Addr::Lis(l)); + TrailEntryTag::TrailedAttrVarListLink => { + let l = self.trail[i + 1].get_value(); + self.heap[h] = list_loc_as_cell!(l); } - TrailRef::BlackboardOffset(key_h, value_h) => { - let key = atom_from!( - self, - self.store(self.deref(self.heap[key_h].as_addr(key_h))) - ); - - let value_addr = self.heap[value_h].as_addr(value_h); + TrailEntryTag::TrailedBlackboardEntry => { + let key = Atom::from(h); match global_variables.get_mut(&key) { - Some((_, ref mut loc)) => *loc = Some(value_addr), + Some((_, ref mut loc)) => *loc = None, None => unreachable!(), } } - TrailRef::BlackboardEntry(key_h) => { - let key = atom_from!( - self, - self.store(self.deref(self.heap[key_h].as_addr(key_h))) - ); + TrailEntryTag::TrailedBlackboardOffset => { + let key = Atom::from(h); + let value_cell = HeapCellValue::from(u64::from(self.trail[i + 1])); match global_variables.get_mut(&key) { - Some((_, ref mut loc)) => *loc = None, + Some((_, ref mut loc)) => *loc = Some(value_cell), None => unreachable!(), } } + TrailEntryTag::TrailedAttachedValue => { + } } } } - pub(super) fn match_partial_string(&mut self, addr: Addr, string: &String, has_tail: bool) { - let mut heap_pstr_iter = self.heap_pstr_iter(addr); + pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) { + let h = self.heap.len(); + self.heap.push(value); - match compare_pstr_to_string(&mut heap_pstr_iter, string) { - Some(prefix_len) if prefix_len == string.len() => { - let focus = heap_pstr_iter.focus(); + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); + let s = string.as_str(); + + match heap_pstr_iter.compare_pstr_to_string(s) { + Some(PStrPrefixCmpResult { focus, offset, prefix_len }) if prefix_len == s.len() => { + let focus_addr = self.heap[focus]; - match focus { - Addr::PStrLocation(h, n) => { + read_heap_cell!(focus_addr, + (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { if has_tail { - self.s = HeapPtr::PStrLocation(h, n); + self.s = HeapPtr::PStrLocation(focus, offset); self.mode = MachineMode::Read; + } else if offset == pstr_atom.len() { + let focus_addr = heap_pstr_iter.focus; + unify!(self, focus_addr, empty_list_as_cell!()); } else { self.fail = true; } } - addr => { + (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, h) => { if has_tail { - let h = self.heap.h(); + let (h, _) = pstr_loc_and_offset(&self.heap, h); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self.bind(Ref::HeapCell(h), addr); + self.s = HeapPtr::PStrLocation(h, offset); + self.mode = MachineMode::Read; + } else { + let end_cell = heap_pstr_iter.focus; + self.fail = end_cell != empty_list_as_cell!(); + } + } + _ => { + let focus = heap_pstr_iter.focus(); - self.s = HeapPtr::HeapCell(h); + if has_tail { + self.s = HeapPtr::HeapCell(focus); self.mode = MachineMode::Read; } else { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::EmptyList); - } else { - self.fail = addr != Addr::EmptyList; - } + let focus = heap_pstr_iter.focus; + unify!(self, focus, empty_list_as_cell!()); } } - } + ); } - Some(prefix_len) => match heap_pstr_iter.focus() { - addr if addr.is_ref() => { - let h = self.heap.h(); - - let pstr_addr = if has_tail { - self.s = HeapPtr::HeapCell(h + 1); - self.mode = MachineMode::Read; - - self.heap.allocate_pstr(&string[prefix_len..]) - } else { - self.heap.put_complete_string(&string[prefix_len..]) - }; + Some(PStrPrefixCmpResult { prefix_len, .. }) => { + // TODO: this is woefully insufficient! you need to + // match the remaining portion of string if offset < + // pstr.len(). + let focus = heap_pstr_iter.focus(); + let tail_addr = self.heap[focus]; - self.bind(addr.as_var().unwrap(), pstr_addr); - } - Addr::Lis(l) => { - let h = self.heap.h(); + let h = self.heap.len(); - let pstr_addr = if has_tail { - self.s = HeapPtr::HeapCell(h + 1); - self.mode = MachineMode::Read; + let target_cell = if has_tail { + self.s = HeapPtr::HeapCell(h + 1); + self.mode = MachineMode::Read; - self.heap.allocate_pstr(&string[prefix_len..]) - } else { - self.heap.put_complete_string(&string[prefix_len..]) - }; + put_partial_string( + &mut self.heap, + &string.as_str()[prefix_len ..], + &mut self.atom_tbl, + ) + } else { + put_complete_string( + &mut self.heap, + &string.as_str()[prefix_len ..], + &mut self.atom_tbl, + ) + }; - (self.unify_fn)(self, Addr::Lis(l), pstr_addr); - } - _ => { - self.fail = true; - } - }, + unify!(self, tail_addr, target_cell); + } None => { self.fail = true; } } } - pub(super) fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) { - match self.store(self.deref(addr)) { - Addr::Con(c1) => { - match &self.heap[c1] { - HeapCellValue::Atom(ref n1, _) => { - self.fail = match c { - Constant::Atom(ref n2, _) => n1 != n2, - Constant::Char(c) if n1.is_char() => { - Some(*c) != n1.as_str().chars().next() - } - _ => true, - }; - } - HeapCellValue::Integer(ref n1) => { - self.fail = match c { - Constant::Fixnum(n2) => n1.to_isize() != Some(*n2), - Constant::Integer(ref n2) => n1 != n2, - Constant::Usize(n2) => n1.to_usize() != Some(*n2), - _ => true, - }; - } - HeapCellValue::Rational(ref r1) => { - self.fail = if let Constant::Rational(ref r2) = c { - r1 != r2 - } else { - true - } - } - HeapCellValue::PartialString(..) => { - if let Constant::String(ref s2) = c { - self.match_partial_string(Addr::PStrLocation(c1, 0), &s2, false); - } else { - self.fail = true; - } - } - _ => { - unreachable!() - } - }; - } - Addr::Char(ch) => { - self.fail = match c { - Constant::Atom(ref n2, _) if n2.is_char() => { - Some(ch) != n2.as_str().chars().next() - } - Constant::Char(c) => *c != ch, - _ => true, - }; - } - Addr::EmptyList => { - if let Constant::EmptyList = c { + pub(super) fn write_literal_to_var(&mut self, deref_v: HeapCellValue, lit: HeapCellValue) { + let store_v = self.store(deref_v); + + read_heap_cell!(lit, + (HeapCellValueTag::Atom, (atom, arity)) => { + if arity == 0 { + self.unify_atom(atom, store_v); } else { self.fail = true; } } - Addr::Lis(l) => { - let addr = self.heap.put_constant(c.clone()); - self.unify(Addr::Lis(l), addr); - } - Addr::PStrLocation(h, n) => { - if let Constant::String(ref s2) = c { - self.match_partial_string(Addr::PStrLocation(h, n), &s2, false) - } else { - self.fail = true; - }; - } - Addr::Stream(_) => { - self.fail = true; + (HeapCellValueTag::Char, c) => { + self.unify_char(c, store_v); + } + (HeapCellValueTag::Fixnum, n) => { + self.unify_fixnum(n, store_v); + } + (HeapCellValueTag::F64, f64_ptr) => { + self.unify_f64(f64_ptr, store_v); + } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, n) => { + self.unify_big_int(n, store_v); + } + (ArenaHeaderTag::Rational, r) => { + self.unify_rational(r, store_v); + } + _ => { + self.fail = true; + } + ) } - addr => { - let c = self.heap.put_constant(c.clone()); - - if let Some(r) = addr.as_var() { - self.bind(r, c); - } else { - self.unify(addr, c); + (HeapCellValueTag::CStr, cstr_atom) => { + match store_v.get_tag() { + HeapCellValueTag::PStrLoc + | HeapCellValueTag::Lis + | HeapCellValueTag::Str => { + self.match_partial_string(store_v, cstr_atom, false); + } + _ => { + self.fail = true; + } } } - }; + _ => { + unreachable!() + } + ) } - pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { - let stub = MachineError::functor_stub(clause_name!("is"), 2); + pub fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { + let stub_gen = || functor_stub(atom!("is"), 2); match instr { &ArithmeticInstruction::Add(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 + n2, stub)); + self.interms[t - 1] = try_or_fail_gen!( + self, + try_numeric_result!(add(n1, n2, &mut self.arena), stub_gen) + ); self.p += 1; } &ArithmeticInstruction::Sub(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 - n2, stub)); + self.interms[t - 1] = try_or_fail_gen!( + self, + try_numeric_result!(sub(n1, n2, &mut self.arena), stub_gen) + ); self.p += 1; } &ArithmeticInstruction::Mul(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 * n2, stub)); + self.interms[t - 1] = try_or_fail_gen!( + self, + try_numeric_result!(mul(n1, n2, &mut self.arena), stub_gen) + ); self.p += 1; } &ArithmeticInstruction::Max(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.max(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, max(n1, n2)); self.p += 1; } &ArithmeticInstruction::Min(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.min(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, min(n1, n2)); self.p += 1; } &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, int_pow(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.gcd(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, gcd(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.pow(n1, n2, "(**)")); + self.interms[t - 1] = try_or_fail_gen!(self, pow(n1, n2, atom!("**"))); self.p += 1; } &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { - let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); + let stub_gen = || functor_stub(atom!("(rdiv)"), 2); - let (r1, stub) = try_or_fail!(self, self.get_rational(a1, stub)); - let (r2, _) = try_or_fail!(self, self.get_rational(a2, stub)); + let r1 = try_or_fail!(self, self.get_rational(a1, stub_gen)); + let r2 = try_or_fail!(self, self.get_rational(a2, stub_gen)); - self.interms[t - 1] = - Number::Rational(Rc::new(try_or_fail!(self, self.rdiv(r1, r2)))); + self.interms[t - 1] = Number::Rational(arena_alloc!( + try_or_fail_gen!(self, rdiv(r1, r2)), + self.arena + )); self.p += 1; } &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.int_floor_div(n1, n2)); + self.interms[t - 1] = + try_or_fail_gen!(self, int_floor_div(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.idiv(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, idiv(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Abs(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = n1.abs(); + self.interms[t - 1] = abs(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Sign(ref a1, t) => { let n = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.sign(n); + self.interms[t - 1] = sign(n); self.p += 1; } &ArithmeticInstruction::Neg(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = -n1; + self.interms[t - 1] = neg(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::BitwiseComplement(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = try_or_fail!(self, self.bitwise_complement(n1)); + self.interms[t - 1] = + try_or_fail_gen!(self, bitwise_complement(n1, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Div(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.div(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, div(n1, n2)); self.p += 1; } &ArithmeticInstruction::Shr(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.shr(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, shr(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Shl(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.shl(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, shl(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Xor(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.xor(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, xor(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::And(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.and(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, and(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Or(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.or(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, or(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Mod(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.modulus(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, modulus(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Rem(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.remainder(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, remainder(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Cos(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.cos(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, cos(n1)))); self.p += 1; } &ArithmeticInstruction::Sin(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.sin(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sin(n1)))); self.p += 1; } &ArithmeticInstruction::Tan(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.tan(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, tan(n1)))); self.p += 1; } &ArithmeticInstruction::Sqrt(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.sqrt(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sqrt(n1)))); self.p += 1; } &ArithmeticInstruction::Log(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.log(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, log(n1)))); self.p += 1; } &ArithmeticInstruction::Exp(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.exp(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, exp(n1)))); self.p += 1; } &ArithmeticInstruction::ACos(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.acos(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, acos(n1)))); self.p += 1; } &ArithmeticInstruction::ASin(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.asin(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, asin(n1)))); self.p += 1; } &ArithmeticInstruction::ATan(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.atan(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, atan(n1)))); self.p += 1; } &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => { @@ -1141,38 +2247,38 @@ impl MachineState { let n2 = try_or_fail!(self, self.get_number(a2)); self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.atan2(n1, n2)))); + Number::Float(OrderedFloat(try_or_fail_gen!(self, atan2(n1, n2)))); self.p += 1; } &ArithmeticInstruction::Float(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.float(n1)))); + Number::Float(OrderedFloat(try_or_fail_gen!(self, float(n1)))); self.p += 1; } &ArithmeticInstruction::Truncate(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.truncate(n1); + self.interms[t - 1] = truncate(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Round(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = try_or_fail!(self, self.round(n1)); + self.interms[t - 1] = try_or_fail_gen!(self, round(n1, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Ceiling(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.ceiling(n1); + self.interms[t - 1] = ceiling(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Floor(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.floor(n1); + self.interms[t - 1] = floor(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Plus(ref a1, t) => { @@ -1184,74 +2290,99 @@ impl MachineState { }; } - pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) { + pub fn execute_fact_instr(&mut self, instr: &FactInstruction) { match instr { - &FactInstruction::GetConstant(_, ref c, reg) => { - let addr = self[reg]; - self.write_constant_to_var(addr, c); + &FactInstruction::GetConstant(_, c, reg) => { + let value = self.deref(self[reg]); + self.write_literal_to_var(value, c); } &FactInstruction::GetList(_, reg) => { - let addr = self.store(self.deref(self[reg])); + let deref_v = self.deref(self[reg]); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::PStrLoc, h) => { + let (h, n) = pstr_loc_and_offset(&self.heap, h); - match addr { - Addr::PStrLocation(h, n) => { - self.s = HeapPtr::PStrChar(h, n); + self.s = HeapPtr::PStrChar(h, n.get_num() as usize); self.mode = MachineMode::Read; } - addr @ Addr::AttrVar(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::HeapCell(_) => { - let h = self.heap.h(); + (HeapCellValueTag::CStr) => { + let h = self.heap.len(); + self.heap.push(store_v); - self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1))); - self.bind(addr.as_var().unwrap(), Addr::HeapCell(h)); - - self.mode = MachineMode::Write; + self.s = HeapPtr::PStrChar(h, 0); + self.mode = MachineMode::Read; } - Addr::Lis(a) => { - self.s = HeapPtr::HeapCell(a); + (HeapCellValueTag::Lis, l) => { + self.s = HeapPtr::HeapCell(l); self.mode = MachineMode::Read; } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.heap.len(); + + self.heap.push(list_loc_as_cell!(h+1)); + self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + + self.mode = MachineMode::Write; + } _ => { self.fail = true; } - }; + ); } - &FactInstruction::GetPartialString(_, ref string, reg, has_tail) => { - let addr = self.store(self.deref(self[reg])); - self.match_partial_string(addr, string, has_tail); + &FactInstruction::GetPartialString(_, string, reg, has_tail) => { + let deref_v = self.deref(self[reg]); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar | + HeapCellValueTag::StackVar | HeapCellValueTag::Var | + HeapCellValueTag::CStr) => { + self.match_partial_string(store_v, string, has_tail); + } + _ => { + self.fail = true; + } + ); } &FactInstruction::GetStructure(ref ct, arity, reg) => { - let addr = self.deref(self[reg]); - - match self.store(addr) { - Addr::Str(a) => { - let result = &self.heap[a]; - - if let &HeapCellValue::NamedStr(narity, ref s, _) = result { - if narity == arity && ct.name() == *s { - self.s = HeapPtr::HeapCell(a + 1); - self.mode = MachineMode::Read; - } else { - self.fail = true; + let deref_v = self.deref(self[reg]); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str, a) => { + let result = self.heap[a]; + + read_heap_cell!(result, + (HeapCellValueTag::Atom, (name, narity)) => { + if narity == arity && ct.name() == name { + self.s = HeapPtr::HeapCell(a + 1); + self.mode = MachineMode::Read; + } else { + self.fail = true; + } } - } + _ => { + unreachable!(); + } + ); } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => { - let h = self.heap.h(); + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1))); - self.heap - .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec())); + self.heap.push(str_loc_as_cell!(h+1)); + self.heap.push(atom_as_cell!(ct.name(), arity)); - self.bind(addr.as_var().unwrap(), Addr::HeapCell(h)); + self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.mode = MachineMode::Write; } _ => { self.fail = true; } - }; + ); } &FactInstruction::GetVariable(norm, arg) => { self[norm] = self.registers[arg]; @@ -1260,36 +2391,32 @@ impl MachineState { let norm_addr = self[norm]; let reg_addr = self.registers[arg]; - (self.unify_fn)(self, norm_addr, reg_addr); + unify_fn!(self, norm_addr, reg_addr); } - &FactInstruction::UnifyConstant(ref c) => { + &FactInstruction::UnifyConstant(v) => { match self.mode { MachineMode::Read => { - let addr = self.s.read(&self.heap); + let addr = self.read_s(); - self.write_constant_to_var(addr, c); + self.write_literal_to_var(addr, v); self.increment_s_ptr(1); } MachineMode::Write => { - let addr = self.heap.put_constant(c.clone()); - - if !addr.is_heap_bound() { - self.heap.push(HeapCellValue::Addr(addr)); - } + self.heap.push(v); } }; } &FactInstruction::UnifyVariable(reg) => { match self.mode { MachineMode::Read => { - self[reg] = self.s.read(&self.heap); + self[reg] = self.read_s(); self.increment_s_ptr(1); } MachineMode::Write => { - let h = self.heap.h(); + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self[reg] = Addr::HeapCell(h); + self.heap.push(heap_loc_as_cell!(h)); + self[reg] = heap_loc_as_cell!(h); } }; } @@ -1297,25 +2424,30 @@ impl MachineState { match self.mode { MachineMode::Read => { let reg_addr = self[reg]; + let value = self.read_s(); - (self.unify_fn)(self, reg_addr, self.s.read(&self.heap)); + unify_fn!(self, reg_addr, value); self.increment_s_ptr(1); } MachineMode::Write => { - let addr = self.store(self.deref(self[reg])); - let h = self.heap.h(); + let value = self.store(self.deref(self[reg])); + let h = self.heap.len(); - if let Addr::HeapCell(hc) = addr { - let val = self.heap.clone(hc); + read_heap_cell!(value, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { + let value = self.heap[hc]; - self.heap.push(val); - self.increment_s_ptr(1); + self.heap.push(value); + self.increment_s_ptr(1); - return; - } + return; + } + _ => { + } + ); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + self.heap.push(heap_loc_as_cell!(h)); + (self.bind_fn)(self, Ref::heap_cell(h), value); } }; } @@ -1323,16 +2455,17 @@ impl MachineState { match self.mode { MachineMode::Read => { let reg_addr = self[reg]; + let value = self.read_s(); - (self.unify_fn)(self, reg_addr, self.s.read(&self.heap)); + unify_fn!(self, reg_addr, value); self.increment_s_ptr(1); } MachineMode::Write => { - let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); let addr = self.store(self[reg]); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + (self.bind_fn)(self, Ref::heap_cell(h), addr); // the former code of this match arm was: @@ -1352,10 +2485,10 @@ impl MachineState { self.increment_s_ptr(n); } MachineMode::Write => { - let h = self.heap.h(); + let h = self.heap.len(); for i in h..h + n { - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i))); + self.heap.push(heap_loc_as_cell!(i)); } } }; @@ -1408,22 +2541,45 @@ impl MachineState { 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 + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Var + | HeapCellValueTag::StackVar + | HeapCellValueTag::AttrVar) => { + v } - 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, - }; + (HeapCellValueTag::PStrLoc + | HeapCellValueTag::Lis + | HeapCellValueTag::CStr) => { + l + } + (HeapCellValueTag::Fixnum + | HeapCellValueTag::Char + | HeapCellValueTag::F64) => { + c + } + (HeapCellValueTag::Atom, (_name, arity)) => { + // if arity == 0 { c } else { s } + debug_assert!(arity == 0); + c + } + (HeapCellValueTag::Str) => { + s + } + (HeapCellValueTag::Cons, ptr) => { + match ptr.get_tag() { + ArenaHeaderTag::Rational | ArenaHeaderTag::Integer | + ArenaHeaderTag::F64 => { + c + } + _ => { + IndexingCodePtr::Fail + } + } + } + _ => { + unreachable!(); + } + ); match offset { IndexingCodePtr::Fail => { @@ -1451,15 +2607,47 @@ impl MachineState { 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 lit = read_heap_cell!(addr, + (HeapCellValueTag::Char, c) => { + Literal::Char(c) + } + (HeapCellValueTag::Fixnum, n) => { + Literal::Fixnum(n) + } + (HeapCellValueTag::F64, f) => { + Literal::Float(f) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + debug_assert_eq!(arity, 0); + Literal::Atom(atom) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Rational, r) => { + Literal::Rational(r) + } + (ArenaHeaderTag::F64, f) => { + Literal::Float(F64Ptr(f)) + } + (ArenaHeaderTag::Integer, n) => { + Literal::Integer(n) + } + _ => { + unreachable!() + } + ) + } + _ => { + unreachable!() + } + ); + + let offset = match hm.get(&lit) { + Some(offset) => *offset, + _ => IndexingCodePtr::Fail, }; match offset { @@ -1488,22 +2676,28 @@ impl MachineState { 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 + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, } } - _ => IndexingCodePtr::Fail, - }; + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, + } + } + _ => { + IndexingCodePtr::Fail + } + ); match offset { IndexingCodePtr::Fail => { @@ -1559,47 +2753,50 @@ impl MachineState { &QueryInstruction::GetVariable(norm, arg) => { self[norm] = self.registers[arg]; } - &QueryInstruction::PutConstant(_, ref c, reg) => { - self[reg] = self.heap.put_constant(c.clone()); + &QueryInstruction::PutConstant(_, c, reg) => { + self[reg] = c; } &QueryInstruction::PutList(_, reg) => { - self[reg] = Addr::Lis(self.heap.h()); + self[reg] = list_loc_as_cell!(self.heap.len()); } - &QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => { + &QueryInstruction::PutPartialString(_, string, reg, has_tail) => { let pstr_addr = if has_tail { - if !string.is_empty() { - let pstr_addr = self.heap.allocate_pstr(&string); - self.heap.pop(); // the tail will be added by the next instruction. - pstr_addr + if string != atom!("") { + let h = self.heap.len(); + self.heap.push(string_as_pstr_cell!(string)); + + // the tail will be pushed by the next + // instruction, so don't push one here. + + pstr_loc_as_cell!(h) } else { - Addr::EmptyList + empty_list_as_cell!() } } else { - self.heap.put_complete_string(&string) + string_as_cstr_cell!(string) }; self[reg] = pstr_addr; } &QueryInstruction::PutStructure(ref ct, arity, reg) => { - let h = self.heap.h(); + let h = self.heap.len(); - self.heap - .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec())); - self[reg] = Addr::Str(h); + self.heap.push(atom_as_cell!(ct.name(), arity)); + self[reg] = str_loc_as_cell!(h); } &QueryInstruction::PutUnsafeValue(n, arg) => { - let e = self.e; - let addr = self.store(self.deref(Addr::StackCell(e, n))); + let s = stack_loc!(AndFrame, self.e, n); + let addr = self.store(self.deref(stack_loc_as_cell!(s))); - if addr.is_protected(e) { + if addr.is_protected(self.e) { self.registers[arg] = addr; } else { - let h = self.heap.h(); + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + self.heap.push(heap_loc_as_cell!(h)); + (self.bind_fn)(self, Ref::heap_cell(h), addr); - self.registers[arg] = self.heap[h].as_addr(h); + self.registers[arg] = heap_loc_as_cell!(h); } } &QueryInstruction::PutValue(norm, arg) => { @@ -1608,71 +2805,52 @@ impl MachineState { &QueryInstruction::PutVariable(norm, arg) => { match norm { RegType::Perm(n) => { - let e = self.e; - - self[norm] = Addr::StackCell(e, n); + self[norm] = stack_loc_as_cell!(AndFrame, self.e, n); self.registers[arg] = self[norm]; } RegType::Temp(_) => { - let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); - self[norm] = Addr::HeapCell(h); - self.registers[arg] = Addr::HeapCell(h); + self[norm] = heap_loc_as_cell!(h); + self.registers[arg] = heap_loc_as_cell!(h); } }; } - &QueryInstruction::SetConstant(ref c) => { - let addr = self.heap.put_constant(c.clone()); - - if !addr.is_heap_bound() { - self.heap.push(HeapCellValue::Addr(addr)); - } + &QueryInstruction::SetConstant(c) => { + self.heap.push(c); } &QueryInstruction::SetLocalValue(reg) => { let addr = self.deref(self[reg]); - let h = self.heap.h(); + let h = self.heap.len(); - if addr < Ref::HeapCell(h) { - self.heap.push(HeapCellValue::Addr(addr)); + if addr < Ref::heap_cell(h) { + self.heap.push(addr); return; } - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + self.heap.push(heap_loc_as_cell!(h)); + (self.bind_fn)(self, Ref::heap_cell(h), addr); } &QueryInstruction::SetVariable(reg) => { - let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self[reg] = Addr::HeapCell(h); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); + self[reg] = heap_loc_as_cell!(h); } &QueryInstruction::SetValue(reg) => { let heap_val = self.store(self[reg]); - self.heap.push(HeapCellValue::Addr(heap_val)); + self.heap.push(heap_val); } &QueryInstruction::SetVoid(n) => { - let h = self.heap.h(); + let h = self.heap.len(); for i in h..h + n { - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i))); + self.heap.push(heap_loc_as_cell!(i)); } } } } - pub(super) fn set_ball(&mut self) { - self.ball.reset(); - - let addr = self[temp_v!(1)]; - self.ball.boundary = self.heap.h(); - - copy_term( - CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub), - addr, - AttrVarPolicy::DeepCopy, - ); - } - pub(super) fn handle_internal_call_n(&mut self, arity: usize) { let arity = arity + 1; let pred = self.registers[1]; @@ -1692,238 +2870,183 @@ impl MachineState { pub(super) fn setup_call_n(&mut self, arity: usize) -> Option { let addr = self.store(self.deref(self.registers[arity])); - let (name, narity) = match addr { - Addr::Str(a) => { - let result = self.heap.clone(a); - - if let HeapCellValue::NamedStr(narity, name, _) = result { - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); + let (name, narity) = read_heap_cell!(addr, + (HeapCellValueTag::Str, s) => { + let (name, narity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); - if narity + arity > MAX_ARITY { - let representation_error = self.error_form( - MachineError::representation_error(RepFlag::MaxArity), - stub, - ); + if narity + arity > MAX_ARITY { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.representation_error(RepFlag::MaxArity); + let representation_error = self.error_form(err, stub); - self.throw_exception(representation_error); - return None; - } + self.throw_exception(representation_error); + return None; + } - for i in (1..arity).rev() { - self.registers[i + narity] = self.registers[i]; - } + for i in (1..arity).rev() { + self.registers[i + narity] = self.registers[i]; + } - for i in 1..narity + 1 { - self.registers[i] = self.heap[a + i].as_addr(a + i); - } + for i in 1..narity + 1 { + self.registers[i] = self.heap[s + i]; + } - (name, narity) + (name, narity) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + (name, 0) } else { self.fail = true; return None; } } - Addr::Char(c) => (clause_name!(c.to_string(), self.atom_tbl), 0), - Addr::Con(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => (name.clone(), 0), - _ => { - self.fail = true; - return None; - } - }, - Addr::HeapCell(_) | Addr::StackCell(_, _) => { - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - let instantiation_error = - self.error_form(MachineError::instantiation_error(), stub); + (HeapCellValueTag::Char, c) => { + (self.atom_tbl.build_with(&c.to_string()), 0) + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.instantiation_error(); + let instantiation_error = self.error_form(err, stub); self.throw_exception(instantiation_error); return None; } - addr => { - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - let type_error = self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Callable, addr), - stub, - ); + _ => { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.type_error(ValidType::Callable, addr); + let type_error = self.error_form(err, stub); self.throw_exception(type_error); - return None; - } - }; - - Some((name, arity + narity - 1)) - } - - pub(super) fn unwind_stack(&mut self) { - self.b = self.block; - self.fail = true; - } - - pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool { - let mut seen = IndexSet::new(); - let mut fail = false; - let mut iter = self.pre_order_iter(addr); - let mut parent_stack = vec![]; - - let is_composite = |addr: Addr| match addr { - Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => true, - _ => false, - }; + return None; + } + ); - 'outer: loop { - if let Some(addr) = iter.stack().last().cloned() { - let addr = self.store(self.deref(addr)); + Some((name, arity + narity - 1)) + } - if is_composite(addr) { - if !seen.contains(&addr) { - seen.insert(addr); - } else { - // when we again encounter a seen composite - // term, check that it precedes itself as a - // parent in the post-order traversal. in the - // future, when value cells have mark bits, - // use them to designate parenthood instead of - // this linear search. - - for (_, prec_addr) in parent_stack.iter().rev().cloned() { - if prec_addr == addr { - fail = true; - break 'outer; - } - } - } + #[inline] + pub fn is_cyclic_term(&mut self, addr: HeapCellValue) -> bool { + if addr.is_constant() { + return false; + } - let arity = match addr { - Addr::Str(h) => match &self.heap[h] { - &HeapCellValue::NamedStr(arity, ..) => arity, - _ => unreachable!(), - }, - _ => 2, - }; + let mut iter = stackful_preorder_iter(&mut self.heap, addr); - parent_stack.push((arity, addr)); - } - } + while let Some(value) = iter.next() { + if value.is_forwarded() { + let value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value)); - if iter.next().is_none() { - break; - } else { - while let Some((rem_children, addr)) = parent_stack.pop() { - if rem_children > 0 { - parent_stack.push((rem_children - 1, addr)); - break; - } + if value.is_compound() { + return true; } } } - fail + false } // arg(+N, +Term, ?Arg) - pub(super) fn try_arg(&mut self) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("arg"), 3); - let n = self.store(self.deref(self[temp_v!(1)])); + pub fn try_arg(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("arg"), 3); + let n = self.registers[1]; //self.store(self.deref(self.registers[1])); // TODO: necessary? - match n { - Addr::HeapCell(_) | Addr::StackCell(..) => { + read_heap_cell!(n, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { // 8.5.2.3 a) - return Err(self.error_form(MachineError::instantiation_error(), stub)); + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - addr => { - let n = match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + _ => { + let n = match Number::try_from(n) { + Ok(Number::Fixnum(n)) => Number::Fixnum(n), + Ok(Number::Integer(n)) => Number::Integer(n), _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, addr), - stub, - )); + let err = self.type_error(ValidType::Integer, n); + return Err(self.error_form(err, stub_gen())); } }; if n < 0 { // 8.5.2.3 e) - let n = Number::from(n); - let dom_err = MachineError::domain_error(DomainErrorType::NotLessThanZero, n); - - return Err(self.error_form(dom_err, stub)); + let err = self.domain_error(DomainErrorType::NotLessThanZero, n); + return Err(self.error_form(err, stub_gen())); } - let n = match n.to_usize() { - Some(n) => n, - None => { + let n = match n { + Number::Fixnum(n) => n.get_num() as usize, + Number::Integer(n) => n.to_usize().unwrap(), + _ => { self.fail = true; return Ok(()); } }; - let term = self.store(self.deref(self[temp_v!(2)])); + let term = self.deref(self.registers[2]); - match term { - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { - // 8.5.2.3 b) - return Err(self.error_form(MachineError::instantiation_error(), stub)); + read_heap_cell!(self.store(term), + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - Addr::Str(o) => match self.heap.clone(o) { - HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => { - let a3 = self[temp_v!(3)]; - let h_a = Addr::HeapCell(o + n); + (HeapCellValueTag::Str, o) => { + let arity = cell_as_atom_cell!(self.heap[o]).get_arity(); - (self.unify_fn)(self, a3, h_a); - } - _ => { + if 1 <= n && n <= arity { + let a3 = self.registers[3]; + unify_fn!(self, a3, heap_loc_as_cell!(o + n)); + } else { self.fail = true; } - }, - Addr::Lis(l) => { + } + (HeapCellValueTag::Lis, l) => { if n == 1 || n == 2 { - let a3 = self[temp_v!(3)]; - let h_a = Addr::HeapCell(l + n - 1); - - (self.unify_fn)(self, a3, h_a); + let a3 = self.registers[3]; + unify_fn!(self, a3, heap_loc_as_cell!(l + n - 1)); } else { self.fail = true; } } - Addr::PStrLocation(h, offset) => { + (HeapCellValueTag::PStrLoc, pstr_loc) => { if n == 1 || n == 2 { - let a3 = self[temp_v!(3)]; - let h_a = - if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(offset..).next() { - if n == 1 { - Addr::Char(c) - } else { - Addr::PStrLocation(h, offset + c.len_utf8()) - } - } else { - unreachable!() - } + let a3 = self.registers[3]; + let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); + + let pstr = cell_as_string!(self.heap[h]); + let offset = offset.get_num() as usize; + + if let Some(c) = pstr.as_str_from(offset).chars().next() { + if n == 1 { + self.unify_char(c, a3); } else { - unreachable!() - }; + let offset = (offset + c.len_utf8()) as i64; + let h_len = self.heap.len(); - (self.unify_fn)(self, a3, h_a); + self.heap.push(pstr_offset_as_cell!(h_len)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); + + unify_fn!(self, pstr_loc_as_cell!(h_len), a3); + } + } else { + unreachable!() + } } else { self.fail = true; } } _ => { // 8.5.2.3 d) - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Compound, term), - stub, - )); + let err = self.type_error(ValidType::Compound, term); + return Err(self.error_form(err, stub_gen())); } - } + ) } - } + ); Ok(()) } - fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) { + pub fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) { let ordering = n1.cmp(&n2); self.fail = match cmp { @@ -1939,403 +3062,52 @@ impl MachineState { self.p += 1; } - pub(super) fn compare_term(&mut self, qt: CompareTermQT) { - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; + pub fn compare_term(&mut self, qt: CompareTermQT) { + let a1 = self.registers[1]; + let a2 = self.registers[2]; - match self.compare_term_test(&a1, &a2) { + match compare_term_test!(self, a1, a2) { Some(Ordering::Greater) => match qt { - CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => return, + CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => {} _ => self.fail = true, }, Some(Ordering::Equal) => match qt { - CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => return, + CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => {} _ => self.fail = true, }, Some(Ordering::Less) => match qt { - CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => return, + CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => {} _ => self.fail = true, }, None => { self.fail = true; } - }; + } } - // returns true on failure. - pub(super) fn eq_test(&self, a1: Addr, a2: Addr) -> bool { - let mut iter = self.zipped_acyclic_pre_order_iter(a1, a2); - - while let Some((v1, v2)) = iter.next() { - match (v1, v2) { - (Addr::Str(s1), Addr::Str(s2)) => { - if let HeapCellValue::NamedStr(ar1, n1, _) = &self.heap[s1] { - if let HeapCellValue::NamedStr(ar2, n2, _) = &self.heap[s2] { - if ar1 != ar2 || n1 != n2 { - return true; - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::PStrLocation(..), Addr::Lis(_)) | (Addr::Lis(_), Addr::PStrLocation(..)) => { - continue; - } - (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => { - let mut i1 = self.heap_pstr_iter(pstr1); - let mut i2 = self.heap_pstr_iter(pstr2); - - let ordering = compare_pstr_prefixes(&mut i1, &mut i2); - - if let Some(ordering) = ordering { - if ordering != Ordering::Equal { - return true; - } - } - - let (lstack, rstack) = iter.stack(); - - lstack.pop(); - lstack.pop(); - - rstack.pop(); - rstack.pop(); - - lstack.push(i1.focus()); - rstack.push(i2.focus()); - } - (Addr::Lis(_), Addr::Lis(_)) => { - continue; - } - (Addr::Con(h1), Addr::Con(h2)) => match (&self.heap[h1], &self.heap[h2]) { - ( - &HeapCellValue::Atom(ref n1, ref spec_1), - &HeapCellValue::Atom(ref n2, ref spec_2), - ) => { - if n1 != n2 || spec_1 != spec_2 { - return true; - } - } - (&HeapCellValue::DBRef(ref db_ref_1), &HeapCellValue::DBRef(ref db_ref_2)) => { - if db_ref_1 != db_ref_2 { - return true; - } - } - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { - continue; - } - } - } - - return true; - } - }, - (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { - match &self.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - if name.as_str().chars().next() != Some(c) { - return true; - } - } - _ => { - return true; - } - } - } - (a1, a2) => { - if let Ok(n1) = Number::try_from((a1, &self.heap)) { - if let Ok(n2) = Number::try_from((a2, &self.heap)) { - if n1 != n2 { - return true; - } else { - continue; - } - } - } - - if a1 != a2 { - return true; - } - } - } + // returns true on failure, false on success. + pub fn eq_test(&mut self, h1: HeapCellValue, h2: HeapCellValue) -> bool { + if h1 == h2 { + return false; } - // did the two iterators expire at the same step? - iter.first_to_expire != Ordering::Equal + compare_term_test!(self, h1, h2) + .map(|o| o != Ordering::Equal) + .unwrap_or(true) } - pub(super) fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Option { - let mut iter = self.zipped_acyclic_pre_order_iter(*a1, *a2); - - while let Some((v1, v2)) = iter.next() { - let order_cat_v1 = v1.order_category(&self.heap); - let order_cat_v2 = v2.order_category(&self.heap); - - if order_cat_v1 != order_cat_v2 { - return Some(order_cat_v1.cmp(&order_cat_v2)); + pub fn reset_block(&mut self, addr: HeapCellValue) { + read_heap_cell!(self.store(addr), + (HeapCellValueTag::Fixnum, n) => { + self.block = n.get_num() as usize; } - - match order_cat_v1 { - Some(TermOrderCategory::Variable) => { - let v1 = v1.as_var().unwrap(); - let v2 = v2.as_var().unwrap(); - - if v1 != v2 { - return Some(v1.cmp(&v2)); - } - } - Some(TermOrderCategory::FloatingPoint) => { - if let Addr::Float(f1) = v1 { - if let Addr::Float(f2) = v2 { - return Some(f1.cmp(&f2)); - } else { - unreachable!() - } - } else { - unreachable!() - } - } - Some(TermOrderCategory::Integer) => match (v1, v2) { - (Addr::Con(h1), Addr::Con(h2)) => { - if let Ok(n1) = Number::try_from(&self.heap[h1]) { - if let Ok(n2) = Number::try_from(&self.heap[h2]) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::Con(h1), v2) => { - if let Ok(n1) = Number::try_from(&self.heap[h1]) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (v1, Addr::Con(h2)) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { - if let Ok(n2) = Number::try_from(&self.heap[h2]) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (v1, v2) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - }, - Some(TermOrderCategory::Atom) => match (v1, v2) { - (Addr::Con(h1), Addr::Con(h2)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if let HeapCellValue::Atom(ref n2, _) = &self.heap[h2] { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::Con(h1), Addr::Char(c)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if n1.is_char() { - if n1.as_str().chars().next() != Some(c) { - return Some(n1.as_str().chars().next().cmp(&Some(c))); - } - } else { - return Some(Ordering::Greater); - } - } else { - unreachable!() - } - } - (Addr::Char(c), Addr::Con(h1)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if n1.is_char() { - if n1.as_str().chars().next() != Some(c) { - return Some(Some(c).cmp(&n1.as_str().chars().next())); - } - } else { - return Some(Ordering::Less); - } - } else { - unreachable!() - } - } - (Addr::EmptyList, Addr::Con(h)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { - if "[]" != n1.as_str() { - return Some("[]".cmp(n1.as_str())); - } - } else { - unreachable!() - } - } - (Addr::Con(h), Addr::EmptyList) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { - if "[]" != n1.as_str() { - return Some(n1.as_str().cmp("[]")); - } - } else { - unreachable!() - } - } - (Addr::Char(c1), Addr::Char(c2)) => { - if c1 != c2 { - return Some(c1.cmp(&c2)); - } - } - (Addr::Char(c), Addr::EmptyList) => { - return if c == '[' { - Some(Ordering::Less) - } else { - Some(c.cmp(&'[')) - }; - } - (Addr::EmptyList, Addr::Char(c)) => { - return if c == '[' { - Some(Ordering::Greater) - } else { - Some('['.cmp(&c)) - }; - } - (Addr::EmptyList, Addr::EmptyList) => {} - _ => { - return None; - } - }, - Some(TermOrderCategory::Compound) => match (v1, v2) { - (Addr::Lis(_), Addr::Lis(_)) => {} - (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => { - let mut i1 = self.heap_pstr_iter(pstr1); - let mut i2 = self.heap_pstr_iter(pstr2); - - let ordering = compare_pstr_prefixes(&mut i1, &mut i2); - - if let Some(ordering) = ordering { - if ordering != Ordering::Equal { - return Some(ordering); - } - } else { - let (lstack, rstack) = iter.stack(); - - lstack.pop(); - lstack.pop(); - - rstack.pop(); - rstack.pop(); - - lstack.push(i1.focus()); - rstack.push(i2.focus()); - } - } - (Addr::Str(h1), Addr::Str(h2)) => { - if let HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[h1] { - if let HeapCellValue::NamedStr(a2, ref n2, _) = &self.heap[h2] { - if a1 != a2 || n1.as_str() != n2.as_str() { - return Some( - a1.cmp(&a2).then_with(|| n1.as_str().cmp(n2.as_str())), - ); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::Lis(_), Addr::PStrLocation(..)) - | (Addr::PStrLocation(..), Addr::Lis(_)) => {} - (Addr::Lis(_), Addr::Str(s)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); - } - } else { - unreachable!() - } - } - (Addr::Str(s), Addr::Lis(_)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); - } - } else { - unreachable!() - } - } - (Addr::PStrLocation(..), Addr::Str(s)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); - } - } else { - unreachable!() - } - } - (Addr::Str(s), Addr::PStrLocation(..)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); - } - } else { - unreachable!() - } - } - _ => { - return None; - } - }, - None => { - return None; - } + _ => { + self.fail = true; } - } - - Some(iter.first_to_expire) - } - - pub(super) fn reset_block(&mut self, addr: Addr) { - match self.store(addr) { - Addr::Usize(b) => self.block = b, - _ => self.fail = true, - }; + ) } - pub(super) fn execute_inlined(&mut self, inlined: &InlinedClauseType) { + pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) { match inlined { &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => { let n1 = try_or_fail!(self, self.get_number(at_1)); @@ -2346,36 +3118,46 @@ impl MachineState { &InlinedClauseType::IsAtom(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Con(h) => { - if let HeapCellValue::Atom(..) = &self.heap[h] { + read_heap_cell!(d, + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.p += 1; + } else { + self.fail = true; + } + } + (HeapCellValueTag::Char) => { + self.p += 1; + } + _ => { + self.fail = true; + } + ); + } + &InlinedClauseType::IsAtomic(r1) => { + let d = self.store(self.deref(self[r1])); + + read_heap_cell!(d, + (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + HeapCellValueTag::Cons) => { + self.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { self.p += 1; } else { self.fail = true; } } - Addr::Char(_) => self.p += 1, - Addr::EmptyList => self.p += 1, - _ => self.fail = true, - }; - } - &InlinedClauseType::IsAtomic(r1) => { - let d = self.store(self.deref(self[r1])); - - match d { - Addr::Char(_) - | Addr::Con(_) - | Addr::EmptyList - | Addr::Fixnum(_) - | Addr::Float(_) - | Addr::Usize(_) => self.p += 1, - _ => self.fail = true, - }; + _ => { + self.fail = true; + } + ); } &InlinedClauseType::IsInteger(r1) => { let d = self.store(self.deref(self[r1])); - match Number::try_from((d, &self.heap)) { + match Number::try_from(d) { Ok(Number::Fixnum(_)) => { self.p += 1; } @@ -2397,22 +3179,39 @@ impl MachineState { &InlinedClauseType::IsCompound(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => self.p += 1, - _ => self.fail = true, - }; + read_heap_cell!(d, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + self.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity > 0 { + self.p += 1; + } else { + self.fail = true; + } + } + _ => { + self.fail = true; + } + ); } &InlinedClauseType::IsFloat(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Float(_) => self.p += 1, - _ => self.fail = true, - }; + match Number::try_from(d) { + Ok(Number::Float(_)) => { + self.p += 1; + } + _ => { + self.fail = true; + } + } } - &InlinedClauseType::IsNumber(r1) => match self.store(self.deref(self[r1])) { - Addr::Float(_) => self.p += 1, - d => match Number::try_from((d, &self.heap)) { + &InlinedClauseType::IsNumber(r1) => { + let d = self.store(self.deref(self[r1])); + + match Number::try_from(d) { Ok(Number::Fixnum(_)) => { self.p += 1; } @@ -2429,156 +3228,134 @@ impl MachineState { _ => { self.fail = true; } - }, - }, + } + } &InlinedClauseType::IsRational(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Con(h) => { - if let HeapCellValue::Rational(_) = &self.heap[h] { - self.p += 1; - } else { - self.fail = true; - } + read_heap_cell!(d, + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Rational, _r) => { + self.p += 1; + } + _ => { + self.fail = true; + } + ); } _ => { self.fail = true; } - }; + ); } &InlinedClauseType::IsNonVar(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { + match d.get_tag() { + HeapCellValueTag::AttrVar + | HeapCellValueTag::Var + | HeapCellValueTag::StackVar => { self.fail = true; } _ => { self.p += 1; } - }; + } } &InlinedClauseType::IsVar(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => { + match d.get_tag() { + HeapCellValueTag::AttrVar + | HeapCellValueTag::Var + | HeapCellValueTag::StackVar => { self.p += 1; } _ => { self.fail = true; } - }; + } } } } - fn try_functor_compound_case( - &mut self, - name: ClauseName, - arity: usize, - spec: Option, - ) { - let name = self.heap.to_unifiable(HeapCellValue::Atom(name, spec)); - self.try_functor_unify_components(name, arity); + #[inline(always)] + fn try_functor_compound_case(&mut self, name: Atom, arity: usize) { + self.try_functor_unify_components(atom_as_cell!(name), arity); } - fn try_functor_unify_components(&mut self, name: Addr, arity: usize) { - let a2 = self[temp_v!(2)]; - let a3 = self[temp_v!(3)]; - - (self.unify_fn)(self, a2, name); + fn try_functor_unify_components(&mut self, name: HeapCellValue, arity: usize) { + let a2 = self.deref(self.registers[2]); + self.write_literal_to_var(a2, name); if !self.fail { - (self.unify_fn)(self, a3, Addr::Usize(arity)); + let a3 = self.store(self.deref(self.registers[3])); + self.unify_fixnum(Fixnum::build_with(arity as i64), a3); } } - fn try_functor_fabricate_struct( - &mut self, - name: ClauseName, - arity: usize, - spec: Option, - op_dir: &OpDir, - r: Ref, - ) { - let spec = spec.and_then(|spec| { - if spec.arity() != arity { - fetch_op_spec(name.clone(), arity, op_dir) - } else { - Some(spec) - } - }); + fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) { + let h = self.heap.len(); + + let f_a = if name == atom!(".") && arity == 2 { + self.heap.push(heap_loc_as_cell!(h)); + self.heap.push(heap_loc_as_cell!(h+1)); - let f_a = if name.as_str() == "." && arity == 2 { - Addr::Lis(self.heap.h()) + list_loc_as_cell!(h) } else { - self.heap - .to_unifiable(HeapCellValue::NamedStr(arity, name, spec)) - }; + self.heap.push(atom_as_cell!(name, arity)); - let h = self.heap.h(); + for i in 0..arity { + self.heap.push(heap_loc_as_cell!(h + i + 1)); + } - for i in 0..arity { - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + i))); - } + str_loc_as_cell!(h) + }; (self.bind_fn)(self, r, f_a); } - pub(super) fn try_functor(&mut self, op_dir: &OpDir) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("functor"), 3); - let a1 = self.store(self.deref(self[temp_v!(1)])); + pub fn try_functor(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("functor"), 3); + let a1 = self.store(self.deref(self.registers[1])); - match a1 { - Addr::Stream(_) => { - self.fail = true; + read_heap_cell!(a1, + (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + HeapCellValueTag::F64) => { + self.try_functor_unify_components(a1, 0); } - Addr::Char(_) - | Addr::Con(_) - | Addr::Fixnum(_) - | Addr::Float(_) - | Addr::EmptyList - | Addr::Usize(_) => { + (HeapCellValueTag::Atom, (_name, arity)) => { + debug_assert_eq!(arity, 0); self.try_functor_unify_components(a1, 0); } - Addr::Str(o) => match self.heap.clone(o) { - HeapCellValue::NamedStr(arity, name, spec) => { - let spec = fetch_op_spec_from_existing(name.clone(), arity, spec, &op_dir); - - self.try_functor_compound_case(name, arity, spec) - } - _ => { - self.fail = true; - } - }, - Addr::Lis(_) | Addr::PStrLocation(..) => { - let spec = fetch_op_spec_from_existing(clause_name!("."), 2, None, &op_dir); - - self.try_functor_compound_case(clause_name!("."), 2, spec) + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + self.try_functor_compound_case(name, arity); + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStrOffset) => { + self.try_functor_compound_case(atom!("."), 2); } - Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => { - let name = self.store(self.deref(self[temp_v!(2)])); - let arity = self.store(self.deref(self[temp_v!(3)])); + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let deref_name = self.deref(self.registers[2]); + let store_name = self.store(deref_name); - if name.is_ref() || arity.is_ref() { + let arity = self.store(self.deref(self.registers[3])); + + if store_name.is_var() || arity.is_var() { // 8.5.1.3 a) & 8.5.1.3 b) - return Err(self.error_form(MachineError::instantiation_error(), stub)); - } - - let arity = match Number::try_from((arity, &self.heap)) { - Ok(Number::Fixnum(n)) => Some(n), - Ok(Number::Integer(n)) => n.to_isize(), - Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().to_isize(), - _ => match arity { - arity => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, arity), - stub, - )); - } - }, + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } + + let arity = match Number::try_from(arity) { + Ok(Number::Fixnum(n)) => Some(n.get_num()), + Ok(Number::Integer(n)) => n.to_i64(), + Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().to_i64(), + _ => { + let err = self.type_error(ValidType::Integer, arity); + return Err(self.error_form(err, stub_gen())); + } }; let arity = match arity { @@ -2589,449 +3366,276 @@ impl MachineState { } }; - if arity > MAX_ARITY as isize { + if arity > MAX_ARITY as i64 { // 8.5.1.3 f) - let rep_err = MachineError::representation_error(RepFlag::MaxArity); - return Err(self.error_form(rep_err, stub)); + let err = self.representation_error(RepFlag::MaxArity); + return Err(self.error_form(err, stub_gen())); } else if arity < 0 { // 8.5.1.3 g) - let arity = Number::Integer(Rc::new(Integer::from(arity))); - let dom_err = - MachineError::domain_error(DomainErrorType::NotLessThanZero, arity); - - return Err(self.error_form(dom_err, stub)); - } - - match name { - Addr::Char(_) - | Addr::Con(_) - | Addr::Fixnum(_) - | Addr::Float(_) - | Addr::EmptyList - | Addr::PStrLocation(..) - | Addr::Usize(_) - if arity == 0 => - { - (self.unify_fn)(self, a1, name); - } - Addr::Con(h) => { - if let HeapCellValue::Atom(name, spec) = self.heap.clone(h) { - self.try_functor_fabricate_struct( - name, - arity as usize, - spec, - &op_dir, - a1.as_var().unwrap(), - ); - } else { - // 8.5.1.3 e) - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Atom, name), - stub, - )); - } + let arity = Number::Fixnum(Fixnum::build_with(arity)); + let err = self.domain_error(DomainErrorType::NotLessThanZero, arity); + + return Err(self.error_form(err, stub_gen())); + } + + read_heap_cell!(store_name, + (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + HeapCellValueTag::F64) if arity == 0 => { + self.bind(a1.as_var().unwrap(), deref_name); + } + (HeapCellValueTag::Atom, (name, atom_arity)) => { + debug_assert_eq!(atom_arity, 0); + self.try_functor_fabricate_struct( + name, + arity as usize, + a1.as_var().unwrap(), + ); } - Addr::Char(c) => { + (HeapCellValueTag::Char, c) => { + let c = self.atom_tbl.build_with(&c.to_string()); + self.try_functor_fabricate_struct( - clause_name!(c.to_string(), self.atom_tbl), + c, arity as usize, - None, - &op_dir, a1.as_var().unwrap(), ); } _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Atomic, name), - stub, - )); + let err = self.type_error(ValidType::Atomic, store_name); + return Err(self.error_form(err, stub_gen())); } // 8.5.1.3 c) - } + ); } _ => { self.fail = true; } - } + ); Ok(()) } - pub(super) fn term_dedup(&self, list: &mut Vec) { - let mut result = vec![]; - - for a2 in list.iter() { - if let Some(a1) = result.last() { - if self.compare_term_test(&a1, &a2) == Some(Ordering::Equal) { - continue; + pub fn try_from_list( + &mut self, + value: HeapCellValue, + stub_gen: impl Fn() -> FunctorStub, + ) -> Result, MachineStub> { + let deref_v = self.deref(value); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Lis, l) => { + self.try_from_inner_list(vec![], l, stub_gen, store_v) + } + (HeapCellValueTag::PStrLoc, h) => { + self.try_from_partial_string(vec![], h, stub_gen, store_v) + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { + let err = self.instantiation_error(); + Err(self.error_form(err, stub_gen())) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + Ok(vec![]) + } else { + let err = self.type_error(ValidType::List, store_v); + Err(self.error_form(err, stub_gen())) } } - - result.push(*a2); - } - - *list = result; - } - - pub(super) fn integers_to_bytevec(&self, r: RegType, caller: MachineStub) -> Vec { - let mut bytes: Vec = Vec::new(); - - match self.try_from_list(r, caller) { - Err(_) => { - unreachable!() - } - Ok(addrs) => { - for addr in addrs { - let addr = self.store(self.deref(addr)); - - match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => { - match u8::try_from(n) { - Ok(b) => { - bytes.push(b); - } - Err(_) => {} - } - - continue; - } - Ok(Number::Integer(n)) => { - if let Some(b) = n.to_u8() { - bytes.push(b); - } - - continue; - } - _ => {} - } - } + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = cstr_atom.as_str(); + Ok(cstr.chars().map(|c| char_as_cell!(c)).collect()) + } + _ => { + let err = self.type_error(ValidType::List, store_v); + Err(self.error_form(err, stub_gen())) } - } - bytes - } - - pub(super) fn try_from_list( - &self, - r: RegType, - caller: MachineStub, - ) -> Result, MachineStub> { - let a1 = self.store(self.deref(self[r])); - - match a1 { - Addr::Lis(l) => self.try_from_inner_list(vec![], l, caller, a1), - Addr::PStrLocation(h, n) => self.try_from_partial_string(vec![], h, n, caller, a1), - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { - Err(self.error_form(MachineError::instantiation_error(), caller)) - } - Addr::EmptyList => Ok(vec![]), - _ => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )), - } + ) } fn try_from_inner_list( - &self, - mut result: Vec, + &mut self, + mut result: Vec, mut l: usize, - caller: MachineStub, - a1: Addr, - ) -> Result, MachineStub> { - result.push(self.heap[l].as_addr(l)); + stub_gen: impl Fn() -> FunctorStub, + a1: HeapCellValue, + ) -> Result, MachineStub> { + result.push(self.heap[l]); l += 1; loop { - match &self.heap[l] { - HeapCellValue::Addr(ref addr) => match self.store(self.deref(*addr)) { - Addr::Lis(hcp) => { - result.push(self.heap[hcp].as_addr(hcp)); - l = hcp + 1; - } - Addr::PStrLocation(h, n) => { - return self.try_from_partial_string(result, h, n, caller, a1); - } - Addr::EmptyList => { + let deref_v = self.deref(self.heap[l]); + let store_v = self.store(self.heap[l]); + + read_heap_cell!(store_v, + (HeapCellValueTag::Lis, hcp) => { + result.push(self.heap[hcp]); + l = hcp + 1; + } + (HeapCellValueTag::PStrOffset) => { + return self.try_from_partial_string(result, deref_v.get_value(), stub_gen, a1); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { break; + } else { + let err = self.type_error(ValidType::List, a1); + return Err(self.error_form(err, stub_gen())); } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { - return Err(self.error_form(MachineError::instantiation_error(), caller)) - } - _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) - } - }, + } _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) + if store_v.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + let err = self.type_error(ValidType::List, a1); + return Err(self.error_form(err, stub_gen())); + } } - } + ); } Ok(result) } fn try_from_partial_string( - &self, - mut chars: Vec, - mut h: usize, - mut n: usize, - caller: MachineStub, - a1: Addr, - ) -> Result, MachineStub> { - loop { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] { - chars.extend(pstr.range_from(n..).map(Addr::Char)); - - if !has_tail { - return Ok(chars); + &mut self, + mut chars: Vec, + h: usize, + stub_gen: impl Fn() -> FunctorStub, + a1: HeapCellValue, + ) -> Result, MachineStub> { + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); + + while let Some(iteratee) = heap_pstr_iter.next() { + match iteratee { + PStrIteratee::Char(_, c) => + chars.push(char_as_cell!(c)), + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c))); } + } + } - let tail = self.heap[h + 1].as_addr(h + 1); - - match self.store(self.deref(tail)) { - Addr::EmptyList => { - return Ok(chars); - } - Addr::Lis(l) => { - return self.try_from_inner_list(chars, l, caller, a1); - } - Addr::PStrLocation(h1, n1) => { - chars.push(Addr::Char('\u{0}')); - - h = h1; - n = n1; - } - _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) - } + match self.heap[h].get_tag() { + HeapCellValueTag::PStr => { + if heap_pstr_iter.at_string_terminator() { + Ok(chars) + } else { + read_heap_cell!(self.heap[heap_pstr_iter.focus()], + (HeapCellValueTag::Lis, l) => { + self.try_from_inner_list(chars, l, stub_gen, a1) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!(".") && arity == 2 { + let l = heap_pstr_iter.focus() + 1; + self.try_from_inner_list(chars, l, stub_gen, a1) + } else { + let err = self.type_error(ValidType::List, a1); + Err(self.error_form(err, stub_gen())) + } + } + _ => { + let err = self.type_error(ValidType::List, a1); + Err(self.error_form(err, stub_gen())) + } + ) } - } else { + } + HeapCellValueTag::CStr => Ok(chars), + _ => { unreachable!() } } } - // see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide. - pub(super) fn project_onto_key(&self, a: Addr) -> Result { - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); - - match self.store(self.deref(a)) { - Addr::HeapCell(_) | Addr::StackCell(..) => { - Err(self.error_form(MachineError::instantiation_error(), stub)) - } - Addr::Str(s) => match self.heap.clone(s) { - HeapCellValue::NamedStr(2, ref name, Some(_)) if *name == clause_name!("-") => { - Ok(Addr::HeapCell(s + 1)) - } - _ => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Pair, - self.heap[s].as_addr(s), - ), - stub, - )), - }, - a => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Pair, a), - stub, - )), + // returns true on failure. + pub fn ground_test(&mut self) -> bool { + if self.registers[1].is_constant() { + return false; } - } - pub(super) fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { - let old_h = self.heap.h(); + let value = self.registers[1]; - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; - - copy_term(CopyTerm::new(self), a1, attr_var_policy); + for v in stackful_preorder_iter(&mut self.heap, value) { + if v.is_var() { + return true; + } + } - (self.unify_fn)(self, Addr::HeapCell(old_h), a2); + false } - // returns true on failure. - pub(super) fn structural_eq_test(&self) -> bool { - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; - - let mut var_pairs = IndexMap::new(); - - let iter = self.zipped_acyclic_pre_order_iter(a1, a2); - - for (v1, v2) in iter { - match ( - self.heap.index_addr(&v1).as_ref(), - self.heap.index_addr(&v2).as_ref(), - ) { - ( - HeapCellValue::Addr(Addr::Lis(_)), - HeapCellValue::Addr(Addr::PStrLocation(..)), - ) - | ( - HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::Lis(_)), - ) => {} - (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => { - if ar1 != ar2 || n1 != n2 { - return true; - } - } - (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => {} - ( - &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), - ) => match (var_pairs.get(&v1), var_pairs.get(&v2)) { - (Some(ref v2_p), Some(ref v1_p)) if **v1_p == v1 && **v2_p == v2 => { - continue; - } - (Some(_), _) | (_, Some(_)) => { - return true; - } - (None, None) => { - var_pairs.insert(v1, v2); - var_pairs.insert(v2, v1); - } - }, - ( - HeapCellValue::PartialString(ref pstr1, has_tail_1), - HeapCellValue::PartialString(ref pstr2, has_tail_2), - ) => { - if has_tail_1 != has_tail_2 { - return true; - } - - let pstr1_iter = pstr1.range_from(0..); - let pstr2_iter = pstr2.range_from(0..); + pub fn integers_to_bytevec( + &mut self, + value: HeapCellValue, + stub_gen: impl Fn() -> FunctorStub, + ) -> Vec { + let mut bytes: Vec = Vec::new(); - for (c1, c2) in pstr1_iter.zip(pstr2_iter) { - if c1 != c2 { - return true; - } - } - } - ( - HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::PStrLocation(..)), - ) => {} - ( - HeapCellValue::Atom(ref n1, ref spec_1), - HeapCellValue::Atom(ref n2, ref spec_2), - ) => { - if n1 != n2 || spec_1 != spec_2 { - return true; - } - } - (HeapCellValue::DBRef(ref db_ref_1), HeapCellValue::DBRef(ref db_ref_2)) => { - if db_ref_1 != db_ref_2 { - return true; - } - } - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 != n2 { - return true; - } else { - continue; - } - } else { - return true; - } - } + match self.try_from_list(value, stub_gen) { + Err(_) => { + unreachable!() + } + Ok(addrs) => { + for addr in addrs { + let addr = self.store(self.deref(addr)); - match (v1, v2) { - (HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) => { - if a1 != a2 { - return true; + match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => match u8::try_from(n.get_num()) { + Ok(b) => bytes.push(b), + Err(_) => {} + }, + Ok(Number::Integer(n)) => { + if let Some(b) = n.to_u8() { + bytes.push(b); } } - _ => { - return true; - } + _ => {} } } } } - false + bytes } - // returns true on failure. - pub(super) fn ground_test(&self) -> bool { - let a = self.store(self.deref(self[temp_v!(1)])); - - for v in self.acyclic_pre_order_iter(a) { - match v { - Addr::HeapCell(..) => return true, - Addr::StackCell(..) => return true, - Addr::AttrVar(..) => return true, - _ => {} - } + // see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide. + pub fn project_onto_key(&mut self, value: HeapCellValue) -> Result { + let stub_gen = || functor_stub(atom!("keysort"), 2); + let store_v = self.store(self.deref(value)); + + if store_v.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - false + read_heap_cell!(store_v, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + if name == atom!("-") && arity == 2 { + Ok(heap_loc_as_cell!(s + 1)) + } else { + let err = self.type_error(ValidType::Pair, self.heap[s]); + Err(self.error_form(err, stub_gen())) + } + } + _ => { + let err = self.type_error(ValidType::Pair, store_v); + Err(self.error_form(err, stub_gen())) + } + ) } - pub(super) fn setup_built_in_call(&mut self, ct: BuiltInClauseType) { + pub fn setup_built_in_call(&mut self, ct: BuiltInClauseType) { self.num_of_args = ct.arity(); self.b0 = self.b; self.p = CodePtr::BuiltInClause(ct, self.p.local()); } - pub(super) fn allocate(&mut self, num_cells: usize) { - let e = self.stack.allocate_and_frame(num_cells); - let and_frame = self.stack.index_and_frame_mut(e); - - and_frame.prelude.e = self.e; - and_frame.prelude.cp = self.cp; - - self.e = e; - self.p += 1; - } - - pub(super) fn deallocate(&mut self) { + pub fn deallocate(&mut self) { let e = self.e; let frame = self.stack.index_and_frame(e); @@ -3046,8 +3650,8 @@ impl MachineState { } fn throw_interrupt_exception(&mut self) { - let err = MachineError::interrupt_error(); - let src = functor!("repl"); + let err = self.interrupt_error(); + let src = functor_stub(atom!("repl"), 0); let err = self.error_form(err, src); self.throw_exception(err); @@ -3121,11 +3725,8 @@ impl MachineState { self.p = CodePtr::Local(self.cp); } } - &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { - try_or_fail!( - self, - call_policy.context_call(self, name.clone(), arity, idx) - ) + &ClauseType::Named(ref name, _, ref idx) => { + try_or_fail!(self, call_policy.context_call(self, *name, arity, idx)) } &ClauseType::System(ref ct) => try_or_fail!( self, @@ -3144,7 +3745,7 @@ impl MachineState { self.last_call = false; } - pub(super) fn execute_ctrl_instr( + pub fn execute_ctrl_instr( &mut self, indices: &mut IndexStore, code_repo: &CodeRepo, @@ -3215,7 +3816,8 @@ impl MachineState { self.cc, ) { Some(_) => { - self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.registers[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); self.num_of_args += 1; self.execute_indexed_choice_instr( @@ -3240,10 +3842,7 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = match self.stack.index_or_frame(self.b)[n - 1] { - Addr::Usize(cc) => cc, - _ => unreachable!(), - }; + self.cc = cell_as_fixnum!(self.stack[n - 1]).get_num() as usize; if is_next_clause { match code_repo.find_living_dynamic( @@ -3264,7 +3863,7 @@ impl MachineState { } } } else { - try_or_fail!(self, call_policy.trust(self, offset, global_variables,)) + try_or_fail!(self, call_policy.trust(self, offset, global_variables)) } } } @@ -3295,7 +3894,7 @@ impl MachineState { or_frame.prelude.b = self.b; or_frame.prelude.bp = self.p.local() + 1; or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.h(); + or_frame.prelude.h = self.heap.len(); or_frame.prelude.b0 = self.b0; self.b = b; @@ -3304,7 +3903,7 @@ impl MachineState { self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; } - self.hb = self.heap.h(); + self.hb = self.heap.len(); self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); } &IndexedChoiceInstruction::Retry(l) => { @@ -3344,7 +3943,8 @@ impl MachineState { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { Some(_) => { - self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.registers[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); self.num_of_args += 1; self.execute_choice_instr( @@ -3369,10 +3969,8 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = match self.stack.index_or_frame(self.b)[n - 1] { - Addr::Usize(cc) => cc, - _ => unreachable!(), - }; + self.cc = cell_as_fixnum!(self.stack.index_or_frame(self.b)[n - 1]) + .get_num() as usize; if next_i > 0 { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { @@ -3389,15 +3987,12 @@ impl MachineState { None => { try_or_fail!( self, - call_policy.trust_me(self, global_variables,) + call_policy.trust_me(self, global_variables) ) } } } else { - try_or_fail!( - self, - call_policy.trust_me(self, global_variables,) - ) + try_or_fail!(self, call_policy.trust_me(self, global_variables)) } } } @@ -3423,7 +4018,8 @@ impl MachineState { FirstOrNext::First => { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { Some(_) => { - self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.registers[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); self.num_of_args += 1; self.execute_choice_instr( @@ -3448,10 +4044,8 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = match self.stack.index_or_frame(self.b)[n - 1] { - Addr::Usize(cc) => cc, - _ => unreachable!(), - }; + self.cc = cell_as_fixnum!(self.stack.index_or_frame(self.b)[n - 1]) + .get_num() as usize; if next_i > 0 { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { @@ -3499,7 +4093,7 @@ impl MachineState { or_frame.prelude.b = self.b; or_frame.prelude.bp = self.p.local() + offset; or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.h(); + or_frame.prelude.h = self.heap.len(); or_frame.prelude.b0 = self.b0; self.b = b; @@ -3508,7 +4102,7 @@ impl MachineState { self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; } - self.hb = self.heap.h(); + self.hb = self.heap.len(); self.p += 1; } &ChoiceInstruction::DefaultRetryMeElse(offset) => { @@ -3557,14 +4151,14 @@ impl MachineState { &CutInstruction::GetLevel(r) => { let b0 = self.b0; - self[r] = Addr::CutPoint(b0); + self[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64)); self.p += 1; } &CutInstruction::GetLevelAndUnify(r) => { let b0 = self[perm_v!(1)]; let a = self[r]; - (self.unify_fn)(self, a, b0); + unify_fn!(self, a, b0); self.p += 1; } &CutInstruction::Cut(r) => { diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs new file mode 100644 index 000000000..540db78fb --- /dev/null +++ b/src/machine/mock_wam.rs @@ -0,0 +1,766 @@ +pub use crate::arena::*; +pub use crate::atom_table::*; +use crate::heap_print::*; +pub use crate::machine::heap::*; +pub use crate::machine::Machine; +pub use crate::machine::machine_state::*; +pub use crate::machine::stack::*; +pub use crate::machine::streams::*; +pub use crate::macros::*; +pub use crate::parser::ast::*; +use crate::read::*; +pub use crate::types::*; + +#[cfg(test)] +use crate::machine::copier::CopierTarget; + +#[cfg(test)] +use std::ops::{Deref, DerefMut, Index, IndexMut}; + +// a mini-WAM for test purposes. + +pub struct MockWAM { + pub machine_st: MachineState, + pub op_dir: OpDir, + pub flags: MachineFlags, +} + +impl MockWAM { + pub fn new() -> Self { + let op_dir = default_op_dir(); + + Self { + machine_st: MachineState::new(), + op_dir, + flags: MachineFlags::default(), + } + } + + pub fn write_parsed_term_to_heap( + &mut self, + input_stream: Stream, + ) -> Result { + self.machine_st.read(input_stream, &self.op_dir) + } + + pub fn parse_and_write_parsed_term_to_heap( + &mut self, + term_string: &'static str, + ) -> Result { + let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena); + self.write_parsed_term_to_heap(stream) + } + + pub fn parse_and_print_term( + &mut self, + term_string: &'static str, + ) -> Result { + let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?; + + print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc); + + let mut printer = HCPrinter::new( + &mut self.machine_st.heap, + &mut self.machine_st.arena, + &self.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(term_write_result.heap_loc), + ); + + printer.var_names = term_write_result + .var_dict + .into_iter() + .map(|(var, cell)| (cell, var)) + .collect(); + + Ok(printer.print().result()) + } +} + +#[cfg(test)] +pub struct TermCopyingMockWAM<'a> { + pub wam: &'a mut MockWAM, +} + +#[cfg(test)] +impl<'a> Index for TermCopyingMockWAM<'a> { + type Output = HeapCellValue; + + fn index(&self, index: usize) -> &HeapCellValue { + &self.wam.machine_st.heap[index] + } +} + +#[cfg(test)] +impl<'a> IndexMut for TermCopyingMockWAM<'a> { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut HeapCellValue { + &mut self.wam.machine_st.heap[index] + } +} + +#[cfg(test)] +impl<'a> Deref for TermCopyingMockWAM<'a> { + type Target = MockWAM; + + fn deref(&self) -> &Self::Target { + &self.wam + } +} + +#[cfg(test)] +impl<'a> DerefMut for TermCopyingMockWAM<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.wam + } +} + +#[cfg(test)] +impl<'a> CopierTarget for TermCopyingMockWAM<'a> { + fn store(&self, val: HeapCellValue) -> HeapCellValue { + read_heap_cell!(val, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + self.wam.machine_st.heap[h] + } + (HeapCellValueTag::StackVar, s) => { + self.wam.machine_st.stack[s] + } + _ => { + val + } + ) + } + + fn deref(&self, mut val: HeapCellValue) -> HeapCellValue { + loop { + let value = self.store(val); + + if value.is_var() && value != val { + val = value; + continue; + } + + return val; + } + } + + fn push(&mut self, val: HeapCellValue) { + self.wam.machine_st.heap.push(val); + } + + fn stack(&mut self) -> &mut Stack { + &mut self.wam.machine_st.stack + } + + fn threshold(&self) -> usize { + self.wam.machine_st.heap.len() + } +} + +#[cfg(test)] +pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) { + for (idx, cell) in heap.iter().enumerate() { + assert_eq!( + cell.get_mark_bit(), + true, + "cell {:?} at index {} is not marked", + cell, + idx + ); + assert!( + cell.get_forwarding_bit() != Some(true), + "cell {:?} at index {} is forwarded", + cell, + idx + ); + } +} + +#[cfg(test)] +pub fn all_cells_unmarked(heap: &Heap) { + for (idx, cell) in heap.iter().enumerate() { + assert!( + !cell.get_mark_bit(), + "cell {:?} at index {} is still marked", + cell, + idx + ); + + assert!( + cell.get_forwarding_bit() != Some(true), + "cell {:?} at index {} is still forwarded", + cell, + idx + ); + } +} + +#[cfg(test)] +pub(crate) fn write_parsed_term_to_heap( + machine_st: &mut MachineState, + input_stream: Stream, + op_dir: &OpDir, +) -> Result { + machine_st.read(input_stream, op_dir) +} + +#[cfg(test)] +pub(crate) fn parse_and_write_parsed_term_to_heap( + machine_st: &mut MachineState, + term_string: &'static str, + op_dir: &OpDir, +) -> Result { + let stream = Stream::from_static_string(term_string, &mut machine_st.arena); + write_parsed_term_to_heap(machine_st, stream, op_dir) +} + +impl Machine { + pub fn test_load_file(&mut self, file: &str) -> Vec { + use std::io::Read; + + let old_output = std::mem::replace( + &mut self.user_output, + Stream::from_owned_string("".to_owned(), &mut self.machine_st.arena), + ); + + let stream = Stream::from_owned_string( + std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), + &mut self.machine_st.arena, + ); + + self.load_file(file.into(), stream); + + let output = self.user_output.bytes().map(|b| b.unwrap()).collect(); + self.user_output = old_output; + output + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn unify_tests() { + let mut wam = MachineState::new(); + let mut op_dir = default_op_dir(); + + op_dir.insert( + (atom!("+"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("*"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("/"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + op_dir.insert( + (atom!("="), Fixity::In), + OpDesc::build_with(700, XFX as u8), + ); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(b,a).", &op_dir).unwrap(); + + unify!( + wam, + str_loc_as_cell!(0), + str_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap(); + + unify!( + wam, + str_loc_as_cell!(1), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap(); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); + + all_cells_unmarked(&wam.heap); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(pstr_as_cell!(atom!("this is a string"))); + wam.heap.push(heap_loc_as_cell!(1)); + + wam.heap.push(pstr_as_cell!(atom!("this is a string"))); + wam.heap.push(pstr_loc_as_cell!(4)); + + wam.heap.push(pstr_offset_as_cell!(0)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6))); + + unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2)); + + assert!(!wam.fail); + + assert_eq!(wam.heap[1], pstr_loc_as_cell!(4)); + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(0)); + + wam.heap.push(list_loc_as_cell!(6)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(5)); + + unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); + + assert!(!wam.fail); + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(0)); + + wam.heap.push(list_loc_as_cell!(6)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(atom_as_cell!(atom!("c"))); + wam.heap.push(heap_loc_as_cell!(5)); + + unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); + + assert!(wam.fail); + + wam.fail = false; + all_cells_unmarked(&wam.heap); + wam.heap.clear(); + + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(5)); + + wam.heap.push(list_loc_as_cell!(6)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(0)); + + unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); + + assert!(!wam.fail); + all_cells_unmarked(&wam.heap); + wam.heap.clear(); + + { + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap(); + + print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc); + + unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4)); + + assert_eq!(wam.heap[2], str_loc_as_cell!(4)); + } + } + + #[test] + fn test_unify_with_occurs_check() { + let mut wam = MachineState::new(); + let mut op_dir = default_op_dir(); + + op_dir.insert( + (atom!("+"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("*"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + op_dir.insert( + (atom!("/"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); + + all_cells_unmarked(&wam.heap); + + unify_with_occurs_check!( + wam, + str_loc_as_cell!(0), + str_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(wam.fail); + } + } + + #[test] + fn test_term_compare() { + use ordered_float::OrderedFloat; + use std::cmp::Ordering; + + let mut wam = MachineState::new(); + + wam.heap.push(heap_loc_as_cell!(0)); + wam.heap.push(heap_loc_as_cell!(1)); + + assert_eq!( + compare_term_test!(wam, wam.heap[0], wam.heap[1]), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!(wam, wam.heap[1], wam.heap[0]), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!(wam, wam.heap[0], wam.heap[0]), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!(wam, wam.heap[1], wam.heap[1]), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + atom_as_cstr_cell!(atom!("string")) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + atom_as_cell!(atom!("atom")) + ), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + atom_as_cell!(atom!("aaa")) + ), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!( + wam, + fixnum_as_cell!(Fixnum::build_with(6)), + heap_loc_as_cell!(1) + ), + Some(Ordering::Greater) + ); + + wam.heap.clear(); + + wam.heap.push(atom_as_cell!(atom!("f"), 1)); + wam.heap.push(heap_loc_as_cell!(1)); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(0) + ), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(0), + atom_as_cell!(atom!("a")) + ), + Some(Ordering::Greater) + ); + + wam.heap.clear(); + + // [1,2,3] + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + wam.heap.push(list_loc_as_cell!(5)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); + wam.heap.push(empty_list_as_cell!()); + + // [1,2] + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + wam.heap.push(list_loc_as_cell!(10)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + wam.heap.push(empty_list_as_cell!()); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(7), + heap_loc_as_cell!(7) + ), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(7) + ), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + heap_loc_as_cell!(7) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + fixnum_as_cell!(Fixnum::build_with(1)) + ), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + atom_as_cstr_cell!(atom!("string")) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + atom_as_cell!(atom!("atom")) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + empty_list_as_cell!() + ), + Some(Ordering::Greater) + ); + + let one_p_one = typed_arena_ptr_as_cell!( + arena_alloc!(OrderedFloat(1.1), &mut wam.arena) + ); + + assert_eq!( + compare_term_test!( + wam, + one_p_one, + fixnum_as_cell!(Fixnum::build_with(1)) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + fixnum_as_cell!(Fixnum::build_with(1)), + one_p_one + ), + Some(Ordering::Greater) + ); + } + + #[test] + fn is_cyclic_term_tests() { + let mut wam = MachineState::new(); + + assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f")))); + assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555)))); + + wam.heap.push(heap_loc_as_cell!(0)); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + wam.heap.clear(); + + wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))])); + + assert!(!wam.is_cyclic_term(str_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1))); + + all_cells_unmarked(&wam.heap); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2))); + + all_cells_unmarked(&wam.heap); + + wam.heap[2] = str_loc_as_cell!(0); + + print_heap_terms(wam.heap.iter(), 0); + + assert!(wam.is_cyclic_term(str_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + + wam.heap[2] = atom_as_cell!(atom!("b")); + wam.heap[1] = str_loc_as_cell!(0); + + assert!(wam.is_cyclic_term(str_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + + assert!(wam.is_cyclic_term(heap_loc_as_cell!(1))); + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(pstr_as_cell!(atom!("a string"))); + wam.heap.push(empty_list_as_cell!()); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0))); + } +} diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 1f7ef41a9..ccb952cd7 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1,67 +1,70 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{clause_name, temp_v}; - -use lazy_static::lazy_static; - -use crate::clause_types::*; +pub mod arithmetic_ops; +pub mod attributed_variables; +pub mod code_repo; +pub mod code_walker; +#[macro_use] +pub mod loader; +pub mod compile; +pub mod copier; +pub mod gc; +pub mod heap; +pub mod load_state; +pub mod machine_errors; +pub mod machine_indices; +pub mod machine_state; +pub mod machine_state_impl; +pub mod mock_wam; +pub mod partial_string; +pub mod preprocessor; +pub mod stack; +pub mod streams; +pub mod system_calls; +pub mod term_stream; + +use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; -use crate::machine::loader::*; -use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream}; -use crate::read::*; - -mod attributed_variables; -pub(super) mod code_repo; -pub(crate) mod code_walker; -#[macro_use] -pub(crate) mod loader; -mod compile; -mod copier; -pub(crate) mod heap; -mod load_state; -pub(crate) mod machine_errors; -pub(crate) mod machine_indices; -pub(super) mod machine_state; -pub(crate) mod partial_string; -mod preprocessor; -mod raw_block; -mod stack; -pub(crate) mod streams; -mod term_stream; - -#[macro_use] -mod arithmetic_ops; -#[macro_use] -mod machine_state_impl; -mod system_calls; - use crate::machine::code_repo::*; use crate::machine::compile::*; +use crate::machine::heap::*; +use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -pub use crate::machine::streams::Stream; +use crate::machine::streams::*; +use crate::types::*; use indexmap::IndexMap; -//use std::convert::TryFrom; -use prolog_parser::ast::ClauseName; -use std::fs::File; -use std::mem; +use lazy_static::lazy_static; + +use std::env; use std::path::PathBuf; use std::sync::atomic::AtomicBool; +lazy_static! { + pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false); +} + +#[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) user_error: Stream, + pub(super) load_contexts: Vec, +} + #[derive(Debug)] pub(crate) struct MachinePolicies { call_policy: Box, cut_policy: Box, } -lazy_static! { - pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false); -} - impl MachinePolicies { #[inline] fn new() -> Self { @@ -80,10 +83,10 @@ impl Default for MachinePolicies { } #[derive(Debug)] -pub(super) struct LoadContext { +pub struct LoadContext { pub(super) path: PathBuf, pub(super) stream: Stream, - pub(super) module: ClauseName, + pub(super) module: Atom, } impl LoadContext { @@ -100,32 +103,49 @@ impl LoadContext { LoadContext { path: path_buf, stream, - module: clause_name!("user"), + module: atom!("user"), } } } -#[derive(Debug)] -pub struct Machine { - pub(super) machine_st: MachineState, - pub(super) policies: MachinePolicies, - pub(super) indices: IndexStore, - pub(super) code_repo: CodeRepo, - pub(super) user_input: Stream, - pub(super) user_output: Stream, - pub(super) user_error: Stream, - pub(super) load_contexts: Vec, -} - #[inline] fn current_dir() -> PathBuf { - std::env::current_dir().unwrap_or(PathBuf::from("./")) + env::current_dir().unwrap_or(PathBuf::from("./")) } include!(concat!(env!("OUT_DIR"), "/libraries.rs")); +pub struct MachinePreludeView<'a> { + pub indices: &'a mut IndexStore, + pub code_repo: &'a mut CodeRepo, + pub load_contexts: &'a mut Vec, +} + +impl Machine { + #[inline] + pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) { + ( + MachinePreludeView { + indices: &mut self.indices, + code_repo: &mut self.code_repo, + load_contexts: &mut self.load_contexts, + }, + &mut self.machine_st + ) + } + + pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { + let err = self.machine_st.session_error(err); + let stub = functor_stub(key.0, key.1); + let err = self.machine_st.error_form(err, stub); + + self.machine_st.throw_exception(err); + return; + } +} + impl Machine { - fn run_module_predicate(&mut self, module_name: ClauseName, key: PredicateKey) { + fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) { if let Some(module) = self.indices.modules.get(&module_name) { if let Some(ref code_index) = module.code_dir.get(&key) { let p = code_index.local().unwrap(); @@ -140,27 +160,29 @@ impl Machine { unreachable!(); } - pub fn load_file(&mut self, path: String, stream: Stream) { - self.machine_st[temp_v!(1)] = - Addr::Stream(self.machine_st.heap.push(HeapCellValue::Stream(stream))); - - self.machine_st[temp_v!(2)] = Addr::Con(self.machine_st.heap.push(HeapCellValue::Atom( - clause_name!(path, self.machine_st.atom_tbl), - None, - ))); + pub fn load_file(&mut self, path: &str, stream: Stream) { + self.machine_st.registers[1] = stream_as_cell!(stream); + self.machine_st.registers[2] = atom_as_cell!( + self.machine_st.atom_tbl.build_with(path) + ); - self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2)); + self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2)); } fn load_top_level(&mut self) { let mut path_buf = current_dir(); - path_buf.push("toplevel.pl"); - let path = path_buf.to_str().unwrap().to_string(); + path_buf.push("src/toplevel.pl"); - self.load_file(path, Stream::from(include_str!("../toplevel.pl"))); + let path = path_buf.to_str().unwrap(); + let toplevel_stream = Stream::from_static_string( + include_str!("../toplevel.pl"), + &mut self.machine_st.arena, + ); - if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) { + self.load_file(path, toplevel_stream); + + if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) { load_module( &mut self.indices.code_dir, &mut self.indices.op_dir, @@ -178,9 +200,15 @@ impl Machine { path_buf.push("machine/attributed_variables.pl"); bootstrapping_compile( - Stream::from(include_str!("attributed_variables.pl")), + Stream::from_static_string( + include_str!("attributed_variables.pl"), + &mut self.machine_st.arena, + ), self, - ListingSource::from_file_and_path(clause_name!("attributed_variables"), path_buf), + ListingSource::from_file_and_path( + atom!("attributed_variables"), + path_buf, + ), ) .unwrap(); @@ -188,44 +216,49 @@ impl Machine { path_buf.push("machine/project_attributes.pl"); bootstrapping_compile( - Stream::from(include_str!("project_attributes.pl")), + Stream::from_static_string( + include_str!("project_attributes.pl"), + &mut self.machine_st.arena, + ), self, - ListingSource::from_file_and_path(clause_name!("project_attributes"), path_buf), + ListingSource::from_file_and_path(atom!("project_attributes"), path_buf), ) .unwrap(); - if let Some(module) = self.indices.modules.get(&clause_name!("$atts")) { - if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) { + if let Some(module) = self.indices.modules.get(&atom!("$atts")) { + if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) { self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap(); } } } pub fn run_top_level(&mut self) { - use std::env; - let mut arg_pstrs = vec![]; for arg in env::args() { - arg_pstrs.push(self.machine_st.heap.put_complete_string(&arg)); + arg_pstrs.push(put_complete_string( + &mut self.machine_st.heap, + &arg, + &mut self.machine_st.atom_tbl, + )); } - let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter())); - - self.machine_st[temp_v!(1)] = list_addr; + self.machine_st.registers[1] = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, arg_pstrs.into_iter()) + ); - self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1)); + self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1)); } pub(crate) fn configure_modules(&mut self) { fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) { for arity in 1..66 { - let key = (clause_name!("call"), arity); + let key = (atom!("call"), arity); match loader.code_dir.get(&key) { Some(src_code_index) => { let target_code_index = target_code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)); target_code_index.set(src_code_index.get()); @@ -237,15 +270,15 @@ impl Machine { } } - if let Some(loader) = self.indices.modules.swap_remove(&clause_name!("loader")) { - if let Some(builtins) = self.indices.modules.get_mut(&clause_name!("builtins")) { + if let Some(loader) = self.indices.modules.swap_remove(&atom!("loader")) { + if let Some(builtins) = self.indices.modules.get_mut(&atom!("builtins")) { // Import loader's exports into the builtins module so they will be // implicitly included in every further module. load_module( &mut builtins.code_dir, &mut builtins.op_dir, &mut builtins.meta_predicates, - &CompilationTarget::Module(clause_name!("builtins")), + &CompilationTarget::Module(atom!("builtins")), &loader, ); @@ -257,7 +290,7 @@ impl Machine { builtins .module_decl .exports - .push(ModuleExport::PredicateKey((clause_name!("call"), arity))); + .push(ModuleExport::PredicateKey((atom!("call"), arity))); } } @@ -267,17 +300,24 @@ impl Machine { update_call_n_indices(&loader, &mut self.indices.code_dir); - self.indices.modules.insert(clause_name!("loader"), loader); + self.indices.modules.insert(atom!("loader"), loader); } else { unreachable!() } } - pub fn new(user_input: Stream, user_output: Stream, user_error: Stream) -> Self { + pub fn new() -> Self { use ref_thread_local::RefThreadLocal; + let mut machine_st = MachineState::new(); + + let user_input = Stream::stdin(&mut machine_st.arena); + let user_output = Stream::stdout(&mut machine_st.arena); + let user_error = Stream::stderr(&mut machine_st.arena); + let mut wam = Machine { - machine_st: MachineState::new(), + machine_st, + inner_heap: Heap::new(), policies: MachinePolicies::new(), indices: IndexStore::new(), code_repo: CodeRepo::new(), @@ -293,23 +333,29 @@ impl Machine { lib_path.push("lib"); bootstrapping_compile( - Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]), + Stream::from_static_string( + LIBRARIES.borrow()["ops_and_meta_predicates"], + &mut wam.machine_st.arena, + ), &mut wam, ListingSource::from_file_and_path( - clause_name!("ops_and_meta_predicates.pl"), + atom!("ops_and_meta_predicates.pl"), lib_path.clone(), ), ) .unwrap(); bootstrapping_compile( - Stream::from(LIBRARIES.borrow()["builtins"]), + Stream::from_static_string( + LIBRARIES.borrow()["builtins"], + &mut wam.machine_st.arena, + ), &mut wam, - ListingSource::from_file_and_path(clause_name!("builtins.pl"), lib_path.clone()), + ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()), ) .unwrap(); - if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) { + if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) { load_module( &mut wam.indices.code_dir, &mut wam.indices.op_dir, @@ -324,15 +370,15 @@ impl Machine { lib_path.pop(); // remove the "lib" at the end bootstrapping_compile( - Stream::from(include_str!("../loader.pl")), + Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena), &mut wam, - ListingSource::from_file_and_path(clause_name!("loader.pl"), lib_path.clone()), + ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()), ) .unwrap(); wam.configure_modules(); - if let Some(loader) = wam.indices.modules.get(&clause_name!("loader")) { + if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { load_module( &mut wam.indices.code_dir, &mut wam.indices.op_dir, @@ -352,38 +398,21 @@ impl Machine { } pub(crate) fn configure_streams(&mut self) { - self.user_input.options_mut().alias = Some(clause_name!("user_input")); + self.user_input.options_mut().set_alias_to_atom_opt(Some(atom!("user_input"))); self.indices .stream_aliases - .insert(clause_name!("user_input"), self.user_input.clone()); + .insert(atom!("user_input"), self.user_input); - self.indices.streams.insert(self.user_input.clone()); + self.indices.streams.insert(self.user_input); - self.user_output.options_mut().alias = Some(clause_name!("user_output")); + self.user_output.options_mut().set_alias_to_atom_opt(Some(atom!("user_output"))); self.indices .stream_aliases - .insert(clause_name!("user_output"), self.user_output.clone()); - - self.user_error.options_mut().alias = Some(clause_name!("user_error")); + .insert(atom!("user_output"), self.user_output); - self.indices - .stream_aliases - .insert(clause_name!("user_error"), self.user_error.clone()); - - self.indices.streams.insert(self.user_output.clone()); - } - - fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { - let h = self.machine_st.heap.h(); - - let err = MachineError::session_error(h, err); - let stub = MachineError::functor_stub(key.0, key.1); - let err = self.machine_st.error_form(err, stub); - - self.machine_st.throw_exception(err); - return; + self.indices.streams.insert(self.user_output); } fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { @@ -604,13 +633,14 @@ impl MachineState { self.b0 = self.stack.index_or_frame(b).prelude.b0; self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); + self.pdl.clear(); self.fail = false; } fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool { match self.p { - CodePtr::Local(LocalCodePtr::DirEntry(p)) - | CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..)) + CodePtr::Local(LocalCodePtr::DirEntry(p)) | + CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..)) if p < code_repo.code.len() => {} CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => { return false; @@ -690,7 +720,9 @@ impl MachineState { self.p = CodePtr::Local(self.attr_var_init.cp); let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p); - let instigating_instr = code_repo.lookup_instr(false, &instigating_p).unwrap(); + let instigating_instr = code_repo + .lookup_instr(false, &instigating_p) + .unwrap(); if !instigating_instr.as_ref().is_head_instr() { let cp = self.p.local(); diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 793548747..da32db4f9 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -1,43 +1,16 @@ -use crate::machine::machine_indices::*; -use crate::machine::*; +use crate::atom_table::*; +use crate::parser::ast::*; -use core::marker::PhantomData; +use crate::machine::machine_errors::CycleSearchResult; +use crate::machine::system_calls::BrentAlgState; +use crate::types::*; -use std::alloc; use std::cmp::Ordering; -use std::mem; -use std::ops::RangeFrom; -use std::ptr; -use std::slice; +use std::ops::Deref; use std::str; -use indexmap::IndexSet; - -#[derive(Debug)] -pub(crate) struct PartialString { - buf: *const u8, - len: usize, - _marker: PhantomData<[u8]>, -} - -impl Drop for PartialString { - fn drop(&mut self) { - unsafe { - let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::()); - alloc::dealloc(self.buf as *mut u8, layout); - - self.buf = ptr::null(); - self.len = 0; - } - } -} - -impl Clone for PartialString { - #[inline] - fn clone(&self) -> Self { - self.clone_from_offset(0) - } -} +#[derive(Copy, Clone, Debug)] +pub struct PartialString(Atom); fn scan_for_terminator>(iter: Iter) -> usize { let mut terminator_idx = 0; @@ -53,432 +26,1114 @@ fn scan_for_terminator>(iter: Iter) -> usize { terminator_idx } -#[derive(Debug)] -pub(crate) struct PStrIter { - buf: *const u8, - len: usize, -} - -impl PStrIter { +impl From for PartialString { #[inline] - fn from(buf: *const u8, len: usize, idx: usize) -> Self { - PStrIter { - buf: (buf as usize + idx) as *const _, - len: len - idx, - } + fn from(buf: Atom) -> PartialString { + PartialString(buf) } } -impl Iterator for PStrIter { - type Item = char; - - fn next(&mut self) -> Option { - unsafe { - let slice = slice::from_raw_parts(self.buf, self.len); - let s = str::from_utf8(slice).unwrap(); - - if let Some(c) = s.chars().next() { - self.buf = self.buf.offset(c.len_utf8() as isize); - self.len -= c.len_utf8(); - - Some(c) - } else { - None - } - } +impl Into for PartialString { + #[inline] + fn into(self: Self) -> Atom { + self.0 } } impl PartialString { #[inline] - pub(super) fn new(src: &str) -> Option<(Self, &str)> { - let pstr = PartialString { - buf: ptr::null_mut(), - len: 0, - _marker: PhantomData, - }; + pub(super) fn new<'a>(src: &'a str, atom_tbl: &mut AtomTable) -> Option<(Self, &'a str)> { + let terminator_idx = scan_for_terminator(src.chars()); + let pstr = PartialString(atom_tbl.build_with(src)); + + Some(if terminator_idx != src.as_bytes().len() { + (pstr, &src[terminator_idx..]) + } else { + (pstr, "") + }) + } - unsafe { pstr.append_chars(src) } + #[inline(always)] + pub(crate) fn as_str_from(&self, n: usize) -> &str { + &self.0.as_str()[n..] } +} - unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> { - let terminator_idx = scan_for_terminator(src.chars()); +#[derive(Clone, Copy)] +pub struct HeapPStrIter<'a> { + pub heap: &'a [HeapCellValue], + pub focus: HeapCellValue, + orig_focus: usize, + brent_st: BrentAlgState, + stepper: fn(&mut HeapPStrIter<'a>) -> Option, +} - let layout = alloc::Layout::from_size_align_unchecked( - terminator_idx + '\u{0}'.len_utf8(), - mem::align_of::(), - ); +#[derive(Debug)] +pub struct PStrPrefixCmpResult { + pub focus: usize, + pub offset: usize, + pub prefix_len: usize, +} - self.buf = alloc::alloc(layout) as *const _; - self.len = terminator_idx + '\u{0}'.len_utf8(); +struct PStrIterStep { + iteratee: PStrIteratee, + next_hare: usize, +} - ptr::copy(src.as_ptr(), self.buf as *mut _, terminator_idx); +impl<'a> HeapPStrIter<'a> { + pub fn new(heap: &'a [HeapCellValue], h: usize) -> Self { + let value = heap[h]; + + Self { + heap, + focus: value, + orig_focus: h, + brent_st: BrentAlgState::new(h), + stepper: HeapPStrIter::pre_cycle_discovery_stepper, + } + } - self.write_terminator_at(terminator_idx); + #[inline(always)] + pub fn focus(&self) -> usize { + self.brent_st.hare + } - Some(if terminator_idx != src.as_bytes().len() { - (self, &src[terminator_idx..]) - } else { - (self, "") - }) + #[inline(always)] + pub fn at_string_terminator(&self) -> bool { + self.focus.is_string_terminator(self.heap) } - pub(super) fn clone_from_offset(&self, n: usize) -> Self { - let len = if self.len - '\u{0}'.len_utf8() > n { - self.len - n - '\u{0}'.len_utf8() - } else { - 0 - }; + #[inline(always)] + pub fn num_steps(&self) -> usize { + self.brent_st.num_steps() + } - let mut pstr = PartialString { - buf: ptr::null_mut(), - len: len + '\u{0}'.len_utf8(), - _marker: PhantomData, + pub fn compare_pstr_to_string(&mut self, s: &str) -> Option { + let mut result = PStrPrefixCmpResult { + focus: self.brent_st.hare, + offset: 0, + prefix_len: 0, }; - unsafe { - let layout = alloc::Layout::from_size_align_unchecked( - len + '\u{0}'.len_utf8(), - mem::align_of::(), - ); + while let Some(iteratee) = self.next() { + result.focus = iteratee.focus(); + result.offset = iteratee.offset(); - pstr.buf = alloc::alloc(layout); + match iteratee { + PStrIteratee::Char(_, c1) => { + if let Some(c2) = s[result.prefix_len..].chars().next() { + if c1 != c2 { + return None; + } else { + result.prefix_len += c1.len_utf8(); + result.offset += c1.len_utf8(); + } + } else { + return Some(result); + } + } + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + let t = pstr.as_str_from(n); + let s = &s[result.prefix_len..]; + + if s.len() >= t.len() { + if s.starts_with(t) { + result.prefix_len += t.len(); + result.offset += t.len(); + } else { + return None; + } + } else if t.starts_with(&s) { + result.prefix_len += s.len(); + result.offset += s.len(); - if len > 0 { - ptr::copy( - (self.buf as usize + n) as *const u8, - pstr.buf as *mut _, - len, - ); + return Some(result); + } else { + return None; + } + } } - pstr.write_terminator_at(len); + if s.len() == result.prefix_len { + return Some(result); + } } - pstr + Some(result) } #[inline] - pub(super) fn write_terminator_at(&mut self, index: usize) { - unsafe { - ptr::write((self.buf as usize + index) as *mut u8, 0u8); + pub fn chars(mut self) -> PStrCharsIter<'a> { + let item = self.next(); + PStrCharsIter { iter: self, item } + } + + fn walk_hare_to_cycle_end(&mut self) { + // walk_hare_to_cycle_end assumes a cycle has been found, + // so it is always safe to unwrap self.step() + + let orig_hare = self.brent_st.hare; + + self.brent_st.hare = self.orig_focus; + self.brent_st.tortoise = self.orig_focus; + + for _ in 0 .. self.brent_st.lam { + self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare; } + + while self.brent_st.hare != self.brent_st.tortoise { + self.brent_st.tortoise = self.step(self.brent_st.tortoise).unwrap().next_hare; + self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare; + } + + self.focus = self.heap[orig_hare]; + self.brent_st.hare = orig_hare; } - #[inline] - pub(crate) fn range_from(&self, index: RangeFrom) -> PStrIter { - if self.len >= '\u{0}'.len_utf8() { - PStrIter::from(self.buf, self.len - '\u{0}'.len_utf8(), index.start) - } else { - PStrIter::from(self.buf, 0, 0) + pub fn to_string(&mut self) -> String { + let mut buf = String::with_capacity(32); + + while let Some(iteratee) = self.next() { + match iteratee { + PStrIteratee::Char(_, c) => { + buf.push(c); + } + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + buf += pstr.as_str_from(n); + } + } } + + buf } #[inline] - pub(crate) fn at_end(&self, end_n: usize) -> bool { - end_n + 1 == self.len + pub fn is_continuable(&self) -> bool { + let mut focus = self.focus; + + loop { + read_heap_cell!(focus, + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + return true; + } + (HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here? + return name == atom!(".") && arity == 2; + } + (HeapCellValueTag::Lis, h) => { + return read_heap_cell!(self.heap[h], + (HeapCellValueTag::Atom, (name, arity)) => { + arity == 0 && name.as_char().is_some() + } + (HeapCellValueTag::Char) => { + true + } + _ => { + false + } + ); + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if focus == self.heap[h] { + return false; + } + + focus = self.heap[h]; + } + _ => { + return false; + } + ); + } } - #[inline] - pub(crate) fn as_str_from(&self, n: usize) -> &str { - unsafe { - let slice = slice::from_raw_parts(self.buf, self.len - '\u{0}'.len_utf8()); + #[inline(always)] + pub fn cycle_detected(&self) -> bool { + self.stepper as usize == HeapPStrIter::post_cycle_discovery_stepper as usize + } + + fn step(&self, mut curr_hare: usize) -> Option { + loop { + read_heap_cell!(self.heap[curr_hare], + (HeapCellValueTag::CStr, cstr_atom) => { + return if self.focus == empty_list_as_cell!() { + None + } else { + Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, cstr_atom, 0), + next_hare: curr_hare, + }) + } + } + (HeapCellValueTag::PStrLoc, h) => { + curr_hare = h; + } + (HeapCellValueTag::PStr, pstr_atom) => { + return Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, 0), + next_hare: curr_hare+1, + }); + } + (HeapCellValueTag::PStrOffset, pstr_offset) => { + if self.focus == empty_list_as_cell!() { + return None; + } + + let pstr_atom = cell_as_atom!(self.heap[pstr_offset]); + let n = cell_as_fixnum!(self.heap[curr_hare+1]).get_num() as usize; + + return if self.heap[pstr_offset].get_tag() == HeapCellValueTag::CStr { + Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), + next_hare: pstr_offset, + }) + } else { + Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), + next_hare: pstr_offset+1, + }) + }; + } + (HeapCellValueTag::Lis, h) => { + return if let Some(c) = self.heap[h].as_char() { + Some(PStrIterStep { + iteratee: PStrIteratee::Char(curr_hare, c), + next_hare: h+1, + }) + } else { + None + } + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + return if name == atom!(".") && arity == 2 { + if let Some(c) = self.heap[s+1].as_char() { + Some(PStrIterStep { + iteratee: PStrIteratee::Char(curr_hare, c), + next_hare: s+2, + }) + } else { + None + } + } else { + None + }; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + debug_assert!(arity == 0); + return None; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == curr_hare { + return None; + } + + curr_hare = h; + } + _ => { + return None; + } + ); + } + } + + fn pre_cycle_discovery_stepper(&mut self) -> Option { + let PStrIterStep { iteratee, next_hare } = + match self.step(self.brent_st.hare) { + Some(results) => results, + None => { + return None; + } + }; + + self.focus = self.heap[iteratee.focus()]; + + if self.focus.is_string_terminator(self.heap) { + self.focus = empty_list_as_cell!(); + self.brent_st.hare = iteratee.focus(); + + return Some(iteratee); + } + + match self.brent_st.step(next_hare) { + Some(cycle_result) => { + debug_assert!(cycle_result == CycleSearchResult::NotList); + + self.walk_hare_to_cycle_end(); + self.stepper = HeapPStrIter::post_cycle_discovery_stepper; + } + None => { + self.focus = self.heap[next_hare]; + } + } - let s = str::from_utf8(slice).unwrap(); + Some(iteratee) + } - &s[n..] + fn post_cycle_discovery_stepper(&mut self) -> Option { + if self.brent_st.hare == self.brent_st.tortoise { + return None; } + + let PStrIterStep { iteratee, next_hare } = + match self.step(self.brent_st.hare) { + Some(results) => results, + None => { + return None; + } + }; + + self.focus = self.heap[next_hare]; + self.brent_st.hare = next_hare; + + Some(iteratee) } } -#[derive(Debug)] -pub(crate) struct HeapPStrIter<'a> { - focus: Addr, - machine_st: &'a MachineState, - seen: IndexSet, +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PStrIteratee { + Char(usize, char), + PStrSegment(usize, Atom, usize), } -impl<'a> HeapPStrIter<'a> { +impl PStrIteratee { #[inline] - pub(super) fn new(machine_st: &'a MachineState, focus: Addr) -> Self { - HeapPStrIter { - focus, - machine_st, - seen: IndexSet::new(), + fn offset(&self) -> usize { + match self { + PStrIteratee::Char(_, _) => 0, + PStrIteratee::PStrSegment(_, _, n) => *n, } } #[inline] - pub(crate) fn focus(&self) -> Addr { - self.machine_st.store(self.machine_st.deref(self.focus)) + fn focus(&self) -> usize { + match self { + PStrIteratee::Char(focus, _) => *focus, + PStrIteratee::PStrSegment(focus, _, _) => *focus, + } } +} - #[inline] - pub(crate) fn to_string(&mut self) -> String { - let mut buf = String::new(); +impl<'a> Iterator for HeapPStrIter<'a> { + type Item = PStrIteratee; - while let Some(iteratee) = self.next() { + #[inline(always)] + fn next(&mut self) -> Option { + (self.stepper)(self) + } +} + +pub struct PStrCharsIter<'a> { + pub iter: HeapPStrIter<'a>, + pub item: Option, +} + +impl<'a> PStrCharsIter<'a> { + pub fn peek(&self) -> Option { + if let Some(iteratee) = self.item { match iteratee { - PStrIteratee::Char(c) => { - buf.push(c); + PStrIteratee::Char(_, c) => { + return Some(c); + } + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + return pstr.as_str_from(n).chars().next(); } - PStrIteratee::PStrSegment(h, n) => match &self.machine_st.heap[h] { - HeapCellValue::PartialString(ref pstr, _) => { - buf += pstr.as_str_from(n); - } - _ => { - unreachable!() - } - }, } } - buf + None } } -#[derive(Debug, Clone, Copy)] -pub(crate) enum PStrIteratee { - Char(char), - PStrSegment(usize, usize), +impl<'a> Deref for PStrCharsIter<'a> { + type Target = HeapPStrIter<'a>; + + fn deref(&self) -> &Self::Target { + &self.iter + } } -impl<'a> Iterator for HeapPStrIter<'a> { - type Item = PStrIteratee; +impl<'a> Iterator for PStrCharsIter<'a> { + type Item = char; fn next(&mut self) -> Option { - let addr = self.machine_st.store(self.machine_st.deref(self.focus)); - - if !self.seen.contains(&addr) { - self.seen.insert(addr); - } else { - return None; + while let Some(item) = self.item { + match item { + PStrIteratee::Char(_, c) => { + self.item = self.iter.next(); + return Some(c); + } + PStrIteratee::PStrSegment(f1, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + + match pstr.as_str_from(n).chars().next() { + Some(c) => { + self.item = Some(PStrIteratee::PStrSegment( + f1, + pstr_atom, + n + c.len_utf8(), + )); + + return Some(c); + } + None => { + self.item = self.iter.next(); + } + } + } + } } - 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 - }; + /* + if !self.iter.at_string_terminator() { + // at a cycle. emit the final character. + match self.iter.step(self.iter.brent_st.hare) { + Some(PStrIterStep { iteratee: PStrIteratee::Char(_, c), .. }) => { + self.iter.focus = empty_list_as_cell!(); + return Some(c); + } + Some(PStrIterStep { iteratee: PStrIteratee::PStrSegment(_, pstr_atom, _), .. }) => { + self.iter.focus = empty_list_as_cell!(); - return Some(PStrIteratee::PStrSegment(h, n)); - } else { - unreachable!() + let c = PartialString::from(pstr_atom).as_str_from(0).chars().next().unwrap(); + return Some(c); } - } - Addr::Lis(l) => { - let addr = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(l))); - - let opt_c = match addr { - Addr::Con(h) if self.machine_st.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] { - if atom.is_char() { - atom.as_str().chars().next() - } else { - None - } - } else { - unreachable!() - } - } - Addr::Char(c) => Some(c), - _ => None, - }; - - if let Some(c) = opt_c { - self.focus = Addr::HeapCell(l + 1); - return Some(PStrIteratee::Char(c)); - } else { + _ => { + self.iter.focus = empty_list_as_cell!(); return None; } } - Addr::EmptyList => { - self.focus = Addr::EmptyList; - return None; - } - _ => { - return None; - } + } + */ + + None + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PStrCmpResult { + Ordered(Ordering), + FirstIterContinuable(PStrIteratee), + SecondIterContinuable(PStrIteratee), + Unordered, +} + +impl PStrCmpResult { + #[inline] + pub fn is_second_iter(&self) -> bool { + if let PStrCmpResult::SecondIterContinuable(_) = self { + true + } else { + false } } } #[inline] -pub(super) fn compare_pstr_prefixes<'a>( +pub fn compare_pstr_prefixes<'a>( i1: &mut HeapPStrIter<'a>, i2: &mut HeapPStrIter<'a>, -) -> Option { - let mut r1 = i1.next(); - let mut r2 = i2.next(); +) -> PStrCmpResult { + #[inline(always)] + fn consolidate_step(iter: &mut HeapPStrIter, step: &PStrIterStep) -> bool { + iter.focus = iter.heap[step.next_hare]; + + if iter.focus.is_string_terminator(iter.heap) { + iter.focus = empty_list_as_cell!(); + } + + !iter.brent_st.step(step.next_hare).is_some() + } + + let mut r1 = i1.step(i1.brent_st.hare); + let mut r2 = i2.step(i2.brent_st.hare); loop { - if let Some(r1i) = r1 { - if let Some(r2i) = r2 { - match (r1i, r2i) { - (PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => { + if let Some(step_1) = r1.as_mut() { + if let Some(step_2) = r2.as_mut() { + match (step_1.iteratee, step_2.iteratee) { + (PStrIteratee::Char(_, c1), PStrIteratee::Char(_, c2)) => { if c1 != c2 { - return c1.partial_cmp(&c2); + return PStrCmpResult::Ordered(c1.cmp(&c2)); + } + + let c1_result = consolidate_step(i1, &step_1); + let c2_result = consolidate_step(i2, &step_2); + + if c1_result { + r1 = i1.step(i1.brent_st.hare); + } + + if c2_result { + r2 = i2.step(i2.brent_st.hare); + } + + if c1_result && c2_result { + continue; + } else { + break; } } - (PStrIteratee::Char(c1), PStrIteratee::PStrSegment(h, n)) => { - if let &HeapCellValue::PartialString(ref pstr, _) = &i2.machine_st.heap[h] { - if let Some(c2) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return c1.partial_cmp(&c2); - } else { - r1 = i1.next(); - r2 = Some(PStrIteratee::PStrSegment(h, n + c2.len_utf8())); + (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => { + let pstr = PartialString::from(pstr_atom); + + if let Some(c2) = pstr.as_str_from(n).chars().next() { + if c1 != c2 { + return PStrCmpResult::Ordered(c1.cmp(&c2)); + } + + let n1 = n + c2.len_utf8(); + + if n1 < pstr_atom.len() { + step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1); + if consolidate_step(i1, &step_1) { + r1 = i1.step(step_1.next_hare); continue; + } else { + break; } } else { - r2 = i2.next(); - continue; + let c1_result = consolidate_step(i1, &step_1); + let c2_result = consolidate_step(i2, &step_2); + + if c1_result { + r1 = i1.step(i1.brent_st.hare); + } + + if c2_result { + r2 = i2.step(i2.brent_st.hare); + } + + if c1_result && c2_result { + continue; + } else { + break; + } } } else { - unreachable!() + if consolidate_step(i2, &step_2) { + r2 = i2.step(step_2.next_hare); + continue; + } else { + break; + } } } - (PStrIteratee::PStrSegment(h, n), PStrIteratee::Char(c2)) => { - if let &HeapCellValue::PartialString(ref pstr, _) = &i1.machine_st.heap[h] { - if let Some(c1) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return c2.partial_cmp(&c1); - } else { - r1 = i1.next(); - r2 = Some(PStrIteratee::PStrSegment(h, n + c1.len_utf8())); + (PStrIteratee::PStrSegment(f1, pstr_atom, n), PStrIteratee::Char(_, c2)) => { + let pstr = PartialString::from(pstr_atom); + if let Some(c1) = pstr.as_str_from(n).chars().next() { + if c1 != c2 { + return PStrCmpResult::Ordered(c2.cmp(&c1)); + } + + let n1 = n + c1.len_utf8(); + + if n1 < pstr_atom.len() { + step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1); + + if consolidate_step(i2, &step_2) { + r2 = i2.step(step_2.next_hare); continue; + } else { + break; } } else { - r1 = i1.next(); - continue; + let c1_result = consolidate_step(i1, &step_1); + let c2_result = consolidate_step(i2, &step_2); + + if c1_result { + r1 = i1.step(i1.brent_st.hare); + } + + if c2_result { + r2 = i2.step(i2.brent_st.hare); + } + + if c1_result && c2_result { + continue; + } else { + break; + } } } else { - unreachable!() + if consolidate_step(i1, &step_1) { + r1 = i1.step(step_1.next_hare); + continue; + } else { + break; + } } } - (PStrIteratee::PStrSegment(h1, n1), PStrIteratee::PStrSegment(h2, n2)) => { - match (&i1.machine_st.heap[h1], &i2.machine_st.heap[h2]) { - ( - &HeapCellValue::PartialString(ref pstr1, _), - &HeapCellValue::PartialString(ref pstr2, _), - ) => { - let str1 = pstr1.as_str_from(n1); - let str2 = pstr2.as_str_from(n2); - - if str1.starts_with(str2) { - r1 = Some(PStrIteratee::PStrSegment(h1, n1 + str2.len())); - r2 = i2.next(); + (PStrIteratee::PStrSegment(f1, pstr1_atom, n1), + PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => { + if pstr1_atom == pstr2_atom && n1 == n2 { + let c_result1 = consolidate_step(i1, &step_1); + let c_result2 = consolidate_step(i2, &step_2); + + if c_result1 { + r1 = i1.step(step_1.next_hare); + } + + if c_result2 { + r2 = i2.step(step_2.next_hare); + } + + if c_result1 && c_result2 { + continue; + } + + break; + } + + let pstr1 = PartialString::from(pstr1_atom); + let pstr2 = PartialString::from(pstr2_atom); + + let str1 = pstr1.as_str_from(n1); + let str2 = pstr2.as_str_from(n2); + match str1.len().cmp(&str2.len()) { + Ordering::Equal if str1 == str2 => { + let c_result1 = consolidate_step(i1, &step_1); + let c_result2 = consolidate_step(i2, &step_2); + + if c_result1 { + r1 = i1.step(step_1.next_hare); + } + + if c_result2 { + r2 = i2.step(step_2.next_hare); + } + + if c_result1 && c_result2 { continue; - } else if str2.starts_with(str1) { - r1 = i1.next(); - r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len())); + } + + break; + } + Ordering::Less if str2.starts_with(str1) => { + step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); + + if consolidate_step(i1, &step_1) { + r1 = i1.step(step_1.next_hare); + continue; + } else { + break; + } + } + Ordering::Greater if str1.starts_with(str2) => { + step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); + if consolidate_step(i2, &step_2) { + r2 = i2.step(step_2.next_hare); continue; } else { - return str1.partial_cmp(str2); + break; } } _ => { - unreachable!() + return PStrCmpResult::Ordered(str1.cmp(str2)); } } } } - - r1 = i1.next(); - r2 = i2.next(); - - continue; } } - let ordering = if r1.is_none() { - mem::swap(&mut r1, &mut r2); - Ordering::Less - } else { - Ordering::Greater - }; - - let machine_st = i1.machine_st; + break; + } - let check_focuses = || match (i1.focus(), i2.focus()) { - (Addr::EmptyList, Addr::EmptyList) => Some(Ordering::Equal), - (Addr::EmptyList, _) => Some(Ordering::Less), - (_, Addr::EmptyList) => Some(Ordering::Greater), - _ => None, - }; + // to have a cyclic term, the cell at i1.focus must be: + // + // 1) 'continuable' as a cell in a string traversal, and, + // 2) matchable by compare_pstr_prefixes to the cell at i2.focus. + // + // If both cells are continuable they must have been encountered + // and thus matched by the compare_pstr_prefixes loop previously, + // so here it suffices to check if they are both continuable. + + if i1.focus == i2.focus { + PStrCmpResult::Ordered(Ordering::Equal) + } else if i1.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Less) + } else if i2.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Greater) + } else if i1.is_continuable() { + if i2.is_continuable() { + return PStrCmpResult::Ordered(Ordering::Equal); + } - return match r1 { - Some(PStrIteratee::PStrSegment(h, n)) => { - if let &HeapCellValue::PartialString(ref pstr, _) = &machine_st.heap[h] { - if pstr.as_str_from(n).chars().next().is_some() { - Some(ordering) - } else { - check_focuses() - } - } else { - unreachable!() - } - } - Some(PStrIteratee::Char(_)) => Some(ordering), - None => check_focuses(), - }; + PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) + } else if i2.is_continuable() { + PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) + } else { + PStrCmpResult::Unordered } } -#[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); +#[cfg(test)] +mod test { + use super::*; + use crate::machine::mock_wam::*; - 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()); + #[test] + fn pstr_iter_tests() { + let mut wam = MockWAM::new(); - s_offset += s[s_offset..].len(); - return Some(s_offset); - } else { - return None; - } - } - _ => { - unreachable!() - } - }, + let pstr_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "abc ", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + ); + assert_eq!(iter.next(), None); + + assert!(!iter.at_string_terminator()); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "def", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + ); + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0)) + ); + + assert_eq!(iter.next(), None); + assert!(!iter.at_string_terminator()); } - if s[s_offset..].is_empty() { - return Some(s_offset); + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + ); + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0)) + ); + + assert_eq!(iter.next(), None); + assert!(iter.at_string_terminator()); } - } - Some(s_offset) + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + while let Some(_) = iter.next() {} + + assert!(!iter.at_string_terminator()); + } + + { + let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); + let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + compare_pstr_prefixes(&mut iter1, &mut iter2), + PStrCmpResult::Ordered(Ordering::Equal) + ); + } + + { + let second_h = wam.machine_st.heap.len(); + + // construct a structurally similar but different cyclic partial string + // matching the one beginning at wam.machine_st.heap[0]. + + put_partial_string( + &mut wam.machine_st.heap, + "ab", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+2)); + + put_partial_string( + &mut wam.machine_st.heap, + "c ", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+4)); + + wam.machine_st.heap.push(pstr_second_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+6)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(second_h)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); + let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h); + + assert_eq!( + compare_pstr_prefixes(&mut iter1, &mut iter2), + PStrCmpResult::Ordered(Ordering::Equal) + ); + } + + wam.machine_st.heap.clear(); + + put_partial_string( + &mut wam.machine_st.heap, + "abc ", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_cell = wam.machine_st.heap[0]; + + wam.machine_st.heap[1] = list_loc_as_cell!(2); + + wam.machine_st.heap.push(char_as_cell!('a')); + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(char_as_cell!('b')); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(heap_loc_as_cell!(7)); + + { + let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); + let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 6); + + assert_eq!( + compare_pstr_prefixes(&mut iter1, &mut iter2), + PStrCmpResult::FirstIterContinuable(PStrIteratee::Char(1, 'a')), + ); + + assert_eq!(iter2.focus, heap_loc_as_cell!(7)); + } + + // test "abc" = [X,Y,Z]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "abc", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(heap_loc_as_cell!(4)); + + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(heap_loc_as_cell!(6)); + + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!( + wam.machine_st.heap[2], + char_as_cell!('a'), + ); + + assert_eq!( + wam.machine_st.heap[4], + char_as_cell!('b'), + ); + + assert_eq!( + wam.machine_st.heap[6], + char_as_cell!('c'), + ); + + // test "abc" = [X,Y,Z|D]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "abc", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X + + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(heap_loc_as_cell!(4)); // Y + + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(heap_loc_as_cell!(6)); // Z + + wam.machine_st.heap.push(heap_loc_as_cell!(7)); // D + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!(wam.machine_st.fail, false); + + assert_eq!( + wam.machine_st.heap[2], + char_as_cell!('a'), + ); + + assert_eq!( + wam.machine_st.heap[4], + char_as_cell!('b'), + ); + + assert_eq!( + wam.machine_st.heap[6], + char_as_cell!('c'), + ); + + assert_eq!( + wam.machine_st.heap[7], + empty_list_as_cell!(), + ); + + // test "d" = [d]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "d", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(char_as_cell!('d')); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!(wam.machine_st.fail, false); + + // test "abc" = [X,b,Z]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "abc", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(char_as_cell!('b')); + + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(heap_loc_as_cell!(6)); + + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!(wam.machine_st.fail, false); + + assert_eq!( + wam.machine_st.heap[2], + char_as_cell!('a'), + ); + + assert_eq!( + wam.machine_st.heap[4], + char_as_cell!('b'), + ); + + assert_eq!( + wam.machine_st.heap[6], + char_as_cell!('c'), + ); + + // test "abcdef" = [a,b,c|X]. + + wam.machine_st.heap.clear(); + + put_complete_string( + &mut wam.machine_st.heap, + "abcdef", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + unify!(wam.machine_st, heap_loc_as_cell!(0), pstr_loc_as_cell!(1)); + + print_heap_terms(wam.machine_st.heap.iter(), 0); + + assert_eq!(wam.machine_st.fail, false); + + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef"))); + assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4)); + assert_eq!(wam.machine_st.heap[6], fixnum_as_cell!(Fixnum::build_with("abc".len() as i64))); + + // test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1)) + ); + + // assert!(iter.next().is_none()); + + while let Some(_) = iter.next() {} + } + } } diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index b93f270ef..e2c74be17 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -1,12 +1,10 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{atom, clause_name, rc_atom}; - +use crate::atom_table::*; +use crate::clause_types::*; use crate::forms::*; use crate::iterators::*; -use crate::machine::load_state::*; +use crate::machine::loader::*; use crate::machine::machine_errors::*; -use crate::machine::*; +use crate::parser::ast::*; use indexmap::IndexSet; @@ -30,89 +28,81 @@ pub(crate) enum CutContext { HasCutVariable, } -pub(crate) fn fold_by_str(terms: I, mut term: Term, sym: ClauseName) -> Term +pub(crate) fn fold_by_str(terms: I, mut term: Term, sym: Atom) -> 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 = Term::Clause(Cell::default(), sym, vec![prec, term]); } term } pub(crate) fn to_op_decl( - prec: usize, - spec: &str, - name: ClauseName, + prec: u16, + spec: Atom, + name: Atom, ) -> Result { match spec { - "xfx" => Ok(OpDecl::new(prec, XFX, name)), - "xfy" => Ok(OpDecl::new(prec, XFY, name)), - "yfx" => Ok(OpDecl::new(prec, YFX, name)), - "fx" => Ok(OpDecl::new(prec, FX, name)), - "fy" => Ok(OpDecl::new(prec, FY, name)), - "xf" => Ok(OpDecl::new(prec, XF, name)), - "yf" => Ok(OpDecl::new(prec, YF, name)), + atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)), + atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)), + atom!("yfx") => Ok(OpDecl::new(OpDesc::build_with(prec, YFX as u8), name)), + atom!("fx") => Ok(OpDecl::new(OpDesc::build_with(prec, FX as u8), name)), + atom!("fy") => Ok(OpDecl::new(OpDesc::build_with(prec, FY as u8), name)), + atom!("xf") => Ok(OpDecl::new(OpDesc::build_with(prec, XF as u8), name)), + atom!("yf") => Ok(OpDecl::new(OpDesc::build_with(prec, YF as u8), name)), _ => Err(CompilationError::InconsistentEntry), } } fn setup_op_decl( - mut terms: Vec>, - atom_tbl: TabledData, + mut terms: Vec, + atom_tbl: &mut AtomTable, ) -> 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), + let name = match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => name, + Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()), _ => return Err(CompilationError::InconsistentEntry), }; - let spec = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Atom(name, _)) => name, - Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl), + let spec = match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => name, + Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()), _ => return Err(CompilationError::InconsistentEntry), }; - let prec = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) { + let prec = match terms.pop().unwrap() { + Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) { Ok(n) if n <= 1200 => n, _ => return Err(CompilationError::InconsistentEntry), }, _ => return Err(CompilationError::InconsistentEntry), }; - to_op_decl(prec, spec.as_str(), name) + to_op_decl(prec, spec, name) } fn setup_predicate_indicator(term: &mut Term) -> Result { match term { - Term::Clause(_, ref slash, ref mut terms, Some(_)) - if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 => + Term::Clause(_, slash, ref mut terms) + if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 => { - let arity = *terms.pop().unwrap(); - let name = *terms.pop().unwrap(); - - let arity = arity - .into_constant() - .and_then(|c| match c { - Constant::Integer(n) => n.to_usize(), - Constant::Fixnum(n) => usize::try_from(n).ok(), - _ => None, - }) - .ok_or(CompilationError::InvalidModuleExport)?; + let arity = terms.pop().unwrap(); + let name = terms.pop().unwrap(); - let name = name - .into_constant() - .and_then(|c| c.to_atom()) - .ok_or(CompilationError::InvalidModuleExport)?; + let arity = match arity { + Term::Literal(_, Literal::Integer(n)) => n.to_usize(), + Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + _ => None, + }.ok_or(CompilationError::InvalidModuleExport)?; + + let name = match name { + Term::Literal(_, Literal::Atom(name)) => Some(name), + _ => None, + }.ok_or(CompilationError::InvalidModuleExport)?; - if slash.as_str() == "/" { + if *slash == atom!("/") { Ok((name, arity)) } else { Ok((name, arity + 2)) @@ -148,13 +138,13 @@ fn setup_scoped_predicate_indicator(term: &mut Term) -> Result, + atom_tbl: &mut AtomTable, ) -> 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" { + if let Term::Clause(_, name, terms) = term { + if terms.len() == 3 && name == atom!("op") { Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?)) } else { Err(CompilationError::InvalidModuleDecl) @@ -167,18 +157,18 @@ fn setup_module_export( pub(super) fn setup_module_export_list( mut export_list: Term, - atom_tbl: TabledData, + atom_tbl: &mut AtomTable, ) -> Result, CompilationError> { let mut exports = vec![]; while let Term::Cons(_, t1, t2) = export_list { - let module_export = setup_module_export(*t1, atom_tbl.clone())?; + let module_export = setup_module_export(*t1, atom_tbl)?; exports.push(module_export); export_list = *t2; } - if let Term::Constant(_, Constant::EmptyList) = export_list { + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { Ok(exports) } else { Err(CompilationError::InvalidModuleDecl) @@ -186,35 +176,33 @@ pub(super) fn setup_module_export_list( } fn setup_module_decl( - mut terms: Vec>, - atom_tbl: TabledData, + mut terms: Vec, + atom_tbl: &mut AtomTable, ) -> Result { - let export_list = *terms.pop().unwrap(); - let name = terms - .pop() - .unwrap() - .into_constant() - .and_then(|c| c.to_atom()) - .ok_or(CompilationError::InvalidModuleDecl)?; + let export_list = terms.pop().unwrap(); + let name = terms.pop().unwrap(); + + let name = match name { + Term::Literal(_, Literal::Atom(name)) => Some(name), + _ => None, + }.ok_or(CompilationError::InvalidModuleDecl)?; let exports = setup_module_export_list(export_list, atom_tbl)?; + Ok(ModuleDecl { name, exports }) } -fn setup_use_module_decl(mut terms: Vec>) -> Result { - match *terms.pop().unwrap() { - Term::Clause(_, ref name, ref mut terms, None) - if name.as_str() == "library" && terms.len() == 1 => +fn setup_use_module_decl(mut terms: Vec) -> Result { + match terms.pop().unwrap() { + Term::Clause(_, name, mut terms) + if name == atom!("library") && terms.len() == 1 => { - terms - .pop() - .unwrap() - .into_constant() - .and_then(|c| c.to_atom()) - .map(|c| ModuleSource::Library(c)) - .ok_or(CompilationError::InvalidUseModuleDecl) + match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), + _ => Err(CompilationError::InvalidModuleDecl), + } } - Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())), + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), _ => Err(CompilationError::InvalidUseModuleDecl), } } @@ -224,10 +212,10 @@ fn setup_double_quotes(mut terms: Vec>) -> Result { match dbl_quotes { - Term::Constant(_, Constant::Atom(name, _)) => { + Term::Literal(_, Literal::Atom(name, _)) => { match name.as_str() { "atom" => Ok(DoubleQuotes::Atom), "chars" => Ok(DoubleQuotes::Chars), @@ -250,34 +238,31 @@ fn setup_double_quotes(mut terms: Vec>) -> Result); fn setup_qualified_import( - mut terms: Vec>, - atom_tbl: TabledData, + mut terms: Vec, + atom_tbl: &mut AtomTable, ) -> 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 => + let mut export_list = terms.pop().unwrap(); + let module_src = match terms.pop().unwrap() { + Term::Clause(_, name, mut terms) + if name == atom!("library") && terms.len() == 1 => { - terms - .pop() - .unwrap() - .into_constant() - .and_then(|c| c.to_atom()) - .map(|c| ModuleSource::Library(c)) - .ok_or(CompilationError::InvalidUseModuleDecl) + match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), + _ => Err(CompilationError::InvalidModuleDecl), + } } - Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())), + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), _ => Err(CompilationError::InvalidUseModuleDecl), }?; let mut exports = IndexSet::new(); while let Term::Cons(_, t1, t2) = export_list { - exports.insert(setup_module_export(*t1, atom_tbl.clone())?); + exports.insert(setup_module_export(*t1, atom_tbl)?); export_list = *t2; } - if let Term::Constant(_, Constant::EmptyList) = export_list { + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { Ok((module_src, exports)) } else { Err(CompilationError::InvalidModuleDecl) @@ -322,29 +307,29 @@ fn setup_qualified_import( * - * ? */ -fn setup_meta_predicate<'a>( - mut terms: Vec>, - load_state: &LoadState<'a>, -) -> Result<(ClauseName, ClauseName, Vec), CompilationError> { +fn setup_meta_predicate<'a, LS: LoadState<'a>>( + mut terms: Vec, + loader: &mut Loader<'a, LS>, +) -> Result<(Atom, Atom, Vec), CompilationError> { fn get_name_and_meta_specs( - name: ClauseName, - terms: &mut [Box], - ) -> Result<(ClauseName, Vec), CompilationError> { + name: Atom, + terms: &mut [Term], + ) -> Result<(Atom, 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::Plus, - "-" => MetaSpec::Minus, - "?" => MetaSpec::Either, + match meta_spec { + Term::Literal(_, Literal::Atom(meta_spec)) => { + let meta_spec = match meta_spec { + atom!("+") => MetaSpec::Plus, + atom!("-") => MetaSpec::Minus, + atom!("?") => MetaSpec::Either, _ => return Err(CompilationError::InvalidMetaPredicateDecl), }; meta_specs.push(meta_spec); } - Term::Constant(_, Constant::Fixnum(n)) => match usize::try_from(*n) { + Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) { Ok(n) if n <= MAX_ARITY => { meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); } @@ -361,16 +346,15 @@ fn setup_meta_predicate<'a>( Ok((name, meta_specs)) } - match *terms.pop().unwrap() { - Term::Clause(_, name, mut terms, _) if name.as_str() == ":" && terms.len() == 2 => { - let spec = *terms.pop().unwrap(); - let module_name = *terms.pop().unwrap(); + match terms.pop().unwrap() { + Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => { + let spec = terms.pop().unwrap(); + let module_name = terms.pop().unwrap(); match module_name { - Term::Constant(_, Constant::Atom(module_name, _)) => match spec { - Term::Clause(_, name, mut terms, _) => { + Term::Literal(_, Literal::Atom(module_name)) => match spec { + Term::Clause(_, name, mut terms) => { let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; - Ok((module_name, name, meta_specs)) } _ => Err(CompilationError::InvalidMetaPredicateDecl), @@ -378,10 +362,10 @@ fn setup_meta_predicate<'a>( _ => Err(CompilationError::InvalidMetaPredicateDecl), } } - Term::Clause(_, name, mut terms, _) => { + Term::Clause(_, name, mut terms) => { let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; Ok(( - load_state.compilation_target.module_name(), + loader.payload.compilation_target.module_name(), name, meta_specs, )) @@ -420,11 +404,11 @@ fn merge_clauses(tls: &mut VecDeque) -> Result, name: ClauseName) { +fn mark_cut_variables_as(terms: &mut Vec, name: Atom) { for term in terms.iter_mut() { match term { - &mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => { - *var = name.clone() + &mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => { + *var = name; } _ => {} } @@ -433,12 +417,12 @@ fn mark_cut_variables_as(terms: &mut Vec, name: ClauseName) { fn mark_cut_variable(term: &mut Term) -> bool { let cut_var_found = match term { - &mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true, + &mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true, _ => false, }; if cut_var_found { - *term = Term::Var(Cell::default(), rc_atom!("!")); + *term = Term::Var(Cell::default(), Rc::new(String::from("!"))); true } else { false @@ -463,21 +447,21 @@ fn check_for_internal_if_then(terms: &mut Vec) { return; } - if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() { - if name.as_str() != "->" || subterms.len() != 2 { + if let Some(Term::Clause(_, name, ref subterms)) = terms.last() { + if *name != atom!("->") || subterms.len() != 2 { return; } } else { return; } - if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() { - let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ",")); - let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ",")); + if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() { + let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(","))); + let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(","))); - conq_terms.push_front(Term::Constant( + conq_terms.push_front(Term::Literal( Cell::default(), - Constant::Atom(clause_name!("blocked_!"), None), + Literal::Atom(atom!("blocked_!")), )); while let Some(term) = pre_cut_terms.pop_back() { @@ -489,37 +473,44 @@ fn check_for_internal_if_then(terms: &mut Vec) { terms.push(fold_by_str( conq_terms.into_iter(), tail_term, - clause_name!(","), + atom!(","), )); } } -pub(super) fn setup_declaration<'a>( - load_state: &LoadState<'a>, - mut terms: Vec>, +pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( + loader: &mut Loader<'a, LS>, + mut terms: Vec, ) -> Result { - let term = *terms.pop().unwrap(); - let atom_tbl = load_state.wam.machine_st.atom_tbl.clone(); + let term = terms.pop().unwrap(); match term { - Term::Clause(_, name, mut terms, _) => match (name.as_str(), terms.len()) { - ("dynamic", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; + Term::Clause(_, name, mut terms) => match (name, terms.len()) { + (atom!("dynamic"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; Ok(Declaration::Dynamic(name, arity)) } - ("module", 2) => Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)), - ("op", 3) => Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)), - ("non_counted_backtracking", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; + (atom!("module"), 2) => { + let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; + Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)) + } + (atom!("op"), 3) => { + let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; + Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)) + } + (atom!("non_counted_backtracking"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; Ok(Declaration::NonCountedBacktracking(name, arity)) } - ("use_module", 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), - ("use_module", 2) => { + (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), + (atom!("use_module"), 2) => { + let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; let (name, exports) = setup_qualified_import(terms, atom_tbl)?; + Ok(Declaration::UseQualifiedModule(name, exports)) } - ("meta_predicate", 1) => { - let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?; + (atom!("meta_predicate"), 1) => { + let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?; Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) } _ => Err(CompilationError::InconsistentEntry), @@ -529,43 +520,43 @@ pub(super) fn setup_declaration<'a>( } #[inline] -fn clause_to_query_term<'a>( - load_state: &mut LoadState<'a>, - name: ClauseName, - terms: Vec>, - fixity: Option, +fn clause_to_query_term<'a, LS: LoadState<'a>>( + loader: &mut Loader<'a, LS>, + name: Atom, + terms: Vec, ) -> QueryTerm { - let ct = load_state.get_clause_type(name, terms.len(), fixity); + let ct = loader.get_clause_type(name, terms.len()); QueryTerm::Clause(Cell::default(), ct, terms, false) } #[inline] -fn qualified_clause_to_query_term<'a>( - load_state: &mut LoadState<'a>, - module_name: ClauseName, - name: ClauseName, - terms: Vec>, - fixity: Option, +fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( + loader: &mut Loader<'a, LS>, + module_name: Atom, + name: Atom, + terms: Vec, ) -> QueryTerm { - let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity); + let ct = loader.get_qualified_clause_type(module_name, name, terms.len()); QueryTerm::Clause(Cell::default(), ct, terms, false) } #[derive(Debug)] pub(crate) struct Preprocessor { + flags: MachineFlags, queue: VecDeque>, } impl Preprocessor { - pub(super) fn new() -> Self { + 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), + Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term), _ => Err(CompilationError::InadmissibleFact), } } @@ -579,20 +570,17 @@ impl Preprocessor { } } - vars.insert(rc_atom!("!")); + vars.insert(Rc::new(String::from("!"))); vars.into_iter() .map(|v| Term::Var(Cell::default(), v)) .collect() } fn fabricate_rule_body(&self, vars: &Vec, body_term: Term) -> Term { - let vars_of_head = vars.iter().cloned().map(Box::new).collect(); - let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None); - - let rule = vec![Box::new(head_term), Box::new(body_term)]; - let turnstile = clause_name!(":-"); + let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone()); + let rule = vec![head_term, body_term]; - Term::Clause(Cell::default(), turnstile, rule, None) + Term::Clause(Cell::default(), atom!(":-"), rule) } // the terms form the body of the rule. We create a head, by @@ -609,16 +597,16 @@ impl Preprocessor { fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque) { let vars = self.compute_head(&body_term); - let results = unfold_by_str(body_term, ";") + let results = unfold_by_str(body_term, atom!(";")) .into_iter() .map(|term| { - let mut subterms = unfold_by_str(term, ","); + let mut subterms = unfold_by_str(term, atom!(",")); mark_cut_variables(&mut subterms); check_for_internal_if_then(&mut subterms); let term = subterms.pop().unwrap(); - let clause = fold_by_str(subterms.into_iter(), term, clause_name!(",")); + let clause = fold_by_str(subterms.into_iter(), term, atom!(",")); self.fabricate_rule_body(&vars, clause) }) @@ -628,80 +616,78 @@ impl Preprocessor { } 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!("!"); + let mut prec_seq = unfold_by_str(prec, atom!(",")); + let comma_sym = atom!(","); + let cut_sym = Literal::Atom(atom!("!")); - prec_seq.push(Term::Constant(Cell::default(), cut_sym)); + prec_seq.push(Term::Literal(Cell::default(), cut_sym)); - mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!")); + mark_cut_variables_as(&mut prec_seq, atom!("blocked_!")); - let mut conq_seq = unfold_by_str(conq, ","); + let mut conq_seq = unfold_by_str(conq, atom!(",")); mark_cut_variables(&mut conq_seq); prec_seq.extend(conq_seq.into_iter()); - let back_term = Box::new(prec_seq.pop().unwrap()); - let front_term = Box::new(prec_seq.pop().unwrap()); + let back_term = prec_seq.pop().unwrap(); + let front_term = prec_seq.pop().unwrap(); let body_term = Term::Clause( Cell::default(), - comma_sym.clone(), + comma_sym, vec![front_term, back_term], - None, ); self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym)) } - fn to_query_term<'a>( + fn to_query_term<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, term: Term, ) -> Result { match term { - Term::Constant(_, Constant::Atom(name, fixity)) => { - if name.as_str() == "!" || name.as_str() == "blocked_!" { + Term::Literal(_, Literal::Atom(name)) => { + if name == atom!("!") || name == atom!("blocked_!") { Ok(QueryTerm::BlockedCut) } else { - Ok(clause_to_query_term(load_state, name, vec![], fixity)) + Ok(clause_to_query_term(loader, name, vec![])) } } - Term::Constant(_, Constant::Char('!')) => Ok(QueryTerm::BlockedCut), + Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut), Term::Var(_, ref v) if v.as_str() == "!" => { Ok(QueryTerm::UnblockedCut(Cell::default())) } - Term::Clause(r, name, mut terms, fixity) => match (name.as_str(), terms.len()) { - (";", 2) => { - let term = Term::Clause(r, name.clone(), terms, fixity); + Term::Clause(r, name, mut terms) => match (name, terms.len()) { + (atom!(";"), 2) => { + let term = Term::Clause(r, name, terms); let (stub, clauses) = self.fabricate_disjunct(term); self.queue.push_back(clauses); Ok(QueryTerm::Jump(stub)) } - ("->", 2) => { - let conq = *terms.pop().unwrap(); - let prec = *terms.pop().unwrap(); + (atom!("->"), 2) => { + let conq = terms.pop().unwrap(); + let prec = terms.pop().unwrap(); let (stub, clauses) = self.fabricate_if_then(prec, conq); self.queue.push_back(clauses); Ok(QueryTerm::Jump(stub)) } - ("\\+", 1) => { - terms.push(Box::new(Term::Constant( + (atom!("\\+"), 1) => { + terms.push(Term::Literal( Cell::default(), - Constant::Atom(clause_name!("$fail"), None), - ))); + Literal::Atom(atom!("$fail")), + )); - let conq = - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)); + let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true"))); - let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None); - let terms = vec![Box::new(prec), Box::new(conq)]; + let prec = Term::Clause(Cell::default(), atom!("->"), terms); + let terms = vec![prec, conq]; - let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None); + let term = Term::Clause(Cell::default(), atom!(";"), terms); let (stub, clauses) = self.fabricate_disjunct(term); debug_assert!(clauses.len() > 0); @@ -709,104 +695,102 @@ impl Preprocessor { Ok(QueryTerm::Jump(stub)) } - ("$get_level", 1) => { - if let Term::Var(_, ref var) = *terms[0] { + (atom!("$get_level"), 1) => { + if let Term::Var(_, ref var) = &terms[0] { Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone())) } else { Err(CompilationError::InadmissibleQueryTerm) } } - (":", 2) => { - let predicate_name = *terms.pop().unwrap(); - let module_name = *terms.pop().unwrap(); + (atom!(":"), 2) => { + let predicate_name = terms.pop().unwrap(); + let module_name = terms.pop().unwrap(); match (module_name, predicate_name) { ( - Term::Constant(_, Constant::Atom(module_name, _)), - Term::Constant(_, Constant::Atom(predicate_name, fixity)), + Term::Literal(_, Literal::Atom(module_name)), + Term::Literal(_, Literal::Atom(predicate_name)), ) => Ok(qualified_clause_to_query_term( - load_state, + loader, module_name, predicate_name, vec![], - fixity, )), ( - Term::Constant(_, Constant::Atom(module_name, _)), - Term::Clause(_, name, terms, fixity), + Term::Literal(_, Literal::Atom(module_name)), + Term::Clause(_, name, terms), ) => Ok(qualified_clause_to_query_term( - load_state, + loader, module_name, name, terms, - fixity, )), (module_name, predicate_name) => { - terms.push(Box::new(module_name)); - terms.push(Box::new(predicate_name)); + terms.push(module_name); + terms.push(predicate_name); - Ok(clause_to_query_term(load_state, name, terms, fixity)) + Ok(clause_to_query_term(loader, name, terms)) } } } - _ => Ok(clause_to_query_term(load_state, name, terms, fixity)), + _ => Ok(clause_to_query_term(loader, name, terms)), }, Term::Var(..) => Ok(QueryTerm::Clause( Cell::default(), ClauseType::CallN, - vec![Box::new(term)], + vec![term], false, )), _ => Err(CompilationError::InadmissibleQueryTerm), } } - fn pre_query_term<'a>( + fn pre_query_term<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, term: Term, ) -> Result { match term { - Term::Clause(r, name, mut subterms, fixity) => { - if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" { - self.to_query_term(load_state, *subterms.pop().unwrap()) + Term::Clause(r, name, mut subterms) => { + if subterms.len() == 1 && name == atom!("$call_with_default_policy") { + self.to_query_term(loader, subterms.pop().unwrap()) .map(|mut query_term| { query_term.set_default_caller(); query_term }) } else { - let clause = Term::Clause(r, name, subterms, fixity); - self.to_query_term(load_state, clause) + let clause = Term::Clause(r, name, subterms); + self.to_query_term(loader, clause) } } - _ => self.to_query_term(load_state, term), + _ => self.to_query_term(loader, term), } } - fn setup_query<'a>( + fn setup_query<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, - terms: Vec>, + loader: &mut Loader<'a, LS>, + 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; + let mut term = term; - if let Term::Clause(cell, name, terms, op_spec) = term { - if name.as_str() == "," && terms.len() == 2 { - let term = Term::Clause(cell, name, terms, op_spec); - let mut subterms = unfold_by_str(term, ","); + if let Term::Clause(cell, name, terms) = term { + if name == atom!(",") && terms.len() == 2 { + let term = Term::Clause(cell, name, terms); + let mut subterms = unfold_by_str(term, atom!(",")); while let Some(subterm) = subterms.pop() { - work_queue.push_front(Box::new(subterm)); + work_queue.push_front(subterm); } continue; } else { - term = Term::Clause(cell, name, terms, op_spec); + term = Term::Clause(cell, name, terms); } } @@ -814,30 +798,30 @@ impl Preprocessor { mark_cut_variable(&mut term); } - query_terms.push(self.pre_query_term(load_state, term)?); + query_terms.push(self.pre_query_term(loader, term)?); } Ok(query_terms) } - fn setup_rule<'a>( + fn setup_rule<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, - mut terms: Vec>, + loader: &mut Loader<'a, LS>, + 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 mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?; let clauses = query_terms.drain(1..).collect(); let qt = query_terms.pop().unwrap(); - match *terms.pop().unwrap() { - Term::Clause(_, name, terms, _) => Ok(Rule { + match terms.pop().unwrap() { + Term::Clause(_, name, terms) => Ok(Rule { head: (name, terms, qt), clauses, }), - Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule { + Term::Literal(_, Literal::Atom(name)) => Ok(Rule { head: (name, vec![], qt), clauses, }), @@ -845,37 +829,37 @@ impl Preprocessor { } } - fn try_term_to_query<'a>( + fn try_term_to_query<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, - terms: Vec>, + loader: &mut Loader<'a, LS>, + terms: Vec, cut_context: CutContext, ) -> Result { Ok(TopLevel::Query(self.setup_query( - load_state, + loader, terms, cut_context, )?)) } - pub(super) fn try_term_to_tl<'a>( + pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, term: Term, cut_context: CutContext, ) -> Result { match term { - Term::Clause(r, name, terms, fixity) => { - if name.as_str() == "?-" { - self.try_term_to_query(load_state, terms, cut_context) - } else if name.as_str() == ":-" && terms.len() == 2 { + Term::Clause(r, name, terms) => { + if name == atom!("?-") { + self.try_term_to_query(loader, terms, cut_context) + } else if name == atom!(":-") && terms.len() == 2 { Ok(TopLevel::Rule(self.setup_rule( - load_state, + loader, terms, cut_context, )?)) } else { - let term = Term::Clause(r, name, terms, fixity); + let term = Term::Clause(r, name, terms); Ok(TopLevel::Fact(self.setup_fact(term)?)) } } @@ -883,30 +867,30 @@ impl Preprocessor { } } - fn try_terms_to_tls<'a, I: IntoIterator>( + fn try_terms_to_tls<'a, I: IntoIterator, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, 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)?); + results.push_back(self.try_term_to_tl(loader, term, cut_context)?); } Ok(results) } - pub(super) fn parse_queue<'a>( + pub(super) fn parse_queue<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, ) -> Result, CompilationError> { let mut queue = VecDeque::new(); while let Some(terms) = self.queue.pop_front() { let clauses = merge_clauses(&mut self.try_terms_to_tls( - load_state, + loader, terms, CutContext::HasCutVariable, )?)?; diff --git a/src/machine/stack.rs b/src/machine/stack.rs index a3c917136..1ab988cdd 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -1,16 +1,15 @@ use core::marker::PhantomData; +use crate::types::*; + use crate::machine::machine_indices::*; -use crate::machine::raw_block::*; +use crate::raw_block::*; use std::mem; use std::ops::{Index, IndexMut}; use std::ptr; -#[derive(Debug)] -struct StackTraits {} - -impl RawBlockTraits for StackTraits { +impl RawBlockTraits for Stack { #[inline] fn init_size() -> usize { 10 * 1024 * 1024 @@ -18,31 +17,23 @@ impl RawBlockTraits for StackTraits { #[inline] fn align() -> usize { - mem::align_of::() - } - - #[inline] - fn base_offset(base: *const u8) -> *const u8 { - unsafe { base.offset(Self::align() as isize) } + mem::align_of::() } } -const fn prelude_size() -> usize { - let size = mem::size_of::(); - let align = mem::align_of::(); - - (size & !(align - 1)) + align +#[inline(always)] +pub const fn prelude_size() -> usize { + mem::size_of::() } #[derive(Debug)] -pub(crate) struct Stack { - buf: RawBlock, - _marker: PhantomData, +pub struct Stack { + buf: RawBlock, + _marker: PhantomData, } impl Drop for Stack { fn drop(&mut self) { - self.drop_in_place(); self.buf.deallocate(); } } @@ -57,7 +48,7 @@ pub(crate) struct AndFramePrelude { pub(crate) univ_prelude: FramePrelude, pub(crate) e: usize, pub(crate) cp: LocalCodePtr, - pub(crate) interrupt_cp: LocalCodePtr, + pub(crate) interrupt_cp: LocalCodePtr, // TODO: get rid of it! } #[derive(Debug)] @@ -67,22 +58,22 @@ pub(crate) struct AndFrame { impl AndFrame { pub(crate) fn size_of(num_cells: usize) -> usize { - prelude_size::() + num_cells * mem::size_of::() + prelude_size::() + num_cells * mem::size_of::() } } impl Index for AndFrame { - type Output = Addr; + type Output = HeapCellValue; fn index(&self, index: usize) -> &Self::Output { let prelude_offset = prelude_size::(); - let index_offset = (index - 1) * mem::size_of::(); + let index_offset = (index - 1) * mem::size_of::(); unsafe { let ptr = mem::transmute::<&AndFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &*(ptr as *const Addr) + &*(ptr as *const HeapCellValue) } } } @@ -90,13 +81,35 @@ impl Index for AndFrame { impl IndexMut for AndFrame { fn index_mut(&mut self, index: usize) -> &mut Self::Output { let prelude_offset = prelude_size::(); - let index_offset = (index - 1) * mem::size_of::(); + let index_offset = (index - 1) * mem::size_of::(); unsafe { let ptr = mem::transmute::<&mut AndFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &mut *(ptr as *mut Addr) + &mut *(ptr as *mut HeapCellValue) + } + } +} + +impl Index for Stack { + type Output = HeapCellValue; + + #[inline] + fn index(&self, index: usize) -> &Self::Output { + unsafe { + let ptr = self.buf.base as usize + index; + &*(ptr as *const HeapCellValue) + } + } +} + +impl IndexMut for Stack { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + unsafe { + let ptr = self.buf.base as usize + index; + &mut *(ptr as *mut HeapCellValue) } } } @@ -119,18 +132,18 @@ pub(crate) struct OrFrame { } impl Index for OrFrame { - type Output = Addr; + type Output = HeapCellValue; #[inline] fn index(&self, index: usize) -> &Self::Output { let prelude_offset = prelude_size::(); - let index_offset = index * mem::size_of::(); + let index_offset = index * mem::size_of::(); unsafe { let ptr = mem::transmute::<&OrFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &*(ptr as *const Addr) + &*(ptr as *const HeapCellValue) } } } @@ -139,20 +152,20 @@ impl IndexMut for OrFrame { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { let prelude_offset = prelude_size::(); - let index_offset = index * mem::size_of::(); + let index_offset = index * mem::size_of::(); unsafe { let ptr = mem::transmute::<&mut OrFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &mut *(ptr as *mut Addr) + &mut *(ptr as *mut HeapCellValue) } } } impl OrFrame { pub(crate) fn size_of(num_cells: usize) -> usize { - prelude_size::() + num_cells * mem::size_of::() + prelude_size::() + num_cells * mem::size_of::() } } @@ -164,26 +177,39 @@ impl Stack { } } + #[inline(always)] + unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 { + loop { + let ptr = self.buf.alloc(frame_size); + + if ptr.is_null() { + self.buf.grow(); + } else { + return ptr; + } + } + } + pub(crate) fn allocate_and_frame(&mut self, num_cells: usize) -> usize { let frame_size = AndFrame::size_of(num_cells); unsafe { - let new_top = self.buf.new_block(frame_size); - let e = self.buf.top as usize - self.buf.base as usize; + let e = self.buf.ptr as usize - self.buf.base as usize; + let new_ptr = self.alloc(frame_size); + let mut offset = prelude_size::(); for idx in 0..num_cells { - let offset = prelude_size::() + idx * mem::size_of::(); ptr::write( - (self.buf.top as usize + offset) as *mut Addr, - Addr::StackCell(e, idx + 1), + (new_ptr as usize + offset) as *mut HeapCellValue, + stack_loc_as_cell!(AndFrame, e, idx + 1), ); + + offset += mem::size_of::(); } - let and_frame = &mut *(self.buf.top as *mut AndFrame); + let and_frame = &mut *(new_ptr as *mut AndFrame); and_frame.prelude.univ_prelude.num_cells = num_cells; - self.buf.top = new_top; - e } } @@ -192,27 +218,27 @@ impl Stack { let frame_size = OrFrame::size_of(num_cells); unsafe { - let new_top = self.buf.new_block(frame_size); - let b = self.buf.top as usize - self.buf.base as usize; + let b = self.buf.ptr as usize - self.buf.base as usize; + let new_ptr = self.alloc(frame_size); + let mut offset = prelude_size::(); for idx in 0..num_cells { - let offset = prelude_size::() + idx * mem::size_of::(); ptr::write( - (self.buf.top as usize + offset) as *mut Addr, - Addr::StackCell(b, idx), + (new_ptr as usize + offset) as *mut HeapCellValue, + stack_loc_as_cell!(OrFrame, b, idx), ); + + offset += mem::size_of::(); } - let or_frame = &mut *(self.buf.top as *mut OrFrame); + let or_frame = &mut *(new_ptr as *mut OrFrame); or_frame.prelude.univ_prelude.num_cells = num_cells; - self.buf.top = new_top; - b } } - #[inline] + #[inline(always)] pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame { unsafe { let ptr = self.buf.base as usize + e; @@ -220,7 +246,7 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame { unsafe { let ptr = self.buf.base as usize + e; @@ -228,7 +254,7 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame { unsafe { let ptr = self.buf.base as usize + b; @@ -236,7 +262,7 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame { unsafe { let ptr = self.buf.base as usize + b; @@ -244,31 +270,65 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn truncate(&mut self, b: usize) { - if b == 0 { - self.inner_truncate(mem::align_of::()); - } else { - self.inner_truncate(b); + let base = self.buf.base as usize + b; + + if base < self.buf.ptr as usize { + self.buf.ptr = base as *mut _; } } +} - #[inline] - fn inner_truncate(&mut self, b: usize) { - let base = b + self.buf.base as usize; +#[cfg(test)] +mod tests { + use super::*; + + use crate::machine::mock_wam::*; + + #[test] + fn stack_tests() { + let mut wam = MockWAM::new(); - if base < self.buf.top as usize { - self.buf.top = base as *const _; + let e = wam.machine_st.stack.allocate_and_frame(10); // create an AND frame! + let and_frame = wam.machine_st.stack.index_and_frame_mut(e); + + assert_eq!( + e, + 0// 10 * mem::size_of::() + prelude_size::() + ); + + assert_eq!(and_frame.prelude.univ_prelude.num_cells, 10); + + for idx in 0..10 { + assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, e, idx + 1)); + } + + and_frame[5] = empty_list_as_cell!(); + + assert_eq!(and_frame[5], empty_list_as_cell!()); + + let b = wam.machine_st.stack.allocate_or_frame(5); + + let or_frame = wam.machine_st.stack.index_or_frame_mut(b); + + for idx in 0..5 { + assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx)); + } + + let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame! + let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e); + + for idx in 0..9 { + assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1)); } - } - pub(crate) fn drop_in_place(&mut self) { - self.truncate(mem::align_of::()); + let and_frame = wam.machine_st.stack.index_and_frame(e); + assert_eq!(and_frame[5], empty_list_as_cell!()); - debug_assert!(if self.buf.top.is_null() { - self.buf.top == self.buf.base - } else { - self.buf.top as usize == self.buf.base as usize + mem::align_of::() - }); + assert_eq!( + wam.machine_st.stack[stack_loc!(AndFrame, e, 5)], + empty_list_as_cell!() + ); } } diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 69f660228..064d9fa8d 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1,47 +1,52 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::char_reader::*; +use crate::read::*; +use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::read::readline::*; -use crate::read::PrologStream; +use crate::types::*; + +pub use modular_bitfield::prelude::*; -use std::cell::RefCell; use std::cmp::Ordering; use std::error::Error; use std::fmt; -use std::fs::File; -use std::hash::{Hash, Hasher}; +use std::fs::{File, OpenOptions}; +use std::hash::{Hash}; use std::io; -use std::io::{stderr, stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; +use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::mem; -use std::net::{Shutdown, TcpStream}; -use std::ops::DerefMut; -use std::rc::Rc; +use std::net::{TcpStream, Shutdown}; +use std::ops::{Deref, DerefMut}; +use std::ptr; use native_tls::TlsStream; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum StreamType { +#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] +#[bits = 1] +pub enum StreamType { Binary, Text, } impl StreamType { #[inline] - pub(crate) fn as_str(&self) -> &'static str { + pub(crate) fn as_atom(&self) -> Atom { match self { - StreamType::Binary => "binary_stream", - StreamType::Text => "text_stream", + StreamType::Binary => atom!("binary_stream"), + StreamType::Text => atom!("text_stream"), } } #[inline] - pub(crate) fn as_property_str(&self) -> &'static str { + pub(crate) fn as_property_atom(&self) -> Atom { match self { - StreamType::Binary => "binary", - StreamType::Text => "text", + StreamType::Binary => atom!("binary"), + StreamType::Text => atom!("text"), } } @@ -54,14 +59,16 @@ impl StreamType { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum EOFAction { +#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] +#[bits = 2] +pub enum EOFAction { EOFCode, Error, Reset, } -#[derive(Debug, PartialEq)] +#[derive(Debug, BitfieldSpecifier, Copy, Clone, PartialEq)] +#[bits = 2] pub(crate) enum AtEndOfStream { Not, At, @@ -70,165 +77,706 @@ pub(crate) enum AtEndOfStream { impl AtEndOfStream { #[inline] - pub(crate) fn as_str(&self) -> &'static str { + pub(crate) fn as_atom(&self) -> Atom { match self { - AtEndOfStream::Not => "not", - AtEndOfStream::Past => "past", - AtEndOfStream::At => "at", + AtEndOfStream::Not => atom!("not"), + AtEndOfStream::Past => atom!("past"), + AtEndOfStream::At => atom!("at"), } } } impl EOFAction { #[inline] - pub(crate) fn as_str(&self) -> &'static str { + pub(crate) fn as_atom(&self) -> Atom { match self { - EOFAction::EOFCode => "eof_code", - EOFAction::Error => "error", - EOFAction::Reset => "reset", + EOFAction::EOFCode => atom!("eof_code"), + EOFAction::Error => atom!("error"), + EOFAction::Reset => atom!("reset"), } } } -fn parser_top_to_bytes(mut buf: Vec>) -> io::Result> { - let mut str_buf = String::new(); +#[derive(Debug)] +pub struct ByteStream(Cursor>); - while let Some(c) = buf.pop() { - str_buf.push(c?); +impl Read for ByteStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf) + } +} + +impl Write for ByteStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.write(buf) } - unsafe { - let array = str_buf.as_bytes_mut(); - array.reverse(); - Ok(Vec::from(array)) + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.0.flush() } } -/* all these streams are closed automatically when the instance is - * dropped. */ -enum StreamInstance { - Bytes(Cursor>), - InputFile(ClauseName, File), - OutputFile(ClauseName, File, bool), // File, append. - Null, - PausedPrologStream(Vec, Box), - ReadlineStream(ReadlineStream), - StaticStr(Cursor<&'static str>), - Stderr, - Stdout, - TcpStream(ClauseName, TcpStream), - TlsStream(ClauseName, TlsStream), +#[derive(Debug)] +pub struct InputFileStream { + file_name: Atom, + file: File, } -impl StreamInstance { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self { - StreamInstance::PausedPrologStream(ref mut put_back, ref mut stream) => { - let mut index = 0; +impl Read for InputFileStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.file.read(buf) + } +} - while index < buf.len() { - if let Some(b) = put_back.pop() { - buf[index] = b; - index += 1; - } else { - break; - } - } +#[derive(Debug)] +pub struct OutputFileStream { + file_name: Atom, + file: File, + is_append: bool, +} - if index == buf.len() { - Ok(buf.len()) - } else { - stream - .read(&mut buf[index..]) - .map(|bytes_read| bytes_read + index) - } - } - StreamInstance::InputFile(_, ref mut file) => file.read(buf), - StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.read(buf), - StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.read(buf), - StreamInstance::ReadlineStream(ref mut rl_stream) => rl_stream.read(buf), - StreamInstance::StaticStr(ref mut src) => src.read(buf), - StreamInstance::Bytes(ref mut cursor) => cursor.read(buf), - StreamInstance::OutputFile(..) - | StreamInstance::Stderr - | StreamInstance::Stdout - | StreamInstance::Null => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::ReadFromOutputStream, - )), +impl Write for OutputFileStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.file.write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.file.flush() + } +} + +#[derive(Debug)] +pub struct StaticStringStream { + stream: Cursor<&'static str>, +} + +impl Read for StaticStringStream { + #[inline(always)] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.stream.read(buf) + } +} + +impl CharRead for StaticStringStream { + #[inline(always)] + fn peek_char(&mut self) -> Option> { + let pos = self.stream.position() as usize; + self.stream.get_ref()[pos ..].chars().next().map(Ok) + } + + #[inline(always)] + fn consume(&mut self, nread: usize) { + self.stream.seek(SeekFrom::Current(nread as i64)).unwrap(); + } + + #[inline(always)] + fn put_back_char(&mut self, c: char) { + self.stream.seek(SeekFrom::Current(- (c.len_utf8() as i64))).unwrap(); + } +} + +#[derive(Debug)] +pub struct NamedTcpStream { + address: Atom, + tcp_stream: TcpStream, +} + +impl Read for NamedTcpStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.tcp_stream.read(buf) + } +} + +impl Write for NamedTcpStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.tcp_stream.write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.tcp_stream.flush() + } +} + +#[derive(Debug)] +pub struct NamedTlsStream { + address: Atom, + tls_stream: TlsStream, +} + +impl Read for NamedTlsStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.tls_stream.read(buf) + } +} + +impl Write for NamedTlsStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.tls_stream.write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.tls_stream.flush() + } +} + +/* +#[derive(Debug)] +pub struct NullStream {} +*/ + +#[derive(Debug)] +pub struct StandardOutputStream {} + +impl Write for StandardOutputStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + io::stdout().write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + io::stdout().flush() + } +} + +#[derive(Debug)] +pub struct StandardErrorStream {} + +impl Write for StandardErrorStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + io::stderr().write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + io::stderr().flush() + } +} + +#[bitfield] +#[repr(u64)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct StreamOptions { + pub stream_type: StreamType, + pub reposition: bool, + pub eof_action: EOFAction, + pub has_alias: bool, + pub alias: B59, +} + +impl StreamOptions { + #[inline] + pub fn get_alias(self) -> Option { + if self.has_alias() { + Some(Atom::from((self.alias() << 3) as usize)) + } else { + None + } + } + + #[inline] + pub fn set_alias_to_atom_opt(&mut self, alias: Option) { + self.set_has_alias(alias.is_some()); + + if let Some(alias) = alias { + self.set_alias(alias.flat_index()); } } } -impl fmt::Debug for StreamInstance { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - &StreamInstance::Bytes(ref bytes) => write!(fmt, "Bytes({:?})", bytes), - &StreamInstance::StaticStr(_) => write!(fmt, "StaticStr(_)"), // Hacky solution. - &StreamInstance::InputFile(_, ref file) => write!(fmt, "InputFile({:?})", file), - &StreamInstance::OutputFile(_, ref file, _) => write!(fmt, "OutputFile({:?})", file), - &StreamInstance::Null => write!(fmt, "Null"), - &StreamInstance::PausedPrologStream(ref put_back, ref stream) => { - write!(fmt, "PausedPrologStream({:?}, {:?})", put_back, stream) - } - &StreamInstance::ReadlineStream(ref readline_stream) => { - write!(fmt, "ReadlineStream({:?})", readline_stream) +impl Default for StreamOptions { + #[inline] + fn default() -> Self { + StreamOptions::new() + .with_stream_type(StreamType::Text) + .with_reposition(false) + .with_eof_action(EOFAction::EOFCode) + .with_has_alias(false) + .with_alias(0) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct StreamLayout { + pub options: StreamOptions, + pub lines_read: usize, + past_end_of_stream: bool, + stream: T, +} + +impl StreamLayout { + #[inline] + pub fn new(stream: T) -> Self { + Self { + options: StreamOptions::default(), + lines_read: 0, + past_end_of_stream: false, + stream, + } + } +} + +impl Deref for StreamLayout { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.stream + } +} + +impl DerefMut for StreamLayout { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.stream + } +} + +macro_rules! arena_allocated_impl_for_stream { + ($stream_type:ty, $stream_tag:ident) => { + impl ArenaAllocated for StreamLayout<$stream_type> { + type PtrToAllocated = TypedArenaPtr>; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::$stream_tag } - &StreamInstance::Stderr => write!(fmt, "Stderr"), - &StreamInstance::Stdout => write!(fmt, "Stdout"), - &StreamInstance::TcpStream(_, ref tcp_stream) => { - write!(fmt, "TcpStream({:?})", tcp_stream) + + #[inline] + fn size(&self) -> usize { + mem::size_of::>() } - &StreamInstance::TlsStream(_, ref tls_stream) => { - write!(fmt, "TlsStream({:?})", tls_stream) + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } } } + }; +} + +/* +pub mod testing { + use super::PausedPrologStream; + + impl PausedPrologStream { + #[allow(dead_code)] + pub fn write_test_input(&mut self, string: &str) { + self.bytes.extend(string.as_bytes().iter().rev()); + } + } +} +*/ +/* +impl ArenaAllocated for PausedPrologStream { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::PausedPrologStream + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } } } #[derive(Debug)] -pub(crate) struct InnerStream { - options: StreamOptions, - stream_inst: StreamInstance, - past_end_of_stream: bool, - lines_read: usize, +pub struct PausedPrologStream { + bytes: Vec, + paused_stream: Stream, } -#[derive(Debug, Clone)] -struct WrappedStreamInstance(Rc>); +impl PausedPrologStream { + #[inline] + pub fn new() -> Self { + PausedPrologStream { + bytes: vec![], + paused_stream: Stream::Null(StreamOptions::default()), + } + } +} -impl WrappedStreamInstance { +impl Read for PausedPrologStream { #[inline] - fn new(stream_inst: StreamInstance, past_end_of_stream: bool) -> Self { - WrappedStreamInstance(Rc::new(RefCell::new(InnerStream { - options: StreamOptions::default(), - stream_inst, - past_end_of_stream, - lines_read: 0, - }))) + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.paused_stream.read(buf) } } +*/ + +arena_allocated_impl_for_stream!(CharReader, ByteStream); +arena_allocated_impl_for_stream!(CharReader, InputFileStream); +arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream); +arena_allocated_impl_for_stream!(CharReader, NamedTcpStream); +arena_allocated_impl_for_stream!(CharReader, NamedTlsStream); +arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream); +arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream); +arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream); +arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream); + +#[derive(Debug, Copy, Clone)] +pub enum Stream { + Byte(TypedArenaPtr>>), + InputFile(TypedArenaPtr>>), + OutputFile(TypedArenaPtr>), + StaticString(TypedArenaPtr>), + NamedTcp(TypedArenaPtr>>), + NamedTls(TypedArenaPtr>>), + Null(StreamOptions), + Readline(TypedArenaPtr>), + StandardOutput(TypedArenaPtr>), + StandardError(TypedArenaPtr>), +} + +impl From>> for Stream { + #[inline] + fn from(stream: TypedArenaPtr>) -> Stream { + Stream::Readline(stream) + } +} + +impl Stream { + #[inline] + pub fn from_readline_stream(stream: ReadlineStream, arena: &mut Arena) -> Stream { + Stream::Readline(arena_alloc!(StreamLayout::new(stream), arena)) + } + + #[inline] + pub fn from_owned_string(string: String, arena: &mut Arena) -> Stream { + Stream::Byte(arena_alloc!( + StreamLayout::new(CharReader::new(ByteStream(Cursor::new(string.into_bytes())))), + arena + )) + } + + #[inline] + pub fn from_static_string(src: &'static str, arena: &mut Arena) -> Stream { + Stream::StaticString(arena_alloc!( + StreamLayout::new(StaticStringStream { + stream: Cursor::new(src) + }), + arena + )) + } + + #[inline] + pub fn stdin(arena: &mut Arena) -> Stream { + Stream::Readline(arena_alloc!( + StreamLayout::new(ReadlineStream::new("")), + arena + )) + } + + pub fn from_tag(tag: ArenaHeaderTag, ptr: *const u8) -> Self { + match tag { + ArenaHeaderTag::ByteStream => Stream::Byte(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::InputFileStream => Stream::InputFile(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::OutputFileStream => { + Stream::OutputFile(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::StaticStringStream => { + Stream::StaticString(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::StandardOutputStream => { + Stream::StandardOutput(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::StandardErrorStream => { + Stream::StandardError(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::NullStream => Stream::Null(StreamOptions::default()), + _ => unreachable!(), + } + } + + #[inline] + pub fn is_stderr(&self) -> bool { + if let Stream::StandardError(_) = self { + true + } else { + false + } + } + + #[inline] + pub fn is_stdout(&self) -> bool { + if let Stream::StandardOutput(_) = self { + true + } else { + false + } + } + + #[inline] + pub fn is_stdin(&self) -> bool { + if let Stream::Readline(_) = self { + true + } else { + false + } + } + + pub fn as_ptr(&self) -> *const ArenaHeader { + match self { + Stream::Byte(ptr) => ptr.header_ptr(), + Stream::InputFile(ptr) => ptr.header_ptr(), + Stream::OutputFile(ptr) => ptr.header_ptr(), + Stream::StaticString(ptr) => ptr.header_ptr(), + Stream::NamedTcp(ptr) => ptr.header_ptr(), + Stream::NamedTls(ptr) => ptr.header_ptr(), + Stream::Null(_) => ptr::null(), + Stream::Readline(ptr) => ptr.header_ptr(), + Stream::StandardOutput(ptr) => ptr.header_ptr(), + Stream::StandardError(ptr) => ptr.header_ptr(), + } + } + + pub fn options(&self) -> &StreamOptions { + match self { + Stream::Byte(ref ptr) => &ptr.options, + Stream::InputFile(ref ptr) => &ptr.options, + Stream::OutputFile(ref ptr) => &ptr.options, + Stream::StaticString(ref ptr) => &ptr.options, + Stream::NamedTcp(ref ptr) => &ptr.options, + Stream::NamedTls(ref ptr) => &ptr.options, + Stream::Null(ref options) => options, + Stream::Readline(ref ptr) => &ptr.options, + Stream::StandardOutput(ref ptr) => &ptr.options, + Stream::StandardError(ref ptr) => &ptr.options, + } + } + + pub fn options_mut(&mut self) -> &mut StreamOptions { + match self { + Stream::Byte(ref mut ptr) => &mut ptr.options, + Stream::InputFile(ref mut ptr) => &mut ptr.options, + Stream::OutputFile(ref mut ptr) => &mut ptr.options, + Stream::StaticString(ref mut ptr) => &mut ptr.options, + Stream::NamedTcp(ref mut ptr) => &mut ptr.options, + Stream::NamedTls(ref mut ptr) => &mut ptr.options, + Stream::Null(ref mut options) => options, + Stream::Readline(ref mut ptr) => &mut ptr.options, + Stream::StandardOutput(ref mut ptr) => &mut ptr.options, + Stream::StandardError(ref mut ptr) => &mut ptr.options, + } + } + + /* + fn unpause_stream(&mut self) { + let stream_inst = match self { + Stream::PausedProlog(paused) if paused.bytes.is_empty() => { + mem::replace(&mut paused.paused_stream, Stream::Null(StreamOptions::default())) + } + _ => { + return; + } + }; + + *self = stream_inst; + } + */ + + #[inline] + pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) { + match self { + Stream::Byte(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::InputFile(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::OutputFile(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::Null(_) => {} + Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::StandardError(ptr) => ptr.lines_read += incr_num_lines_read, + } + } + + #[inline] + pub(crate) fn set_lines_read(&mut self, value: usize) { + match self { + Stream::Byte(ptr) => ptr.lines_read = value, + Stream::InputFile(ptr) => ptr.lines_read = value, + Stream::OutputFile(ptr) => ptr.lines_read = value, + Stream::StaticString(ptr) => ptr.lines_read = value, + Stream::NamedTcp(ptr) => ptr.lines_read = value, + Stream::NamedTls(ptr) => ptr.lines_read = value, + Stream::Null(_) => {} + Stream::Readline(ptr) => ptr.lines_read = value, + Stream::StandardOutput(ptr) => ptr.lines_read = value, + Stream::StandardError(ptr) => ptr.lines_read = value, + } + } + + #[inline] + pub(crate) fn lines_read(&self) -> usize { + match self { + Stream::Byte(ptr) => ptr.lines_read, + Stream::InputFile(ptr) => ptr.lines_read, + Stream::OutputFile(ptr) => ptr.lines_read, + Stream::StaticString(ptr) => ptr.lines_read, + Stream::NamedTcp(ptr) => ptr.lines_read, + Stream::NamedTls(ptr) => ptr.lines_read, + Stream::Null(_) => 0, + Stream::Readline(ptr) => ptr.lines_read, + Stream::StandardOutput(ptr) => ptr.lines_read, + Stream::StandardError(ptr) => ptr.lines_read, + } + } +} + +impl CharRead for Stream { + fn peek_char(&mut self) -> Option> { + match self { + Stream::InputFile(file) => (*file).peek_char(), + Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(), + Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(), + Stream::Readline(rl_stream) => (*rl_stream).peek_char(), + Stream::StaticString(src) => (*src).peek_char(), + Stream::Byte(cursor) => (*cursor).peek_char(), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => Some(Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::ReadFromOutputStream, + ))), + } + } + + fn read_char(&mut self) -> Option> { + match self { + Stream::InputFile(file) => (*file).read_char(), + Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(), + Stream::NamedTls(tls_stream) => (*tls_stream).read_char(), + Stream::Readline(rl_stream) => (*rl_stream).read_char(), + Stream::StaticString(src) => (*src).read_char(), + Stream::Byte(cursor) => (*cursor).read_char(), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => Some(Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::ReadFromOutputStream, + ))), + } + } + + fn put_back_char(&mut self, c: char) { + match self { + Stream::InputFile(file) => file.put_back_char(c), + Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c), + Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c), + Stream::Readline(rl_stream) => rl_stream.put_back_char(c), + Stream::StaticString(src) => src.put_back_char(c), + Stream::Byte(cursor) => cursor.put_back_char(c), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => {} + } + } + + fn consume(&mut self, nread: usize) { + match self { + Stream::InputFile(ref mut file) => file.consume(nread), + Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread), + Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread), + Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread), + Stream::StaticString(ref mut src) => src.consume(nread), + Stream::Byte(ref mut cursor) => cursor.consume(nread), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => {} + } + } +} + +impl Read for Stream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let bytes_read = match self { + Stream::InputFile(file) => (*file).read(buf), + Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf), + Stream::NamedTls(tls_stream) => (*tls_stream).read(buf), + Stream::Readline(rl_stream) => (*rl_stream).read(buf), + Stream::StaticString(src) => (*src).read(buf), + Stream::Byte(cursor) => (*cursor).read(buf), + Stream::OutputFile(_) + | Stream::StandardError(_) + | Stream::StandardOutput(_) + | Stream::Null(_) => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::ReadFromOutputStream, + )), + }; -impl PartialEq for WrappedStreamInstance { - #[inline] - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.0, &other.0) + bytes_read } } -impl Eq for WrappedStreamInstance {} - -impl Hash for WrappedStreamInstance { - fn hash(&self, state: &mut H) { - let rc = &self.0; - let ptr = Rc::into_raw(rc.clone()); - - state.write_usize(ptr as usize); +impl Write for Stream { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + match self { + Stream::OutputFile(ref mut file) => file.write(buf), + Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.get_mut().write(buf), + Stream::NamedTls(ref mut tls_stream) => tls_stream.get_mut().write(buf), + Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf), + Stream::StandardOutput(stream) => stream.write(buf), + Stream::StandardError(stream) => stream.write(buf), + Stream::StaticString(_) | + Stream::Readline(_) | + Stream::InputFile(..) | + Stream::Null(_) => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::WriteToInputStream, + )), + } + } - unsafe { - // necessary to avoid memory leak. - let _ = Rc::from_raw(ptr); - }; + fn flush(&mut self) -> std::io::Result<()> { + match self { + Stream::OutputFile(ref mut file) => file.stream.flush(), + Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.stream.get_mut().flush(), + Stream::NamedTls(ref mut tls_stream) => tls_stream.stream.get_mut().flush(), + Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(), + Stream::StandardError(stream) => stream.stream.flush(), + Stream::StandardOutput(stream) => stream.stream.flush(), + Stream::StaticString(_) | + Stream::Readline(_) | + Stream::InputFile(_) | + Stream::Null(_) => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::FlushToInputStream, + )), + } } } @@ -236,8 +784,8 @@ impl Hash for WrappedStreamInstance { enum StreamError { PeekByteFailed, PeekByteFromNonPeekableStream, - PeekCharFailed, - PeekCharFromNonPeekableStream, + #[allow(unused)] PeekCharFailed, + #[allow(unused)] PeekCharFromNonPeekableStream, ReadFromOutputStream, WriteToInputStream, FlushToInputStream, @@ -273,31 +821,6 @@ impl fmt::Display for StreamError { impl Error for StreamError {} -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct StreamOptions { - pub(crate) stream_type: StreamType, - pub(crate) reposition: bool, - pub(crate) alias: Option, - pub(crate) eof_action: EOFAction, -} - -impl Default for StreamOptions { - #[inline] - fn default() -> Self { - StreamOptions { - stream_type: StreamType::Text, - reposition: false, - alias: None, - eof_action: EOFAction::EOFCode, - } - } -} - -#[derive(Debug, Clone, Hash)] -pub struct Stream { - stream_inst: WrappedStreamInstance, -} - impl PartialOrd for Stream { #[inline] fn partial_cmp(&self, other: &Stream) -> Option { @@ -315,123 +838,44 @@ impl Ord for Stream { impl PartialEq for Stream { #[inline] fn eq(&self, other: &Self) -> bool { - self.stream_inst == other.stream_inst + self.as_ptr() == other.as_ptr() } } impl Eq for Stream {} -impl From for Stream { - fn from(string: String) -> Self { - Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes()))) - } -} - -impl From for Stream { - fn from(rl_stream: ReadlineStream) -> Self { - Stream::from_inst(StreamInstance::ReadlineStream(rl_stream)) - } -} - -impl From<&'static str> for Stream { - fn from(src: &'static str) -> Stream { - Stream::from_inst(StreamInstance::StaticStr(Cursor::new(src))) - } -} - impl Stream { - #[inline] - pub(crate) fn as_ptr(&self) -> *const u8 { - let rc = self.stream_inst.0.clone(); - let ptr = Rc::into_raw(rc); - - unsafe { - // must be done to avoid memory leak. - let _ = Rc::from_raw(ptr); - } - - ptr as *const u8 - } - - pub fn bytes(&self) -> Option>> { - /* - // Replacement of workaround for when we have stable https://github.com/rust-lang/rust/issues/81061 - std::cell::Ref::filter_map( - self.stream_inst.0.borrow(), - |inner_stream| match inner_stream.stream_inst { - StreamInstance::Bytes(cursor) => Some(cursor.get_ref()), - _ => None, - }, - ) - .ok() - */ - let val = std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| { - &inner_stream.stream_inst - }); - match std::ops::Deref::deref(&val) { - StreamInstance::Bytes(_) => Some(std::cell::Ref::map( - std::cell::Ref::clone(&val), - |instance| match instance { - StreamInstance::Bytes(cursor) => cursor.get_ref(), - _ => unreachable!(), - }, - )), - _ => None, - } - } - - #[inline] - pub(crate) fn lines_read(&mut self) -> usize { - self.stream_inst.0.borrow_mut().lines_read - } - - #[inline] - pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) { - self.stream_inst.0.borrow_mut().lines_read += incr_num_lines_read; - } - - #[inline] - pub(crate) fn options(&self) -> std::cell::Ref<'_, StreamOptions> { - std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| { - &inner_stream.options - }) - } - - #[inline] - pub(crate) fn options_mut(&mut self) -> std::cell::RefMut<'_, StreamOptions> { - std::cell::RefMut::map(self.stream_inst.0.borrow_mut(), |inner_stream| { - &mut inner_stream.options - }) - } - #[inline] pub(crate) fn position(&mut self) -> Option<(u64, usize)> { // returns lines_read, position. - let result = match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::InputFile(_, ref mut file) => file.seek(SeekFrom::Current(0)).ok(), - StreamInstance::TcpStream(..) - | StreamInstance::TlsStream(..) - | StreamInstance::ReadlineStream(..) - | StreamInstance::StaticStr(..) - | StreamInstance::PausedPrologStream(..) - | StreamInstance::Bytes(..) => Some(0), + let result = match self { + Stream::InputFile(ref mut file_stream) => { + file_stream.get_mut().file.seek(SeekFrom::Current(0)).ok() + } + Stream::NamedTcp(..) + | Stream::NamedTls(..) + | Stream::Readline(..) + | Stream::StaticString(..) + | Stream::Byte(..) => Some(0), _ => None, }; - result.map(|position| (position, self.stream_inst.0.borrow().lines_read)) + result.map(|position| (position, self.lines_read())) } #[inline] pub(crate) fn set_position(&mut self, position: u64) { - match self.stream_inst.0.borrow_mut().deref_mut() { - InnerStream { - past_end_of_stream, - stream_inst: StreamInstance::InputFile(_, ref mut file), - .. - } => { - file.seek(SeekFrom::Start(position)).unwrap(); + match self { + Stream::InputFile(stream_layout) => { + let StreamLayout { + past_end_of_stream, + stream, + .. + } = &mut **stream_layout; - if let Ok(metadata) = file.metadata() { + stream.get_mut().file.seek(SeekFrom::Start(position)).unwrap(); + + if let Ok(metadata) = stream.get_ref().file.metadata() { *past_end_of_stream = position > metadata.len(); } } @@ -441,7 +885,19 @@ impl Stream { #[inline] pub(crate) fn past_end_of_stream(&self) -> bool { - self.stream_inst.0.borrow_mut().past_end_of_stream + match self { + Stream::Byte(stream) => stream.past_end_of_stream, + Stream::InputFile(stream) => stream.past_end_of_stream, + Stream::OutputFile(stream) => stream.past_end_of_stream, + // Stream::PausedProlog(stream) => stream.paused_stream.past_end_of_stream(), + Stream::StaticString(stream) => stream.past_end_of_stream, + Stream::NamedTcp(stream) => stream.past_end_of_stream, + Stream::NamedTls(stream) => stream.past_end_of_stream, + Stream::Null(_) => false, + Stream::Readline(stream) => stream.past_end_of_stream, + Stream::StandardOutput(stream) => stream.past_end_of_stream, + Stream::StandardError(stream) => stream.past_end_of_stream, + } } #[inline] @@ -450,8 +906,19 @@ impl Stream { } #[inline] - pub(crate) fn set_past_end_of_stream(&mut self) { - self.stream_inst.0.borrow_mut().past_end_of_stream = true; + pub(crate) fn set_past_end_of_stream(&mut self, value: bool) { + match self { + Stream::Byte(stream) => stream.past_end_of_stream = value, + Stream::InputFile(stream) => stream.past_end_of_stream = value, + Stream::OutputFile(stream) => stream.past_end_of_stream = value, + Stream::StaticString(stream) => stream.past_end_of_stream = value, + Stream::NamedTcp(stream) => stream.past_end_of_stream = value, + Stream::NamedTls(stream) => stream.past_end_of_stream = value, + Stream::Null(_) => {} + Stream::Readline(stream) => stream.past_end_of_stream = value, + Stream::StandardOutput(stream) => stream.past_end_of_stream = value, + Stream::StandardError(stream) => stream.past_end_of_stream = value, + } } #[inline] @@ -460,14 +927,16 @@ impl Stream { return AtEndOfStream::Past; } - match self.stream_inst.0.borrow_mut().deref_mut() { - InnerStream { + if let Stream::InputFile(stream_layout) = self { + let StreamLayout { past_end_of_stream, - stream_inst: StreamInstance::InputFile(_, ref mut file), + stream, .. - } => match file.metadata() { + } = &mut **stream_layout; + + match stream.get_ref().file.metadata() { Ok(metadata) => { - if let Ok(position) = file.seek(SeekFrom::Current(0)) { + if let Ok(position) = stream.get_mut().file.seek(SeekFrom::Current(0)) { return match position.cmp(&metadata.len()) { Ordering::Equal => AtEndOfStream::At, Ordering::Less => AtEndOfStream::Not, @@ -485,120 +954,130 @@ impl Stream { *past_end_of_stream = true; AtEndOfStream::Past } - }, - _ => AtEndOfStream::Not, + } + } else { + AtEndOfStream::Not } } #[inline] - pub(crate) fn file_name(&self) -> Option { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::InputFile(ref name, _) => Some(name.clone()), - StreamInstance::OutputFile(ref name, ..) => Some(name.clone()), - StreamInstance::TcpStream(ref name, _) => Some(name.clone()), + pub(crate) fn file_name(&self) -> Option { + match self { + Stream::InputFile(file) => Some(file.stream.get_ref().file_name), + Stream::OutputFile(file) => Some(file.stream.file_name), + Stream::NamedTcp(tcp) => Some(tcp.stream.get_ref().address), + Stream::NamedTls(tls) => Some(tls.stream.get_ref().address), _ => None, } } #[inline] - pub(crate) fn mode(&self) -> &'static str { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Bytes(_) - | StreamInstance::PausedPrologStream(..) - | StreamInstance::ReadlineStream(_) - | StreamInstance::StaticStr(_) - | StreamInstance::InputFile(..) => "read", - StreamInstance::TcpStream(..) | StreamInstance::TlsStream(..) => "read_append", - StreamInstance::OutputFile(_, _, true) => "append", - StreamInstance::Stderr - | StreamInstance::Stdout - | StreamInstance::OutputFile(_, _, false) => "write", - StreamInstance::Null => "", - } - } - - #[inline] - fn from_inst(stream_inst: StreamInstance) -> Self { - Stream { - stream_inst: WrappedStreamInstance::new(stream_inst, false), + pub(crate) fn mode(&self) -> Atom { + match self { + Stream::Byte(_) + | Stream::Readline(_) + | Stream::StaticString(_) + | Stream::InputFile(..) => atom!("read"), + Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"), + Stream::OutputFile(file) if file.is_append => atom!("append"), + Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"), + Stream::Null(_) => atom!(""), } } #[inline] - pub fn stdout() -> Self { - Stream::from_inst(StreamInstance::Stdout) + pub fn stdout(arena: &mut Arena) -> Self { + Stream::StandardOutput(arena_alloc!( + StreamLayout::new(StandardOutputStream {}), + arena + )) } #[inline] - pub fn stderr() -> Self { - Stream::from_inst(StreamInstance::Stderr) + pub fn stderr(arena: &mut Arena) -> Self { + Stream::StandardError(arena_alloc!( + StreamLayout::new(StandardErrorStream {}), + arena + )) } #[inline] - pub(crate) fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self { + pub(crate) fn from_tcp_stream( + address: Atom, + tcp_stream: TcpStream, + arena: &mut Arena, + ) -> Self { tcp_stream.set_read_timeout(None).unwrap(); tcp_stream.set_write_timeout(None).unwrap(); - Stream::from_inst(StreamInstance::TcpStream(address, tcp_stream)) - } - - #[inline] - pub(crate) fn from_tls_stream(address: ClauseName, tls_stream: TlsStream) -> Self { - Stream::from_inst(StreamInstance::TlsStream(address, tls_stream)) - } - - #[inline] - pub(crate) fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self { - Stream::from_inst(StreamInstance::OutputFile(name, file, in_append_mode)) - } - - #[inline] - pub(crate) fn from_file_as_input(name: ClauseName, file: File) -> Self { - Stream::from_inst(StreamInstance::InputFile(name, file)) + Stream::NamedTcp(arena_alloc!( + StreamLayout::new(CharReader::new(NamedTcpStream { + address, + tcp_stream + })), + arena + )) } #[inline] - pub(crate) fn is_stderr(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Stderr => true, - _ => false, - } + pub(crate) fn from_tls_stream( + address: Atom, + tls_stream: TlsStream, + arena: &mut Arena, + ) -> Self { + Stream::NamedTls(arena_alloc!( + StreamLayout::new(CharReader::new(NamedTlsStream { + address, + tls_stream + })), + arena + )) } #[inline] - pub(crate) fn is_stdout(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Stdout => true, - _ => false, - } + pub(crate) fn from_file_as_output( + file_name: Atom, + file: File, + is_append: bool, + arena: &mut Arena, + ) -> Self { + Stream::OutputFile(arena_alloc!( + StreamLayout::new(OutputFileStream { + file_name, + file, + is_append + }), + arena + )) } #[inline] - pub(crate) fn is_stdin(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::ReadlineStream(_) => true, - _ => false, - } + pub(crate) fn from_file_as_input(file_name: Atom, file: File, arena: &mut Arena) -> Self { + Stream::InputFile(arena_alloc!( + StreamLayout::new(CharReader::new(InputFileStream { file_name, file })), + arena + )) } #[inline] pub(crate) fn close(&mut self) -> Result<(), std::io::Error> { - let result = match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::TcpStream(_, ref mut tcp_stream) => { - tcp_stream.shutdown(Shutdown::Both) + let result = match self { + Stream::NamedTcp(ref mut tcp_stream) => { + tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both) }, - StreamInstance::TlsStream(_, ref mut tls_stream) => { - tls_stream.shutdown() + Stream::NamedTls(ref mut tls_stream) => { + tls_stream.inner_mut().tls_stream.shutdown() } _ => Ok(()) }; - self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::Null; + + *self = Stream::Null(StreamOptions::default()); result } #[inline] pub(crate) fn is_null_stream(&self) -> bool { - if let StreamInstance::Null = self.stream_inst.0.borrow().stream_inst { + if let Stream::Null(_) = self { true } else { false @@ -607,98 +1086,77 @@ impl Stream { #[inline] pub(crate) fn is_input_stream(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::TcpStream(..) - | StreamInstance::TlsStream(..) - | StreamInstance::Bytes(_) - | StreamInstance::PausedPrologStream(..) - | StreamInstance::ReadlineStream(_) - | StreamInstance::StaticStr(_) - | StreamInstance::InputFile(..) => true, + match self { + Stream::NamedTcp(..) + | Stream::NamedTls(..) + | Stream::Byte(_) + | Stream::Readline(_) + | Stream::StaticString(_) + | Stream::InputFile(..) => true, _ => false, } } #[inline] pub(crate) fn is_output_stream(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Stderr - | StreamInstance::Stdout - | StreamInstance::TcpStream(..) - | StreamInstance::TlsStream(..) - | StreamInstance::Bytes(_) - | StreamInstance::OutputFile(..) => true, + match self { + Stream::StandardError(_) + | Stream::StandardOutput(_) + | Stream::NamedTcp(..) + | Stream::NamedTls(..) + | Stream::Byte(_) + | Stream::OutputFile(..) => true, _ => false, } } - fn unpause_stream(&mut self) { - let stream_inst = match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::PausedPrologStream(ref put_back, ref mut stream_inst) - if put_back.is_empty() => - { - mem::replace(&mut **stream_inst, StreamInstance::Null) - } - _ => { - return; - } - }; - - self.stream_inst.0.borrow_mut().stream_inst = stream_inst; - } - // returns true on success. #[inline] pub(super) fn reset(&mut self) -> bool { - self.stream_inst.0.borrow_mut().lines_read = 0; - self.stream_inst.0.borrow_mut().past_end_of_stream = false; + self.set_lines_read(0); + self.set_past_end_of_stream(false); loop { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::Bytes(ref mut cursor) => { - cursor.set_position(0); + match self { + Stream::Byte(ref mut cursor) => { + cursor.stream.get_mut().0.set_position(0); return true; } - StreamInstance::InputFile(_, ref mut file) => { - file.seek(SeekFrom::Start(0)).unwrap(); + Stream::InputFile(ref mut file_stream) => { + file_stream.stream.get_mut().file.seek(SeekFrom::Start(0)).unwrap(); return true; } - StreamInstance::PausedPrologStream(ref mut put_back, _) => { - put_back.clear(); - } - StreamInstance::ReadlineStream(_) => { + Stream::Readline(_) => { return true; } _ => { return false; } } - - self.unpause_stream(); } } #[inline] pub(crate) fn peek_byte(&mut self) -> std::io::Result { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::Bytes(ref mut cursor) => { + match self { + Stream::Byte(ref mut cursor) => { let mut b = [0u8; 1]; - let pos = cursor.position(); + let pos = cursor.stream.get_mut().0.position(); match cursor.read(&mut b)? { 1 => { - cursor.set_position(pos); + cursor.stream.get_mut().0.set_position(pos); Ok(b[0]) } _ => Err(std::io::Error::new(ErrorKind::UnexpectedEof, "end of file")), } } - StreamInstance::InputFile(_, ref mut file) => { + Stream::InputFile(ref mut file) => { let mut b = [0u8; 1]; match file.read(&mut b)? { 1 => { - file.seek(SeekFrom::Current(-1))?; + file.stream.get_mut().file.seek(SeekFrom::Current(-1))?; Ok(b[0]) } _ => Err(std::io::Error::new( @@ -707,10 +1165,10 @@ impl Stream { )), } } - StreamInstance::ReadlineStream(ref mut stream) => stream.peek_byte(), - StreamInstance::TcpStream(_, ref mut tcp_stream) => { + Stream::Readline(ref mut stream) => stream.stream.peek_byte(), + Stream::NamedTcp(ref mut stream) => { let mut b = [0u8; 1]; - tcp_stream.peek(&mut b)?; + stream.stream.get_mut().tcp_stream.peek(&mut b)?; Ok(b[0]) } _ => Err(std::io::Error::new( @@ -719,113 +1177,37 @@ impl Stream { )), } } - - #[inline] - pub(crate) fn peek_char(&mut self) -> std::io::Result { - use unicode_reader::CodePoints; - - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::InputFile(_, ref mut file) => { - let c = { - let mut iter = CodePoints::from(&*file); - - if let Some(Ok(c)) = iter.next() { - c - } else { - return Err(std::io::Error::new( - ErrorKind::UnexpectedEof, - StreamError::PeekCharFailed, - )); - } - }; - - file.seek(SeekFrom::Current(-(c.len_utf8() as i64)))?; - - Ok(c) - } - StreamInstance::ReadlineStream(ref mut stream) => stream.peek_char(), - StreamInstance::TcpStream(_, ref tcp_stream) => { - let c = { - let mut buf = [0u8; 8]; - tcp_stream.peek(&mut buf)?; - - let mut iter = CodePoints::from(buf.bytes()); - - if let Some(Ok(c)) = iter.next() { - c - } else { - return Err(std::io::Error::new( - ErrorKind::UnexpectedEof, - StreamError::PeekCharFailed, - )); - } - }; - - Ok(c) - } - _ => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::PeekCharFromNonPeekableStream, - )), - } - } - - #[inline] - pub(crate) fn pause_stream(&mut self, buf: Vec>) -> io::Result<()> { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::PausedPrologStream(ref mut inner_buf, _) => { - inner_buf.extend(parser_top_to_bytes(buf)?.into_iter()); - return Ok(()); - } - _ => {} - } - - if !buf.is_empty() { - let stream_inst = mem::replace( - &mut self.stream_inst.0.borrow_mut().stream_inst, - StreamInstance::Null, - ); - - self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::PausedPrologStream( - parser_top_to_bytes(buf)?, - Box::new(stream_inst), - ); - } - - Ok(()) - } } impl MachineState { #[inline] pub(crate) fn eof_action( &mut self, - result: Addr, - stream: &mut Stream, - caller: ClauseName, + result: HeapCellValue, + mut stream: Stream, + caller: Atom, arity: usize, ) -> CallResult { - let eof_action = stream.options().eof_action; + let eof_action = stream.options().eof_action(); match eof_action { EOFAction::Error => { - stream.set_past_end_of_stream(); - return Err(self.open_past_eos_error(stream.clone(), caller, arity)); + stream.set_past_end_of_stream(true); + return Err(self.open_past_eos_error(stream, caller, arity)); } EOFAction::EOFCode => { - let end_of_stream = if stream.options().stream_type == StreamType::Binary { - Addr::Fixnum(-1) + let end_of_stream = if stream.options().stream_type() == StreamType::Binary { + fixnum_as_cell!(Fixnum::build_with(-1)) } else { - self.heap - .to_unifiable(HeapCellValue::Atom(clause_name!("end_of_file"), None)) + atom_as_cell!(atom!("end_of_file")) }; - stream.set_past_end_of_stream(); - Ok(self.unify(result, end_of_stream)) + stream.set_past_end_of_stream(true); + Ok(unify!(self, result, end_of_stream)) } EOFAction::Reset => { if !stream.reset() { - stream.set_past_end_of_stream(); + stream.set_past_end_of_stream(true); } Ok(self.fail = stream.past_end_of_stream()) @@ -834,182 +1216,176 @@ impl MachineState { } pub(crate) fn to_stream_options( - &self, - alias: Addr, - eof_action: Addr, - reposition: Addr, - stream_type: Addr, + &mut self, + alias: HeapCellValue, + eof_action: HeapCellValue, + reposition: HeapCellValue, + stream_type: HeapCellValue, ) -> StreamOptions { - let alias = match self.store(self.deref(alias)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - Some(name.clone()) - } else { - unreachable!() - } + let alias = read_heap_cell!(self.store(MachineState::deref(self, alias)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + Some(name) } - _ => None, - }; + _ => { + None + } + ); - let eof_action = match self.store(self.deref(eof_action)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - match name.as_str() { - "eof_code" => EOFAction::EOFCode, - "error" => EOFAction::Error, - "reset" => EOFAction::Reset, - _ => unreachable!(), - } - } else { - unreachable!() + let eof_action = read_heap_cell!(self.store(MachineState::deref(self, eof_action)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + match name { + atom!("eof_code") => EOFAction::EOFCode, + atom!("error") => EOFAction::Error, + atom!("reset") => EOFAction::Reset, + _ => unreachable!(), } } _ => { unreachable!() } - }; + ); - let reposition = match self.store(self.deref(reposition)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.as_str() == "true" - } else { - unreachable!() - } + let reposition = read_heap_cell!(self.store(MachineState::deref(self, reposition)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + name == atom!("true") } _ => { unreachable!() } - }; + ); - let stream_type = match self.store(self.deref(stream_type)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - match name.as_str() { - "text" => StreamType::Text, - "binary" => StreamType::Binary, - _ => unreachable!(), - } - } else { - unreachable!() + let stream_type = read_heap_cell!(self.store(MachineState::deref(self, stream_type)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + match name { + atom!("text") => StreamType::Text, + atom!("binary") => StreamType::Binary, + _ => unreachable!(), } } _ => { unreachable!() } - }; + ); let mut options = StreamOptions::default(); - options.stream_type = stream_type; - options.reposition = reposition; - options.alias = alias; - options.eof_action = eof_action; + options.set_stream_type(stream_type); + options.set_reposition(reposition); + options.set_alias_to_atom_opt(alias); + options.set_eof_action(eof_action); options } pub(crate) fn get_stream_or_alias( &mut self, - addr: Addr, + addr: HeapCellValue, stream_aliases: &StreamAliasDir, - caller: &'static str, + caller: Atom, arity: usize, ) -> Result { - Ok(match self.store(self.deref(addr)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) { - match stream_aliases.get(atom) { - Some(stream) if !stream.is_null_stream() => stream.clone(), - _ => { - let stub = MachineError::functor_stub(clause_name!(caller), arity); - - let addr = self - .heap - .to_unifiable(HeapCellValue::Atom(atom.clone(), spec.clone())); - - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(addr), - ), - stub, - )); - } + let addr = self.store(MachineState::deref(self, addr)); + + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + return match stream_aliases.get(&name) { + Some(stream) if !stream.is_null_stream() => Ok(*stream), + _ => { + let stub = functor_stub(caller, arity); + let addr = atom_as_cell!(name); + + let existence_error = self.existence_error(ExistenceError::Stream(addr)); + + Err(self.error_form(existence_error, stub)) } - } else { - unreachable!() - } + }; } - Addr::Stream(h) => { - if let HeapCellValue::Stream(ref stream) = &self.heap[h] { - if stream.is_null_stream() { - return Err(self.open_permission_error(Addr::Stream(h), caller, arity)); - } else { - stream.clone() - } - } else { - unreachable!() - } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Stream, stream) => { + return if stream.is_null_stream() { + Err(self.open_permission_error(stream_as_cell!(stream), caller, arity)) + } else { + Ok(stream) + }; + } + _ => { + } + ); } - addr => { - let stub = MachineError::functor_stub(clause_name!(caller), arity); - - if addr.is_ref() { - return Err(self.error_form(MachineError::instantiation_error(), stub)); - } else { - return Err(self.error_form( - MachineError::domain_error(DomainErrorType::StreamOrAlias, addr), - stub, - )); - } + _ => { } - }) + ); + + let stub = functor_stub(caller, arity); + + if addr.is_var() { + let instantiation_error = self.instantiation_error(); + Err(self.error_form(instantiation_error, stub)) + } else { + let domain_error = self.domain_error(DomainErrorType::StreamOrAlias, addr); + Err(self.error_form(domain_error, stub)) + } } pub(crate) fn open_parsing_stream( - &self, - stream: Stream, - stub_name: &'static str, + &mut self, + mut stream: Stream, + stub_name: Atom, stub_arity: usize, - ) -> Result { - match parsing_stream(stream) { - Ok(parsing_stream) => Ok(parsing_stream), - Err(e) => { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = MachineError::session_error(self.heap.h(), SessionError::from(e)); + ) -> Result { + match stream.peek_char() { + None => Ok(stream), // empty stream is handled gracefully by Lexer::eof + Some(Err(e)) => { + let err = self.session_error(SessionError::from(e)); + let stub = functor_stub(stub_name, stub_arity); Err(self.error_form(err, stub)) } + Some(Ok(c)) => { + if c == '\u{feff}' { + // skip UTF-8 BOM + stream.consume(c.len_utf8()); + } + + Ok(stream) + } } } pub(crate) fn stream_permission_error( - &self, + &mut self, perm: Permission, - err_string: &'static str, + err_atom: Atom, stream: Stream, - caller: ClauseName, + caller: Atom, arity: usize, ) -> MachineStub { - let stub = MachineError::functor_stub(caller, arity); - let payload = vec![HeapCellValue::Stream(stream)]; + let stub = functor_stub(caller, arity); + let payload = vec![stream_as_cell!(stream)]; - let err = MachineError::permission_error(self.heap.h(), perm, err_string, payload); + let err = self.permission_error(perm, err_atom, payload); return self.error_form(err, stub); } #[inline] pub(crate) fn open_past_eos_error( - &self, + &mut self, stream: Stream, - caller: ClauseName, + caller: Atom, arity: usize, ) -> MachineStub { self.stream_permission_error( Permission::InputStream, - "past_end_of_stream", + atom!("past_end_of_stream"), stream, caller, arity, @@ -1017,67 +1393,58 @@ impl MachineState { } pub(crate) fn open_permission_error( - &self, + &mut self, culprit: T, - stub_name: &'static str, + stub_name: Atom, stub_arity: usize, ) -> MachineStub { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = - MachineError::permission_error(self.heap.h(), Permission::Open, "source_sink", culprit); + let stub = functor_stub(stub_name, stub_arity); + let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit); return self.error_form(err, stub); } pub(crate) fn occupied_alias_permission_error( - &self, - alias: ClauseName, - stub_name: &'static str, + &mut self, + alias: Atom, + stub_name: Atom, stub_arity: usize, ) -> MachineStub { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = MachineError::permission_error( - self.heap.h(), + let stub = functor_stub(stub_name, stub_arity); + let alias_name = atom!("alias"); + + let err = self.permission_error( Permission::Open, - "source_sink", - functor!("alias", [clause_name(alias)]), + atom!("source_sink"), + functor!(alias_name, [atom(alias)]), ); return self.error_form(err, stub); } - pub(crate) fn reposition_error( - &self, - stub_name: &'static str, - stub_arity: usize, - ) -> MachineStub { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let rep_stub = functor!("reposition", [atom("true")]); + pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub { + let stub = functor_stub(stub_name, stub_arity); - let err = MachineError::permission_error( - self.heap.h(), - Permission::Open, - "source_sink", - rep_stub, - ); + let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]); + let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub); return self.error_form(err, stub); } pub(crate) fn check_stream_properties( &mut self, - stream: &mut Stream, + stream: Stream, expected_type: StreamType, - input: Option, - caller: ClauseName, + input: Option, + caller: Atom, arity: usize, ) -> CallResult { let opt_err = if input.is_some() && !stream.is_input_stream() { - Some("stream") // 8.14.2.3 g) + Some(atom!("stream")) // 8.14.2.3 g) } else if input.is_none() && !stream.is_output_stream() { - Some("stream") // 8.14.2.3 g) - } else if stream.options().stream_type != expected_type { - Some(expected_type.other().as_str()) // 8.14.2.3 h) + Some(atom!("stream")) // 8.14.2.3 g) + } else if stream.options().stream_type() != expected_type { + Some(expected_type.other().as_atom()) // 8.14.2.3 h) } else { None }; @@ -1088,14 +1455,8 @@ impl MachineState { Permission::OutputStream }; - if let Some(err_string) = opt_err { - return Err(self.stream_permission_error( - permission, - err_string, - stream.clone(), - caller, - arity, - )); + if let Some(err_atom) = opt_err { + return Err(self.stream_permission_error(permission, err_atom, stream, caller, arity)); } if let Some(input) = input { @@ -1106,53 +1467,96 @@ impl MachineState { Ok(()) } -} -impl Read for Stream { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - let bytes_read = self.stream_inst.0.borrow_mut().stream_inst.read(buf)?; - self.unpause_stream(); - Ok(bytes_read) - } -} + pub(crate) fn stream_from_file_spec( + &mut self, + file_spec: Atom, + indices: &mut IndexStore, + options: &StreamOptions, + ) -> Result { + if file_spec == atom!("") { + let stub = functor_stub(atom!("open"), 4); + let err = self.domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]); -impl Write for Stream { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::OutputFile(_, ref mut file, _) => file.write(buf), - StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.write(buf), - StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.write(buf), - StreamInstance::Bytes(ref mut cursor) => cursor.write(buf), - StreamInstance::Stdout => stdout().write(buf), - StreamInstance::Stderr => stderr().write(buf), - StreamInstance::PausedPrologStream(..) - | StreamInstance::StaticStr(_) - | StreamInstance::ReadlineStream(_) - | StreamInstance::InputFile(..) - | StreamInstance::Null => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::WriteToInputStream, - )), + return Err(self.error_form(err, stub)); } - } - fn flush(&mut self) -> std::io::Result<()> { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::OutputFile(_, ref mut file, _) => file.flush(), - StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.flush(), - StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.flush(), - StreamInstance::Bytes(ref mut cursor) => cursor.flush(), - StreamInstance::Stderr => stderr().flush(), - StreamInstance::Stdout => stdout().flush(), - StreamInstance::PausedPrologStream(..) - | StreamInstance::StaticStr(_) - | StreamInstance::ReadlineStream(_) - | StreamInstance::InputFile(..) - | StreamInstance::Null => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::FlushToInputStream, - )), + // 8.11.5.3l) + if let Some(alias) = options.get_alias() { + if indices.stream_aliases.contains_key(&alias) { + return Err(self.occupied_alias_permission_error(alias, atom!("open"), 4)); + } } + + let mode = MachineState::deref(self, self[temp_v!(2)]); + let mode = cell_as_atom!(self.store(mode)); + + let mut open_options = OpenOptions::new(); + + let (is_input_file, in_append_mode) = match mode { + atom!("read") => { + open_options.read(true).write(false).create(false); + (true, false) + } + atom!("write") => { + open_options + .read(false) + .write(true) + .truncate(true) + .create(true); + + (false, false) + } + atom!("append") => { + open_options + .read(false) + .write(true) + .create(true) + .append(true); + + (false, true) + } + _ => { + let stub = functor_stub(atom!("open"), 4); + let err = self.domain_error(DomainErrorType::IOMode, self[temp_v!(2)]); + + // 8.11.5.3h) + return Err(self.error_form(err, stub)); + } + }; + + let file = match open_options.open(file_spec.as_str()) { + Ok(file) => file, + Err(err) => { + match err.kind() { + ErrorKind::NotFound => { + // 8.11.5.3j) + let stub = functor_stub(atom!("open"), 4); + + let err = self.existence_error( + ExistenceError::SourceSink(self[temp_v!(1)]), + ); + + return Err(self.error_form(err, stub)); + } + ErrorKind::PermissionDenied => { + // 8.11.5.3k) + return Err(self.open_permission_error(self[temp_v!(1)], atom!("open"), 4)); + } + _ => { + let stub = functor_stub(atom!("open"), 4); + let err = self.syntax_error(ParserError::IO(err)); + + return Err(self.error_form(err, stub)); + } + } + } + }; + + Ok(if is_input_file { + Stream::from_file_as_input(file_spec, file, &mut self.arena) + } else { + Stream::from_file_as_output(file_spec, file, in_append_mode, &mut self.arena) + }) } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 0505e1383..9f3dd0895 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1,30 +1,32 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::*; -use prolog_parser::{ - alpha_char, alpha_numeric_char, binary_digit_char, clause_name, decimal_digit_char, - exponent_char, graphic_char, graphic_token_char, hexadecimal_digit_char, layout_char, - meta_char, new_line_char, octal_digit_char, octet_char, prolog_char, sign_char, solo_char, - symbolic_control_char, symbolic_hexadecimal_char, temp_v, -}; +use crate::parser::ast::*; +use crate::parser::parser::*; use lazy_static::lazy_static; +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::heap_print::*; use crate::instructions::*; use crate::machine; use crate::machine::code_repo::CodeRepo; use crate::machine::code_walker::*; use crate::machine::copier::*; +use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::machine::partial_string::*; use crate::machine::preprocessor::to_op_decl; +use crate::machine::stack::*; use crate::machine::streams::*; +use crate::parser::char_reader::*; +use crate::parser::rug::Integer; +use crate::read::*; +use crate::types::*; -use crate::read::readline; -use crate::rug::Integer; use ordered_float::OrderedFloat; use indexmap::IndexSet; @@ -40,7 +42,6 @@ use std::iter::{once, FromIterator}; use std::net::{TcpListener, TcpStream}; use std::num::NonZeroU32; use std::ops::Sub; -use std::rc::Rc; use std::process; use chrono::{offset::Local, DateTime}; @@ -92,147 +93,287 @@ pub(crate) fn get_key() -> KeyEvent { key } -#[derive(Debug)] -struct BrentAlgState { - hare: Addr, - tortoise: Addr, - power: usize, - steps: usize, +#[derive(Debug, Clone, Copy)] +pub struct BrentAlgState { + pub hare: usize, + pub tortoise: usize, + pub power: usize, + pub lam: usize, + pub pstr_chars: usize, } impl BrentAlgState { - fn new(hare: Addr) -> Self { - BrentAlgState { - hare: hare, + pub fn new(hare: usize) -> Self { + Self { + hare, tortoise: hare, - power: 2, - steps: 0, + power: 1, + lam: 0, + pstr_chars: 0, } } - #[inline] - fn conclude_or_move_tortoise(&mut self) -> Option { + #[inline(always)] + pub fn step(&mut self, hare: usize) -> Option { + self.hare = hare; + self.lam += 1; + if self.tortoise == self.hare { return Some(CycleSearchResult::NotList); - } else if self.steps == self.power { + } else if self.lam == self.power { self.tortoise = self.hare; self.power <<= 1; + self.lam = 0; } None } - #[inline] - fn step(&mut self, hare: Addr) -> Option { - self.hare = hare; - self.steps += 1; - - self.conclude_or_move_tortoise() + #[inline(always)] + pub fn num_steps(&self) -> usize { + return self.lam + self.pstr_chars + self.power - 1; } - fn to_result(self) -> CycleSearchResult { - match self.hare { - addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { - CycleSearchResult::PartialList(self.steps, addr.as_var().unwrap()) - } - Addr::PStrLocation(h, n) => CycleSearchResult::PStrLocation(self.steps, h, n), - Addr::EmptyList => CycleSearchResult::ProperList(self.steps), - _ => CycleSearchResult::NotList, + pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult { + if let Some(var) = heap[self.hare].as_var() { + return CycleSearchResult::PartialList(self.num_steps(), var); } + + read_heap_cell!(heap[self.hare], + (HeapCellValueTag::PStrOffset) => { + let n = cell_as_fixnum!(heap[self.hare+1]).get_num() as usize; + + let pstr = cell_as_string!(heap[self.hare]); + self.pstr_chars += pstr.as_str_from(n).chars().count(); + + CycleSearchResult::PStrLocation(self.num_steps(), n) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + CycleSearchResult::ProperList(self.num_steps()) + } else { + CycleSearchResult::NotList + } + } + _ => { + CycleSearchResult::NotList + } + ) } -} -fn is_builtin_predicate(name: &ClauseName) -> bool { - let in_builtins = name.owning_module().as_str() == "builtins"; - let hidden_name = name.as_str().starts_with("$"); + fn add_pstr_chars_and_step(&mut self, heap: &[HeapCellValue], h: usize) -> Option { + read_heap_cell!(heap[h], + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); + + self.pstr_chars += cstr.as_str_from(0).chars().count(); + Some(CycleSearchResult::ProperList(self.num_steps())) + } + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + self.pstr_chars += pstr.as_str_from(0).chars().count() - 1; + self.step(h+1) + } + (HeapCellValueTag::PStrOffset, offset) => { + let pstr = cell_as_string!(heap[offset]); + let n = cell_as_fixnum!(heap[h+1]).get_num() as usize; + + self.pstr_chars += pstr.as_str_from(n).chars().count(); - in_builtins || hidden_name + if let HeapCellValueTag::PStr = heap[offset].get_tag() { + self.pstr_chars -= 1; + self.step(offset+1) + } else { + debug_assert!(heap[offset].get_tag() == HeapCellValueTag::CStr); + Some(CycleSearchResult::ProperList(self.num_steps())) + } + } + _ => { + unreachable!() + } + ) + } } impl MachineState { - // a step in Brent's algorithm. - fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { - match self.store(self.deref(brent_st.hare)) { - Addr::EmptyList => Some(CycleSearchResult::ProperList(brent_st.steps)), - addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { - Some(CycleSearchResult::PartialList( - brent_st.steps, - addr.as_var().unwrap(), - )) - } - Addr::PStrLocation(h, n) => match &self.heap[h] { - HeapCellValue::PartialString(ref pstr, _) => { - if let Some(c) = pstr.range_from(n..).next() { - brent_st.step(Addr::PStrLocation(h, n + c.len_utf8())) - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }, - Addr::Lis(l) => brent_st.step(Addr::HeapCell(l + 1)), - _ => Some(CycleSearchResult::NotList), + #[inline(always)] + pub fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { + let deref_v = self.deref(self.heap[brent_st.hare]); + let store_v = self.store(deref_v); + + if let Some(var) = store_v.as_var() { + return Some(CycleSearchResult::PartialList(brent_st.num_steps(), var)); + } + + if store_v == empty_list_as_cell!() { + return Some(CycleSearchResult::ProperList(brent_st.num_steps())); } + + read_heap_cell!(store_v, + (HeapCellValueTag::PStrLoc, h) => { + brent_st.add_pstr_chars_and_step(&self.heap, h) + } + (HeapCellValueTag::PStrOffset) => { + brent_st.add_pstr_chars_and_step(&self.heap, brent_st.hare) + } + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); + + brent_st.pstr_chars += cstr.as_str_from(0).chars().count(); + Some(CycleSearchResult::ProperList(brent_st.num_steps())) + } + (HeapCellValueTag::Lis, h) => { + brent_st.step(h+1) + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + brent_st.step(s+2) + } else { + Some(CycleSearchResult::NotList) + } + } + (HeapCellValueTag::Atom, (_name, arity)) => { + debug_assert!(arity == 0); + Some(CycleSearchResult::NotList) + } + _ => { + Some(CycleSearchResult::NotList) + } + ) } - pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult { - let hare = match self.store(self.deref(addr)) { - Addr::Lis(offset) if max_steps > 0 => Addr::Lis(offset), - Addr::Lis(offset) => { - return CycleSearchResult::UntouchedList(offset); + pub fn detect_cycles(&self, value: HeapCellValue) -> CycleSearchResult { + let deref_v = self.deref(value); + let store_v = self.store(deref_v); + + let mut pstr_chars = 0; + + let hare = read_heap_cell!(store_v, + (HeapCellValueTag::Lis, offset) => { + offset+1 } - Addr::PStrLocation(h, n) if max_steps > 0 => Addr::PStrLocation(h, n), - Addr::PStrLocation(h, _) => { - return CycleSearchResult::UntouchedList(h); + (HeapCellValueTag::PStrLoc, h) => { + let (h_offset, n) = pstr_loc_and_offset(&self.heap, h); + let n = n.get_num() as usize; + let pstr = cell_as_string!(self.heap[h_offset]); + + pstr_chars = pstr.as_str_from(n).chars().count() - 1; + + if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + + if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr { + return CycleSearchResult::ProperList(pstr_chars + 1); + } + } + + h_offset+1 + } + (HeapCellValueTag::PStrOffset) => { + unreachable!() } - Addr::EmptyList => { - return CycleSearchResult::EmptyList; + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); + return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count()); } - Addr::Con(h) if max_steps > 0 => { - if let HeapCellValue::PartialString(..) = &self.heap[h] { - Addr::PStrLocation(h, 0) + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; + } else if name == atom!(".") && arity == 2 { + s + 2 } else { return CycleSearchResult::NotList; } } - Addr::Con(h) => { - if let HeapCellValue::PartialString(..) = &self.heap[h] { - return CycleSearchResult::UntouchedList(h); + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; + } else { + return CycleSearchResult::NotList; } - - return CycleSearchResult::NotList; } _ => { return CycleSearchResult::NotList; } - }; + ); let mut brent_st = BrentAlgState::new(hare); - loop { - if brent_st.steps == max_steps { - return brent_st.to_result(); - } + brent_st.power += 1; // advance a step. + brent_st.pstr_chars = pstr_chars; + loop { if let Some(result) = self.brents_alg_step(&mut brent_st) { return result; } } } - pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult { - let addr = self.store(self.deref(addr)); - let hare = match addr { - Addr::Lis(offset) => Addr::Lis(offset), - Addr::EmptyList => { - return CycleSearchResult::EmptyList; - } - Addr::PStrLocation(h, n) => Addr::PStrLocation(h, n), - Addr::Con(h) => { - if let HeapCellValue::PartialString(..) = &self.heap[h] { - Addr::PStrLocation(h, 0) + pub fn detect_cycles_with_max(&self, max_steps: usize, value: HeapCellValue) -> CycleSearchResult { + let deref_v = self.deref(value); + let store_v = self.store(deref_v); + + // let mut pstr_chars = 0; + + let hare = read_heap_cell!(store_v, + (HeapCellValueTag::Lis, offset) => { + if max_steps > 0 { + offset+1 + } else { + return CycleSearchResult::UntouchedList(offset); + } + } + (HeapCellValueTag::PStrLoc, h) => { + let (h_offset, _n) = pstr_loc_and_offset(&self.heap, h); + + if self.heap[h].get_tag() == HeapCellValueTag::PStr { + h_offset+1 + } else { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + h + } + } + (HeapCellValueTag::PStrOffset) => { + unreachable!() + } + (HeapCellValueTag::CStr, cstr_atom) => { + return if max_steps > 0 { + let cstr = PartialString::from(cstr_atom); + let pstr_chars = cstr.as_str_from(0).chars().count(); + + if pstr_chars < max_steps { + CycleSearchResult::ProperList(pstr_chars) + } else { + CycleSearchResult::UntouchedCStr(cstr_atom, max_steps) + } + } else { + CycleSearchResult::UntouchedCStr(cstr_atom, 0) + }; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; + } else if name == atom!(".") && arity == 2 { + if max_steps > 0 { + s + 2 + } else { + return CycleSearchResult::UntouchedList(s + 1); + } + } else { + return CycleSearchResult::NotList; + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; } else { return CycleSearchResult::NotList; } @@ -240,221 +381,179 @@ impl MachineState { _ => { return CycleSearchResult::NotList; } - }; + ); let mut brent_st = BrentAlgState::new(hare); + brent_st.power += 1; // advance a step. + // brent_st.pstr_chars = pstr_chars; + loop { + if brent_st.num_steps() == max_steps { + return brent_st.to_result(&self.heap); + } + if let Some(result) = self.brents_alg_step(&mut brent_st) { return result; } } } - fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) { - let target_n = self[temp_v!(1)]; - self.unify(Addr::Usize(n), target_n); + fn term_variables_under_max_depth( + &mut self, + term: HeapCellValue, + max_depth: usize, + list_of_vars: HeapCellValue, + ) { + let mut seen_set = IndexSet::new(); + + { + let mut iter = stackful_post_order_iter(&mut self.heap, term); + + while let Some(value) = iter.next() { + if iter.parent_stack_len() >= max_depth { + iter.pop_stack(); + continue; + } + + let value = unmark_cell_bits!(value); + + if value.is_var() && !seen_set.contains(&value) { + seen_set.insert(value); + } + } + } + + let outcome = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, + seen_set.into_iter().rev(), + ) + ); + + unify_fn!(self, list_of_vars, outcome); + } + + fn finalize_skip_max_list(&mut self, n: usize, value: HeapCellValue) { + let target_n = self.registers[1]; + self.unify_fixnum(Fixnum::build_with(n as i64), target_n); if !self.fail { - let xs = self[temp_v!(4)]; - self.unify(addr, xs); + let xs = self.registers[4]; + unify!(self, value, xs); } } - fn skip_max_list_result(&mut self, max_steps: Option) { + fn skip_max_list_result(&mut self, max_steps: Option) { let search_result = if let Some(max_steps) = max_steps { if max_steps == -1 { - self.detect_cycles(self[temp_v!(3)]) + self.detect_cycles(self.registers[3]) } else { - self.detect_cycles_with_max(max_steps as usize, self[temp_v!(3)]) + self.detect_cycles_with_max(max_steps as usize, self.registers[3]) } } else { - self.detect_cycles(self[temp_v!(3)]) + self.detect_cycles(self.registers[3]) }; match search_result { - CycleSearchResult::PStrLocation(steps, h, n) => { - self.finalize_skip_max_list(steps, Addr::PStrLocation(h, n)); + CycleSearchResult::PStrLocation(steps, pstr_loc) => { + self.finalize_skip_max_list(steps, heap_loc_as_cell!(pstr_loc)); + } + CycleSearchResult::UntouchedList(l) => { + self.finalize_skip_max_list(0, list_loc_as_cell!(l)); + } + CycleSearchResult::UntouchedCStr(cstr_atom, n) => { + self.finalize_skip_max_list(n, string_as_cstr_cell!(cstr_atom)); + } + CycleSearchResult::EmptyList => { + self.finalize_skip_max_list(0, empty_list_as_cell!()); + } + CycleSearchResult::PartialList(n, r) => { + self.finalize_skip_max_list(n, r.as_heap_cell_value()); } - CycleSearchResult::UntouchedList(l) => self.finalize_skip_max_list(0, Addr::Lis(l)), - CycleSearchResult::EmptyList => self.finalize_skip_max_list(0, Addr::EmptyList), - CycleSearchResult::PartialList(n, r) => self.finalize_skip_max_list(n, r.as_addr()), CycleSearchResult::ProperList(steps) => { - self.finalize_skip_max_list(steps, Addr::EmptyList) + self.finalize_skip_max_list(steps, empty_list_as_cell!()) } CycleSearchResult::NotList => { - let xs0 = self[temp_v!(3)]; + let xs0 = self.registers[3]; self.finalize_skip_max_list(0, xs0); } }; } - pub(super) fn skip_max_list(&mut self) -> CallResult { - let max_steps = self.store(self.deref(self[temp_v!(2)])); - - match max_steps { - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { - let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); - return Err(self.error_form(MachineError::instantiation_error(), stub)); - } - addr => { - let max_steps_n = match Number::try_from((max_steps, &self.heap)) { - Ok(Number::Integer(n)) => n.to_isize(), - Ok(Number::Fixnum(n)) => Some(n), - _ => None, - }; - - if max_steps_n.map(|i| i >= -1).unwrap_or(false) { - let n = self.store(self.deref(self[temp_v!(1)])); - - match Number::try_from((n, &self.heap)) { - Ok(Number::Integer(n)) => { - if n.as_ref() == &0 { - let xs0 = self[temp_v!(3)]; - let xs = self[temp_v!(4)]; - - self.unify(xs0, xs); - } else { - self.skip_max_list_result(max_steps_n); - } - } - Ok(Number::Fixnum(n)) => { - if n == 0 { - let xs0 = self[temp_v!(3)]; - let xs = self[temp_v!(4)]; - - self.unify(xs0, xs); - } else { - self.skip_max_list_result(max_steps_n); - } - } - _ => { - self.skip_max_list_result(max_steps_n); - } - } - } else { - let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, addr), - stub, - )); - } - } - } - - Ok(()) - } + pub fn skip_max_list(&mut self) -> CallResult { + let max_steps = self.store(self.deref(self.registers[2])); - fn stream_from_file_spec( - &self, - file_spec: ClauseName, - indices: &mut IndexStore, - options: &StreamOptions, - ) -> Result { - if file_spec.as_str().is_empty() { - let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]); + if max_steps.is_var() { + let stub = functor_stub(atom!("$skip_max_list"), 4); + let err = self.instantiation_error(); return Err(self.error_form(err, stub)); } - // 8.11.5.3l) - if let Some(ref alias) = &options.alias { - if indices.stream_aliases.contains_key(alias) { - return Err(self.occupied_alias_permission_error(alias.clone(), "open", 4)); - } - } - - let mode = atom_from!(self, self.store(self.deref(self[temp_v!(2)]))); - let mut open_options = fs::OpenOptions::new(); - - let (is_input_file, in_append_mode) = match mode.as_str() { - "read" => { - open_options.read(true).write(false).create(false); - (true, false) - } - "write" => { - open_options - .read(false) - .write(true) - .truncate(true) - .create(true); - (false, false) - } - "append" => { - open_options - .read(false) - .write(true) - .create(true) - .append(true); - (false, true) - } - _ => { - let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::domain_error(DomainErrorType::IOMode, self[temp_v!(2)]); - - // 8.11.5.3h) - return Err(self.error_form(err, stub)); - } + let max_steps_n = match Number::try_from(max_steps) { + Ok(Number::Fixnum(n)) => Some(n.get_num()), + Ok(Number::Integer(n)) => n.to_i64(), + _ => None, }; - let file = match open_options.open(file_spec.as_str()) { - Ok(file) => file, - Err(err) => { - match err.kind() { - ErrorKind::NotFound => { - // 8.11.5.3j) - let stub = MachineError::functor_stub(clause_name!("open"), 4); - - let err = MachineError::existence_error( - self.heap.h(), - ExistenceError::SourceSink(self[temp_v!(1)]), - ); + if max_steps_n.map(|i| i >= -1).unwrap_or(false) { + let n = self.store(self.deref(self.registers[1])); - return Err(self.error_form(err, stub)); - } - ErrorKind::PermissionDenied => { - // 8.11.5.3k) - return Err(self.open_permission_error(self[temp_v!(1)], "open", 4)); - } - _ => { - let stub = MachineError::functor_stub(clause_name!("open"), 4); + match Number::try_from(n) { + Ok(Number::Integer(n)) => { + if &*n == &0 { + let xs0 = self.registers[3]; + let xs = self.registers[4]; - let err = MachineError::syntax_error(self.heap.h(), ParserError::IO(err)); + unify!(self, xs0, xs); + } else { + self.skip_max_list_result(max_steps_n); + } + } + Ok(Number::Fixnum(n)) => { + if n.get_num() == 0 { + let xs0 = self.registers[3]; + let xs = self.registers[4]; - return Err(self.error_form(err, stub)); + unify!(self, xs0, xs); + } else { + self.skip_max_list_result(max_steps_n); } } + _ => { + self.skip_max_list_result(max_steps_n); + } } - }; - - Ok(if is_input_file { - Stream::from_file_as_input(file_spec, file) } else { - Stream::from_file_as_output(file_spec, file, in_append_mode) - }) + let stub = functor_stub(atom!("$skip_max_list"), 4); + let err = self.type_error(ValidType::Integer, max_steps); + + return Err(self.error_form(err, stub)); + } + + Ok(()) } +} +impl MachineState { #[inline] - fn install_new_block(&mut self, r: RegType) -> usize { + fn install_new_block(&mut self, value: HeapCellValue) -> usize { self.block = self.b; + self.unify_fixnum(Fixnum::build_with(self.block as i64), value); - let c = Constant::Usize(self.block); - let addr = self[r]; - - self.write_constant_to_var(addr, &c); self.block } - fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: Addr) -> usize { - let threshold = self.lifted_heap.h() - lh_offset; + fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: HeapCellValue) -> usize { + let threshold = self.lifted_heap.len() - lh_offset; let mut copy_ball_term = CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.lifted_heap); - copy_ball_term.push(HeapCellValue::Addr(Addr::Lis(threshold + 1))); - copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 3))); - copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2))); + copy_ball_term.push(list_loc_as_cell!(threshold + 1)); + copy_ball_term.push(heap_loc_as_cell!(threshold + 3)); + copy_ball_term.push(heap_loc_as_cell!(threshold + 2)); copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy); @@ -471,124 +570,70 @@ impl MachineState { Ok(self.p = CodePtr::REPL(repl_code_ptr, p)) } - fn truncate_if_no_lifted_heap_diff(&mut self, addr_constr: AddrConstr) - where - AddrConstr: Fn(usize) -> Addr, - { - match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => { - if lh_offset >= self.lifted_heap.h() { + #[inline(always)] + fn truncate_if_no_lifted_heap_diff( + &mut self, + addr_constr: impl Fn(usize) -> HeapCellValue, + ) { + read_heap_cell!(self.store(self.deref(self.registers[1])), + (HeapCellValueTag::Fixnum, n) => { + let lh_offset = n.get_num() as usize; + + if lh_offset >= self.lifted_heap.len() { self.lifted_heap.truncate(lh_offset); } else { - let threshold = self.lifted_heap.h() - lh_offset; - self.lifted_heap - .push(HeapCellValue::Addr(addr_constr(threshold))); + let threshold = self.lifted_heap.len() - lh_offset; + self.lifted_heap.push(addr_constr(threshold)); } } - _ => self.fail = true, - } + _ => { + self.fail = true; + } + ); } - fn get_next_db_ref(&mut self, indices: &IndexStore, db_ref: &DBRef) { + fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option { match db_ref { - &DBRef::NamedPred(ref name, arity, _) => { - let key = (name.clone(), arity); - let mut iter = indices.code_dir.range(key..).skip(1); - - while let Some(((name, arity), idx)) = iter.next() { - if idx.is_undefined() { - self.fail = true; - return; - } - - if is_builtin_predicate(&name) { - continue; - } + DBRef::NamedPred(name, arity) => { + let key = (*name, *arity); - let a2 = self[temp_v!(2)]; + if let Some((last_idx, _, _)) = indices.code_dir.get_full(&key) { + for idx in last_idx + 1 .. indices.code_dir.len() { + let ((name, arity), idx) = indices.code_dir.get_index(idx).unwrap(); - if let Some(r) = a2.as_var() { - let spec = get_clause_spec( - name.clone(), - *arity, - &CompositeOpDir::new(&indices.op_dir, None), - ); - - let addr = self - .heap - .to_unifiable(HeapCellValue::DBRef(DBRef::NamedPred( - name.clone(), - *arity, - spec, - ))); + if idx.is_undefined() { + return None; + } - self.bind(r, addr); + if SystemClauseType::from(*name, *arity).is_some() { + continue; + } - return; + return Some(DBRef::NamedPred(*name, *arity)); } } - - self.fail = true; } - &DBRef::Op(_, spec, ref name, ref op_dir, _) => { - let fixity = match spec { - XF | YF => Fixity::Post, - FX | FY => Fixity::Pre, - _ => Fixity::In, - }; - - let key = OrderedOpDirKey(name.clone(), fixity); + DBRef::Op(name, fixity, op_dir) => { + let key = (*name, *fixity); - match op_dir.range(key..).skip(1).next() { - Some((OrderedOpDirKey(name, _), (priority, spec))) => { - let a2 = self[temp_v!(2)]; - - if let Some(r) = a2.as_var() { - let addr = self.heap.to_unifiable(HeapCellValue::DBRef(DBRef::Op( - *priority, - *spec, - name.clone(), - op_dir.clone(), - SharedOpDesc::new(*priority, *spec), - ))); - - self.bind(r, addr); - } else { - self.fail = true; - } + if let Some((last_idx, _, _)) = op_dir.get_full(&key) { + if let Some(((name, fixity), _)) = op_dir.get_index(last_idx+1) { + return Some(DBRef::Op(*name, *fixity, *op_dir)); } - None => self.fail = true, } } } - } - - fn int_to_char( - &self, - n: &Integer, - stub: &'static str, - arity: usize, - ) -> Result { - let c = n.to_u32().and_then(std::char::from_u32); - if let Some(c) = c { - Ok(c) - } else { - let stub = MachineError::functor_stub(clause_name!(stub), arity); - let err = MachineError::representation_error(RepFlag::CharacterCode); - let err = self.error_form(err, stub); - - Err(err) - } + None } fn parse_number_from_string( &mut self, mut string: String, indices: &IndexStore, - stub: MachineStub, + stub_gen: impl Fn() -> FunctorStub, ) -> CallResult { - let nx = self[temp_v!(2)]; + let nx = self.registers[2]; if let Some(c) = string.chars().last() { if layout_char!(c) { @@ -600,106 +645,159 @@ impl MachineState { } }); let err = ParserError::UnexpectedChar(c, line_num, col_num); + let err = self.syntax_error(err); - let h = self.heap.h(); - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); + return Err(self.error_form(err, stub_gen())); } } string.push('.'); - let mut stream = match parsing_stream(std::io::Cursor::new(string)) { - Ok(stream) => stream, - Err(e) => { - let err = MachineError::session_error(self.heap.h(), SessionError::from(e)); - - return Err(self.error_form(err, stub)); - } - }; - - let mut parser = Parser::new(&mut stream, self.atom_tbl.clone(), self.machine_flags()); + let stream = CharReader::new(std::io::Cursor::new(string)); + let mut parser = Parser::new(stream, self); match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) { Err(err) => { - let h = self.heap.h(); - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); + let err = self.syntax_error(err); + return Err(self.error_form(err, stub_gen())); } - Ok(Term::Constant(_, Constant::Rational(n))) => { - let addr = self.heap.put_constant(Constant::Rational(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Rational(n))) => { + self.unify_rational(n, nx); } - Ok(Term::Constant(_, Constant::Float(n))) => { - let addr = self.heap.put_constant(Constant::Float(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Float(n))) => { + self.unify_f64(n, nx); } - Ok(Term::Constant(_, Constant::Integer(n))) => { - let addr = self.heap.put_constant(Constant::Integer(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Integer(n))) => { + self.unify_big_int(n, nx); } - Ok(Term::Constant(_, Constant::Fixnum(n))) => { - let addr = self.heap.put_constant(Constant::Fixnum(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Fixnum(n))) => { + self.unify_fixnum(n, nx); } _ => { let err = ParserError::ParseBigInt(0, 0); + let err = self.syntax_error(err); - let h = self.heap.h(); - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); + return Err(self.error_form(err, stub_gen())); } } Ok(()) } - fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr { + fn call_continuation_chunk(&mut self, chunk: HeapCellValue, return_p: LocalCodePtr) -> LocalCodePtr { let chunk = self.store(self.deref(chunk)); - match chunk { - Addr::Str(s) => { - match &self.heap[s] { - HeapCellValue::NamedStr(arity, ..) => { - let num_cells = arity - 1; - let p_functor = self.heap[s + 1].as_addr(s + 1); + let s = chunk.get_value(); + let arity = cell_as_atom_cell!(self.heap[s]).get_arity(); - let cp = self.heap.to_local_code_ptr(&p_functor).unwrap(); - let prev_e = self.e; + let num_cells = arity - 1; + let p_functor = self.heap[s + 1]; - let e = self.stack.allocate_and_frame(num_cells); - let and_frame = self.stack.index_and_frame_mut(e); + let cp = to_local_code_ptr(&self.heap, p_functor).unwrap(); + let prev_e = self.e; - and_frame.prelude.e = prev_e; - and_frame.prelude.cp = return_p; + let e = self.stack.allocate_and_frame(num_cells); + let and_frame = self.stack.index_and_frame_mut(e); - self.p = CodePtr::Local(cp + 1); + and_frame.prelude.e = prev_e; + and_frame.prelude.cp = return_p; - // adjust cut point to occur after call_continuation. - if num_cells > 0 { - if let Addr::CutPoint(_) = self.heap[s + 2].as_addr(s + 2) { - and_frame[1] = Addr::CutPoint(self.b); - } else { - and_frame[1] = self.heap[s + 2].as_addr(s + 2); - } - } + self.p = CodePtr::Local(cp + 1); - for index in s + 3..s + 2 + num_cells { - and_frame[index - (s + 1)] = self.heap[index].as_addr(index); - } + // adjust cut point to occur after call_continuation. + if num_cells > 0 { + if let HeapCellValueTag::Fixnum = self.heap[s + 2].get_tag() { + and_frame[1] = fixnum_as_cell!(Fixnum::build_with(self.b as i64)); + } else { + and_frame[1] = self.heap[s + 2]; + } + } - self.e = e; + for index in s + 3..s + 2 + num_cells { + and_frame[index - (s + 1)] = self.heap[index]; + } - self.p.local() + self.e = e; + self.p.local() + } + + pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option { + read_heap_cell!(value, + (HeapCellValueTag::CStr, cstr_atom) => { + // avoid allocating a String if possible ... + Some(AtomOrString::Atom(cstr_atom)) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + if arity == 0 { + // ... likewise. + Some(AtomOrString::Atom(atom)) + } else { + None + } + } + _ => { + if value.is_constant() { + return None; + } + + let h = self.heap.len(); + self.heap.push(value); + + let mut iter = HeapPStrIter::new(&self.heap, h); + let string = iter.to_string(); + let at_terminator = iter.at_string_terminator(); + + self.heap.pop(); + + // if the iteration doesn't terminate like a string + // (i.e. with the [] atom or a CStr), it is not + // "str_like" so return None. + if at_terminator { + Some(AtomOrString::String(string)) + } else { + None + } + } + ) + } + + fn codes_to_string( + &mut self, + addrs: impl Iterator, + stub_gen: impl Fn() -> FunctorStub, + ) -> Result { + let mut string = String::new(); + + for addr in addrs { + match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => { + match u32::try_from(n.get_num()) { + Ok(n) => { + if let Some(c) = std::char::from_u32(n) { + string.push(c); + continue; + } + } + _ => {} + } + } + Ok(Number::Integer(n)) => { + if let Some(c) = n.to_u32().and_then(std::char::from_u32) { + string.push(c); + continue; } - _ => unreachable!(), + } + _ => { + let err = self.type_error(ValidType::Integer, addr); + return Err(self.error_form(err, stub_gen())); } } - _ => unreachable!(), + + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); } + + Ok(string) } pub(super) fn system_call( @@ -714,10 +812,10 @@ impl MachineState { ) -> CallResult { match ct { &SystemClauseType::BindFromRegister => { - let reg = self.store(self.deref(self[temp_v!(2)])); - let n = match Number::try_from((reg, &self.heap)) { + let reg = self.store(self.deref(self.registers[2])); + let n = match Number::try_from(reg) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), Ok(Number::Integer(n)) => n.to_usize(), - Ok(Number::Fixnum(n)) => usize::try_from(n).ok(), _ => { unreachable!() } @@ -725,10 +823,10 @@ impl MachineState { if let Some(n) = n { if n <= MAX_ARITY { - let target = self[temp_v!(n)]; - let addr = self[temp_v!(1)]; + let target = self.registers[n]; + let addr = self.registers[1]; - (self.unify_fn)(self, addr, target); + unify_fn!(self, addr, target); return return_from_clause!(self.last_call, self); } } @@ -737,14 +835,11 @@ impl MachineState { } &SystemClauseType::CurrentHostname => { match hostname::get().ok() { - Some(host) => match host.into_string().ok() { + Some(host) => match host.to_str() { Some(host) => { - let hostname = self.heap.to_unifiable(HeapCellValue::Atom( - clause_name!(host, self.atom_tbl), - None, - )); + let hostname = self.atom_tbl.build_with(host); - (self.unify_fn)(self, self[temp_v!(1)], hostname); + self.unify_atom(hostname, self.store(self.deref(self.registers[1]))); return return_from_clause!(self.last_call, self); } None => {} @@ -756,171 +851,202 @@ impl MachineState { return Ok(()); } &SystemClauseType::CurrentInput => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); + let stream = *current_input_stream; - let stream = current_input_stream.clone(); + if let Some(var) = addr.as_var() { + self.bind(var, stream_as_cell!(stream)); + return return_from_clause!(self.last_call, self); + } - match addr { - addr if addr.is_ref() => { - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - (self.unify_fn)(self, stream, addr); - } - Addr::Stream(other_stream) => { - if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { - self.fail = current_input_stream != other_stream; - } else { - unreachable!() - } - } - addr => { - let stub = MachineError::functor_stub(clause_name!("current_input"), 1); + read_heap_cell!(addr, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Stream, other_stream) => { + self.fail = stream != other_stream; + } + _ => { + let stub = functor_stub(atom!("current_input"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); - let err = MachineError::domain_error(DomainErrorType::Stream, addr); + return Err(self.error_form(err, stub)); + } + ); + } + _ => { + let stub = functor_stub(atom!("current_input"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); return Err(self.error_form(err, stub)); } - } + ); } &SystemClauseType::CurrentOutput => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let stream = current_output_stream.clone(); + let addr = self.store(self.deref(self.registers[1])); + let stream = *current_output_stream; - match addr { - addr if addr.is_ref() => { - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - (self.unify_fn)(self, stream, addr); - } - Addr::Stream(other_stream) => { - if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { - self.fail = current_output_stream != other_stream; - } else { - unreachable!() - } - } - addr => { - let stub = MachineError::functor_stub(clause_name!("current_input"), 1); + if let Some(var) = addr.as_var() { + self.bind(var, stream_as_cell!(stream)); + return return_from_clause!(self.last_call, self); + } - let err = MachineError::domain_error(DomainErrorType::Stream, addr); + read_heap_cell!(addr, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Stream, other_stream) => { + self.fail = stream != other_stream; + } + _ => { + let stub = functor_stub(atom!("current_output"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); + + return Err(self.error_form(err, stub)); + } + ); + } + _ => { + let stub = functor_stub(atom!("current_output"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); return Err(self.error_form(err, stub)); } - } + ); } &SystemClauseType::DirectoryFiles => { - let dir = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let path = std::path::Path::new(&dir); - let mut files = Vec::new(); - - if let Ok(entries) = fs::read_dir(path) { - for entry in entries { - if let Ok(entry) = entry { - match entry.file_name().into_string() { - Ok(name) => { - files.push(self.heap.put_complete_string(&name)); - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("directory_files"), - 2, - ); - let err = - MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + let path = std::path::Path::new(dir.as_str()); + let mut files = Vec::new(); + + if let Ok(entries) = fs::read_dir(path) { + for entry in entries { + if let Ok(entry) = entry { + if let Some(name) = entry.file_name().to_str() { + let name = self.atom_tbl.build_with(name); + files.push(atom_as_cstr_cell!(name)); + + continue; } } + + let stub = functor_stub(atom!("directory_files"), 2); + let err = self.representation_error(RepFlag::Character); + let err = self.error_form(err, stub); + + return Err(err); } + + let files_list = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, files.into_iter()) + ); + + unify!(self, self.registers[2], files_list); + return return_from_clause!(self.last_call, self); } } - let files_list = Addr::HeapCell(self.heap.to_list(files.into_iter())); - (self.unify_fn)(self, self[temp_v!(2)], files_list); + self.fail = true; } &SystemClauseType::FileSize => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let len = Integer::from(fs::metadata(&file).unwrap().len()); - - let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len))); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + let len = Number::arena_from( + fs::metadata(file.as_str()).unwrap().len(), + &mut self.arena, + ); - (self.unify_fn)(self, self[temp_v!(2)], len); + match len { + Number::Fixnum(n) => self.unify_fixnum(n, self.registers[2]), + Number::Integer(n) => self.unify_big_int(n, self.registers[2]), + _ => unreachable!(), + } + } else { + self.fail = true; + } } &SystemClauseType::FileExists => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - if !std::path::Path::new(&file).exists() || !fs::metadata(&file).unwrap().is_file() - { + if let Some(file) = self.value_to_str_like(self.registers[1]) { + let file_str = file.as_str(); + + if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() { + self.fail = true; + } + } else { self.fail = true; - return Ok(()); } } &SystemClauseType::DirectoryExists => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - if !std::path::Path::new(&directory).exists() - || !fs::metadata(&directory).unwrap().is_dir() - { + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + let dir_str = dir.as_str(); + + if !std::path::Path::new(dir_str).exists() + || !fs::metadata(dir_str).unwrap().is_dir() + { + self.fail = true; + return Ok(()); + } + } else { self.fail = true; - return Ok(()); } } &SystemClauseType::DirectorySeparator => { - let addr = self - .heap - .put_constant(Constant::Char(std::path::MAIN_SEPARATOR)); - (self.unify_fn)(self, self[temp_v!(1)], addr); + self.unify_char(std::path::MAIN_SEPARATOR, self.registers[1]); } &SystemClauseType::MakeDirectory => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - match fs::create_dir(directory) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + match fs::create_dir(dir.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; } } &SystemClauseType::MakeDirectoryPath => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { - match fs::create_dir_all(directory) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + match fs::create_dir_all(dir.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; } } &SystemClauseType::DeleteFile => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - match fs::remove_file(file) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + match fs::remove_file(file.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } } } &SystemClauseType::RenameFile => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let renamed = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - - match fs::rename(file, renamed) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + if let Some(renamed) = self.value_to_str_like(self.registers[2]) { + if fs::rename(file.as_str(), renamed.as_str()).is_ok() { + return return_from_clause!(self.last_call, self); + } } } + + self.fail = true; } &SystemClauseType::DeleteDirectory => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - match fs::remove_dir(directory) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + match fs::remove_dir(dir.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } } } @@ -929,283 +1055,211 @@ impl MachineState { let current = match dir.to_str() { Some(d) => d, _ => { - let stub = - MachineError::functor_stub(clause_name!("working_directory"), 2); - let err = MachineError::representation_error(RepFlag::Character); + let stub = functor_stub(atom!("working_directory"), 2); + let err = self.representation_error(RepFlag::Character); let err = self.error_form(err, stub); return Err(err); } }; - let chars = self.heap.put_complete_string(current); - (self.unify_fn)(self, self[temp_v!(1)], chars); + let current_atom = self.atom_tbl.build_with(¤t); - let next = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); + self.unify_complete_string( + current_atom, + self.store(self.deref(self.registers[1])), + ); - match env::set_current_dir(std::path::Path::new(&next)) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if self.fail { + return Ok(()); + } + + if let Some(next) = self.value_to_str_like(self.registers[2]) { + if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() { + return return_from_clause!(self.last_call, self); } } - } else { - self.fail = true; - return Ok(()); } + + self.fail = true; } &SystemClauseType::PathCanonical => { - let path = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + if let Some(path) = self.value_to_str_like(self.registers[1]) { + match fs::canonicalize(path.as_str()) { + Ok(canonical) => { + let cs = match canonical.to_str() { + Some(s) => s, + _ => { + let stub = functor_stub(atom!("path_canonical"), 2); + let err = self.representation_error(RepFlag::Character); + let err = self.error_form(err, stub); - match fs::canonicalize(path) { - Ok(canonical) => { - let cs = match canonical.to_str() { - Some(s) => s, - _ => { - let stub = - MachineError::functor_stub(clause_name!("path_canonical"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + return Err(err); + } + }; - return Err(err); - } - }; - let chars = self.heap.put_complete_string(cs); - (self.unify_fn)(self, self[temp_v!(2)], chars); - } - _ => { - self.fail = true; - return Ok(()); + let canonical_atom = self.atom_tbl.build_with(cs); + + self.unify_complete_string( + canonical_atom, + self.store(self.deref(self.registers[2])), + ); + + return return_from_clause!(self.last_call, self); + } + _ => { + } } } + + self.fail = true; } &SystemClauseType::FileTime => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + let which = cell_as_atom!(self.store(self.deref(self.registers[2]))); + + if let Ok(md) = fs::metadata(file.as_str()) { + if let Ok(time) = match which { + atom!("modification") => md.modified(), + atom!("access") => md.accessed(), + atom!("creation") => md.created(), + _ => { + unreachable!() + } + } { + let chars_atom = self.systemtime_to_timestamp(time); - let which = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.as_str() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + self.unify_complete_string( + chars_atom, + self.registers[3], + ); - if let Ok(md) = fs::metadata(file) { - if let Ok(time) = match which { - "modification" => md.modified(), - "access" => md.accessed(), - "creation" => md.created(), - _ => { - unreachable!() + return return_from_clause!(self.last_call, self); } - } { - let chars = self.systemtime_to_timestamp(time); - (self.unify_fn)(self, self[temp_v!(3)], chars); - } else { - self.fail = true; - return Ok(()); } - } else { - self.fail = true; - return Ok(()); } + + self.fail = true; } &SystemClauseType::AtomChars => { - let a1 = self[temp_v!(1)]; + let a1 = self.store(self.deref(self.registers[1])); - match self.store(self.deref(a1)) { - Addr::Char(c) => { - let iter = once(Addr::Char(c)); - let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); + read_heap_cell!(a1, + (HeapCellValueTag::Char) => { + let h = self.heap.len(); - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, a2, list_of_chars); - } - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - let s = self.heap.put_complete_string(name.as_str()); - let a2 = self[temp_v!(2)]; + self.heap.push(a1); + self.heap.push(empty_list_as_cell!()); - (self.unify_fn)(self, s, a2); + unify!(self, self.registers[2], list_loc_as_cell!(h)); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + self.unify_complete_string( + name, + self.store(self.deref(self.registers[2])), + ); } else { - unreachable!() + self.fail = true; } } - Addr::EmptyList => { - let a2 = self[temp_v!(2)]; - let chars = vec![Addr::Char('['), Addr::Char(']')]; - - let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter())); - - (self.unify_fn)(self, a2, list_of_chars); - } - addr if addr.is_ref() => { - let mut iter = self.heap_pstr_iter(self[temp_v!(2)]); - let string = iter.to_string(); - - match iter.focus() { - Addr::EmptyList => { - if &string == "[]" { - (self.unify_fn)(self, addr, Addr::EmptyList); - } else { - let chars = clause_name!(string, self.atom_tbl); - let atom = - self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let a2 = self.store(self.deref(self.registers[2])); - (self.unify_fn)(self, addr, atom); + if let Some(str_like) = self.value_to_str_like(a2) { + let atom = match str_like { + AtomOrString::Atom(atom) => { + atom } - } - focus => { - if let Addr::Lis(l) = focus { - let stub = - MachineError::functor_stub(clause_name!("atom_chars"), 2); - - let err = MachineError::type_error( - self.heap.h(), - ValidType::Character, - Addr::HeapCell(l), - ); - - return Err(self.error_form(err, stub)); - } else { - unreachable!() + AtomOrString::String(string) => { + self.atom_tbl.build_with(&string) } - } + }; + + self.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); + return return_from_clause!(self.last_call, self); } + + self.fail = true; } - _ => unreachable!(), - }; + _ => { + unreachable!(); + } + ); } &SystemClauseType::AtomCodes => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Char(c) => { - let iter = once(Addr::Fixnum(c as isize)); - let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); + let a1 = self.store(self.deref(self.registers[1])); - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, a2, list_of_codes); - } - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - let a2 = self.store(self.deref(self[temp_v!(2)])); + read_heap_cell!(a1, + (HeapCellValueTag::Char, c) => { + let h = self.heap.len(); - let iter = name.as_str().chars().map(|c| Addr::Fixnum(c as isize)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); + self.heap.push(empty_list_as_cell!()); - let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); + unify!(self, list_loc_as_cell!(h), self.registers[2]); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + let iter = name.chars() + .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - (self.unify_fn)(self, a2, list_of_codes); + let h = iter_to_heap_list(&mut self.heap, iter); + unify!(self, heap_loc_as_cell!(h), self.registers[2]); } else { - unreachable!() + self.fail = true; } } - Addr::EmptyList => { - let chars = vec![Addr::Fixnum('[' as isize), Addr::Fixnum(']' as isize)]; - - let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter())); - let a2 = self[temp_v!(2)]; + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let stub_gen = || functor_stub(atom!("atom_codes"), 2); - (self.unify_fn)(self, a2, list_of_codes); - } - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("atom_codes"), 2); - - match self.try_from_list(temp_v!(2), stub) { - Err(e) => return Err(e), + match self.try_from_list(self.registers[2], stub_gen) { Ok(addrs) => { - let mut chars = String::new(); - - for addr in addrs { - let addr = self.store(self.deref(addr)); + let string = self.codes_to_string(addrs.into_iter(), stub_gen)?; + let atom = self.atom_tbl.build_with(&string); - match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => { - let c = self.int_to_char( - &Integer::from(n), - "atom_codes", - 2, - )?; - - chars.push(c); - continue; - } - Ok(Number::Integer(n)) => { - let c = self.int_to_char(&n, "atom_codes", 2)?; - chars.push(c); - - continue; - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("atom_codes"), - 2, - ); - - let err = MachineError::type_error( - self.heap.h(), - ValidType::Integer, - addr, - ); - - return Err(self.error_form(err, stub)); - } - } - } - - let string = self.heap.to_unifiable(HeapCellValue::Atom( - clause_name!(chars, self.atom_tbl), - None, - )); - - self.bind(addr.as_var().unwrap(), string); + self.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); + } + Err(e) => { + return Err(e); } } } _ => { - unreachable!() + unreachable!(); } - }; + ); } &SystemClauseType::AtomLength => { - let a1 = self.store(self.deref(self[temp_v!(1)])); + let a1 = self.store(self.deref(self.registers[1])); - let atom = match self.store(self.deref(a1)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() + let len: i64 = read_heap_cell!(a1, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + name.chars().count() as i64 } else { - unreachable!() + self.fail = true; + return Ok(()); } } - Addr::EmptyList => { - clause_name!("[]") - } - Addr::Char(c) => { - clause_name!(c.to_string(), self.atom_tbl) + (HeapCellValueTag::Char) => { + 1 } _ => { unreachable!() } - }; - - let len = Integer::from(atom.as_str().chars().count()); - let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len))); - - let a2 = self[temp_v!(2)]; + ); - (self.unify_fn)(self, a2, len); + self.unify_fixnum( + Fixnum::build_with(len), + self.store(self.deref(self.registers[2])), + ); } &SystemClauseType::CallContinuation => { - let stub = MachineError::functor_stub(clause_name!("call_continuation"), 1); + let stub_gen = || functor_stub(atom!("call_continuation"), 1); + let a1 = self.store(self.deref(self.registers[1])); - match self.try_from_list(temp_v!(1), stub) { + match self.try_from_list(a1, stub_gen) { Err(e) => return Err(e), Ok(cont_chunks) => { let mut return_p = if self.last_call { @@ -1225,125 +1279,97 @@ impl MachineState { return Ok(()); } &SystemClauseType::CharsToNumber => { - let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); + let stub_gen = || functor_stub(atom!("number_chars"), 2); + let a1 = self.store(self.deref(self.registers[1])); - match self.try_from_list(temp_v!(1), stub) { - Err(e) => { - return Err(e); - } - Ok(addrs) => match self.try_char_list(addrs) { - Ok(string) => { - let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); - self.parse_number_from_string(string, indices, stub)?; - } - Err(err) => { - let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); - - return Err(self.error_form(err, stub)); - } - }, + if let Some(atom_or_string) = self.value_to_str_like(a1) { + self.parse_number_from_string(atom_or_string.to_string(), indices, stub_gen)?; + } else { + // a1 is a ground list at the call site within + // number_chars/2, so failure of value_to_str_like + // means the list contains a non-character. + let err = self.type_error(ValidType::Character, a1); + return Err(self.error_form(err, stub_gen())); } } &SystemClauseType::CreatePartialString => { - let atom = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let atom = cell_as_atom!(self.store(self.deref(self.registers[1]))); - if atom.as_str().is_empty() { + if atom == atom!("") { self.fail = true; return Ok(()); } - let pstr = self.heap.allocate_pstr(atom.as_str()); - (self.unify_fn)(self, self[temp_v!(2)], pstr); + let pstr_h = self.heap.len(); - if !self.fail { - let h = self.heap.h(); - let pstr_tail = self.heap[h - 1].as_addr(h - 1); + self.heap.push(pstr_as_cell!(atom)); + self.heap.push(heap_loc_as_cell!(pstr_h+1)); - (self.unify_fn)(self, self[temp_v!(3)], pstr_tail); + unify!(self, self.registers[2], pstr_loc_as_cell!(pstr_h)); + + if !self.fail { + self.bind(Ref::heap_cell(pstr_h+1), self.registers[3]); } } &SystemClauseType::IsPartialString => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let value = self.store(self.deref(self.registers[1])); - match addr { - Addr::EmptyList => { - return return_from_clause!(self.last_call, self); - } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { - self.fail = true; - return Ok(()); - } - _ => {} - } + let h = self.heap.len(); + self.heap.push(value); - let mut heap_pstr_iter = self.heap_pstr_iter(addr); + let mut iter = HeapPStrIter::new(&self.heap, h); - while let Some(_) = heap_pstr_iter.next() {} + while let Some(_) = iter.next() {} - self.fail = match heap_pstr_iter.focus() { - Addr::AttrVar(_) - | Addr::HeapCell(_) - | Addr::StackCell(..) - | Addr::EmptyList => false, - _ => true, - }; + let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator(); + self.fail = !at_end_of_pstr; + + self.heap.pop(); } &SystemClauseType::PartialStringTail => { - let pstr = self.store(self.deref(self[temp_v!(1)])); + let pstr = self.store(self.deref(self.registers[1])); - match pstr { - Addr::PStrLocation(h, _) => { - if let HeapCellValue::PartialString(_, true) = &self.heap[h] { - let tail = self.heap[h + 1].as_addr(h + 1); - let target = self[temp_v!(2)]; + read_heap_cell!(pstr, + (HeapCellValueTag::PStrLoc, h) => { + let (h, _) = pstr_loc_and_offset(&self.heap, h); - (self.unify_fn)(self, tail, target); + if HeapCellValueTag::CStr == self.heap[h].get_tag() { + self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); } else { - self.fail = true; - return Ok(()); + unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]); } } - Addr::Lis(h) => { - (self.unify_fn)(self, Addr::HeapCell(h + 1), self[temp_v!(2)]); + (HeapCellValueTag::CStr) => { + self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); } - Addr::EmptyList => { - self.fail = true; - return Ok(()); + (HeapCellValueTag::Lis, h) => { + unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]); } _ => { - unreachable!() + self.fail = true; } - } + ); } &SystemClauseType::PeekByte => { + let stub_gen = || functor_stub(atom!("peek_byte"), 2); + let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "peek_byte", + atom!("peek_byte"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Binary, - Some(self[temp_v!(2)]), - clause_name!("peek_byte"), + Some(self.registers[2]), + atom!("peek_byte"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1351,45 +1377,38 @@ impl MachineState { } if stream.at_end_of_stream() { - stream.set_past_end_of_stream(); - (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1)); + stream.set_past_end_of_stream(true); + + self.unify_fixnum( + Fixnum::build_with(-1), + self.store(self.deref(self.registers[2])), + ); + return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { + let addr = match self.store(self.deref(self.registers[2])) { + addr if addr.is_var() => addr, + addr => match Number::try_from(addr) { Ok(Number::Integer(n)) => { if let Some(nb) = n.to_u8() { - Addr::Usize(nb as usize) + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - Addr::Usize(nb as usize) + if let Ok(nb) = u8::try_from(n.get_num()) { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } _ => { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } }, }; @@ -1397,15 +1416,7 @@ impl MachineState { loop { match stream.peek_byte().map_err(|e| e.kind()) { Ok(b) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Usize(b as usize)); - break; - } else if addr == Addr::Usize(b as usize) { - break; - } else { - self.fail = true; - return Ok(()); - } + self.unify_fixnum(Fixnum::build_with(b as i64), addr); } Err(ErrorKind::PermissionDenied) => { self.fail = true; @@ -1413,13 +1424,13 @@ impl MachineState { } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("peek_byte"), + self.registers[2], + stream, + atom!("peek_byte"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1429,23 +1440,25 @@ impl MachineState { } } &SystemClauseType::PeekChar => { + let stub_gen = || functor_stub(atom!("peek_char"), 2); + let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "peek_char", + atom!("peek_char"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("peek_char"), + Some(self.registers[2]), + atom!("peek_char"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1453,106 +1466,87 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = clause_name!("end_of_file"); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Atom(end_of_file, None)); - - stream.set_past_end_of_stream(); + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - Addr::Char(c) + let a2 = self.store(self.deref(self.registers[2])); + + let a2 = read_heap_cell!(a2, + (HeapCellValueTag::Char) => { + a2 + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + if let Some(c) = name.as_char() { + char_as_cell!(c) } else { - unreachable!() + let err = self.type_error(ValidType::InCharacter, a2); + return Err(self.error_form(err, stub_gen())); } + } else { + let err = self.type_error(ValidType::InCharacter, a2); + return Err(self.error_form(err, stub_gen())); } - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit.as_addr(h), - clause_name!("peek_char"), - 2, - )); - } - }, - Addr::Char(d) => Addr::Char(d), - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit, - clause_name!("peek_char"), - 2, - )); } - }; + (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { + a2 + } + _ => { + let err = self.type_error(ValidType::InCharacter, a2); + return Err(self.error_form(err, stub_gen())); + } + ); loop { - match stream.peek_char().map_err(|e| e.kind()) { - Ok(d) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Char(d)); - break; - } else if addr == Addr::Char(d) { - break; - } else { - self.fail = true; - return Ok(()); - } + match stream.peek_char().map(|result| result.map_err(|e| e.kind())) { + Some(Ok(d)) => { + self.unify_char(d, a2); } - Err(ErrorKind::PermissionDenied) => { + Some(Err(ErrorKind::PermissionDenied)) => { self.fail = true; break; } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("peek_char"), + self.registers[2], + stream, + atom!("peek_char"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - } /* - _ => { - let stub = MachineError::functor_stub(clause_name!("peek_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); - }*/ + } } } } &SystemClauseType::PeekCode => { + let stub_gen = || functor_stub(atom!("peek_code"), 2); + let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "peek_code", + atom!("peek_code"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("peek_code"), + Some(self.registers[2]), + atom!("peek_code"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1560,89 +1554,73 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = clause_name!("end_of_file"); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Atom(end_of_file, None)); - - stream.set_past_end_of_stream(); + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - let n = n - .to_u32() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + let a2 = self.store(self.deref(self.registers[2])); - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("peek_code"), - 2, - )); + let addr = read_heap_cell!(a2, + (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { + a2 + } + _ => { + match Number::try_from(a2) { + Ok(Number::Integer(n)) => { + let n = n + .to_u32() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + + if let Some(n) = n { + fixnum_as_cell!(Fixnum::build_with(n as i64)) + } else { + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); + } } - } - Ok(Number::Fixnum(n)) => { - let n = u32::try_from(n) - .ok() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + Ok(Number::Fixnum(n)) => { + let n = u32::try_from(n.get_num()) + .ok() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("peek_code"), - 2, - )); + if let Some(n) = n { + fixnum_as_cell!(Fixnum::build_with(n as i64)) + } else { + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); + } + } + _ => { + let err = self.type_error(ValidType::Integer, self.registers[2]); + return Err(self.error_form(err, stub_gen())); } } - _ => { - return Err(self.type_error( - ValidType::Integer, - self[temp_v!(2)], - clause_name!("peek_code"), - 2, - )); - } - }, - }; + } + ); loop { let result = stream.peek_char(); - match result.map_err(|e| e.kind()) { - Ok(c) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Fixnum(c as isize)); - break; - } else if addr == Addr::Fixnum(c as isize) { - break; - } else { - self.fail = true; - return Ok(()); - } + match result.map(|result| result.map_err(|e| e.kind())) { + Some(Ok(c)) => { + self.unify_fixnum(Fixnum::build_with(c as i64), addr); } - Err(ErrorKind::PermissionDenied) => { + Some(Err(ErrorKind::PermissionDenied)) => { self.fail = true; break; } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("peek_code"), + self.registers[2], + stream, + atom!("peek_code"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1652,16 +1630,16 @@ impl MachineState { } } &SystemClauseType::NumberToChars => { - let n = self[temp_v!(1)]; - let chs = self[temp_v!(2)]; + let n = self.registers[1]; + let chs = self.registers[2]; let n = self.store(self.deref(n)); - let string = match Number::try_from((n, &self.heap)) { + let string = match Number::try_from(n) { Ok(Number::Float(OrderedFloat(n))) => { format!("{0:<20?}", n) } - Ok(Number::Fixnum(n)) => n.to_string(), + Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), Ok(Number::Rational(r)) => { // n has already been confirmed as an integer, and @@ -1674,20 +1652,18 @@ impl MachineState { } }; - let chars = string.trim().chars().map(|c| Addr::Char(c)); - let char_list = Addr::HeapCell(self.heap.to_list(chars)); - - (self.unify_fn)(self, char_list, chs); + let chars_atom = self.atom_tbl.build_with(&string.trim()); + self.unify_complete_string(chars_atom, self.store(self.deref(chs))); } &SystemClauseType::NumberToCodes => { - let n = self[temp_v!(1)]; - let chs = self[temp_v!(2)]; + let n = self.store(self.deref(self.registers[1])); + let chs = self.registers[2]; - let string = match Number::try_from((n, &self.heap)) { + let string = match Number::try_from(n) { Ok(Number::Float(OrderedFloat(n))) => { format!("{0:<20?}", n) } - Ok(Number::Fixnum(n)) => n.to_string(), + Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), Ok(Number::Rational(r)) => { // n has already been confirmed as an integer, and @@ -1700,219 +1676,199 @@ impl MachineState { } }; - let codes = string.trim().chars().map(|c| Addr::Fixnum(c as isize)); - - let codes_list = Addr::HeapCell(self.heap.to_list(codes)); + let codes = string.trim().chars().map(|c| { + fixnum_as_cell!(Fixnum::build_with(c as i64)) + }); - (self.unify_fn)(self, codes_list, chs); + let h = iter_to_heap_list(&mut self.heap, codes); + unify!(self, heap_loc_as_cell!(h), chs); } &SystemClauseType::CodesToNumber => { - let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); + let stub_gen = || functor_stub(atom!("number_codes"), 2); - match self.try_from_list(temp_v!(1), stub) { + match self.try_from_list(self.registers[1], stub_gen) { Err(e) => { return Err(e); } - Ok(addrs) => match self.try_char_list(addrs) { - Ok(chars) => { - let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); - self.parse_number_from_string(chars, indices, stub)?; - } - Err(err) => { - let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); - - return Err(self.error_form(err, stub)); - } - }, + Ok(addrs) => { + let string = self.codes_to_string(addrs.into_iter(), stub_gen)?; + self.parse_number_from_string(string, indices, stub_gen)?; + } } } &SystemClauseType::LiftedHeapLength => { - let a1 = self[temp_v!(1)]; - let lh_len = Addr::Usize(self.lifted_heap.h()); + let a1 = self.registers[1]; + let lh_len = Fixnum::build_with(self.lifted_heap.len() as i64); - (self.unify_fn)(self, a1, lh_len); + self.unify_fixnum(lh_len, a1); } &SystemClauseType::CharCode => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Con(h) if self.heap.atom_at(h) => { - let c = if let HeapCellValue::Atom(name, _) = &self.heap[h] { - if name.is_char() { - name.as_str().chars().next().unwrap() - } else { - self.fail = true; - return Ok(()); - } - } else { - unreachable!() - }; + let stub_gen = || functor_stub(atom!("char_code"), 2); + let a1 = self.store(self.deref(self.registers[1])); - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::Fixnum(c as isize), a2); + let c = read_heap_cell!(a1, + (HeapCellValueTag::Atom, (name, _arity)) => { + name.as_char().unwrap() } - Addr::Char(c) => { - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::Fixnum(c as isize), a2); + (HeapCellValueTag::Char, c) => { + c } - addr if addr.is_ref() => { - let a2 = self[temp_v!(2)]; - let a2 = self.store(self.deref(a2)); + _ => { + let a2 = self.store(self.deref(self.registers[2])); + + match Number::try_from(a2) { + Ok(Number::Integer(n)) => { + let c = match n.to_u32().and_then(std::char::from_u32) { + Some(c) => c, + _ => { + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); + } + }; - let c = match Number::try_from((a2, &self.heap)) { - Ok(Number::Integer(n)) => self.int_to_char(&n, "char_code", 2)?, + self.unify_char(c, a2); + return return_from_clause!(self.last_call, self); + } Ok(Number::Fixnum(n)) => { - self.int_to_char(&Integer::from(n), "char_code", 2)? + match u32::try_from(n.get_num()) { + Ok(n) => { + if let Some(c) = std::char::from_u32(n) { + self.unify_char(c, a1); + return return_from_clause!(self.last_call, self); + } + } + _ => {} + } + + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); } _ => { self.fail = true; return Ok(()); } - }; - - (self.unify_fn)(self, Addr::Char(c), addr); - } - _ => { - unreachable!(); + } } - }; + ); + + self.unify_fixnum( + Fixnum::build_with(c as i64), + self.store(self.deref(self.registers[2])), + ); } &SystemClauseType::CharType => { - let a1 = self.store(self.deref(self[temp_v!(1)])); - let a2 = self.store(self.deref(self[temp_v!(2)])); - - let c = match a1 { - Addr::Char(c) => c, - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - name.as_str().chars().next().unwrap() - } else { - unreachable!() - } + let a1 = self.store(self.deref(self.registers[1])); + let a2 = self.store(self.deref(self.registers[2])); + + let c = read_heap_cell!(a1, + (HeapCellValueTag::Char, c) => { + c } - _ => unreachable!(), - }; - let chars = match a2 { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - name.as_str().to_string() - } else { - unreachable!() - } + (HeapCellValueTag::Atom, (name, _arity)) => { + name.as_char().unwrap() } - Addr::Char(c) => c.to_string(), - _ => unreachable!(), - }; + _ => { + unreachable!() + } + ); + + let chars = cell_as_atom!(a2); self.fail = true; // This predicate fails by default. + macro_rules! macro_check { - ($id:ident, $name:tt) => { + ($id:ident, $name:expr) => { if $id!(c) && chars == $name { self.fail = false; - return return_from_clause!(self.last_call, self); } }; } + macro_rules! method_check { - ($id:ident, $name:tt) => { + ($id:ident, $name:expr) => { if c.$id() && chars == $name { self.fail = false; - return return_from_clause!(self.last_call, self); } }; } - macro_check!(alpha_char, "alpha"); - method_check!(is_alphabetic, "alphabetic"); - method_check!(is_alphanumeric, "alphanumeric"); - macro_check!(alpha_numeric_char, "alnum"); - method_check!(is_ascii, "ascii"); - method_check!(is_ascii_punctuation, "ascii_ponctuaction"); - method_check!(is_ascii_graphic, "ascii_graphic"); - // macro_check!(backslash_char, "backslash"); - // macro_check!(back_quote_char, "back_quote"); - macro_check!(binary_digit_char, "binary_digit"); - // macro_check!(capital_letter_char, "upper"); + + macro_check!(alpha_char, atom!("alpha")); + method_check!(is_alphabetic, atom!("alphabetic")); + method_check!(is_alphanumeric, atom!("alphanumeric")); + macro_check!(alpha_numeric_char, atom!("alnum")); + method_check!(is_ascii, atom!("ascii")); + method_check!(is_ascii_punctuation, atom!("ascii_ponctuaction")); + method_check!(is_ascii_graphic, atom!("ascii_graphic")); + // macro_check!(backslash_char, atom!("backslash")); + // macro_check!(back_quote_char, atom!("back_quote")); + macro_check!(binary_digit_char, atom!("binary_digit")); + // macro_check!(capital_letter_char, atom!("upper")); // macro_check!(comment_1_char, "comment_1"); // macro_check!(comment_2_char, "comment_2"); - method_check!(is_control, "control"); - // macro_check!(cut_char, "cut"); - macro_check!(decimal_digit_char, "decimal_digit"); - // macro_check!(decimal_point_char, "decimal_point"); - // macro_check!(double_quote_char, "double_quote"); - macro_check!(exponent_char, "exponent"); - macro_check!(graphic_char, "graphic"); - macro_check!(graphic_token_char, "graphic_token"); - macro_check!(hexadecimal_digit_char, "hexadecimal_digit"); - macro_check!(layout_char, "layout"); - method_check!(is_lowercase, "lower"); - macro_check!(meta_char, "meta"); - // macro_check!(new_line_char, "new_line"); - method_check!(is_numeric, "numeric"); - macro_check!(octal_digit_char, "octal_digit"); - macro_check!(octet_char, "octet"); - macro_check!(prolog_char, "prolog"); - // macro_check!(semicolon_char, "semicolon"); - macro_check!(sign_char, "sign"); - // macro_check!(single_quote_char, "single_quote"); - // macro_check!(small_letter_char, "lower"); - macro_check!(solo_char, "solo"); - // macro_check!(space_char, "space"); - macro_check!(symbolic_hexadecimal_char, "symbolic_hexadecimal"); - macro_check!(symbolic_control_char, "symbolic_control"); - method_check!(is_uppercase, "upper"); - // macro_check!(variable_indicator_char, "variable_indicator"); - method_check!(is_whitespace, "whitespace"); + method_check!(is_control, atom!("control")); + // macro_check!(cut_char, atom!("cut")); + macro_check!(decimal_digit_char, atom!("decimal_digit")); + // macro_check!(decimal_point_char, atom!("decimal_point")); + // macro_check!(double_quote_char, atom!("double_quote")); + macro_check!(exponent_char, atom!("exponent")); + macro_check!(graphic_char, atom!("graphic")); + macro_check!(graphic_token_char, atom!("graphic_token")); + macro_check!(hexadecimal_digit_char, atom!("hexadecimal_digit")); + macro_check!(layout_char, atom!("layout")); + method_check!(is_lowercase, atom!("lower")); + macro_check!(meta_char, atom!("meta")); + // macro_check!(new_line_char, atom!("new_line")); + method_check!(is_numeric, atom!("numeric")); + macro_check!(octal_digit_char, atom!("octal_digit")); + macro_check!(octet_char, atom!("octet")); + macro_check!(prolog_char, atom!("prolog")); + // macro_check!(semicolon_char, atom!("semicolon")); + macro_check!(sign_char, atom!("sign")); + // macro_check!(single_quote_char, atom!("single_quote")); + // macro_check!(small_letter_char, atom!("lower")); + macro_check!(solo_char, atom!("solo")); + // macro_check!(space_char, atom!("space")); + macro_check!(symbolic_hexadecimal_char, atom!("symbolic_hexadecimal")); + macro_check!(symbolic_control_char, atom!("symbolic_control")); + method_check!(is_uppercase, atom!("upper")); + // macro_check!(variable_indicator_char, atom!("variable_indicator")); + method_check!(is_whitespace, atom!("whitespace")); } &SystemClauseType::CheckCutPoint => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); + let old_b = cell_as_fixnum!(addr).get_num() as usize; - match addr { - Addr::Usize(old_b) | Addr::CutPoint(old_b) => { - let prev_b = self.stack.index_or_frame(self.b).prelude.b; - let prev_b = self.stack.index_or_frame(prev_b).prelude.b; + let prev_b = self.stack.index_or_frame(self.b).prelude.b; + let prev_b = self.stack.index_or_frame(prev_b).prelude.b; - if prev_b > old_b { - self.fail = true; - } - } - _ => self.fail = true, - }; + if prev_b > old_b { + self.fail = true; + } } &SystemClauseType::CopyTermWithoutAttrVars => { self.copy_term(AttrVarPolicy::StripAttributes); } &SystemClauseType::FetchGlobalVar => { - let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - (h, atom.clone()) - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; - - let addr = self[temp_v!(2)]; + let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let addr = self.registers[2]; match indices.global_variables.get_mut(&key) { Some((ref ball, ref mut loc)) => match loc { - Some(ref value_addr) => { - (self.unify_fn)(self, addr, *value_addr); + Some(value_loc) => { + unify_fn!(self, addr, *value_loc); } - loc @ None if !ball.stub.is_empty() => { - let h = self.heap.h(); + None if !ball.stub.is_empty() => { + let h = self.heap.len(); let stub = ball.copy_and_align(h); self.heap.extend(stub.into_iter()); - (self.unify_fn)(self, addr, Addr::HeapCell(h)); + + unify_fn!(self, addr, heap_loc_as_cell!(h)); if !self.fail { - *loc = Some(Addr::HeapCell(h)); - self.trail(TrailRef::BlackboardEntry(key_h)); + *loc = Some(heap_loc_as_cell!(h)); + self.trail(TrailRef::BlackboardEntry(key)); } } _ => self.fail = true, @@ -1922,308 +1878,252 @@ impl MachineState { } &SystemClauseType::PutCode => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "put_code", + atom!("put_code"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, None, - clause_name!("put_code"), + atom!("put_code"), 2, )?; - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("put_code"), 2); - let err = MachineError::instantiation_error(); + let stub_gen = || functor_stub(atom!("put_code"), 2); - return Err(self.error_form(err, stub)); - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } - } - Ok(Number::Fixnum(n)) => { - if let Some(c) = - u32::try_from(n).ok().and_then(|c| char::try_from(c).ok()) - { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } - } - _ => { - let stub = MachineError::functor_stub(clause_name!("put_code"), 2); - let err = MachineError::type_error( - self.heap.h(), - ValidType::Integer, - self[temp_v!(2)], - ); - - return Err(self.error_form(err, stub)); + let addr = self.store(self.deref(self.registers[2])); + + if addr.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); } } + Ok(Number::Fixnum(n)) => { + let n = n.get_num(); - let stub = MachineError::functor_stub(clause_name!("put_code"), 2); - let err = MachineError::representation_error(RepFlag::CharacterCode); - - return Err(self.error_form(err, stub)); + if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); + } + } + _ => { + let err = self.type_error(ValidType::Integer, addr); + return Err(self.error_form(err, stub_gen())); + } } + + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); } } &SystemClauseType::PutChar => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "put_char", + atom!("put_char"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, None, - clause_name!("put_char"), + atom!("put_char"), 2, )?; - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("put_char"), 2); - let err = MachineError::instantiation_error(); + let stub_gen = || functor_stub(atom!("put_char"), 2); + let addr = self.store(self.deref(self.registers[2])); - return Err(self.error_form(err, stub)); - } - addr => { - match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } else { - unreachable!() - } - } - _ => {} - }, - Addr::Char(c) => { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } - _ => {} + if addr.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, _arity)) => { + let c = name.as_char().unwrap(); + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); } + (HeapCellValueTag::Char, c) => { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); + } + _ => { + } + ); - let stub = MachineError::functor_stub(clause_name!("put_char"), 2); - let err = - MachineError::type_error(self.heap.h(), ValidType::Character, addr); - - return Err(self.error_form(err, stub)); - } + let err = self.type_error(ValidType::Character, addr); + return Err(self.error_form(err, stub_gen())); } } &SystemClauseType::PutChars => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "$put_chars", + atom!("$put_chars"), 2, )?; let mut bytes = Vec::new(); - let string = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); + let stub_gen = || functor_stub(atom!("$put_chars"), 2); + + if let Some(string) = self.value_to_str_like(self.registers[2]) { + if stream.options().stream_type() == StreamType::Binary { + for c in string.as_str().chars() { + if c as u32 > 255 { + let err = self.type_error(ValidType::Byte, char_as_cell!(c)); + return Err(self.error_form(err, stub_gen())); + } - if stream.options().stream_type == StreamType::Binary { - for c in string.chars() { - bytes.push(c as u8); + bytes.push(c as u8); + } + } else { + bytes = string.as_str().bytes().collect(); } - } else { - bytes = string.into_bytes(); - } - match stream.write_all(&bytes) { - Ok(_) => { - return return_from_clause!(self.last_call, self); - } - _ => { - let stub = MachineError::functor_stub(clause_name!("$put_chars"), 2); - - let addr = self - .heap - .to_unifiable(HeapCellValue::Stream(stream.clone())); - - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(addr), - ), - stub, - )); + match stream.write_all(&bytes) { + Ok(_) => { + return return_from_clause!(self.last_call, self); + } + _ => { + let addr = stream_as_cell!(stream); + let err = self.existence_error(ExistenceError::Stream(addr)); + + return Err(self.error_form(err, stub_gen())); + } } + } else { + self.fail = true; } } &SystemClauseType::PutByte => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "put_byte", + atom!("put_byte"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Binary, None, - clause_name!("put_byte"), + atom!("put_byte"), 2, )?; - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("put_byte"), 2); - let err = MachineError::instantiation_error(); + let stub_gen = || functor_stub(atom!("put_byte"), 2); + let addr = self.store(self.deref(self.registers[2])); - return Err(self.error_form(err, stub)); - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - if let Some(nb) = n.to_u8() { - match stream.write(&mut [nb]) { - Ok(1) => { - return return_from_clause!(self.last_call, self); - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("put_byte"), - 2, - ); - - let addr = self.heap.to_unifiable( - HeapCellValue::Stream(stream.clone()), - ); - - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(addr), - ), - stub, - )); - } + if addr.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + match stream.write(&mut [nb]) { + Ok(1) => { + return return_from_clause!(self.last_call, self); + } + _ => { + let err = self.existence_error( + ExistenceError::Stream(stream_as_cell!(stream)) + ); + + return Err(self.error_form(err, stub_gen())); } } } - Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - match stream.write(&mut [nb]) { - Ok(1) => { - return return_from_clause!(self.last_call, self); - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("put_byte"), - 2, - ); - - let addr = self.heap.to_unifiable( - HeapCellValue::Stream(stream.clone()), - ); - - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(addr), - ), - stub, - )); - } + } + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n.get_num()) { + match stream.write(&mut [nb]) { + Ok(1) => { + return return_from_clause!(self.last_call, self); + } + _ => { + let err = self.existence_error( + ExistenceError::Stream(stream_as_cell!(stream)) + ); + + return Err(self.error_form(err, stub_gen())); } } } - _ => {} } - - let stub = MachineError::functor_stub(clause_name!("put_byte"), 2); - let err = MachineError::type_error( - self.heap.h(), - ValidType::Byte, - self[temp_v!(2)], - ); - - return Err(self.error_form(err, stub)); + _ => { + } } } + + let err = self.type_error(ValidType::Byte, self.registers[2]); + return Err(self.error_form(err, stub_gen())); } &SystemClauseType::GetByte => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_byte", + atom!("get_byte"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Binary, - Some(self[temp_v!(2)]), - clause_name!("get_byte"), + Some(self.registers[2]), + atom!("get_byte"), 2, )?; if stream.past_end_of_stream() { - self.eof_action(self[temp_v!(2)], &mut stream, clause_name!("get_byte"), 2)?; + self.eof_action(self.registers[2], stream, atom!("get_byte"), 2)?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { + let stub_gen = || functor_stub(atom!("get_byte"), 2); + let addr = self.store(self.deref(self.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + match Number::try_from(addr) { Ok(Number::Integer(n)) => { if let Some(nb) = n.to_u8() { - Addr::Usize(nb as usize) + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - Addr::Usize(nb as usize) + if let Ok(nb) = u8::try_from(n.get_num()) { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } _ => { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } - }, + } }; loop { @@ -2231,19 +2131,12 @@ impl MachineState { match stream.read(&mut b) { Ok(1) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Usize(b[0] as usize)); - break; - } else if addr == Addr::Usize(b[0] as usize) { - break; - } else { - self.fail = true; - return Ok(()); - } + self.unify_fixnum(Fixnum::build_with(b[0] as i64), addr); + break; } _ => { - stream.set_past_end_of_stream(); - (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1)); + stream.set_past_end_of_stream(true); + self.unify_fixnum(Fixnum::build_with(-1), self.registers[2]); return return_from_clause!(self.last_call, self); } } @@ -2251,22 +2144,22 @@ impl MachineState { } &SystemClauseType::GetChar => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_char", + atom!("get_char"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("get_char"), + Some(self.registers[2]), + atom!("get_char"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2274,98 +2167,73 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = clause_name!("end_of_file"); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Atom(end_of_file, None)); - - stream.set_past_end_of_stream(); + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let mut iter = self.open_parsing_stream(stream.clone(), "get_char", 2)?; + let stub_gen = || functor_stub(atom!("get_char"), 2); + let mut iter = self.open_parsing_stream(stream, atom!("get_char"), 2)?; - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - Addr::Char(c) - } else { - unreachable!() - } + let addr = self.store(self.deref(self.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (atom, _arity)) => { + char_as_cell!(atom.as_char().unwrap()) } - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit.as_addr(h), - clause_name!("get_char"), - 2, - )); + (HeapCellValueTag::Char) => { + addr } - }, - Addr::Char(d) => Addr::Char(d), - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit, - clause_name!("get_char"), - 2, - )); - } + _ => { + let err = self.type_error(ValidType::InCharacter, addr); + return Err(self.error_form(err, stub_gen())); + } + ) }; loop { - let result = iter.next(); + let result = iter.read_char(); match result { - Some(Ok(d)) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Char(d)); - break; - } else if addr == Addr::Char(d) { - break; - } else { - self.fail = true; + Some(Ok(c)) => { + self.unify_char(c, addr); + + if self.fail { return Ok(()); } } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("get_char"), + self.registers[2], + stream, + atom!("get_char"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - } /* - _ => { - let stub = MachineError::functor_stub(clause_name!("get_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); - }*/ + } } } } &SystemClauseType::GetNChars => { let stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_n_chars", + atom!("get_n_chars"), 3, )?; - let num = match Number::try_from((self[temp_v!(2)], &self.heap)) { - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + let num = match Number::try_from(self.store(self.deref(self.registers[2]))) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_usize() { Some(u) => u, _ => { @@ -2380,18 +2248,20 @@ impl MachineState { let mut string = String::new(); - if stream.options().stream_type == StreamType::Binary { + if stream.options().stream_type() == StreamType::Binary { let mut buf = vec![]; let mut chunk = stream.take(num as u64); + chunk.read_to_end(&mut buf).ok(); + for c in buf { string.push(c as char); } } else { - let mut iter = self.open_parsing_stream(stream.clone(), "get_n_chars", 2)?; + let mut iter = self.open_parsing_stream(stream, atom!("get_n_chars"), 2)?; for _ in 0..num { - let result = iter.next(); + let result = iter.read_char(); match result { Some(Ok(c)) => { @@ -2403,27 +2273,28 @@ impl MachineState { } } }; - let string = self.heap.put_complete_string(&string); - (self.unify_fn)(self, self[temp_v!(3)], string); + + let atom = self.atom_tbl.build_with(&string); + self.unify_complete_string(atom, self.store(self.deref(self.registers[3]))); } &SystemClauseType::GetCode => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_code", + atom!("get_code"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("get_code"), + Some(self.registers[2]), + atom!("get_code"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2431,87 +2302,74 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = Integer::from(-1); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(end_of_file))); + let end_of_file = atom!("end_of_file"); - stream.set_past_end_of_stream(); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { + let stub_gen = || functor_stub(atom!("get_code"), 2); + let addr = self.store(self.deref(self.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + match Number::try_from(addr) { Ok(Number::Integer(n)) => { let n = n .to_u32() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + .and_then(|n| std::char::from_u32(n)); if let Some(n) = n { - Addr::Fixnum(n as isize) + fixnum_as_cell!(Fixnum::build_with(n as i64)) } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("get_code"), - 2, - )); + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { - let n = u32::try_from(n) + let nf = u32::try_from(n.get_num()) .ok() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + .and_then(|n| std::char::from_u32(n)); - if let Some(n) = n { - Addr::Fixnum(n as isize) + if nf.is_some() { + fixnum_as_cell!(n) } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("get_code"), - 2, - )); + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); } } _ => { - return Err(self.type_error( - ValidType::Integer, - self[temp_v!(2)], - clause_name!("get_code"), - 2, - )); + let err = self.type_error(ValidType::Integer, self.registers[2]); + return Err(self.error_form(err, stub_gen())); } - }, + } }; - let mut iter = self.open_parsing_stream(stream.clone(), "get_code", 2)?; + let mut iter = self.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?; loop { - let result = iter.next(); + let result = iter.read_char(); match result { Some(Ok(c)) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Fixnum(c as isize)); - break; - } else if addr == Addr::Fixnum(c as isize) { - break; - } else { - self.fail = true; + self.unify_fixnum(Fixnum::build_with(c as i64), addr); + + if self.fail { return Ok(()); } } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("get_code"), + self.registers[2], + stream, + atom!("get_code"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2536,9 +2394,9 @@ impl MachineState { indices.streams = indices.streams.sub(&null_streams); if let Some(first_stream) = first_stream { - let stream = self.heap.to_unifiable(HeapCellValue::Stream(first_stream)); + let stream = stream_as_cell!(first_stream); - let var = self.store(self.deref(self[temp_v!(1)])).as_var().unwrap(); + let var = self.store(self.deref(self.registers[1])).as_var().unwrap(); self.bind(var, stream); } else { self.fail = true; @@ -2546,25 +2404,14 @@ impl MachineState { } } &SystemClauseType::NextStream => { - let prev_stream = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Stream(h) => { - if let HeapCellValue::Stream(ref stream) = &self.heap[h] { - stream.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let prev_stream = cell_as_stream!(self.store(self.deref(self.registers[1]))); let mut next_stream = None; let mut null_streams = BTreeSet::new(); for stream in indices .streams - .range(prev_stream.clone()..) + .range(prev_stream..) .skip(1) .cloned() { @@ -2579,8 +2426,8 @@ impl MachineState { indices.streams = indices.streams.sub(&null_streams); if let Some(next_stream) = next_stream { - let var = self.store(self.deref(self[temp_v!(2)])).as_var().unwrap(); - let next_stream = self.heap.to_unifiable(HeapCellValue::Stream(next_stream)); + let var = self.store(self.deref(self.registers[2])).as_var().unwrap(); + let next_stream = stream_as_cell!(next_stream); self.bind(var, next_stream); } else { @@ -2590,21 +2437,19 @@ impl MachineState { } &SystemClauseType::FlushOutput => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "flush_output", + atom!("flush_output"), 1, )?; if !stream.is_output_stream() { - let stub = MachineError::functor_stub(clause_name!("flush_output"), 1); - - let addr = vec![HeapCellValue::Stream(stream)]; + let stub = functor_stub(atom!("flush_output"), 1); + let addr = stream_as_cell!(stream); // vec![HeapCellValue::Stream(stream)]; - let err = MachineError::permission_error( - self.heap.h(), + let err = self.permission_error( Permission::OutputStream, - "stream", + atom!("stream"), addr, ); @@ -2618,14 +2463,17 @@ impl MachineState { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, }; + let key = get_key(); + if key == ctrl_c { - let stub = MachineError::functor_stub(clause_name!("get_single_char"), 1); - let err = MachineError::interrupt_error(); + let stub = functor_stub(atom!("get_single_char"), 1); + let err = self.interrupt_error(); let err = self.error_form(err, stub); return Err(err); } + let c = match key.code { KeyCode::Enter => '\n', KeyCode::Tab => '\t', @@ -2633,37 +2481,30 @@ impl MachineState { _ => unreachable!(), }; - let a1 = self[temp_v!(1)]; - - (self.unify_fn)(self, Addr::Char(c), a1); + self.unify_char(c, self.store(self.deref(self.registers[1]))); } &SystemClauseType::HeadIsDynamic => { - let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - - self.fail = !match self.store(self.deref(self[temp_v!(2)])) { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ..) => { - indices.is_dynamic_predicate(module_name, (name.clone(), arity)) - } - _ => unreachable!(), - }, - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - indices.is_dynamic_predicate(module_name, (name.clone(), 0)) - } else { - unreachable!() - } - } + let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); + + let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])), + (HeapCellValueTag::Str, s) => { + cell_as_atom_cell!(self.heap[s]).get_name_and_arity() + } + (HeapCellValueTag::Atom, (name, _arity)) => { + (name, 0) + } _ => { - unreachable!() - } - }; + unreachable!() + } + ); + + self.fail = !indices.is_dynamic_predicate(module_name, (name, arity)); } &SystemClauseType::Close => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "close", + atom!("close"), 2, )?; @@ -2676,404 +2517,423 @@ impl MachineState { if stream == *current_input_stream { *current_input_stream = indices .stream_aliases - .get(&clause_name!("user_input")) + .get(&atom!("user_input")) .cloned() .unwrap(); - indices.streams.insert(current_input_stream.clone()); + indices.streams.insert(*current_input_stream); } else if stream == *current_output_stream { *current_output_stream = indices .stream_aliases - .get(&clause_name!("user_output")) + .get(&atom!("user_output")) .cloned() .unwrap(); - indices.streams.insert(current_output_stream.clone()); + indices.streams.insert(*current_output_stream); } if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() { let close_result = stream.close(); - if let Some(ref alias) = stream.options().alias { - indices.stream_aliases.remove(alias); + if let Some(alias) = stream.options().get_alias() { + indices.stream_aliases.remove(&alias); } if let Err(_) = close_result { - let stub = MachineError::functor_stub( - clause_name!("close"), - 1, - ); - - let addr = self.heap.to_unifiable( - HeapCellValue::Stream(stream.clone()), - ); + let stub = functor_stub(atom!("close"), 1); + let addr = stream_as_cell!(stream); + let err = self.existence_error(ExistenceError::Stream(addr)); - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(addr), - ), - stub, - )); + return Err(self.error_form(err, stub)); } } } - &SystemClauseType::CopyToLiftedHeap => match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => { - let copy_target = self[temp_v!(2)]; + &SystemClauseType::CopyToLiftedHeap => { + let lh_offset = cell_as_fixnum!( + self.store(self.deref(self.registers[1])) + ).get_num() as usize; - let old_threshold = self.copy_findall_solution(lh_offset, copy_target); - let new_threshold = self.lifted_heap.h() - lh_offset; + let copy_target = self.registers[2]; - self.lifted_heap[old_threshold] = - HeapCellValue::Addr(Addr::HeapCell(new_threshold)); + let old_threshold = self.copy_findall_solution(lh_offset, copy_target); + let new_threshold = self.lifted_heap.len() - lh_offset; - for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) { - match addr { - HeapCellValue::Addr(ref mut addr) => { - *addr -= self.heap.h() + lh_offset; - } - _ => {} - } - } - } - _ => { - self.fail = true; + self.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); + + for addr in self.lifted_heap[old_threshold + 1 ..].iter_mut() { + *addr -= self.heap.len() + lh_offset; } }, &SystemClauseType::DeleteAttribute => { - let ls0 = self.store(self.deref(self[temp_v!(1)])); + let ls0 = self.store(self.deref(self.registers[1])); - if let Addr::Lis(l1) = ls0 { - if let Addr::Lis(l2) = self.store(self.deref(Addr::HeapCell(l1 + 1))) { - let old_addr = self.heap[l1 + 1].as_addr(l1 + 1); - let tail = self.store(self.deref(Addr::HeapCell(l2 + 1))); + if let HeapCellValueTag::Lis = ls0.get_tag() { + let l1 = ls0.get_value(); + let ls1 = self.store(self.deref(heap_loc_as_cell!(l1 + 1))); - let tail = if tail.is_ref() { - Addr::HeapCell(l1 + 1) + if let HeapCellValueTag::Lis = ls1.get_tag() { + let l2 = ls1.get_value(); + + let old_addr = self.heap[l1+1]; + let tail = self.store(self.deref(heap_loc_as_cell!(l2 + 1))); + + let tail = if tail.is_var() { + heap_loc_as_cell!(l1 + 1) } else { tail }; - let trail_ref = match old_addr { - Addr::HeapCell(h) => TrailRef::AttrVarHeapLink(h), - Addr::Lis(l) => TrailRef::AttrVarListLink(l1 + 1, l), - _ => unreachable!(), - }; + let trail_ref = read_heap_cell!(old_addr, + (HeapCellValueTag::Var, h) => { + TrailRef::AttrVarHeapLink(h) + } + (HeapCellValueTag::Lis, l) => { + TrailRef::AttrVarListLink(l1 + 1, l) + } + _ => { + unreachable!() + } + ); - self.heap[l1 + 1] = HeapCellValue::Addr(tail); + self.heap[l1 + 1] = tail; self.trail(trail_ref); } } } &SystemClauseType::DeleteHeadAttribute => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); - match addr { - Addr::AttrVar(h) => { - let addr = self.heap[h + 1].as_addr(h + 1); - let addr = self.store(self.deref(addr)); + debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar); - match addr { - Addr::Lis(l) => { - let tail = self.store(self.deref(Addr::HeapCell(l + 1))); - let tail = if tail.is_ref() { - self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h)); - self.trail(TrailRef::Ref(Ref::AttrVar(h))); + let h = addr.get_value(); + let addr = self.store(self.deref(self.heap[h + 1])); - Addr::HeapCell(h + 1) - } else { - tail - }; + debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis); - self.heap[h + 1] = HeapCellValue::Addr(tail); - self.trail(TrailRef::AttrVarListLink(h + 1, l)); - } - _ => { - unreachable!(); - } - } - } - _ => { - unreachable!(); - } - } + let l = addr.get_value(); + let tail = self.store(self.deref(heap_loc_as_cell!(l + 1))); + + let tail = if tail.is_var() { + self.heap[h] = heap_loc_as_cell!(h); + self.trail(TrailRef::Ref(Ref::attr_var(h))); + + heap_loc_as_cell!(h + 1) + } else { + tail + }; + + self.heap[h + 1] = tail; + self.trail(TrailRef::AttrVarListLink(h + 1, l)); } &SystemClauseType::DynamicModuleResolution(narity) => { - let module_name = self.store(self.deref(self[temp_v!(1 + narity)])); + let module_name = self.store(self.deref(self.registers[1 + narity])); + let module_name = cell_as_atom!(module_name); - let module_name = match module_name { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref module_name, _) = self.heap[h] { - module_name.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let addr = self.store(self.deref(self.registers[2 + narity])); - match self.store(self.deref(self[temp_v!(2 + narity)])) { - Addr::Str(a) => { - if let HeapCellValue::NamedStr(arity, name, _) = self.heap.clone(a) { - for i in (arity + 1..arity + narity + 1).rev() { - self.registers[i] = self.registers[i - arity]; - } + read_heap_cell!(addr, + (HeapCellValueTag::Str, a) => { + let (name, arity) = cell_as_atom_cell!(self.heap[a]) + .get_name_and_arity(); - for i in 1..arity + 1 { - self.registers[i] = self.heap[a + i].as_addr(a + i); - } + for i in (arity + 1..arity + narity + 1).rev() { + self.registers[i] = self.registers[i - arity]; + } - return self.module_lookup( - indices, - call_policy, - (name, arity + narity), - module_name, - true, - &indices.stream_aliases, - ); - } else { - unreachable!() + for i in 1..arity + 1 { + self.registers[i] = self.heap[a + i]; } + + return self.module_lookup( + indices, + call_policy, + (name, arity + narity), + module_name, + true, + &indices.stream_aliases, + ); } - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - return self.module_lookup( - indices, - call_policy, - (name.clone(), narity), - module_name, - true, - &indices.stream_aliases, - ); - } else { - unreachable!() - } + (HeapCellValueTag::Atom, (name, _arity)) => { + return self.module_lookup( + indices, + call_policy, + (name, narity), + module_name, + true, + &indices.stream_aliases, + ); } - Addr::Char(c) => { + (HeapCellValueTag::Char, c) => { + let key = (self.atom_tbl.build_with(&c.to_string()), narity); + return self.module_lookup( indices, call_policy, - (clause_name!(c.to_string(), self.atom_tbl), narity), + key, module_name, true, &indices.stream_aliases, ); } - addr => { - let stub = MachineError::functor_stub(clause_name!("(:)"), 2); - - let type_error = - MachineError::type_error(self.heap.h(), ValidType::Callable, addr); + _ => { + let stub = functor_stub(atom!("(:)"), 2); + let err = self.type_error(ValidType::Callable, addr); - let type_error = self.error_form(type_error, stub); - return Err(type_error); + return Err(self.error_form(err, stub)); } - } + ); } &SystemClauseType::EnqueueAttributedVar => { - let addr = self[temp_v!(1)]; + let addr = self.store(self.deref(self.registers[1])); - match self.store(self.deref(addr)) { - Addr::AttrVar(h) => { - self.attr_var_init.attr_var_queue.push(h); - } - _ => {} - } + read_heap_cell!(addr, + (HeapCellValueTag::AttrVar, h) => { + self.attr_var_init.attr_var_queue.push(h); + } + _ => { + } + ); } &SystemClauseType::GetNextDBRef => { - let a1 = self[temp_v!(1)]; + let a1 = self.store(self.deref(self.registers[1])); - match self.store(self.deref(a1)) { - addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { - let mut iter = indices.code_dir.iter(); + if let Some(name_var) = a1.as_var() { + let mut iter = indices.code_dir.iter(); - while let Some(((name, arity), _)) = iter.next() { - if is_builtin_predicate(&name) { - continue; - } + while let Some(((name, arity), _)) = iter.next() { + if SystemClauseType::from(*name, *arity).is_some() { + continue; + } - let spec = get_clause_spec( - name.clone(), - *arity, - &CompositeOpDir::new(&indices.op_dir, None), - ); + let arity_var = self.deref(self.registers[2]) + .as_var().unwrap(); - let db_ref = DBRef::NamedPred(name.clone(), *arity, spec); - let r = addr.as_var().unwrap(); + self.bind(name_var, atom_as_cell!(name)); + self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64))); + + return return_from_clause!(self.last_call, self); + } - let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref)); + self.fail = true; + } else if a1.get_tag() == HeapCellValueTag::Atom { + let name = cell_as_atom!(a1); + let arity = cell_as_fixnum!(self.store(self.deref(self.registers[2]))) + .get_num() as usize; - self.bind(r, addr); + match self.get_next_db_ref(indices, &DBRef::NamedPred(name, arity)) { + Some(DBRef::NamedPred(name, arity)) => { + let atom_var = self.deref(self.registers[3]) + .as_var().unwrap(); - return return_from_clause!(self.last_call, self); - } + let arity_var = self.deref(self.registers[4]) + .as_var().unwrap(); - self.fail = true; - } - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::Op(..)) => { - self.fail = true; - } - HeapCellValue::DBRef(ref db_ref) => { - self.get_next_db_ref(indices, db_ref); + self.bind(atom_var, atom_as_cell!(name)); + self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64))); } - _ => { + Some(DBRef::Op(..)) | None => { self.fail = true; } - }, - _ => { - self.fail = true; } + } else { + self.fail = true; + return Ok(()); } } &SystemClauseType::GetNextOpDBRef => { - let a1 = self[temp_v!(1)]; + let prec = self.store(self.deref(self.registers[1])); + + if let Some(prec_var) = prec.as_var() { + let spec = self.store(self.deref(self.registers[2])); + let op = self.store(self.deref(self.registers[3])); + let orig_op = self.store(self.deref(self.registers[7])); + + let spec_num = if spec.get_tag() == HeapCellValueTag::Atom { + (match cell_as_atom!(spec) { + atom!("xfx") => XFX, + atom!("xfy") => XFY, + atom!("yfx") => YFX, + atom!("fx") => FX, + atom!("fy") => FY, + atom!("xf") => XF, + _ => unreachable!(), + }) as u8 + } else { + 0 + }; + + let unossified_op_dir = if !orig_op.is_var() { + let orig_op = cell_as_atom!(orig_op); + + let op_descs = [ + indices.op_dir.get_key_value(&(orig_op, Fixity::In)), + indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)), + indices.op_dir.get_key_value(&(orig_op, Fixity::Post)), + ]; + + let number_of_keys = op_descs[0].is_some() as usize + + op_descs[1].is_some() as usize + + op_descs[2].is_some() as usize; + + match number_of_keys { + 0 => { + self.fail = true; + return Ok(()); + } + 1 => { + for op_desc in op_descs { + if let Some((_, op_desc)) = op_desc { + let (op_prec, op_spec) = + (op_desc.get_prec(), op_desc.get_spec()); + + let op_spec = match op_spec as u32 { + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + _ => unreachable!(), + }; + + let op_prec = Fixnum::build_with(op_prec as i64); + + self.unify_fixnum(op_prec, prec); + self.unify_atom(op_spec, spec); + } + } + + return return_from_clause!(self.last_call, self); + } + _ => { + let mut unossified_op_dir = OssifiedOpDir::new(); + + for op_desc in op_descs { + if let Some((key, op_desc)) = op_desc { + let (prec, spec) = (op_desc.get_prec(), op_desc.get_spec()); + unossified_op_dir.insert(*key, (prec as usize, spec as Specifier)); + } + } - match self.store(self.deref(a1)) { - addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { + unossified_op_dir + } + } + } else { let mut unossified_op_dir = OssifiedOpDir::new(); unossified_op_dir.extend(indices.op_dir.iter().filter_map( - |(key, op_dir_val)| { - let (name, fixity) = key.clone(); - - let prec = op_dir_val.shared_op_desc().prec(); + |(key, op_desc)| { + let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec()); + let name = key.0; - if prec == 0 { + if other_prec == 0 { return None; } - let assoc = op_dir_val.shared_op_desc().assoc(); + if (!orig_op.is_var() && atom_as_cell!(name) != orig_op) || + (!spec.is_var() && other_spec != spec_num) { + return None; + } - Some((OrderedOpDirKey(name, fixity), (prec, assoc))) - }, + Some((*key, (other_prec as usize, other_spec as Specifier))) + } )); - let ossified_op_dir = Rc::new(unossified_op_dir); + unossified_op_dir + }; - match ossified_op_dir.iter().next() { - Some((OrderedOpDirKey(name, _), (priority, spec))) => { - let db_ref = DBRef::Op( - *priority, - *spec, - name.clone(), - ossified_op_dir.clone(), - SharedOpDesc::new(*priority, *spec), - ); + let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.arena); + + match ossified_op_dir.iter().next() { + Some(((op_atom, _), (op_prec, op_spec))) => { + let ossified_op_dir_var = self.store(self.deref(self.registers[4])) + .as_var().unwrap(); + + let spec_atom = match *op_spec { + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), + _ => { + self.fail = true; + return Ok(()); + } + }; - let r = addr.as_var().unwrap(); - let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref)); + let spec_var = spec.as_var().unwrap(); + let op_var = op.as_var().unwrap(); - self.bind(r, addr); - } - None => { - self.fail = true; - return Ok(()); - } - } - } - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::NamedPred(..)) => { - self.fail = true; + self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64))); + self.bind(spec_var, atom_as_cell!(spec_atom)); + self.bind(op_var, atom_as_cell!(op_atom)); + self.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir)); } - HeapCellValue::DBRef(ref db_ref) => { - self.get_next_db_ref(indices, db_ref); - } - _ => { + None => { self.fail = true; + return Ok(()); } - }, - _ => { - self.fail = true; } - } - } - &SystemClauseType::LookupDBRef => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::NamedPred(name, arity, spec)) => { - let a2 = self[temp_v!(2)]; - let a3 = self[temp_v!(3)]; + } else { + let spec = cell_as_atom!(self.store(self.deref(self.registers[2]))); + let op_atom = cell_as_atom!(self.store(self.deref(self.registers[3]))); + let ossified_op_dir_cell = self.store(self.deref(self.registers[4])); - let atom = self.heap.to_unifiable(HeapCellValue::Atom(name, spec)); + if ossified_op_dir_cell.is_var() { + self.fail = true; + return Ok(()); + } - (self.unify_fn)(self, a2, atom); + let ossified_op_dir = cell_as_ossified_op_dir!( + ossified_op_dir_cell + ); - if !self.fail { - (self.unify_fn)(self, a3, Addr::Usize(arity)); - } - } + let fixity = match spec { + atom!("xfy") | atom!("yfx") | atom!("xfx") => Fixity::In, + atom!("xf") | atom!("yf") => Fixity::Post, + atom!("fx") | atom!("fy") => Fixity::Pre, _ => { self.fail = true; + return Ok(()); } - }, - _ => { - self.fail = true; - } - } - } - &SystemClauseType::LookupOpDBRef => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::Op( - priority, - spec, - name, - _, - shared_op_desc, - )) => { - let prec = self[temp_v!(2)]; - let specifier = self[temp_v!(3)]; - let op = self[temp_v!(4)]; - - let spec = match spec { - FX => "fx", - FY => "fy", - XF => "xf", - YF => "yf", - XFX => "xfx", - XFY => "xfy", - YFX => "yfx", + }; + + match self.get_next_db_ref(indices, &DBRef::Op(op_atom, fixity, ossified_op_dir)) { + Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => { + let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap(); + + let prec_var = self.deref(self.registers[5]) + .as_var().unwrap(); + + let spec_var = self.deref(self.registers[6]) + .as_var().unwrap(); + + let op_var = self.deref(self.registers[7]) + .as_var().unwrap(); + + let spec_atom = match *spec { + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), _ => { self.fail = true; return Ok(()); } }; - let a3 = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!(spec), None)); - - let a4 = self - .heap - .to_unifiable(HeapCellValue::Atom(name, Some(shared_op_desc))); - - (self.unify_fn)(self, Addr::Usize(priority), prec); - - if !self.fail { - (self.unify_fn)(self, a3, specifier); - } - - if !self.fail { - (self.unify_fn)(self, a4, op); - } + self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64))); + self.bind(spec_var, atom_as_cell!(spec_atom)); + self.bind(op_var, atom_as_cell!(op_atom)); } - _ => { + Some(DBRef::NamedPred(..)) | None => { self.fail = true; } - }, - _ => { - self.fail = true; } } } @@ -3086,62 +2946,82 @@ impl MachineState { self.fail = result; } &SystemClauseType::CpuNow => { - let a1 = self[temp_v!(1)]; - let a2 = ProcessTime::now().as_duration().as_secs_f64(); - let addr = self.heap.put_constant(Constant::Float(OrderedFloat(a2))); + let secs = ProcessTime::now().as_duration().as_secs_f64(); + let secs = arena_alloc!(OrderedFloat(secs), &mut self.arena); - (self.unify_fn)(self, a1, addr); + self.unify_f64(secs, self.registers[1]); } &SystemClauseType::CurrentTime => { - let str = self.systemtime_to_timestamp(SystemTime::now()); - (self.unify_fn)(self, self[temp_v!(1)], str); + let timestamp = self.systemtime_to_timestamp(SystemTime::now()); + self.unify_atom(timestamp, self.registers[1]); + } + &SystemClauseType::Open => { + let alias = self.registers[4]; + let eof_action = self.registers[5]; + let reposition = self.registers[6]; + let stream_type = self.registers[7]; + + let options = self.to_stream_options(alias, eof_action, reposition, stream_type); + let src_sink = self.store(self.deref(self.registers[1])); + + if let Some(atom_or_string) = self.value_to_str_like(src_sink) { + let file_spec = self.atom_tbl.build_with(atom_or_string.as_str()); + let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?; + + *stream.options_mut() = options; + indices.streams.insert(stream); + + if let Some(alias) = stream.options().get_alias() { + indices.stream_aliases.insert(alias, stream); + } + + let stream_var = self.store(self.deref(self.registers[3])); + self.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream)); + } else { + let err = self.domain_error(DomainErrorType::SourceSink, src_sink); + let stub = functor_stub(atom!("open"), 4); + + return Err(self.error_form(err, stub)); + } } &SystemClauseType::OpDeclaration => { - let priority = self[temp_v!(1)]; - let specifier = self[temp_v!(2)]; - let op = self[temp_v!(3)]; + let priority = self.registers[1]; + let specifier = self.registers[2]; + let op = self.registers[3]; let priority = self.store(self.deref(priority)); - let priority = match Number::try_from((priority, &self.heap)) { - Ok(Number::Integer(n)) => n.to_usize().unwrap(), - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + let priority = match Number::try_from(priority) { + Ok(Number::Integer(n)) => n.to_u16().unwrap(), + Ok(Number::Fixnum(n)) => u16::try_from(n.get_num()).unwrap(), _ => { unreachable!(); } }; - let specifier = match self.store(self.deref(specifier)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref specifier, _) = &self.heap[h] { - specifier.clone() - } else { - unreachable!() - } - } - _ => unreachable!(), - }; + let specifier = cell_as_atom_cell!(self.store(self.deref(specifier))) + .get_name(); - let op = match self.store(self.deref(op)) { - Addr::Char(c) => clause_name!(c.to_string(), self.atom_tbl), - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() - } else { - unreachable!() - } + let op = read_heap_cell!(self.store(self.deref(op)), + (HeapCellValueTag::Char) => { + self.atom_tbl.build_with(&op.to_string()) } - _ => unreachable!(), - }; + (HeapCellValueTag::Atom, (name, _arity)) => { + name + } + _ => { + unreachable!() + } + ); - let result = to_op_decl(priority, specifier.as_str(), op) + let result = to_op_decl(priority, specifier, op) .map_err(SessionError::from) .and_then(|mut op_decl| { - if op_decl.prec == 0 { + if op_decl.op_desc.get_prec() == 0 { Ok(op_decl.remove(&mut indices.op_dir)) } else { let spec = get_op_desc( - op_decl.name.clone(), + op_decl.name, &CompositeOpDir::new(&indices.op_dir, None), ); @@ -3153,128 +3033,96 @@ impl MachineState { Ok(()) => {} Err(e) => { // 8.14.3.3 l) - let e = MachineError::session_error(self.heap.h(), e); - let stub = MachineError::functor_stub(clause_name!("op"), 3); - let permission_error = self.error_form(e, stub); + let err = self.session_error(e); + let stub = functor_stub(atom!("op"), 3); - return Err(permission_error); + return Err(self.error_form(err, stub)); } - }; - } - &SystemClauseType::Open => { - let alias = self[temp_v!(4)]; - let eof_action = self[temp_v!(5)]; - let reposition = self[temp_v!(6)]; - let stream_type = self[temp_v!(7)]; - - let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - - let mut iter = self.heap_pstr_iter(self[temp_v!(1)]); - let file_spec = clause_name!(iter.to_string(), self.atom_tbl); - - let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?; - - *stream.options_mut() = options; - - indices.streams.insert(stream.clone()); - - if let Some(ref alias) = &stream.options().alias { - indices.stream_aliases.insert(alias.clone(), stream.clone()); } - - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - let stream_var = self.store(self.deref(self[temp_v!(3)])); - - self.bind(stream_var.as_var().unwrap(), stream); } &SystemClauseType::SetStreamOptions => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "open", + atom!("open"), 4, )?; - let alias = self[temp_v!(2)]; - let eof_action = self[temp_v!(3)]; - let reposition = self[temp_v!(4)]; - let stream_type = self[temp_v!(5)]; + let alias = self.registers[2]; + let eof_action = self.registers[3]; + let reposition = self.registers[4]; + let stream_type = self.registers[5]; let options = self.to_stream_options(alias, eof_action, reposition, stream_type); *stream.options_mut() = options; } &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { - self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)) + self.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h)) } &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { - self.truncate_if_no_lifted_heap_diff(|_| Addr::EmptyList) + self.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!()) } &SystemClauseType::GetAttributedVariableList => { - let attr_var = self.store(self.deref(self[temp_v!(1)])); - let attr_var_list = match attr_var { - Addr::AttrVar(h) => h + 1, - attr_var @ Addr::HeapCell(_) | attr_var @ Addr::StackCell(..) => { + let attr_var = self.store(self.deref(self.registers[1])); + let attr_var_list = read_heap_cell!(attr_var, + (HeapCellValueTag::AttrVar, h) => { + h + 1 + } + (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { // create an AttrVar in the heap. - let h = self.heap.h(); + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h))); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); + self.heap.push(attr_var_as_cell!(h)); + self.heap.push(heap_loc_as_cell!(h+1)); - self.bind(Ref::AttrVar(h), attr_var); + self.bind(Ref::attr_var(h), attr_var); h + 1 } _ => { self.fail = true; return Ok(()); } - }; + ); - let list_addr = self[temp_v!(2)]; - self.bind(Ref::HeapCell(attr_var_list), list_addr); + let list_addr = self.store(self.deref(self.registers[2])); + self.bind(Ref::heap_cell(attr_var_list), list_addr); } &SystemClauseType::GetAttrVarQueueDelimiter => { - let addr = self[temp_v!(1)]; - let value = Addr::Usize(self.attr_var_init.attr_var_queue.len()); + let addr = self.registers[1]; + let value = Fixnum::build_with(self.attr_var_init.attr_var_queue.len() as i64); - (self.unify_fn)(self, addr, value); + self.unify_fixnum(value, self.store(self.deref(addr))); } &SystemClauseType::GetAttrVarQueueBeyond => { - let addr = self[temp_v!(1)]; + let addr = self.registers[1]; let addr = self.store(self.deref(addr)); - let b = match addr { - Addr::Usize(b) => Some(b), - _ => match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => n.to_usize(), - Ok(Number::Fixnum(n)) => usize::try_from(n).ok(), - _ => { - self.fail = true; - return Ok(()); - } - }, + let b = match Number::try_from(addr) { + Ok(Number::Integer(n)) => n.to_usize(), + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + _ => { + self.fail = true; + return Ok(()); + } }; if let Some(b) = b { let iter = self.gather_attr_vars_created_since(b); - let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); - let list_addr = self[temp_v!(2)]; + let var_list_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, iter) + ); - (self.unify_fn)(self, var_list_addr, list_addr); + let list_addr = self.registers[2]; + unify!(self, var_list_addr, list_addr); } } &SystemClauseType::GetContinuationChunk => { - let e = self.store(self.deref(self[temp_v!(1)])); - - let e = if let Addr::Usize(e) = e { - e - } else { - self.fail = true; - return Ok(()); - }; + let e = self.store(self.deref(self.registers[1])); + let e = cell_as_fixnum!(e).get_num() as usize; - let p_functor = self.store(self.deref(self[temp_v!(2)])); - let p = self.heap.to_local_code_ptr(&p_functor).unwrap(); + let p_functor = self.store(self.deref(self.registers[2])); + let p = to_local_code_ptr(&self.heap, p_functor).unwrap(); let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) { Some(line) => { @@ -3290,137 +3138,81 @@ impl MachineState { let mut addrs = vec![]; - for index in 1..num_cells + 1 { - addrs.push(self.stack.index_and_frame(e)[index]); + for idx in 1..num_cells + 1 { + addrs.push(self.stack[stack_loc!(AndFrame, e, idx)]); } - let chunk = Addr::HeapCell(self.heap.h()); + let chunk = str_loc_as_cell!(self.heap.len()); - self.heap.push(HeapCellValue::NamedStr( - 1 + num_cells, - clause_name!("cont_chunk"), - None, - )); - - self.heap.push(HeapCellValue::Addr(p_functor)); - self.heap.extend(addrs.into_iter().map(HeapCellValue::Addr)); + self.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); + self.heap.push(p_functor); + self.heap.extend(addrs); - (self.unify_fn)(self, self[temp_v!(3)], chunk); + unify!(self, self.registers[3], chunk); } &SystemClauseType::GetLiftedHeapFromOffsetDiff => { - let lh_offset = self[temp_v!(1)]; + let lh_offset = self.registers[1]; + let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize; - match self.store(self.deref(lh_offset)) { - Addr::Usize(lh_offset) => { - if lh_offset >= self.lifted_heap.h() { - let solutions = self[temp_v!(2)]; - let diff = self[temp_v!(3)]; - - (self.unify_fn)(self, solutions, diff); - } else { - let h = self.heap.h(); - let mut last_index = h; + if lh_offset >= self.lifted_heap.len() { + let solutions = self.registers[2]; + let diff = self.registers[3]; - for value in self.lifted_heap.iter_from(lh_offset) { - last_index = self.heap.h(); + unify_fn!(self, solutions, diff); + } else { + let h = self.heap.len(); + let mut last_index = h; - match value { - HeapCellValue::Addr(ref addr) => { - self.heap.push(HeapCellValue::Addr(*addr + h)); - } - value => { - self.heap.push(value.context_free_clone()); - } - } - } + for value in self.lifted_heap[lh_offset ..].iter().cloned() { + last_index = self.heap.len(); + self.heap.push(value + h); + } - if last_index < self.heap.h() { - let addr_opt = - if let HeapCellValue::Addr(ref addr) = &self.heap[last_index] { - Some(*addr) - } else { - None - }; - - addr_opt.map(|addr| { - let diff = self[temp_v!(3)]; - (self.unify_fn)(self, diff, addr); - }); - } + if last_index < self.heap.len() { + let diff = self.registers[3]; + unify_fn!(self, diff, self.heap[last_index]); + } - self.lifted_heap.truncate(lh_offset); + self.lifted_heap.truncate(lh_offset); - let solutions = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::HeapCell(h), solutions); - } - } - _ => { - self.fail = true; - } + let solutions = self.registers[2]; + unify_fn!(self, heap_loc_as_cell!(h), solutions); } } &SystemClauseType::GetLiftedHeapFromOffset => { - let lh_offset = self[temp_v!(1)]; + let lh_offset = self.registers[1]; + let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize; - match self.store(self.deref(lh_offset)) { - Addr::Usize(lh_offset) => { - if lh_offset >= self.lifted_heap.h() { - let solutions = self[temp_v!(2)]; - (self.unify_fn)(self, solutions, Addr::EmptyList); - } else { - let h = self.heap.h(); + if lh_offset >= self.lifted_heap.len() { + let solutions = self.registers[2]; + unify_fn!(self, solutions, empty_list_as_cell!()); + } else { + let h = self.heap.len(); - for addr in self.lifted_heap.iter_from(lh_offset) { - match addr { - HeapCellValue::Addr(ref addr) => { - self.heap.push(HeapCellValue::Addr(*addr + h)); - } - value => { - self.heap.push(value.context_free_clone()); - } - } - } + for addr in self.lifted_heap[lh_offset..].iter().cloned() { + self.heap.push(addr + h); + } - self.lifted_heap.truncate(lh_offset); + self.lifted_heap.truncate(lh_offset); - let solutions = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::HeapCell(h), solutions); - } - } - _ => { - self.fail = true; - } + let solutions = self.registers[2]; + unify_fn!(self, heap_loc_as_cell!(h), solutions); } } &SystemClauseType::GetDoubleQuotes => { - let a1 = self[temp_v!(1)]; - - match self.flags.double_quotes { - DoubleQuotes::Chars => { - let atom = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("chars"), None)); + let a1 = self.store(self.deref(self.registers[1])); - (self.unify_fn)(self, a1, atom); - } - DoubleQuotes::Atom => { - let atom = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("atom"), None)); - - (self.unify_fn)(self, a1, atom); - } - DoubleQuotes::Codes => { - let atom = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("codes"), None)); - - (self.unify_fn)(self, a1, atom); - } - } + self.unify_atom( + match self.flags.double_quotes { + DoubleQuotes::Chars => atom!("chars"), + DoubleQuotes::Atom => atom!("atom"), + DoubleQuotes::Codes => atom!("codes"), + }, + a1, + ); } &SystemClauseType::GetSCCCleaner => { - let dest = self[temp_v!(1)]; + let dest = self.registers[1]; match cut_policy.downcast_mut::().ok() { Some(sgc_policy) => { @@ -3440,15 +3232,15 @@ impl MachineState { } } None => {} - }; + } self.fail = true; } &SystemClauseType::Halt => { - let code = self.store(self.deref(self[temp_v!(1)])); + let code = self.store(self.deref(self.registers[1])); - let code = match Number::try_from((code, &self.heap)) { - Ok(Number::Fixnum(n)) => n as i32, + let code = match Number::try_from(code) { + Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => n.to_i32().unwrap(), Ok(Number::Rational(r)) => { // n has already been confirmed as an integer, and @@ -3464,7 +3256,7 @@ impl MachineState { std::process::exit(code); } &SystemClauseType::InstallSCCCleaner => { - let addr = self[temp_v!(1)]; + let addr = self.registers[1]; let b = self.b; let prev_block = self.block; @@ -3475,7 +3267,7 @@ impl MachineState { match cut_policy.downcast_mut::().ok() { Some(cut_policy) => { - self.install_new_block(temp_v!(2)); + self.install_new_block(self.registers[2]); cut_policy.push_cont_pt(addr, b, prev_block); } None => panic!( @@ -3486,155 +3278,111 @@ impl MachineState { } &SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L - let a1 = self.store(self.deref(self[temp_v!(1)])); - let a2 = self.store(self.deref(self[temp_v!(2)])); + let a1 = self.store(self.deref(self.registers[1])); + let a2 = self.store(self.deref(self.registers[2])); if call_policy.downcast_ref::().is_err() { CWILCallPolicy::new_in_place(call_policy); } - let n = match Number::try_from((a2, &self.heap)) { - Ok(Number::Integer(n)) => Integer::from(&*n.clone()), - Ok(Number::Fixnum(n)) => Integer::from(n), + let n = match Number::try_from(a2) { + Ok(Number::Fixnum(bp)) => bp.get_num() as usize, + Ok(Number::Integer(n)) => n.to_usize().unwrap(), _ => { - let stub = MachineError::functor_stub( - clause_name!("call_with_inference_limit"), + let stub = functor_stub( + atom!("call_with_inference_limit"), 3, ); - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, a2), - stub, - )); + let err = self.type_error(ValidType::Integer, a2); + return Err(self.error_form(err, stub)); } }; - match a1 { - Addr::Usize(bp) | Addr::CutPoint(bp) => { - match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let count = call_policy.add_limit(n, bp).clone(); - let count = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(count))); - - let a3 = self[temp_v!(3)]; - (self.unify_fn)(self, a3, count); - } - None => { - panic!( - "install_inference_counter: should have installed \\ - CWILCallPolicy." - ) - } - } + let bp = cell_as_fixnum!(a1).get_num() as usize; + + match call_policy.downcast_mut::().ok() { + Some(call_policy) => { + let count = call_policy.add_limit(n, bp); + let count = arena_alloc!(count.clone(), &mut self.arena); + + let a3 = self.store(self.deref(self.registers[3])); + self.unify_big_int(count, a3); } - _ => { - unreachable!(); + None => { + panic!( + "install_inference_counter: should have installed \\ + CWILCallPolicy." + ) } } } &SystemClauseType::ModuleExists => { - let module = self.store(self.deref(self[temp_v!(1)])); + let module = self.store(self.deref(self.registers[1])); + let module_name = cell_as_atom!(module); - match module { - Addr::Con(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - self.fail = !indices.modules.contains_key(name); - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + self.fail = !indices.modules.contains_key(&module_name); } &SystemClauseType::NoSuchPredicate => { - let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - - self.fail = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ref spec) => { - if CLAUSE_TYPE_FORMS - .borrow() - .get(&(name.as_str(), arity)) - .is_some() - { - true - } else { - let index = indices - .get_predicate_code_index( - name.clone(), - arity, - module_name, - spec.clone(), - ) - .map(|index| index.get()) - .unwrap_or(IndexPtr::DynamicUndefined); - - match index { - IndexPtr::DynamicUndefined => false, - _ => true, - } - } - } - _ => { - unreachable!() - } - }, - Addr::Con(h) if self.heap.atom_at(h) => { - if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] { - let spec = - fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir); - - if CLAUSE_TYPE_FORMS - .borrow() - .get(&(name.as_str(), 0)) - .is_some() - { - true - } else { - let index = indices - .get_predicate_code_index( - name.clone(), - 0, - module_name, - spec.clone(), - ) - .map(|index| index.get()) - .unwrap_or(IndexPtr::DynamicUndefined); - - match index { - IndexPtr::DynamicUndefined => false, - _ => true, - } + let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let head = self.store(self.deref(self.registers[2])); + + self.fail = read_heap_cell!(head, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + if clause_type_form(name, arity).is_some() { + true + } else { + let index = indices.get_predicate_code_index( + name, + arity, + module_name, + ) + .map(|index| index.get()) + .unwrap_or(IndexPtr::DynamicUndefined); + + match index { + IndexPtr::DynamicUndefined => false, + _ => true, } + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + if clause_type_form(name, 0).is_some() { + true } else { - unreachable!() + let index = indices.get_predicate_code_index( + name, + 0, + module_name, + ) + .map(|index| index.get()) + .unwrap_or(IndexPtr::DynamicUndefined); + + match index { + IndexPtr::DynamicUndefined => false, + _ => true, + } } } - head => { - let err = - MachineError::type_error(self.heap.h(), ValidType::Callable, head); - let stub = MachineError::functor_stub(clause_name!("clause"), 2); + _ => { + let err = self.type_error(ValidType::Callable, head); + let stub = functor_stub(atom!("clause"), 2); return Err(self.error_form(err, stub)); } - }; + ); } &SystemClauseType::RedoAttrVarBinding => { - let var = self.store(self.deref(self[temp_v!(1)])); - let value = self.store(self.deref(self[temp_v!(2)])); + let var = self.store(self.deref(self.registers[1])); + let value = self.store(self.deref(self.registers[2])); - match var { - Addr::AttrVar(h) => { - self.heap[h] = HeapCellValue::Addr(value); - } - _ => { - unreachable!() - } - } + debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag()); + self.heap[var.get_value()] = value; } &SystemClauseType::ResetAttrVarState => { self.attr_var_init.reset(); @@ -3642,19 +3390,13 @@ impl MachineState { &SystemClauseType::RemoveCallPolicyCheck => { let restore_default = match call_policy.downcast_mut::().ok() { Some(call_policy) => { - let a1 = self.store(self.deref(self[temp_v!(1)])); + let a1 = self.store(self.deref(self.registers[1])); + let bp = cell_as_fixnum!(a1).get_num() as usize; - match a1 { - Addr::Usize(bp) | Addr::CutPoint(bp) => { - if call_policy.is_empty() && bp == self.b { - Some(call_policy.into_inner()) - } else { - None - } - } - _ => { - panic!("remove_call_policy_check: expected Usize in A1."); - } + if call_policy.is_empty() && bp == self.b { + Some(call_policy.into_inner()) + } else { + None } } None => panic!( @@ -3670,23 +3412,15 @@ impl MachineState { &SystemClauseType::RemoveInferenceCounter => { match call_policy.downcast_mut::().ok() { Some(call_policy) => { - let a1 = self.store(self.deref(self[temp_v!(1)])); + let a1 = self.store(self.deref(self.registers[1])); + let bp = cell_as_fixnum!(a1).get_num() as usize; - match a1 { - Addr::Usize(bp) | Addr::CutPoint(bp) => { - let count = call_policy.remove_limit(bp).clone(); - let count = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(count))); + let count = call_policy.remove_limit(bp).clone(); + let count = arena_alloc!(count.clone(), &mut self.arena); - let a2 = self[temp_v!(2)]; + let a2 = self.store(self.deref(self.registers[2])); - (self.unify_fn)(self, a2, count); - } - _ => { - panic!("remove_inference_counter: expected Usize in A1."); - } - } + self.unify_big_int(count, a2); } None => panic!( "remove_inference_counter: requires \\ @@ -3702,16 +3436,14 @@ impl MachineState { let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells; for i in 1..frame_len - 1 { - self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i]; + self.registers[i] = self.stack[stack_loc!(AndFrame, e, i)]; } - if let &Addr::CutPoint(b0) = &self.stack.index_and_frame(e)[frame_len - 1] { - self.b0 = b0; - } + self.b0 = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len - 1)]) + .get_num() as usize; - if let &Addr::Usize(num_of_args) = &self.stack.index_and_frame(e)[frame_len] { - self.num_of_args = num_of_args; - } + self.num_of_args = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len)]) + .get_num() as usize; self.deallocate(); self.p = CodePtr::Local(self.stack.index_and_frame(e).prelude.interrupt_cp); @@ -3737,21 +3469,18 @@ impl MachineState { } &SystemClauseType::SetCutPointByDefault(r) => deref_cut(self, r), &SystemClauseType::SetInput => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); let stream = - self.get_stream_or_alias(addr, &indices.stream_aliases, "set_input", 1)?; + self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_input"), 1)?; if !stream.is_input_stream() { - let stub = MachineError::functor_stub(clause_name!("set_input"), 1); + let stub = functor_stub(atom!("set_input"), 1); - let user_alias = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None)); + let user_alias = atom_as_cell!(atom!("user")); - let err = MachineError::permission_error( - self.heap.h(), + let err = self.permission_error( Permission::InputStream, - "stream", + atom!("stream"), user_alias, ); @@ -3761,21 +3490,17 @@ impl MachineState { *current_input_stream = stream; } &SystemClauseType::SetOutput => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); let stream = - self.get_stream_or_alias(addr, &indices.stream_aliases, "set_output", 1)?; + self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_output"), 1)?; if !stream.is_output_stream() { - let stub = MachineError::functor_stub(clause_name!("set_input"), 1); - - let user_alias = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None)); + let stub = functor_stub(atom!("set_input"), 1); - let err = MachineError::permission_error( - self.heap.h(), + let user_alias = atom_as_cell!(atom!("user")); + let err = self.permission_error( Permission::OutputStream, - "stream", + atom!("stream"), user_alias, ); @@ -3784,68 +3509,41 @@ impl MachineState { *current_output_stream = stream; } - &SystemClauseType::SetDoubleQuotes => match self[temp_v!(1)] { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - self.flags.double_quotes = match atom.as_str() { - "atom" => DoubleQuotes::Atom, - "chars" => DoubleQuotes::Chars, - "codes" => DoubleQuotes::Codes, - _ => { - self.fail = true; - return Ok(()); - } - }; - } else { - unreachable!() - } - } - _ => { - self.fail = true; - } - }, - &SystemClauseType::InferenceLevel => { - let a1 = self[temp_v!(1)]; - let a2 = self.store(self.deref(self[temp_v!(2)])); - - match a2 { - Addr::CutPoint(bp) | Addr::Usize(bp) => { - let prev_b = self.stack.index_or_frame(self.b).prelude.b; - - if prev_b <= bp { - let a2 = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("!"), None)); + &SystemClauseType::SetDoubleQuotes => { + let atom = cell_as_atom!(self.registers[1]); - (self.unify_fn)(self, a1, a2); - } else { - let a2 = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("true"), None)); - - (self.unify_fn)(self, a1, a2); - } - } + self.flags.double_quotes = match atom { + atom!("atom") => DoubleQuotes::Atom, + atom!("chars") => DoubleQuotes::Chars, + atom!("codes") => DoubleQuotes::Codes, _ => { self.fail = true; + return Ok(()); } + }; + } + &SystemClauseType::InferenceLevel => { + let a1 = self.registers[1]; + let a2 = self.store(self.deref(self.registers[2])); + + let bp = cell_as_fixnum!(a2).get_num() as usize; + let prev_b = self.stack.index_or_frame(self.b).prelude.b; + + if prev_b <= bp { + self.unify_atom(atom!("!"), a1) + } else { + self.unify_atom(atom!("true"), a1); } } &SystemClauseType::CleanUpBlock => { - let nb = self.store(self.deref(self[temp_v!(1)])); + let nb = self.store(self.deref(self.registers[1])); + let nb = cell_as_fixnum!(nb).get_num() as usize; - match nb { - Addr::Usize(nb) => { - let b = self.b; + let b = self.b; - if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb { - self.b = self.stack.index_or_frame(nb).prelude.b; - } - } - _ => { - self.fail = true; - } - }; + if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb { + self.b = self.stack.index_or_frame(nb).prelude.b; + } } &SystemClauseType::EraseBall => { self.ball.reset(); @@ -3854,10 +3552,10 @@ impl MachineState { self.fail = true; } &SystemClauseType::GetBall => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let h = self.heap.h(); + let addr = self.store(self.deref(self.registers[1])); + let h = self.heap.len(); - if self.ball.stub.h() > 0 { + if self.ball.stub.len() > 0 { let stub = self.ball.copy_and_align(h); self.heap.extend(stub.into_iter()); } else { @@ -3865,96 +3563,87 @@ impl MachineState { return Ok(()); } - let ball = self.heap[h].as_addr(h); - match addr.as_var() { - Some(r) => self.bind(r, ball), + Some(r) => self.bind(r, self.heap[h]), _ => self.fail = true, }; } &SystemClauseType::GetCurrentBlock => { - let c = Constant::Usize(self.block); - let addr = self[temp_v!(1)]; - - self.write_constant_to_var(addr, &c); + let n = Fixnum::build_with(i64::try_from(self.block).unwrap()); + self.unify_fixnum(n, self.registers[1]); } &SystemClauseType::GetBValue => { - let a1 = self[temp_v!(1)]; - let a2 = Addr::Usize(self.b); - - (self.unify_fn)(self, a1, a2); + let n = Fixnum::build_with(i64::try_from(self.b).unwrap()); + self.unify_fixnum(n, self.registers[1]); } &SystemClauseType::GetCutPoint => { - let a1 = self[temp_v!(1)]; - let a2 = Addr::CutPoint(self.b0); - - (self.unify_fn)(self, a1, a2); + let n = Fixnum::build_with(i64::try_from(self.b0).unwrap()); + self.unify_fixnum(n, self.registers[1]); } &SystemClauseType::InstallNewBlock => { - self.install_new_block(temp_v!(1)); + self.install_new_block(self.registers[1]); } &SystemClauseType::NextEP => { - let first_arg = self.store(self.deref(self[temp_v!(1)])); + let first_arg = self.store(self.deref(self.registers[1])); - match first_arg { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = self.heap.clone(h) { - if name.as_str() == "first" { - if self.e == 0 { - self.fail = true; - return Ok(()); - } + read_heap_cell!(first_arg, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(name, atom!("first")); + debug_assert_eq!(arity, 0); + + if self.e == 0 { + self.fail = true; + return Ok(()); + } - let cp = - (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap(); + let and_frame = self.stack.index_and_frame(self.e); + let cp = (and_frame.prelude.cp - 1).unwrap(); - let e = self.stack.index_and_frame(self.e).prelude.e; - let e = Addr::Usize(e); + let e = and_frame.prelude.e; + let e = Fixnum::build_with(i64::try_from(e).unwrap()); - let p = cp.as_functor(&mut self.heap); + let p = str_loc_as_cell!(self.heap.len()); - (self.unify_fn)(self, self[temp_v!(2)], e); + self.heap.extend(cp.as_functor()); + self.unify_fixnum(e, self.registers[2]); - if !self.fail { - (self.unify_fn)(self, self[temp_v!(3)], p); - } - } else { - unreachable!() - } - } else { - unreachable!() + if !self.fail { + unify!(self, p, self.registers[3]); } } - Addr::Usize(e) => { + (HeapCellValueTag::Fixnum, n) => { + let e = n.get_num() as usize; + if e == 0 { self.fail = true; return Ok(()); } - // get the call site so that the number of active permanent variables can be read - // from it later. - let cp = (self.stack.index_and_frame(e).prelude.cp - 1).unwrap(); + // get the call site so that the number of + // active permanent variables can be read from + // it later. + let and_frame = self.stack.index_and_frame(e); + let cp = (and_frame.prelude.cp - 1).unwrap(); - let p = cp.as_functor(&mut self.heap); - let e = self.stack.index_and_frame(e).prelude.e; + let p = str_loc_as_cell!(self.heap.len()); + self.heap.extend(cp.as_functor()); - let e = Addr::Usize(e); - - (self.unify_fn)(self, self[temp_v!(2)], e); + let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); + self.unify_fixnum(e, self.registers[2]); if !self.fail { - (self.unify_fn)(self, self[temp_v!(3)], p); + unify!(self, p, self.registers[3]); } } _ => { - unreachable!() + unreachable!(); } - } + ); } &SystemClauseType::PointsToContinuationResetMarker => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); - let p = match self.heap.to_local_code_ptr(&addr) { + let p = match to_local_code_ptr(&self.heap, addr) { Some(p) => p + 1, None => { self.fail = true; @@ -3970,11 +3659,11 @@ impl MachineState { return Ok(()); } &SystemClauseType::QuotedToken => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); - match addr { - Addr::Fixnum(n) => { - let n = u32::try_from(n).ok(); + read_heap_cell!(addr, + (HeapCellValueTag::Fixnum, n) => { + let n = u32::try_from(n.get_num()).ok(); let n = n.and_then(std::char::from_u32); self.fail = match n { @@ -3982,111 +3671,96 @@ impl MachineState { None => true, }; } - Addr::Char(c) => { + (HeapCellValueTag::Char, c) => { self.fail = non_quoted_token(once(c)); } - Addr::Con(h) => { - if let HeapCellValue::Atom(atom, _) = &self.heap[h] { - self.fail = non_quoted_token(atom.as_str().chars()); - } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + self.fail = non_quoted_token(name.as_str().chars()); } _ => { self.fail = true; } - } + ); } &SystemClauseType::ReadQueryTerm => { current_input_stream.reset(); - readline::set_prompt(true); - let result = self.read_term(current_input_stream.clone(), indices); - readline::set_prompt(false); + set_prompt(true); + let result = self.read_term(*current_input_stream, indices); + set_prompt(false); match result { Ok(()) => {} Err(e) => { - *current_input_stream = readline::input_stream(); + *current_input_stream = input_stream(&mut self.arena); return Err(e); } } } &SystemClauseType::ReadTerm => { - readline::set_prompt(false); + set_prompt(false); let stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "read_term", + atom!("read_term"), 3, )?; self.read_term(stream, indices)?; } &SystemClauseType::ReadTermFromChars => { - let mut heap_pstr_iter = self.heap_pstr_iter(self[temp_v!(1)]); - let chars = heap_pstr_iter.to_string(); - - if let Addr::EmptyList = heap_pstr_iter.focus() { - let term_write_result = match self.read( - Stream::from(chars), - self.atom_tbl.clone(), - &indices.op_dir, - ) { + if let Some(atom_or_string) = self.value_to_str_like(self.registers[1]) { + let chars = atom_or_string.to_string(); + let stream = Stream::from_owned_string(chars, &mut self.arena); + + let term_write_result = match self.read(stream, &indices.op_dir) { Ok(term_write_result) => term_write_result, Err(e) => { - let stub = - MachineError::functor_stub(clause_name!("read_term_from_chars"), 2); - - let h = self.heap.h(); - let e = MachineError::session_error(h, SessionError::from(e)); + let stub = functor_stub(atom!("read_term_from_chars"), 2); + let e = self.session_error(SessionError::from(e)); return Err(self.error_form(e, stub)); } }; - let result = Addr::HeapCell(term_write_result.heap_loc); + let result = heap_loc_as_cell!(term_write_result.heap_loc); + let var = self.store(self.deref(self.registers[2])).as_var().unwrap(); - if let Some(var) = self.store(self.deref(self[temp_v!(2)])).as_var() { - self.bind(var, result); - } else { - unreachable!() - } + self.bind(var, result); } else { unreachable!() } } &SystemClauseType::ResetBlock => { - let addr = self.deref(self[temp_v!(1)]); + let addr = self.deref(self.registers[1]); self.reset_block(addr); } &SystemClauseType::ResetContinuationMarker => { - self[temp_v!(3)] = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("none"), None)); + self.registers[3] = atom_as_cell!(atom!("none")); - let h = self.heap.h(); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self[temp_v!(4)] = Addr::HeapCell(h); + self.registers[4] = heap_loc_as_cell!(h); } &SystemClauseType::SetBall => { self.set_ball(); } &SystemClauseType::SetSeed => { - let seed = self.store(self.deref(self[temp_v!(1)])); + let seed = self.store(self.deref(self.registers[1])); + let mut rand = RANDOM_STATE.borrow_mut(); - let seed = match Number::try_from((seed, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(n.as_ref()), - Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().clone(), + match Number::try_from(seed) { + Ok(Number::Fixnum(n)) => rand.seed(&Integer::from(n)), + Ok(Number::Integer(n)) => rand.seed(&*n), + Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()), _ => { self.fail = true; return Ok(()); } - }; - - let mut rand = RANDOM_STATE.borrow_mut(); - rand.seed(&seed); + } } &SystemClauseType::SkipMaxList => { if let Err(err) = self.skip_max_list() { @@ -4094,11 +3768,11 @@ impl MachineState { } } &SystemClauseType::Sleep => { - let time = self.store(self.deref(self[temp_v!(1)])); + let time = self.store(self.deref(self.registers[1])); - let time = match Number::try_from((time, &self.heap)) { - Ok(Number::Float(OrderedFloat(n))) => n, - Ok(Number::Fixnum(n)) => n as f64, + let time = match Number::try_from(time) { + Ok(Number::Float(n)) => n.into_inner(), + Ok(Number::Fixnum(n)) => n.get_num() as f64, Ok(Number::Integer(n)) => n.to_f64(), _ => { unreachable!() @@ -4107,96 +3781,78 @@ impl MachineState { let duration = Duration::new(1, 0); let duration = duration.mul_f64(time); - ::std::thread::sleep(duration); + + std::thread::sleep(duration); } &SystemClauseType::SocketClientOpen => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let port = self.store(self.deref(self[temp_v!(2)])); + let addr = self.store(self.deref(self.registers[1])); + let port = self.store(self.deref(self.registers[2])); - let socket_atom = match addr { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() - } else { - unreachable!() - } + let socket_atom = cell_as_atom!(addr); + + let _port = read_heap_cell!(port, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + name } _ => { - unreachable!() + self.atom_tbl.build_with(&match Number::try_from(port) { + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), + _ => { + unreachable!() + } + }) } - }; + ); - let port = match port { - Addr::Fixnum(n) => n.to_string(), - Addr::Usize(n) => n.to_string(), - Addr::Con(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => name.as_str().to_string(), - HeapCellValue::Integer(ref n) => n.to_string(), - _ => { - unreachable!() - } - }, - _ => { - unreachable!() - } + let socket_addr = if socket_atom == atom!("") { + atom!("127.0.0.1") + } else { + socket_atom }; - let socket_addr = format!( - "{}:{}", - if socket_atom.as_str() == "" { - "127.0.0.1" - } else { - socket_atom.as_str() - }, - port, - ); - - let alias = self[temp_v!(4)]; - let eof_action = self[temp_v!(5)]; - let reposition = self[temp_v!(6)]; - let stream_type = self[temp_v!(7)]; + let alias = self.registers[4]; + let eof_action = self.registers[5]; + let reposition = self.registers[6]; + let stream_type = self.registers[7]; let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - if options.reposition { - return Err(self.reposition_error("socket_client_open", 3)); + if options.reposition() { + return Err(self.reposition_error(atom!("socket_client_open"), 3)); } - if let Some(ref alias) = &options.alias { - if indices.stream_aliases.contains_key(alias) { + if let Some(alias) = options.get_alias() { + if indices.stream_aliases.contains_key(&alias) { return Err(self.occupied_alias_permission_error( - alias.clone(), - "socket_client_open", + alias, + atom!("socket_client_open"), 3, )); } } - let stream = match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) { + let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) { Ok(tcp_stream) => { - let socket_addr = clause_name!(socket_addr, self.atom_tbl); - - let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream); + let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.arena); *stream.options_mut() = options; - if let Some(ref alias) = &stream.options().alias { - indices.stream_aliases.insert(alias.clone(), stream.clone()); + if let Some(alias) = stream.options().get_alias() { + indices.stream_aliases.insert(alias, stream); } - indices.streams.insert(stream.clone()); + indices.streams.insert(stream); - self.heap.to_unifiable(HeapCellValue::Stream(stream)) + stream_as_cell!(stream) } Err(ErrorKind::PermissionDenied) => { - return Err(self.open_permission_error(addr, "socket_client_open", 3)); + return Err(self.open_permission_error(addr, atom!("socket_client_open"), 3)); } Err(ErrorKind::NotFound) => { - let stub = - MachineError::functor_stub(clause_name!("socket_client_open"), 3); - - let err = MachineError::existence_error( - self.heap.h(), + let stub = functor_stub(atom!("socket_client_open"), 3); + let err = self.existence_error( ExistenceError::SourceSink(addr), ); @@ -4209,45 +3865,39 @@ impl MachineState { } }; - let stream_addr = self.store(self.deref(self[temp_v!(3)])); + let stream_addr = self.store(self.deref(self.registers[3])); self.bind(stream_addr.as_var().unwrap(), stream); } &SystemClauseType::SocketServerOpen => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let socket_atom = match addr { - Addr::EmptyList => "127.0.0.1".to_string(), - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => name.as_str().to_string(), - _ => { - unreachable!() - } - }, - _ => { - unreachable!() - } + let addr = self.store(self.deref(self.registers[1])); + let socket_atom = cell_as_atom_cell!(addr).get_name(); + + let socket_atom = if socket_atom == atom!("[]") { + atom!("127.0.0.1") + } else { + socket_atom }; - let port = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Fixnum(n) => n.to_string(), - Addr::Usize(n) => n.to_string(), - Addr::Con(h) => match &self.heap[h] { - HeapCellValue::Integer(ref n) => n.to_string(), + let port = self.store(self.deref(self.registers[2])); + + let port = if port.is_var() { + String::from("0") + } else { + match Number::try_from(port) { + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), _ => { unreachable!() } - }, - addr if addr.is_ref() => "0".to_string(), - _ => { - unreachable!() } }; let had_zero_port = &port == "0"; - let server_addr = if socket_atom.is_empty() { + let server_addr = if socket_atom == atom!("") { port } else { - format!("{}:{}", socket_atom, port) + format!("{}:{}", socket_atom.as_str(), port) }; let (tcp_listener, port) = @@ -4256,18 +3906,14 @@ impl MachineState { let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); if let Some(port) = port { - ( - self.heap - .to_unifiable(HeapCellValue::TcpListener(tcp_listener)), - port as usize, - ) + (arena_alloc!(tcp_listener, &mut self.arena), port as usize) } else { self.fail = true; return Ok(()); } } Err(ErrorKind::PermissionDenied) => { - return Err(self.open_permission_error(addr, "socket_server_open", 2)); + return Err(self.open_permission_error(addr, atom!("socket_server_open"), 2)); } _ => { self.fail = true; @@ -4275,334 +3921,313 @@ impl MachineState { } }; - let addr = self.store(self.deref(self[temp_v!(3)])); - self.bind(addr.as_var().unwrap(), tcp_listener); + let addr = self.store(self.deref(self.registers[3])); + self.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener)); if had_zero_port { - (self.unify_fn)(self, self[temp_v!(2)], Addr::Usize(port)); + self.unify_fixnum(Fixnum::build_with(port as i64), self.registers[2]); } } &SystemClauseType::SocketServerAccept => { - let alias = self[temp_v!(4)]; - let eof_action = self[temp_v!(5)]; - let reposition = self[temp_v!(6)]; - let stream_type = self[temp_v!(7)]; + let alias = self.registers[4]; + let eof_action = self.registers[5]; + let reposition = self.registers[6]; + let stream_type = self.registers[7]; let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - if options.reposition { - return Err(self.reposition_error("socket_server_accept", 4)); + if options.reposition() { + return Err(self.reposition_error(atom!("socket_server_accept"), 4)); } - if let Some(ref alias) = &options.alias { - if indices.stream_aliases.contains_key(alias) { + if let Some(alias) = options.get_alias() { + if indices.stream_aliases.contains_key(&alias) { return Err(self.occupied_alias_permission_error( - alias.clone(), - "socket_server_accept", + alias, + atom!("socket_server_accept"), 4, )); } } - match self.store(self.deref(self[temp_v!(1)])) { - Addr::TcpListener(h) => match &mut self.heap[h] { - HeapCellValue::TcpListener(ref mut tcp_listener) => { - match tcp_listener.accept().ok() { - Some((tcp_stream, socket_addr)) => { - let client = - clause_name!(format!("{}", socket_addr), self.atom_tbl); + let culprit = self.store(self.deref(self.registers[1])); - let mut tcp_stream = - Stream::from_tcp_stream(client.clone(), tcp_stream); + read_heap_cell!(culprit, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::TcpListener, tcp_listener) => { + match tcp_listener.accept().ok() { + Some((tcp_stream, socket_addr)) => { + let client = self.atom_tbl.build_with(&socket_addr.to_string()); - *tcp_stream.options_mut() = options; + let mut tcp_stream = Stream::from_tcp_stream( + client, + tcp_stream, + &mut self.arena, + ); - if let Some(ref alias) = &tcp_stream.options().alias { - indices - .stream_aliases - .insert(alias.clone(), tcp_stream.clone()); - } + *tcp_stream.options_mut() = options; - indices.streams.insert(tcp_stream.clone()); + if let Some(alias) = &tcp_stream.options().get_alias() { + indices.stream_aliases.insert(*alias, tcp_stream); + } - let tcp_stream = - self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream)); + indices.streams.insert(tcp_stream); - let client = - self.heap.to_unifiable(HeapCellValue::Atom(client, None)); + let tcp_stream = stream_as_cell!(tcp_stream); + let client = atom_as_cell!(client); - let client_addr = self.store(self.deref(self[temp_v!(2)])); - let stream_addr = self.store(self.deref(self[temp_v!(3)])); + let client_addr = self.store(self.deref(self.registers[2])); + let stream_addr = self.store(self.deref(self.registers[3])); - self.bind(client_addr.as_var().unwrap(), client); - self.bind(stream_addr.as_var().unwrap(), tcp_stream); - } - None => { - self.fail = true; - return Ok(()); - } - } - } - culprit => { - let culprit = culprit.as_addr(h); - - return Err(self.type_error( - ValidType::TcpListener, - culprit, - clause_name!("socket_server_accept"), - 4, - )); - } - }, - culprit => { - return Err(self.type_error( - ValidType::TcpListener, - culprit, - clause_name!("socket_server_accept"), - 4, - )); + self.bind(client_addr.as_var().unwrap(), client); + self.bind(stream_addr.as_var().unwrap(), tcp_stream); + + return return_from_clause!(self.last_call, self); + } + None => { + self.fail = true; + return Ok(()); + } + } + } + _ => { + } + ); } - } - } - &SystemClauseType::SocketServerClose => { - match self.store(self.deref(self[temp_v!(1)])) { - Addr::TcpListener(h) => { - let closed_tcp_listener = clause_name!("$closed_tcp_listener"); - self.heap[h] = HeapCellValue::Atom(closed_tcp_listener, None); - } - culprit => { - return Err(self.type_error( - ValidType::TcpListener, - culprit, - clause_name!("socket_server_close"), - 1, - )); + _ => { } - } + ); } &SystemClauseType::TLSClientConnect => { - let hostname = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - let stream0 = self.get_stream_or_alias( - self[temp_v!(2)], - &indices.stream_aliases, - "tls_client_negotiate", - 3, - )?; - - let connector = TlsConnector::new().unwrap(); - let stream = - match connector.connect(&hostname, stream0) { - Ok(tls_stream) => tls_stream, - Err(_) => { - return Err(self.open_permission_error( - self[temp_v!(1)], - "tls_client_negotiate", - 3, - )); - } - }; + if let Some(hostname) = self.value_to_str_like(self.registers[1]) { + let stream0 = self.get_stream_or_alias( + self.registers[2], + &indices.stream_aliases, + atom!("tls_client_negotiate"), + 3, + )?; + + let connector = TlsConnector::new().unwrap(); + let stream = + match connector.connect(hostname.as_str(), stream0) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.open_permission_error( + self[temp_v!(1)], + atom!("tls_client_negotiate"), + 3, + )); + } + }; - let addr = clause_name!("TLS".to_string(), self.atom_tbl); - let stream = Stream::from_tls_stream(addr, stream); - indices.streams.insert(stream.clone()); + let addr = atom!("TLS"); + let stream = Stream::from_tls_stream(addr, stream, &mut self.arena); + indices.streams.insert(stream); - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - let stream_addr = self.store(self.deref(self[temp_v!(3)])); - self.bind(stream_addr.as_var().unwrap(), stream); + self.heap.push(stream_as_cell!(stream)); + let stream_addr = self.store(self.deref(self.registers[3])); + self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); + } else { + unreachable!(); + } } &SystemClauseType::TLSAcceptClient => { - let pkcs12 = self.string_encoding_bytes(1, "octet"); - let password = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - let identity = - match Identity::from_pkcs12(&pkcs12, &password) { - Ok(identity) => identity, - Err(_) => { - return Err(self.open_permission_error( - self[temp_v!(1)], - "tls_server_negotiate", - 3, - )); - } - }; - - let stream0 = self.get_stream_or_alias( - self[temp_v!(3)], - &indices.stream_aliases, - "tls_server_negotiate", - 3, - )?; - - let acceptor = TlsAcceptor::new(identity).unwrap(); - - let stream = - match acceptor.accept(stream0) { - Ok(tls_stream) => tls_stream, - Err(_) => { - return Err(self.open_permission_error( - self[temp_v!(3)], - "tls_server_negotiate", - 3, - )); - } - }; - let addr = clause_name!("TLS".to_string(), self.atom_tbl); - let stream = Stream::from_tls_stream(addr, stream); - indices.streams.insert(stream.clone()); - - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - let stream_addr = self.store(self.deref(self[temp_v!(4)])); - self.bind(stream_addr.as_var().unwrap(), stream); - } - &SystemClauseType::SetStreamPosition => { - let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], - &indices.stream_aliases, - "set_stream_position", - 2, - )?; + let pkcs12 = self.string_encoding_bytes(self.registers[1], atom!("octet")); + + if let Some(password) = self.value_to_str_like(self.registers[2]) { + let identity = + match Identity::from_pkcs12(&pkcs12, password.as_str()) { + Ok(identity) => identity, + Err(_) => { + return Err(self.open_permission_error( + self.registers[1], + atom!("tls_server_negotiate"), + 3, + )); + } + }; - if !stream.options().reposition { - let stub = MachineError::functor_stub(clause_name!("set_stream_position"), 2); + let stream0 = self.get_stream_or_alias( + self.registers[3], + &indices.stream_aliases, + atom!("tls_server_negotiate"), + 3, + )?; + + let acceptor = TlsAcceptor::new(identity).unwrap(); + + let stream = + match acceptor.accept(stream0) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.open_permission_error( + self.registers[3], + atom!("tls_server_negotiate"), + 3, + )); + } + }; - let err = MachineError::permission_error( - self.heap.h(), - Permission::Reposition, - "stream", - vec![HeapCellValue::Stream(stream)], - ); + let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.arena); + indices.streams.insert(stream); - return Err(self.error_form(err, stub)); + let stream_addr = self.store(self.deref(self.registers[4])); + self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); + } else { + unreachable!(); } + } + &SystemClauseType::SocketServerClose => { + let culprit = self.store(self.deref(self.registers[1])); + + read_heap_cell!(culprit, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::TcpListener, tcp_listener) => { + unsafe { + // dropping closes the instance. + std::ptr::drop_in_place(&mut tcp_listener as *mut _); + } - let position = self.store(self.deref(self[temp_v!(2)])); - - let position = match Number::try_from((position, &self.heap)) { - Ok(Number::Fixnum(n)) => n as u64, - Ok(Number::Integer(n)) => { - if let Some(n) = n.to_u64() { - n - } else { - self.fail = true; - return Ok(()); - } + tcp_listener.set_tag(ArenaHeaderTag::Dropped); + return return_from_clause!(self.last_call, self); + } + _ => { + } + ); } _ => { - unreachable!() } - }; + ); - stream.set_position(position); + let err = self.type_error(ValidType::TcpListener, culprit); + let stub = functor_stub(atom!("socket_server_close"), 1); + + return Err(self.error_form(err, stub)); } - &SystemClauseType::StreamProperty => { + &SystemClauseType::SetStreamPosition => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "stream_property", + atom!("set_stream_position"), 2, )?; - let property = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => match name.as_str() { - "file_name" => { - if let Some(file_name) = stream.file_name() { - HeapCellValue::Atom(file_name, None) - } else { - self.fail = true; - return Ok(()); - } - } - "mode" => HeapCellValue::Atom(clause_name!(stream.mode()), None), - "direction" => HeapCellValue::Atom( - if stream.is_input_stream() && stream.is_output_stream() { - clause_name!("input_output") - } else if stream.is_input_stream() { - clause_name!("input") - } else { - clause_name!("output") - }, - None, - ), - "alias" => { - if let Some(alias) = &stream.options().alias { - HeapCellValue::Atom(alias.clone(), None) - } else { - self.fail = true; - return Ok(()); - } - } - "position" => { - if let Some((position, lines_read)) = stream.position() { - let h = self.heap.h(); - - let position_term = functor!( - "position_and_lines_read", - [integer(position), integer(lines_read)] - ); + if !stream.options().reposition() { + let stub = functor_stub(atom!("set_stream_position"), 2); - self.heap.extend(position_term.into_iter()); + let err = self.permission_error( + Permission::Reposition, + atom!("stream"), + vec![stream_as_cell!(stream)], + ); - HeapCellValue::Addr(Addr::HeapCell(h)) - } else { - self.fail = true; - return Ok(()); - } - } - "end_of_stream" => { - let end_of_stream_pos = stream.position_relative_to_end(); - HeapCellValue::Atom(clause_name!(end_of_stream_pos.as_str()), None) - } - "eof_action" => HeapCellValue::Atom( - clause_name!(stream.options().eof_action.as_str()), - None, - ), - "reposition" => HeapCellValue::Atom( - clause_name!(if stream.options().reposition { - "true" - } else { - "false" - }), - None, - ), - "type" => HeapCellValue::Atom( - clause_name!(stream.options().stream_type.as_property_str()), - None, - ), - _ => { - unreachable!() - } - }, - _ => { - unreachable!() + return Err(self.error_form(err, stub)); + } + + let position = self.store(self.deref(self.registers[2])); + + let position = match Number::try_from(position) { + Ok(Number::Fixnum(n)) => n.get_num() as u64, + Ok(Number::Integer(n)) => { + if let Some(n) = n.to_u64() { + n + } else { + self.fail = true; + return Ok(()); } - }, + } _ => { unreachable!() } }; - let property = self.heap.to_unifiable(property); - (self.unify_fn)(self, self[temp_v!(3)], property); + stream.set_position(position); } - &SystemClauseType::StoreGlobalVar => { - let key = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.clone() + &SystemClauseType::StreamProperty => { + let mut stream = self.get_stream_or_alias( + self.registers[1], + &indices.stream_aliases, + atom!("stream_property"), + 2, + )?; + + let atom = cell_as_atom!(self.store(self.deref(self.registers[2]))); + + let property = match atom { + atom!("file_name") => { + atom_as_cell!(if let Some(file_name) = stream.file_name() { + file_name } else { - unreachable!() + self.fail = true; + return Ok(()); + }) + } + atom!("mode") => atom_as_cell!(stream.mode()), + atom!("direction") => + atom_as_cell!(if stream.is_input_stream() && stream.is_output_stream() { + atom!("input_output") + } else if stream.is_input_stream() { + atom!("input") + } else { + atom!("output") + }), + atom!("alias") => { + atom_as_cell!(if let Some(alias) = stream.options().get_alias() { + alias + } else { + self.fail = true; + return Ok(()); + }) + } + atom!("position") => { + if let Some((position, lines_read)) = stream.position() { + let h = self.heap.len(); + + let position_term = functor!( + atom!("position_and_lines_read"), + [integer(position, &mut self.arena), + integer(lines_read, &mut self.arena)] + ); + + self.heap.extend(position_term.into_iter()); + str_loc_as_cell!(h) + } else { + self.fail = true; + return Ok(()); } } + atom!("end_of_stream") => { + let end_of_stream_pos = stream.position_relative_to_end(); + atom_as_cell!(end_of_stream_pos.as_atom()) + } + atom!("eof_action") => { + atom_as_cell!(stream.options().eof_action().as_atom()) + } + atom!("reposition") => + atom_as_cell!(if stream.options().reposition() { + atom!("true") + } else { + atom!("false") + }), + atom!("type") => { + atom_as_cell!(stream.options().stream_type().as_property_atom()) + } _ => { unreachable!() } }; - let value = self[temp_v!(2)]; + unify!(self, property, self.registers[3]); + } + &SystemClauseType::StoreGlobalVar => { + let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); + + let value = self.registers[2]; let mut ball = Ball::new(); - ball.boundary = self.heap.h(); + ball.boundary = self.heap.len(); copy_term( CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub), @@ -4613,74 +4238,101 @@ impl MachineState { indices.global_variables.insert(key, (ball, None)); } &SystemClauseType::StoreBacktrackableGlobalVar => { - let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - (h, atom.clone()) - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; - - let new_value = self.store(self.deref(self[temp_v!(2)])); + let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let new_value = self.store(self.deref(self.registers[2])); match indices.global_variables.get_mut(&key) { Some((_, ref mut loc)) => match loc { Some(ref mut value) => { - let old_value_loc = self.heap.push(HeapCellValue::Addr(*value)); - self.trail(TrailRef::BlackboardOffset(key_h, old_value_loc)); + self.trail(TrailRef::BlackboardOffset(key, *value)); *value = new_value; } loc @ None => { - self.trail(TrailRef::BlackboardEntry(key_h)); + self.trail(TrailRef::BlackboardEntry(key)); *loc = Some(new_value); } }, None => { - self.trail(TrailRef::BlackboardEntry(key_h)); + self.trail(TrailRef::BlackboardEntry(key)); indices .global_variables .insert(key, (Ball::new(), Some(new_value))); } } } - &SystemClauseType::Succeed => {} &SystemClauseType::TermAttributedVariables => { - let seen_vars = self.attr_vars_of_term(self[temp_v!(1)]); - let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); + if self.registers[1].is_constant() { + self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); + return return_from_clause!(self.last_call, self); + } + + let seen_vars = self.attr_vars_of_term(self.registers[1]); + let outcome = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, seen_vars.into_iter()) + ); - (self.unify_fn)(self, self[temp_v!(2)], outcome); + unify_fn!(self, self.registers[2], outcome); } + &SystemClauseType::Succeed => {} &SystemClauseType::TermVariables => { - let a1 = self[temp_v!(1)]; + let a1 = self.registers[1]; + let a2 = self.registers[2]; + + let stored_v = self.store(self.deref(a1)); + + if stored_v.is_constant() { + self.unify_atom(atom!("[]"), self.store(self.deref(a2))); + return return_from_clause!(self.last_call, self); + } + let mut seen_set = IndexSet::new(); - let mut seen_vars = vec![]; - for addr in self.acyclic_pre_order_iter(a1) { - if addr.is_ref() && !seen_set.contains(&addr) { - seen_vars.push(addr); - seen_set.insert(addr); + { + let mut iter = stackless_preorder_iter(&mut self.heap, stored_v); + + while let Some(addr) = iter.next() { + let addr = unmark_cell_bits!(addr); + + if addr.is_var() { + seen_set.insert(addr); + } } } - let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); - (self.unify_fn)(self, self[temp_v!(2)], outcome); + let outcome = heap_loc_as_cell!( + filtered_iter_to_heap_list( + &mut self.heap, + seen_set.into_iter().rev(), + |heap, value| { + heap_bound_store( + heap, + heap_bound_deref(heap, value), + ).is_var() + }, + ) + ); + + unify_fn!(self, a2, outcome); + } + &SystemClauseType::TermVariablesUnderMaxDepth => { + // Term, MaxDepth, VarList + let max_depth = cell_as_fixnum!( + self.store(self.deref(self.registers[2])) + ).get_num() as usize; + + self.term_variables_under_max_depth(self.registers[1], max_depth, self.registers[3]); } &SystemClauseType::TruncateLiftedHeapTo => { - match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => self.lifted_heap.truncate(lh_offset), - _ => self.fail = true, - } + let a1 = self.store(self.deref(self.registers[1])); + let lh_offset = cell_as_fixnum!(a1).get_num() as usize; + + self.lifted_heap.truncate(lh_offset); } &SystemClauseType::UnifyWithOccursCheck => { - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; + let a1 = self.registers[1]; + let a2 = self.registers[2]; - self.unify_with_occurs_check(a1, a2); + unify_with_occurs_check!(self, a1, a2); } &SystemClauseType::UnwindEnvironments => { let mut e = self.e; @@ -4694,66 +4346,52 @@ impl MachineState { return Ok(()); } - cp = self.stack.index_and_frame(e).prelude.cp; - e = self.stack.index_and_frame(e).prelude.e; + let and_frame = self.stack.index_and_frame(e); + + cp = and_frame.prelude.cp; + e = and_frame.prelude.e; } } &SystemClauseType::UnwindStack => { self.unwind_stack(); } + /* &SystemClauseType::Variant => { self.fail = self.structural_eq_test(); } + */ &SystemClauseType::WAMInstructions => { - let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - - let name = self[temp_v!(2)]; - let arity = self[temp_v!(3)]; + let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); - let name = match self.store(self.deref(name)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let name = self.registers[2]; + let arity = self.registers[3]; + let name = cell_as_atom!(self.store(self.deref(name))); let arity = self.store(self.deref(arity)); - let arity = match Number::try_from((arity, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + let arity = match Number::try_from(arity) { + Ok(Number::Fixnum(n)) => n.get_num() as usize, + Ok(Number::Integer(n)) => n.to_usize().unwrap(), _ => { unreachable!() } }; - let key = (name.clone(), arity.to_usize().unwrap()); + let key = (name, arity); - let first_idx = match module_name.as_str() { - "user" => indices.code_dir.get(&key), + let first_idx = match module_name { + atom!("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 = MachineError::session_error( - h, + let stub = functor_stub(key.0, key.1); + let err = self.session_error( SessionError::from(CompilationError::InvalidModuleResolution( module_name, )), ); - let err = self.error_form(err, stub); - - self.throw_exception(err); - return Ok(()); + return Err(self.error_form(err, stub)); } }, }; @@ -4767,34 +4405,39 @@ impl MachineState { } } _ => { - 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, + let stub = functor_stub(name, arity); + let err = self.existence_error( ExistenceError::Procedure(name, arity), ); - let err = self.error_form(err, stub); - - self.throw_exception(err); - return Ok(()); + return Err(self.error_form(err, stub)); } }; - let mut h = self.heap.h(); + let mut h = self.heap.len(); + let mut functors = vec![]; let mut functor_list = vec![]; walk_code(&code_repo.code, first_idx, |instr| { let old_len = functors.len(); - instr.enqueue_functors(h, &mut functors); + instr.enqueue_functors(h, &mut self.arena, &mut functors); let new_len = functors.len(); for index in old_len..new_len { - functor_list.push(Addr::HeapCell(h)); - h += functors[index].len(); + let functor_len = functors[index].len(); + + match functor_len { + 0 => {} + 1 => { + functor_list.push(heap_loc_as_cell!(h)); + h += functor_len; + } + _ => { + functor_list.push(str_loc_as_cell!(h)); + h += functor_len; + } + } } }); @@ -4802,64 +4445,69 @@ impl MachineState { 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)]; + let listing = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, functor_list.into_iter()) + ); + + let listing_var = self.registers[4]; - (self.unify_fn)(self, listing, listing_var); + unify!(self, listing, listing_var); } &SystemClauseType::WriteTerm => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "write_term", + atom!("write_term"), 3, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, None, // input - clause_name!("write_term"), + atom!("write_term"), 3, )?; let opt_err = if !stream.is_output_stream() { - Some("stream") // 8.14.2.3 g) - } else if stream.options().stream_type == StreamType::Binary { - Some("binary_stream") // 8.14.2.3 h) + Some(atom!("stream")) // 8.14.2.3 g) + } else if stream.options().stream_type() == StreamType::Binary { + Some(atom!("binary_stream")) // 8.14.2.3 h) } else { None }; - if let Some(err_string) = opt_err { + if let Some(err_atom) = opt_err { return Err(self.stream_permission_error( Permission::OutputStream, - err_string, + err_atom, stream, - clause_name!("write_term"), + atom!("write_term"), 3, )); } - let addr = self[temp_v!(2)]; - let printer = match self.write_term(&indices.op_dir)? { + Some(printer) => printer, None => { - self.fail = true; + // this next line is executed by + // MachineState::write_term in this case. it's + // commented here because rustc can't prove + // that it's no longer borrowed. + + // self.fail = true; return Ok(()); } - Some(printer) => printer, }; - let output = printer.print(addr); + let output = printer.print(); match write!(&mut stream, "{}", output.result()) { Ok(_) => {} Err(_) => { - let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(self[temp_v!(1)]), + let stub = functor_stub(atom!("open"), 4); + let err = self.existence_error( + ExistenceError::Stream(self.registers[1]), ); return Err(self.error_form(err, stub)); @@ -4869,20 +4517,23 @@ impl MachineState { stream.flush().unwrap(); } &SystemClauseType::WriteTermToChars => { - let addr = self[temp_v!(2)]; - let printer = match self.write_term(&indices.op_dir)? { None => { - self.fail = true; + // this next line is executed by + // MachineState::write_term in this case. it's + // commented here because rustc can't prove + // that it's no longer borrowed. + + // self.fail = true; return Ok(()); } Some(printer) => printer, }; - let result = printer.print(addr).result(); - let chars = self.heap.put_complete_string(&result); + let result = printer.print().result(); + let chars = put_complete_string(&mut self.heap, &result, &mut self.atom_tbl); - let result_addr = self.store(self.deref(self[temp_v!(1)])); + let result_addr = self.store(self.deref(self.registers[1])); if let Some(var) = result_addr.as_var() { self.bind(var, chars); @@ -4892,14 +4543,14 @@ impl MachineState { } &SystemClauseType::ScryerPrologVersion => { use git_version::git_version; - let version = self[temp_v!(1)]; + let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); - let chars = buffer.chars().map(|c| Addr::Char(c)); - let result = Addr::HeapCell(self.heap.to_list(chars)); - (self.unify_fn)(self, version, result); + let buffer_atom = self.atom_tbl.build_with(buffer); + + self.unify_complete_string(buffer_atom, self.store(self.deref(self.registers[1]))); } &SystemClauseType::CryptoRandomByte => { - let arg = self[temp_v!(1)]; + let arg = self.registers[1]; let mut bytes: [u8; 1] = [0]; match rng().fill(&mut bytes) { @@ -4913,149 +4564,163 @@ impl MachineState { } } - let byte = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(Integer::from(bytes[0])))); - - (self.unify_fn)(self, arg, byte); + let byte = Fixnum::build_with(bytes[0] as i64); + self.unify_fixnum(byte, arg); } &SystemClauseType::CryptoDataHash => { - let encoding = self.atom_argument_to_string(2); - let bytes = self.string_encoding_bytes(1, &encoding); + let encoding = cell_as_atom!(self.registers[2]); + let bytes = self.string_encoding_bytes(self.registers[1], encoding); - let algorithm = self.atom_argument_to_string(4); + let algorithm = cell_as_atom!(self.registers[4]); - let ints_list = match algorithm.as_str() { - "sha3_224" => { + let ints_list = match algorithm { + atom!("sha3_224") => { let mut context = Sha3_224::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "sha3_256" => { + atom!("sha3_256") => { let mut context = Sha3_256::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "sha3_384" => { + atom!("sha3_384") => { let mut context = Sha3_384::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "sha3_512" => { + atom!("sha3_512") => { let mut context = Sha3_512::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "blake2s256" => { + atom!("blake2s256") => { let mut context = Blake2s::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "blake2b512" => { + atom!("blake2b512") => { let mut context = Blake2b::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "ripemd160" => { + atom!("ripemd160") => { let mut context = Ripemd160::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } _ => { let ints = digest::digest( - match algorithm.as_str() { - "sha256" => &digest::SHA256, - "sha384" => &digest::SHA384, - "sha512" => &digest::SHA512, - "sha512_256" => &digest::SHA512_256, + match algorithm { + atom!("sha256") => &digest::SHA256, + atom!("sha384") => &digest::SHA384, + atom!("sha512") => &digest::SHA512, + atom!("sha512_256") => &digest::SHA512_256, _ => { unreachable!() } }, &bytes, ); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, ints.as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } }; - (self.unify_fn)(self, self[temp_v!(3)], ints_list); + unify!(self, self.registers[3], ints_list); } &SystemClauseType::CryptoDataHKDF => { - let encoding = self.atom_argument_to_string(2); - let data = self.string_encoding_bytes(1, &encoding); - let stub1 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4); - let salt = self.integers_to_bytevec(temp_v!(3), stub1); - let stub2 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4); - let info = self.integers_to_bytevec(temp_v!(4), stub2); + let encoding = cell_as_atom!(self.registers[2]); + let data = self.string_encoding_bytes(self.registers[1], encoding); - let algorithm = self.atom_argument_to_string(5); + let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); + let salt = self.integers_to_bytevec(self.registers[3], stub1_gen); - let length = self.store(self.deref(self[temp_v!(6)])); + let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); + let info = self.integers_to_bytevec(self.registers[4], stub2_gen); - let length = match Number::try_from((length, &self.heap)) { - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + let algorithm = cell_as_atom!(self.registers[5]); + + let length = self.store(self.deref(self.registers[6])); + + let length = match Number::try_from(length) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_usize() { Some(u) => u, _ => { @@ -5069,18 +4734,21 @@ impl MachineState { }; let ints_list = { - let digest_alg = match algorithm.as_str() { - "sha256" => hkdf::HKDF_SHA256, - "sha384" => hkdf::HKDF_SHA384, - "sha512" => hkdf::HKDF_SHA512, + let digest_alg = match algorithm { + atom!("sha256") => hkdf::HKDF_SHA256, + atom!("sha384") => hkdf::HKDF_SHA384, + atom!("sha512") => hkdf::HKDF_SHA512, _ => { self.fail = true; return Ok(()); } }; + let salt = hkdf::Salt::new(digest_alg, &salt); let mut bytes: Vec = Vec::new(); + bytes.resize(length, 0); + match salt.extract(&data).expand(&[&info[..]], MyKey(length)) { Ok(r) => { r.fill(&mut bytes).unwrap(); @@ -5091,27 +4759,28 @@ impl MachineState { } } - Addr::HeapCell( - self.heap.to_list( + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, bytes .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) }; - (self.unify_fn)(self, self[temp_v!(7)], ints_list); + unify!(self, self.registers[7], ints_list); } &SystemClauseType::CryptoPasswordHash => { - let stub1 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3); - let data = self.integers_to_bytevec(temp_v!(1), stub1); - let stub2 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3); - let salt = self.integers_to_bytevec(temp_v!(2), stub2); + let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3); + let data = self.integers_to_bytevec(self.registers[1], stub1_gen); + let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3); + let salt = self.integers_to_bytevec(self.registers[2], stub2_gen); - let iterations = self.store(self.deref(self[temp_v!(3)])); + let iterations = self.store(self.deref(self.registers[3])); - let iterations = match Number::try_from((iterations, &self.heap)) { - Ok(Number::Fixnum(n)) => u64::try_from(n).unwrap(), + let iterations = match Number::try_from(iterations) { + Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_u64() { Some(i) => i, None => { @@ -5126,6 +4795,7 @@ impl MachineState { let ints_list = { let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN]; + pbkdf2::derive( pbkdf2::PBKDF2_HMAC_SHA512, NonZeroU32::new(iterations as u32).unwrap(), @@ -5134,31 +4804,36 @@ impl MachineState { &mut bytes, ); - Addr::HeapCell( - self.heap.to_list( + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, bytes .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) }; - (self.unify_fn)(self, self[temp_v!(4)], ints_list); + unify!(self, self.registers[4], ints_list); } &SystemClauseType::CryptoDataEncrypt => { - let encoding = self.atom_argument_to_string(3); - let data = self.string_encoding_bytes(1, &encoding); - let aad = self.string_encoding_bytes(2, &encoding); - let stub2 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7); - let key = self.integers_to_bytevec(temp_v!(4), stub2); - let stub3 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7); - let iv = self.integers_to_bytevec(temp_v!(5), stub3); + let encoding = cell_as_atom!(self.registers[3]); + + let data = self.string_encoding_bytes(self.registers[1], encoding); + let aad = self.string_encoding_bytes(self.registers[2], encoding); + + let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); + let key = self.integers_to_bytevec(self.registers[4], stub2_gen); + + let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); + let iv = self.integers_to_bytevec(self.registers[5], stub3_gen); let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); let key = aead::LessSafeKey::new(unbound_key); - let mut in_out = data.clone(); + let mut in_out = data; + let tag = match key.seal_in_place_separate_tag( nonce, aead::Aad::from(aad), @@ -5171,36 +4846,39 @@ impl MachineState { } }; - let tag_list = Addr::HeapCell( - self.heap.to_list( + let tag_list = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, tag.as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ); let complete_string = { let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); - self.heap.put_complete_string(&buffer) + put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl) }; - (self.unify_fn)(self, self[temp_v!(6)], tag_list); - (self.unify_fn)(self, self[temp_v!(7)], complete_string); + unify!(self, self.registers[6], tag_list); + unify!(self, self.registers[7], complete_string); } &SystemClauseType::CryptoDataDecrypt => { - let data = self.string_encoding_bytes(1, "octet"); - let encoding = self.atom_argument_to_string(5); - let aad = self.string_encoding_bytes(2, &encoding); - let stub1 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7); - let key = self.integers_to_bytevec(temp_v!(3), stub1); - let stub2 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7); - let iv = self.integers_to_bytevec(temp_v!(4), stub2); + let data = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.registers[5]); + + let aad = self.string_encoding_bytes(self.registers[2], encoding); + let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); + + let key = self.integers_to_bytevec(self.registers[3], stub1_gen); + let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); + let iv = self.integers_to_bytevec(self.registers[4], stub2_gen); let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); let key = aead::LessSafeKey::new(unbound_key); - let mut in_out = data.clone(); + let mut in_out = data; let complete_string = { let decrypted_data = @@ -5212,9 +4890,9 @@ impl MachineState { } }; - let buffer = match encoding.as_str() { - "octet" => String::from_iter(decrypted_data.iter().map(|b| *b as char)), - "utf8" => match String::from_utf8(decrypted_data.to_vec()) { + let buffer = match encoding { + atom!("octet") => String::from_iter(decrypted_data.iter().map(|b| *b as char)), + atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) { Ok(str) => str, _ => { self.fail = true; @@ -5226,67 +4904,80 @@ impl MachineState { } }; - self.heap.put_complete_string(&buffer) + put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl) }; - (self.unify_fn)(self, self[temp_v!(6)], complete_string); + unify!(self, self.registers[6], complete_string); } &SystemClauseType::CryptoCurveScalarMult => { - let curve = self.atom_argument_to_string(1); - let curve_id = match curve.as_str() { - "secp112r1" => Nid::SECP112R1, - "secp256k1" => Nid::SECP256K1, + let curve = cell_as_atom!(self.registers[1]); + + let curve_id = match curve { + atom!("secp112r1") => Nid::SECP112R1, + atom!("secp256k1") => Nid::SECP256K1, _ => { unreachable!() } }; - let scalar = self.store(self.deref(self[temp_v!(2)])); + let scalar = self.store(self.deref(self.registers[2])); - let scalar = match Number::try_from((scalar, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(&*n.clone()), + let scalar = match Number::try_from(scalar) { + Ok(Number::Fixnum(n)) => Integer::from(n.get_num()), + Ok(Number::Integer(n)) => Integer::from(&*n), _ => { unreachable!() } }; - let stub = MachineError::functor_stub(clause_name!("crypto_curve_scalar_mult"), 5); - let qbytes = self.integers_to_bytevec(temp_v!(3), stub); + let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5); + let qbytes = self.integers_to_bytevec(self.registers[3], stub_gen); let mut bnctx = BigNumContext::new().unwrap(); let group = EcGroup::from_curve_name(curve_id).unwrap(); let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap(); let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap(); let mut result = EcPoint::new(&group).unwrap(); + result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok(); let mut rx = BigNum::new().unwrap(); let mut ry = BigNum::new().unwrap(); + result .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx) .ok(); - let sx = self - .heap - .put_complete_string(&rx.to_dec_str().unwrap().to_string()); - let sy = self - .heap - .put_complete_string(&ry.to_dec_str().unwrap().to_string()); - (self.unify_fn)(self, self[temp_v!(4)], sx); - (self.unify_fn)(self, self[temp_v!(5)], sy); + let sx = put_complete_string( + &mut self.heap, + &rx.to_dec_str().unwrap(), + &mut self.atom_tbl, + ); + + let sy = put_complete_string( + &mut self.heap, + &ry.to_dec_str().unwrap(), + &mut self.atom_tbl, + ); + + unify!(self, self.registers[4], sx); + unify!(self, self.registers[5], sy); } &SystemClauseType::Ed25519NewKeyPair => { let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); let complete_string = { let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); - self.heap.put_complete_string(&buffer) + put_complete_string( + &mut self.heap, + &buffer, + &mut self.atom_tbl, + ) }; - (self.unify_fn)(self, self[temp_v!(1)], complete_string); + unify!(self, self.registers[1], complete_string) } &SystemClauseType::Ed25519KeyPairPublicKey => { - let bytes = self.string_encoding_bytes(1, "octet"); + let bytes = self.string_encoding_bytes(self.registers[1], atom!("octet")); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) { Ok(kp) => kp, @@ -5300,15 +4991,20 @@ impl MachineState { let buffer = String::from_iter( key_pair.public_key().as_ref().iter().map(|b| *b as char), ); - self.heap.put_complete_string(&buffer) + + put_complete_string( + &mut self.heap, + &buffer, + &mut self.atom_tbl, + ) }; - (self.unify_fn)(self, self[temp_v!(2)], complete_string); + unify!(self, self.registers[2], complete_string); } &SystemClauseType::Ed25519Sign => { - let key = self.string_encoding_bytes(1, "octet"); - let encoding = self.atom_argument_to_string(3); - let data = self.string_encoding_bytes(2, &encoding); + let key = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.registers[3]); + let data = self.string_encoding_bytes(self.registers[2], encoding); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) { Ok(kp) => kp, @@ -5320,24 +5016,26 @@ impl MachineState { let sig = key_pair.sign(&data); - let sig_list = Addr::HeapCell( - self.heap.to_list( + let sig_list = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, sig.as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ); - (self.unify_fn)(self, self[temp_v!(4)], sig_list); + unify!(self, self.registers[4], sig_list); } &SystemClauseType::Ed25519Verify => { - let key = self.string_encoding_bytes(1, "octet"); - let encoding = self.atom_argument_to_string(3); - let data = self.string_encoding_bytes(2, &encoding); - let stub = MachineError::functor_stub(clause_name!("ed25519_verify"), 5); - let signature = self.integers_to_bytevec(temp_v!(4), stub); + let key = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.registers[3]); + let data = self.string_encoding_bytes(self.registers[2], encoding); + let stub_gen = || functor_stub(atom!("ed25519_verify"), 5); + let signature = self.integers_to_bytevec(self.registers[4], stub_gen); let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key); + match peer_public_key.verify(&data, &signature) { Ok(_) => {} _ => { @@ -5347,73 +5045,112 @@ impl MachineState { } } &SystemClauseType::Curve25519ScalarMult => { - let stub1 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3); - let scalar_bytes = self.integers_to_bytevec(temp_v!(1), stub1); + let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); + let scalar_bytes = self.integers_to_bytevec(self.registers[1], stub1_gen); let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap()); - let stub2 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3); - let point_bytes = self.integers_to_bytevec(temp_v!(2), stub2); + let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); + let point_bytes = self.integers_to_bytevec(self.registers[2], stub2_gen); let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap()); let result = scalarmult(&scalar, &point).unwrap(); let string = String::from_iter(result[..].iter().map(|b| *b as char)); - let cstr = self.heap.put_complete_string(&string); - (self.unify_fn)(self, self[temp_v!(3)], cstr); + let cstr = put_complete_string(&mut self.heap, &string, &mut self.atom_tbl); + + unify!(self, self.registers[3], cstr); } &SystemClauseType::FirstNonOctet => { - for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() { - if c as u32 > 255 { - let chars = clause_name!(String::from(c.to_string()), self.atom_tbl); - let non_octet = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); - (self.unify_fn)(self, self[temp_v!(2)], non_octet); - return return_from_clause!(self.last_call, self); + let addr = self.store(self.deref(self.registers[1])); + + if let Some(string) = self.value_to_str_like(addr) { + for c in string.as_str().chars() { + if c as u32 > 255 { + let non_octet = self.atom_tbl.build_with(&c.to_string()); + self.unify_atom(non_octet, self.registers[2]); + return return_from_clause!(self.last_call, self); + } } } + self.fail = true; return Ok(()); } &SystemClauseType::LoadHTML => { - let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let doc = select::document::Document::from_read(string.as_bytes()).unwrap(); - let result = self.html_node_to_term(indices, doc.nth(0).unwrap()); + if let Some(string) = self.value_to_str_like(self.registers[1]) { + let doc = select::document::Document::from_read(string.as_str().as_bytes()) + .unwrap(); - (self.unify_fn)(self, self[temp_v!(2)], result); + let result = self.html_node_to_term(indices, doc.nth(0).unwrap()); + unify!(self, self.registers[2], result); + } else { + self.fail = true; + return Ok(()); + } } &SystemClauseType::LoadXML => { - let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - match roxmltree::Document::parse(&string) { - Ok(doc) => { - let result = self.xml_node_to_term(indices, doc.root_element()); - (self.unify_fn)(self, self[temp_v!(2)], result); - } - _ => { - self.fail = true; - return Ok(()); + if let Some(string) = self.value_to_str_like(self.registers[1]) { + match roxmltree::Document::parse(string.as_str()) { + Ok(doc) => { + let result = self.xml_node_to_term(indices, doc.root_element()); + unify!(self, self.registers[2], result); + } + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; + return Ok(()); } } &SystemClauseType::GetEnv => { - let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - match env::var(key) { - Ok(value) => { - let cstr = self.heap.put_complete_string(&value); - (self.unify_fn)(self, self[temp_v!(2)], cstr); - } - _ => { - self.fail = true; - return Ok(()); + if let Some(key) = self.value_to_str_like(self.registers[1]) { + match env::var(key.as_str()) { + Ok(value) => { + let cstr = put_complete_string( + &mut self.heap, + &value, + &mut self.atom_tbl, + ); + + unify!(self, self.registers[2], cstr); + } + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; + return Ok(()); } } &SystemClauseType::SetEnv => { - let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let value = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - env::set_var(key, value); + let key = self.value_to_str_like(self.registers[1]).unwrap(); + let value = self.value_to_str_like(self.registers[2]).unwrap(); + + env::set_var(key.as_str(), value.as_str()); } &SystemClauseType::UnsetEnv => { - let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - env::remove_var(key); + let key = self.value_to_str_like(self.registers[1]).unwrap(); + env::remove_var(key.as_str()); + } + &SystemClauseType::PID => { + let pid = process::id(); + + match fixnum!(Number, pid as i64, &mut self.arena) { + Number::Fixnum(pid) => { + self.unify_fixnum(pid, self.registers[1]); + } + Number::Integer(pid) => { + self.unify_big_int(pid, self.registers[1]); + } + _ => { + unreachable!(); + } + } } &SystemClauseType::Shell => { // shell executes a command in a system shell @@ -5426,8 +5163,8 @@ impl MachineState { Ok(status) => { match status.code() { Some(code) => { - let addr = machine.heap.put_constant(Constant::Integer(Rc::new(Integer::from(code)))); - (machine.unify_fn)(machine, machine[temp_v!(2)], addr); + let code = integer_as_cell!(Number::arena_from(code, &mut machine.arena)); + unify!(machine, code, machine.registers[2]); } _ => { machine.fail = true; @@ -5440,12 +5177,13 @@ impl MachineState { } } - let command = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + let command = self.value_to_str_like(self.store(self.deref(self.registers[1]))).unwrap(); + match env::var("SHELL") { Ok(value) => { let command = process::Command::new(&value) .arg("-c") - .arg(command) + .arg(command.as_str()) .status(); command_result(self, command); } @@ -5454,7 +5192,7 @@ impl MachineState { Ok(value) => { let command = process::Command::new(&value) .arg("/C") - .arg(command) + .arg(command.as_str()) .status(); command_result(self, command); } @@ -5465,39 +5203,38 @@ impl MachineState { } }; } - &SystemClauseType::PID => { - let a1 = self[temp_v!(1)]; - let pid = process::id(); - let addr = self.heap.put_constant(Constant::Integer(Rc::new(Integer::from(pid)))); - (self.unify_fn)(self, a1, addr); - } &SystemClauseType::CharsBase64 => { - let padding = self.atom_argument_to_string(3); - let charset = self.atom_argument_to_string(4); + let padding = cell_as_atom!(self.registers[3]); + let charset = cell_as_atom!(self.registers[4]); - let config = if padding == "true" { - if charset == "standard" { + let config = if padding == atom!("true") { + if charset == atom!("standard") { base64::STANDARD } else { base64::URL_SAFE } } else { - if charset == "standard" { + if charset == atom!("standard") { base64::STANDARD_NO_PAD } else { base64::URL_SAFE_NO_PAD } }; - if self.store(self.deref(self[temp_v!(1)])).is_ref() { - let b64 = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - let bytes = base64::decode_config(b64, config); + if self.store(self.deref(self.registers[1])).is_var() { + let b64 = self.value_to_str_like(self.registers[2]).unwrap(); + let bytes = base64::decode_config(b64.as_str(), config); match bytes { Ok(bs) => { let string = String::from_iter(bs.iter().map(|b| *b as char)); - let cstr = self.heap.put_complete_string(&string); - (self.unify_fn)(self, self[temp_v!(1)], cstr); + let cstr = put_complete_string( + &mut self.heap, + &string, + &mut self.atom_tbl, + ); + + unify!(self, self.registers[1], cstr); } _ => { self.fail = true; @@ -5506,28 +5243,40 @@ impl MachineState { } } else { let mut bytes = vec![]; - for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() { + for c in self.value_to_str_like(self.registers[1]).unwrap().as_str().chars() { + if c as u32 > 255 { + let stub = functor_stub(atom!("chars_base64"), 3); + + let err = self.type_error( + ValidType::Byte, + char_as_cell!(c), + ); + + return Err(self.error_form(err, stub)); + } + bytes.push(c as u8); } + let b64 = base64::encode_config(bytes, config); + let cstr = put_complete_string( + &mut self.heap, + &b64, + &mut self.atom_tbl, + ); - let cstr = self.heap.put_complete_string(&b64); - (self.unify_fn)(self, self[temp_v!(2)], cstr); + unify!(self, self.registers[2], cstr); } } &SystemClauseType::LoadLibraryAsStream => { - let library_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); + let library_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); - use crate::LIBRARIES; + use crate::machine::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 lib_stream = Stream::from_static_string(library, &mut self.arena); + unify!(self, stream_as_cell!(lib_stream), self.registers[2]); let mut path_buf = machine::current_dir(); @@ -5535,35 +5284,31 @@ impl MachineState { 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 = self.atom_tbl.build_with(library_path_str); - let library_path_ref = - Ref::HeapCell(self.heap.push(HeapCellValue::Atom(library_path, None))); - - self.bind(library_path_ref, self[temp_v!(3)]); + self.unify_atom(library_path, self.registers[3]); } None => { - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::ModuleSource(ModuleSource::Library(library_name)), - ), - MachineError::functor_stub(clause_name!("load"), 1), - )); + let stub = functor_stub(atom!("load"), 1); + let err = self.existence_error( + ExistenceError::ModuleSource(ModuleSource::Library(library_name)) + ); + + return Err(self.error_form(err, stub)); } } } &SystemClauseType::DevourWhitespace => { let stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "$devour_whitespace", + atom!("$devour_whitespace"), 1, )?; - match self.devour_whitespace(stream, self.atom_tbl.clone()) { - Ok(false) => {} // not at EOF. + match self.devour_whitespace(stream) { + Ok(false) => { // not at EOF. + } _ => { self.fail = true; return Ok(()); @@ -5572,25 +5317,13 @@ impl MachineState { } &SystemClauseType::IsSTOEnabled => { if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize { - let value = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("true"), None)); - - (self.unify_fn)(self, self[temp_v!(1)], value); + self.unify_atom(atom!("true"), self.registers[1]); } else if self.unify_fn as usize == MachineState::unify_with_occurs_check_with_error as usize { - let value = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("error"), None)); - - (self.unify_fn)(self, self[temp_v!(1)], value); + self.unify_atom(atom!("error"), self.registers[1]); } else { - let value = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("false"), None)); - - (self.unify_fn)(self, self[temp_v!(1)], value); + self.unify_atom(atom!("false"), self.registers[1]); } } &SystemClauseType::SetSTOAsUnify => { @@ -5616,9 +5349,13 @@ impl MachineState { if path.is_dir() { if let Some(path) = path.to_str() { - let path_string = self.heap.put_complete_string(path); + let path_string = put_complete_string( + &mut self.heap, + path, + &mut self.atom_tbl, + ); - self.unify(self[temp_v!(1)], path_string); + unify!(self, self.registers[1], path_string); return return_from_clause!(self.last_call, self); } } @@ -5629,66 +5366,51 @@ impl MachineState { self.fail = false; } &SystemClauseType::PopCount => { - let number = self.store(self.deref(self[temp_v!(1)])); - let count = match Number::try_from((number, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n.count_ones()), - Ok(Number::Integer(n)) => Integer::from((&*n).count_ones().unwrap()), + let number = self.store(self.deref(self.registers[1])); + let pop_count = integer_as_cell!(match Number::try_from(number) { + Ok(Number::Fixnum(n)) => { + Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64)) + } + Ok(Number::Integer(n)) => { + Number::arena_from(n.count_ones().unwrap(), &mut self.arena) + } _ => { unreachable!() } - }; + }); - let pop_count = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(count))); - (self.unify_fn)(self, self[temp_v!(2)], pop_count); + unify!(self, self.registers[2], pop_count); } }; return_from_clause!(self.last_call, self) } - pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Addr { + pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom { let datetime: DateTime = system_time.into(); let mut fstr = "[".to_string(); - let specifiers = vec![ + const SPECIFIERS: [&'static str; 19] = [ "Y", "m", "d", "H", "M", "S", "y", "b", "B", "a", "A", "w", "u", "U", "W", "j", "D", "x", "v", ]; - for spec in specifiers { + + for spec in SPECIFIERS { fstr.push_str(&format!("'{}'=\"%{}\", ", spec, spec).to_string()); } + fstr.push_str("finis]."); let s = datetime.format(&fstr).to_string(); - self.heap.put_complete_string(&s) - } - pub(super) fn atom_argument_to_string(&mut self, atom_arg: usize) -> String { - match self.store(self.deref(self[temp_v!(atom_arg)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.as_str().to_string() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - } + self.atom_tbl.build_with(&s) } - pub(super) fn string_encoding_bytes(&mut self, data_arg: usize, encoding: &str) -> Vec { - let data = self.heap_pstr_iter(self[temp_v!(data_arg)]).to_string(); + pub(super) fn string_encoding_bytes(&mut self, data_arg: HeapCellValue, encoding: Atom) -> Vec { + let data = self.value_to_str_like(data_arg).unwrap(); match encoding { - "utf8" => data.into_bytes(), - "octet" => { - let mut buf = vec![]; - for c in data.chars() { - buf.push(c as u8); - } - buf - } + atom!("utf8") => data.as_str().bytes().collect(), + atom!("octet") => data.as_str().chars().map(|c| c as u8).collect(), _ => { unreachable!() } @@ -5699,43 +5421,53 @@ impl MachineState { &mut self, indices: &mut IndexStore, node: roxmltree::Node, - ) -> Addr { + ) -> HeapCellValue { if node.is_text() { - let string = String::from(node.text().unwrap()); - self.heap.put_complete_string(&string) + put_complete_string( + &mut self.heap, + node.text().unwrap(), + &mut self.atom_tbl, + ) } else { let mut avec = Vec::new(); - for attr in node.attributes() { - let chars = clause_name!(String::from(attr.name()), self.atom_tbl); - let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); - let value = self.heap.put_complete_string(&attr.value()); + for attr in node.attributes() { + let name = self.atom_tbl.build_with(attr.name()); + let value = put_complete_string( + &mut self.heap, + &attr.value(), + &mut self.atom_tbl, + ); - avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h()))); + avec.push(heap_loc_as_cell!(self.heap.len())); - self.heap - .push(HeapCellValue::NamedStr(2, clause_name!("="), None)); - self.heap.push(HeapCellValue::Addr(name)); - self.heap.push(HeapCellValue::Addr(value)); + self.heap.push(atom_as_cell!(atom!("="), 2)); + self.heap.push(atom_as_cell!(name)); + self.heap.push(value); } - let attrs = Addr::HeapCell(self.heap.to_list(avec.into_iter())); + + let attrs = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, avec.into_iter()) + ); let mut cvec = Vec::new(); + for child in node.children() { cvec.push(self.xml_node_to_term(indices, child)); } - let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); - let chars = clause_name!(String::from(node.tag_name().name()), self.atom_tbl); - let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); + let children = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, cvec.into_iter()) + ); + + let tag = self.atom_tbl.build_with(node.tag_name().name()); - let result = Addr::HeapCell(self.heap.h()); + let result = heap_loc_as_cell!(self.heap.len()); - self.heap - .push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); - self.heap.push(HeapCellValue::Addr(tag)); - self.heap.push(HeapCellValue::Addr(attrs)); - self.heap.push(HeapCellValue::Addr(children)); + self.heap.push(atom_as_cell!(atom!("element"), 3)); + self.heap.push(atom_as_cell!(tag)); + self.heap.push(attrs); + self.heap.push(children); result } @@ -5745,45 +5477,54 @@ impl MachineState { &mut self, indices: &mut IndexStore, node: select::node::Node, - ) -> Addr { + ) -> HeapCellValue { match node.name() { None => { - let string = String::from(node.text()); - self.heap.put_complete_string(&string) + put_complete_string( + &mut self.heap, + &node.text(), + &mut self.atom_tbl, + ) } Some(name) => { let mut avec = Vec::new(); - for attr in node.attrs() { - let chars = clause_name!(String::from(attr.0), self.atom_tbl); - let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); - let value = self.heap.put_complete_string(&String::from(attr.1)); + for attr in node.attrs() { + let name = self.atom_tbl.build_with(attr.0); + let value = put_complete_string( + &mut self.heap, + &attr.1, + &mut self.atom_tbl, + ); - avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h()))); + avec.push(heap_loc_as_cell!(self.heap.len())); - self.heap - .push(HeapCellValue::NamedStr(2, clause_name!("="), None)); - self.heap.push(HeapCellValue::Addr(name)); - self.heap.push(HeapCellValue::Addr(value)); + self.heap.push(atom_as_cell!(atom!("="), 2)); + self.heap.push(atom_as_cell!(name)); + self.heap.push(value); } - let attrs = Addr::HeapCell(self.heap.to_list(avec.into_iter())); + + let attrs = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, avec.into_iter()) + ); let mut cvec = Vec::new(); + for child in node.children() { cvec.push(self.html_node_to_term(indices, child)); } - let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); - let chars = clause_name!(String::from(name), self.atom_tbl); - let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); + let children = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, cvec.into_iter()) + ); - let result = Addr::HeapCell(self.heap.h()); + let tag = self.atom_tbl.build_with(name); + let result = heap_loc_as_cell!(self.heap.len()); - self.heap - .push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); - self.heap.push(HeapCellValue::Addr(tag)); - self.heap.push(HeapCellValue::Addr(attrs)); - self.heap.push(HeapCellValue::Addr(children)); + self.heap.push(atom_as_cell!(atom!("element"), 3)); + self.heap.push(atom_as_cell!(tag)); + self.heap.push(attrs); + self.heap.push(children); result } @@ -5808,3 +5549,4 @@ impl hkdf::KeyType for MyKey { self.0 } } + diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index e55a54996..a1d382710 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -1,48 +1,53 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::*; - -use crate::machine::machine_errors::CompilationError; +use crate::forms::*; use crate::machine::*; +use crate::machine::load_state::*; +use crate::machine::loader::*; +use crate::machine::machine_errors::*; +use crate::parser::ast::*; +use crate::parser::parser::*; + +use crate::predicate_queue; use indexmap::IndexSet; use std::collections::VecDeque; use std::fmt; -pub(crate) trait TermStream: Sized { - type Evacuable; +pub struct LoadStatePayload { + pub term_stream: TS, + pub(super) compilation_target: CompilationTarget, + pub(super) retraction_info: RetractionInfo, + pub(super) module_op_exports: ModuleOpExports, + pub(super) non_counted_bt_preds: IndexSet, + pub(super) predicates: PredicateQueue, + pub(super) clause_clauses: Vec<(Term, Term)>, +} +pub trait TermStream: Sized { 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> { +pub struct BootstrappingTermStream<'a> { listing_src: ListingSource, - parser: Parser<'a, Stream>, + pub(super) parser: Parser<'a, Stream>, } impl<'a> BootstrappingTermStream<'a> { #[inline] - pub(super) fn from_prolog_stream( - stream: &'a mut PrologStream, - atom_tbl: TabledData, - flags: MachineFlags, + pub(super) fn from_char_reader( + stream: Stream, + machine_st: &'a mut MachineState, listing_src: ListingSource, ) -> Self { - let parser = Parser::new(stream, atom_tbl, flags); - Self { - parser, - listing_src, - } + let parser = Parser::new(stream, machine_st); + Self { parser, listing_src } } } impl<'a> TermStream for BootstrappingTermStream<'a> { - type Evacuable = CompilationTarget; - #[inline] fn next(&mut self, op_dir: &CompositeOpDir) -> Result { self.parser.reset(); @@ -61,24 +66,9 @@ impl<'a> TermStream for BootstrappingTermStream<'a> { fn listing_src(&self) -> &ListingSource { &self.listing_src } - - fn evacuate(mut loader: Loader) -> 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(crate) struct LiveTermStream { +pub struct LiveTermStream { pub(super) term_queue: VecDeque, pub(super) listing_src: ListingSource, } @@ -93,28 +83,18 @@ impl LiveTermStream { } } -pub(crate) struct LoadStatePayload { - pub(super) term_stream: LiveTermStream, - pub(super) compilation_target: CompilationTarget, - pub(super) retraction_info: RetractionInfo, - pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>, - pub(super) non_counted_bt_preds: IndexSet, - pub(super) predicates: PredicateQueue, - pub(super) clause_clauses: Vec<(Term, Term)>, -} - -impl fmt::Debug for LoadStatePayload { +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 { +impl LoadStatePayload { + pub(super) fn new(code_repo_len: usize, term_stream: TS) -> Self { Self { - term_stream: LiveTermStream::new(ListingSource::User), + term_stream, compilation_target: CompilationTarget::default(), - retraction_info: RetractionInfo::new(wam.code_repo.code.len()), + retraction_info: RetractionInfo::new(code_repo_len), module_op_exports: vec![], non_counted_bt_preds: IndexSet::new(), predicates: predicate_queue![], @@ -124,8 +104,6 @@ impl LoadStatePayload { } impl TermStream for LiveTermStream { - type Evacuable = LoadStatePayload; - #[inline] fn next(&mut self, _: &CompositeOpDir) -> Result { Ok(self.term_queue.pop_front().unwrap()) @@ -140,9 +118,4 @@ impl TermStream for LiveTermStream { fn listing_src(&self) -> &ListingSource { &self.listing_src } - - #[inline] - fn evacuate(loader: Loader) -> Result { - Ok(loader.to_load_state_payload()) - } } diff --git a/src/macros.rs b/src/macros.rs index b8b6d802a..1b4599281 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,53 +13,421 @@ macro_rules! count_tt { ($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 }; } -macro_rules! functor { - ($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ - { - #[allow(unused_variables, unused_mut)] - let mut addendum = Heap::new(); - let arity = count_tt!($($dt) +); - let aux_lens = [$($aux.len()),*]; +macro_rules! char_as_cell { + ($c: expr) => { + HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64) + }; +} - let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)), - $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; +macro_rules! fixnum_as_cell { + ($n: expr) => { + HeapCellValue::from_bytes($n.into_bytes()) //HeapCellValueTag::Fixnum, $n.get_num() as u64) + }; +} - $( - result.extend($aux.into_iter()); - )* +macro_rules! cell_as_fixnum { + ($cell:expr) => { + Fixnum::from_bytes($cell.into_bytes()) + }; +} - result.extend(addendum.into_iter()); - result +macro_rules! integer_as_cell { + ($n: expr) => {{ + match $n { + Number::Float(_) => unreachable!(), + Number::Fixnum(n) => fixnum_as_cell!(n), + Number::Rational(r) => typed_arena_ptr_as_cell!(r), + Number::Integer(n) => typed_arena_ptr_as_cell!(n), } + }}; +} + +macro_rules! empty_list_as_cell { + () => { + // the empty list atom has the fixed index of 8 (8 >> 3 == 1 in the condensed atom representation). + atom_as_cell!(atom!("[]")) + }; +} + +macro_rules! atom_as_cell { + ($atom:expr) => { + HeapCellValue::from_bytes( + AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(), + ) + }; + ($atom:expr, $arity:expr) => { + HeapCellValue::from_bytes( + AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom) + .into_bytes(), + ) + }; +} + +macro_rules! cell_as_ossified_op_dir { + ($cell:expr) => {{ + let ptr_u64 = cell_as_untyped_arena_ptr!($cell); + TypedArenaPtr::new(ptr_u64.payload_offset() as *mut OssifiedOpDir) + }}; +} + +macro_rules! cell_as_string { + ($cell:expr) => { + PartialString::from(cell_as_atom!($cell)) + }; +} + +macro_rules! cell_as_atom { + ($cell:expr) => {{ + let cell = AtomCell::from_bytes($cell.into_bytes()); + let name = cell.get_index() << 3; + + Atom::from(name as usize) + }}; +} + +macro_rules! cell_as_atom_cell { + ($cell:expr) => { + AtomCell::from_bytes($cell.into_bytes()) + }; +} + +macro_rules! cell_as_f64_ptr { + ($cell:expr) => {{ + let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes()); + F64Ptr(TypedArenaPtr::new( + ptr_u64.as_ptr() as *mut OrderedFloat + )) + }}; +} + +macro_rules! cell_as_untyped_arena_ptr { + ($cell:expr) => { + UntypedArenaPtr::from(u64::from($cell) as *const ArenaHeader) + }; +} + +macro_rules! pstr_as_cell { + ($atom:expr) => { + HeapCellValue::from_bytes( + AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::PStr).into_bytes(), + ) + }; +} + +macro_rules! pstr_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64) + }; +} + +macro_rules! pstr_offset_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::PStrOffset, $h as u64) + }; +} + +macro_rules! list_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64) + }; +} + +macro_rules! str_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::Str, $h as u64) + }; +} + +macro_rules! stack_loc { + (OrFrame, $b:expr, $idx:expr) => ({ + $b + prelude_size::() + $idx * std::mem::size_of::() }); - ($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({ - { - #[allow(unused_variables, unused_mut)] - let mut addendum = Heap::new(); - let arity = count_tt!($($dt) +); + (AndFrame, $e:expr, $idx:expr) => ({ + $e + prelude_size::() + ($idx - 1) * std::mem::size_of::() + }); +} - let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)), - $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]; +macro_rules! stack_loc_as_cell { + (OrFrame, $b:expr, $idx:expr) => { + stack_loc_as_cell!(stack_loc!(OrFrame, $b, $idx)) + }; + (AndFrame, $b:expr, $idx:expr) => { + stack_loc_as_cell!(stack_loc!(AndFrame, $b, $idx)) + }; + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::StackVar, $h as u64) + }; +} - result.extend(addendum.into_iter()); - result +#[macro_export] +macro_rules! heap_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::Var, $h as u64) + }; +} + +macro_rules! attr_var_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64) + }; +} + +#[allow(unused)] +macro_rules! attr_var_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64) + }; +} + +macro_rules! typed_arena_ptr_as_cell { + ($ptr:expr) => { + untyped_arena_ptr_as_cell!($ptr.header_ptr()) + }; +} + +macro_rules! untyped_arena_ptr_as_cell { + ($ptr:expr) => { + HeapCellValue::from_bytes(unsafe { std::mem::transmute($ptr) }) + }; +} + +macro_rules! atom_as_cstr_cell { + ($atom:expr) => {{ + let offset = $atom.flat_index(); + + HeapCellValue::from_bytes( + AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(), + ) + }}; +} + +macro_rules! string_as_cstr_cell { + ($ptr:expr) => {{ + let atom: Atom = $ptr.into(); + let offset = atom.flat_index(); + + HeapCellValue::from_bytes( + AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(), + ) + }}; +} + +macro_rules! string_as_pstr_cell { + ($ptr:expr) => {{ + let atom: Atom = $ptr.into(); + let offset = atom.flat_index(); + + HeapCellValue::from_bytes( + AtomCell::build_with(offset as u64, 0, HeapCellValueTag::PStr).into_bytes(), + ) + }}; +} + +macro_rules! stream_as_cell { + ($ptr:expr) => { + untyped_arena_ptr_as_cell!($ptr.as_ptr()) + }; +} + +macro_rules! cell_as_stream { + ($cell:expr) => {{ + let ptr = cell_as_untyped_arena_ptr!($cell); + Stream::from_tag(ptr.get_tag(), ptr.payload_offset()) + }}; +} + +macro_rules! cell_as_load_state_payload { + ($cell:expr) => { unsafe { + let ptr = cell_as_untyped_arena_ptr!($cell); + let ptr = std::mem::transmute::<_, *mut LiveLoadState>(ptr.payload_offset()); + + TypedArenaPtr::new(ptr) + }}; +} + +macro_rules! match_untyped_arena_ptr_pat_body { + ($ptr:ident, Integer, $n:ident, $code:expr) => {{ + let payload_ptr = unsafe { std::mem::transmute::<_, *mut Integer>($ptr.payload_offset()) }; + let $n = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, F64, $n:ident, $code:expr) => {{ + let payload_ptr = + unsafe { std::mem::transmute::<_, *mut OrderedFloat>($ptr.payload_offset()) }; + let $n = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, Rational, $n:ident, $code:expr) => {{ + let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) }; + let $n = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($cell:ident, OssifiedOpDir, $n:ident, $code:expr) => {{ + let $n = cell_as_ossified_op_dir!($cell); + #[allow(unused_braces)] + $code + }}; + ($cell:ident, LiveLoadState, $n:ident, $code:expr) => {{ + let $n = cell_as_load_state_payload!($cell); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, Stream, $s:ident, $code:expr) => {{ + let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset()); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, TcpListener, $listener:ident, $code:expr) => {{ + let payload_ptr = unsafe { std::mem::transmute::<_, *mut TcpListener>($ptr.payload_offset()) }; + #[allow(unused_mut)] + let mut $listener = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{ + let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset()); + #[allow(unused_braces)] + $code + }}; +} + +macro_rules! match_untyped_arena_ptr_pat { + (Stream) => { + ArenaHeaderTag::InputFileStream + | ArenaHeaderTag::OutputFileStream + | ArenaHeaderTag::NamedTcpStream + | ArenaHeaderTag::NamedTlsStream + | ArenaHeaderTag::ReadlineStream + | ArenaHeaderTag::StaticStringStream + | ArenaHeaderTag::ByteStream + | ArenaHeaderTag::NullStream + | ArenaHeaderTag::StandardOutputStream + | ArenaHeaderTag::StandardErrorStream + }; + ($tag:ident) => { + ArenaHeaderTag::$tag + }; +} + +macro_rules! match_untyped_arena_ptr { + ($ptr:expr, $( ($(ArenaHeaderTag::$tag:tt)|+, $n:ident) => $code:block $(,)?)+ $(_ => $misc_code:expr $(,)?)?) => ({ + let ptr_id = $ptr; + + match ptr_id.get_tag() { + $($(match_untyped_arena_ptr_pat!($tag) => { + match_untyped_arena_ptr_pat_body!(ptr_id, $tag, $n, $code) + })+)+ + $(_ => $misc_code)? + } + }); +} + +macro_rules! read_heap_cell_pat_body { + ($cell:ident, Cons, $n:ident, $code:expr) => ({ + let $n = cell_as_untyped_arena_ptr!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, F64, $n:ident, $code:expr) => ({ + let $n = cell_as_f64_ptr!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => ({ + let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity(); + #[allow(unused_braces)] + $code + }); + ($cell:ident, PStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, CStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, CStr | PStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, PStr | CStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, Fixnum, $value:ident, $code:expr) => ({ + let $value = Fixnum::from_bytes($cell.into_bytes()); + #[allow(unused_braces)] + $code + }); + ($cell:ident, Char, $value:ident, $code:expr) => ({ + let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) }; + #[allow(unused_braces)] + $code + }); + ($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => ({ + let $value = $cell.get_value() as usize; + #[allow(unused_braces)] + $code + }); +} + +macro_rules! read_heap_cell_pat { + (($(HeapCellValueTag::$tag:tt)|+, $n:tt)) => { + $(HeapCellValueTag::$tag)|+ + }; + (($(HeapCellValueTag::$tag:tt)|+)) => { + $(HeapCellValueTag::$tag)|+ + }; + (_) => { _ }; +} + +macro_rules! read_heap_cell_pat_expander { + ($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+, $n:tt), $code:block) => ({ + read_heap_cell_pat_body!($cell_id, $($tag)|+, $n, $code) + }); + ($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+), $code:block) => ({ + $code + }); + ($cell_id:ident, _, $code:block) => ({ + $code + }); +} + +macro_rules! read_heap_cell { + ($cell:expr, $($pat:tt $(if $guard_expr:expr)? => $code:block $(,)?)+) => ({ + let cell_id = $cell; + + match cell_id.get_tag() { + $(read_heap_cell_pat!($pat) $(if $guard_expr)? => { + read_heap_cell_pat_expander!(cell_id, $pat, $code) + })+ } }); +} + +macro_rules! functor { ($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ { #[allow(unused_variables, unused_mut)] let mut addendum = Heap::new(); - let arity = count_tt!($($dt) +); - let aux_lens = [$($aux.len()),*]; + let arity: usize = count_tt!($($dt) +); + + #[allow(unused_variables)] + let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*]; let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), + vec![ atom_as_cell!($name, arity as u16), $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; $( - result.extend($aux.into_iter()); + result.extend($aux.iter()); )* result.extend(addendum.into_iter()); @@ -68,143 +436,126 @@ macro_rules! functor { }); ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ { - use crate::machine::heap::*; + let arity: usize = count_tt!($($dt) +); - let arity = count_tt!($($dt) +); #[allow(unused_variables, unused_mut)] let mut addendum = Heap::new(); let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), + vec![ atom_as_cell!($name, arity as u16), $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]; result.extend(addendum.into_iter()); result } }); - ($name:expr, $fixity:expr) => ( - vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ] - ); - (clause_name($name:expr)) => ( - vec![ HeapCellValue::Atom($name, None) ] - ); - ($name:expr) => ( - vec![ HeapCellValue::Atom(clause_name!($name), None) ] - ); + ($name:expr) => ({ + vec![ atom_as_cell!($name) ] + }); } macro_rules! functor_term { - (aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - HeapCellValue::Addr(Addr::HeapCell($arity + 1)) + (str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + str_loc_as_cell!($arity + 1) }); - (aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + (str($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ let len: usize = $aux_lens[0 .. $e].iter().sum(); - HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len)) + str_loc_as_cell!($arity + 1 + len) }); - (aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1)) + (str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + str_loc_as_cell!($arity + $h + 1) }); - (aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + (str($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ let len: usize = $aux_lens[0 .. $e].iter().sum(); - HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len)) + str_loc_as_cell!($arity + $h + 1 + len) }); - (addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Addr($e) + (literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + HeapCellValue::from($e) ); - (constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - from_constant!($e, $h, $arity, $aux_lens, $addendum) + (integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena) ); - (constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - from_constant!($e, 0, $arity, $aux_lens, $addendum) - ); - (number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - $e.into() - ); - (integer($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Integer(Rc::new(Integer::from($e))) + (fixnum($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + fixnum_as_cell!(Fixnum::build_with($e as i64)) ); (indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ let stub = match $e { - IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]), - IndexingCodePtr::External(o) => functor!("external", [integer(o)]), - IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]), - IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)], + IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]), + IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), + IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), + IndexingCodePtr::Fail => { + vec![atom_as_cell!(atom!("fail"))] + }, }; let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.h() + $h; + let h = len + $arity + 1 + $addendum.len() + $h; $addendum.extend(stub.into_iter()); - HeapCellValue::Addr(Addr::HeapCell(h)) + str_loc_as_cell!(h) }); - (clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Atom($e, None) + (number($arena:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + HeapCellValue::from(($e, $arena)) ); (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Atom(clause_name!($e), None) - ); - (value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( - $e + atom_as_cell!($e) ); (string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.h() + $h; + let h = len + $arity + 1 + $addendum.len() + $h; - $addendum.put_complete_string(&$e); + let cell = string_as_pstr_cell!($e); - HeapCellValue::Addr(Addr::PStrLocation(h, 0)) + $addendum.push(cell); + $addendum.push(empty_list_as_cell!()); + + heap_loc_as_cell!(h) }); (boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ if $e { - functor_term!(atom("true"), $arity, $aux_lens, $addendum) + functor_term!(atom(atom!("true")), $arity, $aux_lens, $addendum) } else { - functor_term!(atom("false"), $arity, $aux_lens, $addendum) + functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum) } }); - ($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ( + (cell($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( $e ); } -macro_rules! from_constant { - ($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - match $e { - &Constant::Atom(ref name, ref op) => { - HeapCellValue::Atom(name.clone(), op.clone()) - } - &Constant::Char(c) => { - HeapCellValue::Addr(Addr::Char(c)) - } - &Constant::Fixnum(n) => { - HeapCellValue::Addr(Addr::Fixnum(n)) - } - &Constant::Integer(ref n) => { - HeapCellValue::Integer(n.clone()) - } - &Constant::Rational(ref r) => { - HeapCellValue::Rational(r.clone()) - } - &Constant::Float(f) => { - HeapCellValue::Addr(Addr::Float(f)) - } - &Constant::String(ref s) => { - let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.h() + $over_h; +macro_rules! ar_reg { + ($r: expr) => { + ArithmeticTerm::Reg($r) + }; +} - $addendum.put_complete_string(&s); +macro_rules! unmark_cell_bits { + ($e:expr) => {{ + let mut result = $e; - HeapCellValue::Addr(Addr::PStrLocation(h, 0)) - } - &Constant::Usize(u) => { - HeapCellValue::Addr(Addr::Usize(u)) - } - &Constant::EmptyList => { - HeapCellValue::Addr(Addr::EmptyList) - } + result.set_mark_bit(false); + result.set_forwarding_bit(false); + + result + }}; +} + +macro_rules! index_store { + ($code_dir:expr, $op_dir:expr, $modules:expr) => { + IndexStore { + code_dir: $code_dir, + extensible_predicates: ExtensiblePredicates::new(), + local_extensible_predicates: LocalExtensiblePredicates::new(), + global_variables: GlobalVarDir::new(), + meta_predicates: MetaPredicateDir::new(), + modules: $modules, + op_dir: $op_dir, + streams: StreamDir::new(), + stream_aliases: StreamAliasDir::new(), } - }) + }; } macro_rules! is_atom { @@ -358,22 +709,6 @@ macro_rules! dir_entry { }; } -macro_rules! index_store { - ($code_dir:expr, $op_dir:expr, $modules:expr) => { - IndexStore { - code_dir: $code_dir, - extensible_predicates: ExtensiblePredicates::new(), - local_extensible_predicates: LocalExtensiblePredicates::new(), - global_variables: GlobalVarDir::new(), - meta_predicates: MetaPredicateDir::new(), - modules: $modules, - op_dir: $op_dir, - streams: StreamDir::new(), - stream_aliases: StreamAliasDir::new(), - } - }; -} - macro_rules! put_constant { ($lvl:expr, $cons:expr, $r:expr) => { QueryInstruction::PutConstant($lvl, $cons, $r) @@ -408,43 +743,58 @@ macro_rules! discard_result { }; } */ -macro_rules! ar_reg { - ($r: expr) => { - ArithmeticTerm::Reg($r) - }; -} -macro_rules! atom_from { - ($self:expr, $e:expr) => { +macro_rules! try_or_fail { + ($s:expr, $e:expr) => {{ match $e { - Addr::Con(h) if $self.heap.atom_at(h) => { - match &$self.heap[h] { - HeapCellValue::Atom(ref atom, _) => { - atom.clone() - } - _ => { - unreachable!() - } - } - } - Addr::Char(c) => { - clause_name!(c.to_string(), $self.atom_tbl) - } - _ => { - unreachable!() + Ok(val) => val, + Err(msg) => { + $s.throw_exception(msg); + return; } } - } + }}; } -macro_rules! try_or_fail { +macro_rules! try_or_fail_gen { ($s:expr, $e:expr) => {{ match $e { Ok(val) => val, - Err(msg) => { - $s.throw_exception(msg); + Err(msg_fn) => { + let e = msg_fn($s); + $s.throw_exception(e); return; } } }}; } + +macro_rules! unify { + ($machine_st:expr, $($value:expr),*) => {{ + $($machine_st.pdl.push($value);)* + $machine_st.unify() + }}; +} + +macro_rules! unify_fn { + ($machine_st:expr, $($value:expr),*) => {{ + $($machine_st.pdl.push($value);)* + ($machine_st.unify_fn)($machine_st) + }}; +} + +macro_rules! unify_with_occurs_check { + ($machine_st:expr, $($value:expr),*) => {{ + $($machine_st.pdl.push($value);)* + $machine_st.unify_with_occurs_check() + }}; +} + +macro_rules! compare_term_test { + ($machine_st:expr, $e1:expr, $e2:expr) => {{ + $machine_st.pdl.push($e2); + $machine_st.pdl.push($e1); + + $machine_st.compare_term_test() + }}; +} diff --git a/src/parser/ast.rs b/src/parser/ast.rs new file mode 100644 index 000000000..1bbde9c29 --- /dev/null +++ b/src/parser/ast.rs @@ -0,0 +1,631 @@ +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::char_reader::*; +use crate::types::HeapCellValueTag; + +use std::cell::Cell; +use std::fmt; +use std::hash::Hash; +use std::io::{Error as IOError}; +use std::ops::Neg; +use std::rc::Rc; +use std::vec::Vec; + +use rug::{Integer, Rational}; + +use indexmap::IndexMap; +use modular_bitfield::error::OutOfBounds; +use modular_bitfield::prelude::*; + +pub type Specifier = u32; + +pub const MAX_ARITY: usize = 1023; + +pub const XFX: u32 = 0x0001; +pub const XFY: u32 = 0x0002; +pub const YFX: u32 = 0x0004; +pub const XF: u32 = 0x0010; +pub const YF: u32 = 0x0020; +pub const FX: u32 = 0x0040; +pub const FY: u32 = 0x0080; +pub const DELIMITER: u32 = 0x0100; +pub const TERM: u32 = 0x1000; +pub const LTERM: u32 = 0x3000; + +pub const NEGATIVE_SIGN: u32 = 0x0200; + +#[macro_export] +macro_rules! fixnum { + ($wrapper:tt, $n:expr, $arena:expr) => { + Fixnum::build_with_checked($n) + .map(<$wrapper>::Fixnum) + .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena))) + }; +} + +macro_rules! is_term { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::TERM) != 0 + }; +} + +macro_rules! is_lterm { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::LTERM) != 0 + }; +} + +macro_rules! is_op { + ($x:expr) => { + $x as u32 + & ($crate::parser::ast::XF + | $crate::parser::ast::YF + | $crate::parser::ast::FX + | $crate::parser::ast::FY + | $crate::parser::ast::XFX + | $crate::parser::ast::XFY + | $crate::parser::ast::YFX) + != 0 + }; +} + +macro_rules! is_negate { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::NEGATIVE_SIGN) != 0 + }; +} + +#[macro_export] +macro_rules! is_prefix { + ($x:expr) => { + $x as u32 & ($crate::parser::ast::FX | $crate::parser::ast::FY) != 0 + }; +} + +#[macro_export] +macro_rules! is_postfix { + ($x:expr) => { + $x as u32 & ($crate::parser::ast::XF | $crate::parser::ast::YF) != 0 + }; +} + +#[macro_export] +macro_rules! is_infix { + ($x:expr) => { + ($x as u32 + & ($crate::parser::ast::XFX | $crate::parser::ast::XFY | $crate::parser::ast::YFX)) + != 0 + }; +} + +#[macro_export] +macro_rules! is_xfx { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::XFX) != 0 + }; +} + +#[macro_export] +macro_rules! is_xfy { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::XFY) != 0 + }; +} + +#[macro_export] +macro_rules! is_yfx { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::YFX) != 0 + }; +} + +#[macro_export] +macro_rules! is_yf { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::YF) != 0 + }; +} + +#[macro_export] +macro_rules! is_xf { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::XF) != 0 + }; +} + +#[macro_export] +macro_rules! is_fx { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::FX) != 0 + }; +} + +#[macro_export] +macro_rules! is_fy { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::FY) != 0 + }; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum RegType { + Perm(usize), + Temp(usize), +} + +impl Default for RegType { + fn default() -> Self { + RegType::Temp(0) + } +} + +impl RegType { + pub fn reg_num(self) -> usize { + match self { + RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num, + } + } + + pub fn is_perm(self) -> bool { + matches!(self, RegType::Perm(_)) + } +} + +impl fmt::Display for RegType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RegType::Perm(val) => write!(f, "Y{}", val), + RegType::Temp(val) => write!(f, "X{}", val), + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum VarReg { + ArgAndNorm(RegType, usize), + Norm(RegType), +} + +impl VarReg { + pub fn norm(self) -> RegType { + match self { + VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, + } + } +} + +impl fmt::Display for VarReg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), + VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), + VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), + VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), + } + } +} + +impl Default for VarReg { + fn default() -> Self { + VarReg::Norm(RegType::default()) + } +} + +#[macro_export] +macro_rules! temp_v { + ($x:expr) => { + $crate::parser::ast::RegType::Temp($x) + }; +} + +#[macro_export] +macro_rules! perm_v { + ($x:expr) => { + $crate::parser::ast::RegType::Perm($x) + }; +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum GenContext { + Head, + Mid(usize), + Last(usize), // Mid & Last: chunk_num +} + +impl GenContext { + pub fn chunk_num(self) -> usize { + match self { + GenContext::Head => 0, + GenContext::Mid(cn) | GenContext::Last(cn) => cn, + } + } +} + +#[bitfield] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct OpDesc { + prec: B11, + spec: B8, + #[allow(unused)] padding: B13, +} + +impl OpDesc { + #[inline] + pub fn build_with(prec: u16, spec: u8) -> Self { + OpDesc::new().with_spec(spec).with_prec(prec) + } + + #[inline] + pub fn get(self) -> (u16, u8) { + (self.prec(), self.spec()) + } + + pub fn set(&mut self, prec: u16, spec: u8) { + self.set_prec(prec); + self.set_spec(spec); + } + + #[inline] + pub fn get_prec(self) -> u16 { + self.prec() + } + + #[inline] + pub fn get_spec(self) -> u8 { + self.spec() + } + + #[inline] + pub fn arity(self) -> usize { + if self.spec() as u32 & (XFX | XFY | YFX) == 0 { + 1 + } else { + 2 + } + } +} + +// name and fixity -> operator type and precedence. +pub type OpDir = IndexMap<(Atom, Fixity), OpDesc>; + +#[derive(Debug, Clone, Copy)] +pub struct MachineFlags { + pub double_quotes: DoubleQuotes, +} + +impl Default for MachineFlags { + fn default() -> Self { + MachineFlags { + double_quotes: DoubleQuotes::default(), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum DoubleQuotes { + Atom, + Chars, + Codes, +} + +impl DoubleQuotes { + pub fn is_chars(self) -> bool { + matches!(self, DoubleQuotes::Chars) + } + + pub fn is_atom(self) -> bool { + matches!(self, DoubleQuotes::Atom) + } + + pub fn is_codes(self) -> bool { + matches!(self, DoubleQuotes::Codes) + } +} + +impl Default for DoubleQuotes { + fn default() -> Self { + DoubleQuotes::Chars + } +} + +pub fn default_op_dir() -> OpDir { + let mut op_dir = OpDir::new(); + + op_dir.insert( + (atom!(":-"), Fixity::In), + OpDesc::build_with(1200, XFX as u8), + ); + op_dir.insert( + (atom!(":-"), Fixity::Pre), + OpDesc::build_with(1200, FX as u8), + ); + op_dir.insert( + (atom!("?-"), Fixity::Pre), + OpDesc::build_with(1200, FX as u8), + ); + op_dir.insert( + (atom!(","), Fixity::In), + OpDesc::build_with(1000, XFY as u8), + ); + + op_dir +} + +#[derive(Debug, Clone)] +pub enum ArithmeticError { + NonEvaluableFunctor(Literal, usize), + UninstantiatedVar, +} + +#[derive(Debug)] +pub enum ParserError { + BackQuotedString(usize, usize), + UnexpectedChar(char, usize, usize), + UnexpectedEOF, + IO(IOError), + IncompleteReduction(usize, usize), + InvalidSingleQuotedCharacter(char), + MissingQuote(usize, usize), + NonPrologChar(usize, usize), + ParseBigInt(usize, usize), + LexicalError(lexical::Error), + Utf8Error(usize, usize), +} + +impl ParserError { + pub fn line_and_col_num(&self) -> Option<(usize, usize)> { + match self { + &ParserError::BackQuotedString(line_num, col_num) + | &ParserError::UnexpectedChar(_, line_num, col_num) + | &ParserError::IncompleteReduction(line_num, col_num) + | &ParserError::MissingQuote(line_num, col_num) + | &ParserError::NonPrologChar(line_num, col_num) + | &ParserError::ParseBigInt(line_num, col_num) + | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), + _ => None, + } + } + + pub fn as_atom(&self) -> Atom { + match self { + ParserError::BackQuotedString(..) => atom!("back_quoted_string"), + ParserError::UnexpectedChar(..) => atom!("unexpected_char"), + ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"), + ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"), + ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"), + ParserError::IO(_) => atom!("input_output_error"), + ParserError::LexicalError(_) => atom!("lexical_error"), // TODO: ? + ParserError::MissingQuote(..) => atom!("missing_quote"), + ParserError::NonPrologChar(..) => atom!("non_prolog_character"), + ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), + ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), + } + } +} + +impl From for ParserError { + fn from(e: lexical::Error) -> ParserError { + ParserError::LexicalError(e) + } +} + +impl From for ParserError { + fn from(e: IOError) -> ParserError { + ParserError::IO(e) + } +} + +impl From<&IOError> for ParserError { + fn from(error: &IOError) -> ParserError { + if error.get_ref().filter(|e| e.is::()).is_some() { + ParserError::Utf8Error(0, 0) + } else { + ParserError::IO(error.kind().into()) + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct CompositeOpDir<'a, 'b> { + pub primary_op_dir: Option<&'b OpDir>, + pub secondary_op_dir: &'a OpDir, +} + +impl<'a, 'b> CompositeOpDir<'a, 'b> { + #[inline] + pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self { + CompositeOpDir { + primary_op_dir, + secondary_op_dir, + } + } + + #[inline] + pub(crate) fn get(&self, name: Atom, fixity: Fixity) -> Option { + let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir { + primary_op_dir.get(&(name, fixity)) + } else { + None + }; + + entry + .or_else(move || self.secondary_op_dir.get(&(name, fixity))) + .cloned() + } +} + +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub enum Fixity { + In, + Post, + Pre, +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Fixnum { + num: B57, + #[allow(unused)] m: bool, + #[allow(unused)] tag: B6, +} + +impl Fixnum { + #[inline] + pub fn build_with(num: i64) -> Self { + Fixnum::new() + .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1)) + .with_tag(HeapCellValueTag::Fixnum as u8) + .with_m(false) + //num as u64).with__m(false) + } + + #[inline] + pub fn build_with_checked(num: i64) -> Result { + const UPPER_BOUND: i64 = (1 << 56) - 1; + const LOWER_BOUND: i64 = -(1 << 56); + + if LOWER_BOUND <= num && num <= UPPER_BOUND { + Ok(Fixnum::new() + .with_m(false) + .with_tag(HeapCellValueTag::Fixnum as u8) + .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1))) + } else { + Err(OutOfBounds {}) + } + } + + #[inline] + pub fn get_num(self) -> i64 { + let n = self.num() as i64; + let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum. + debug_assert_eq!(overflowed, false); + n + } +} + +impl Neg for Fixnum { + type Output = Self; + + #[inline] + fn neg(self) -> Self::Output { + Fixnum::build_with(-self.get_num()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Literal { + Atom(Atom), + Char(char), + Fixnum(Fixnum), + Integer(TypedArenaPtr), + Rational(TypedArenaPtr), + Float(F64Ptr), + String(Atom), +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Atom(ref atom) => { + // if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) { + // write!(f, "'{}'", atom) + // } else { + write!(f, "{}", atom.flat_index()) + // } + } + Literal::Char(c) => write!(f, "'{}'", *c as u32), + Literal::Fixnum(n) => write!(f, "{}", n.get_num()), + Literal::Integer(ref n) => write!(f, "{}", n), + Literal::Rational(ref n) => write!(f, "{}", n), + Literal::Float(ref n) => write!(f, "{}", *n), + Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()), + // Literal::Usize(integer) => write!(f, "u{}", integer), + } + } +} + +impl Literal { + pub fn to_atom(&self, atom_tbl: &mut AtomTable) -> Option { + match self { + Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)), + _ => None, + } + } +} + +#[derive(Debug, Clone)] +pub enum Term { + AnonVar, + Clause(Cell, Atom, Vec), + Cons(Cell, Box, Box), + Literal(Cell, Literal), + PartialString(Cell, Atom, Option>), + Var(Cell, Rc), +} + +impl Term { + pub fn into_literal(self) -> Option { + match self { + Term::Literal(_, c) => Some(c), + _ => None, + } + } + + pub fn first_arg(&self) -> Option<&Term> { + match self { + Term::Clause(_, _, ref terms) => terms.first(), + _ => None, + } + } + + pub fn set_name(&mut self, new_name: Atom) { + match self { + Term::Literal(_, Literal::Atom(ref mut atom)) | Term::Clause(_, ref mut atom, ..) => { + *atom = new_name; + } + _ => {} + } + } + + pub fn name(&self) -> Option { + match self { + &Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => { + Some(*atom) + } + _ => None, + } + } + + pub fn arity(&self) -> usize { + match self { + Term::Clause(_, _, ref child_terms, ..) => child_terms.len(), + _ => 0, + } + } +} + +fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> { + if let Term::Clause(_, ref name, ref mut subterms) = term { + if name == &s && subterms.len() == 2 { + let snd = subterms.pop().unwrap(); + let fst = subterms.pop().unwrap(); + + return Some((fst, snd)); + } + } + + None +} + +pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { + let mut terms = vec![]; + + while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) { + terms.push(fst); + term = snd; + } + + terms.push(term); + terms +} diff --git a/src/parser/char_reader.rs b/src/parser/char_reader.rs new file mode 100644 index 000000000..9c23371e0 --- /dev/null +++ b/src/parser/char_reader.rs @@ -0,0 +1,747 @@ +/* + * CharReader is a not entirely redundant flattening/chimera of std's + * BufReader and unicode_reader's CodePoints, introduced to allow + * peekable buffered UTF-8 codepoints and access to the underlying + * reader. + * + * Unlike CodePoints, it doesn't make the reader inaccessible by + * wrapping it a Bytes struct. + * + * Unlike BufReader, its buffer is peekable as a char. + */ + +use smallvec::*; + +use std::error::Error; +use std::fmt; +use std::io; +use std::io::{ErrorKind, IoSliceMut, Read}; +use std::str; + +pub struct CharReader { + inner: R, + buf: SmallVec<[u8;4]>, + pos: usize, +} + +/// An error raised when parsing a UTF-8 byte stream fails. +#[derive(Debug)] +pub struct BadUtf8Error { + /// The bytes that could not be parsed as a code point. + pub bytes: Vec, +} + +impl Error for BadUtf8Error { + fn description(&self) -> &str { + "BadUtf8Error" + } +} + +impl fmt::Display for BadUtf8Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Bad UTF-8: {:?}", self.bytes) + } +} + +impl CharReader { + pub fn new(inner: R) -> CharReader { + Self { + inner, + buf: SmallVec::new(), + pos: 0, + } + } + + #[inline] + pub fn inner(&self) -> &R { + &self.inner + } + + #[inline] + pub fn inner_mut(&mut self) -> &mut R { + &mut self.inner + } +} + +pub trait CharRead { + fn read_char(&mut self) -> Option> { + match self.peek_char() { + Some(Ok(c)) => { + self.consume(c.len_utf8()); + Some(Ok(c)) + } + result => result + } + } + + fn peek_char(&mut self) -> Option>; + fn put_back_char(&mut self, c: char); + fn consume(&mut self, nread: usize); +} + +impl CharReader { + pub fn get_ref(&self) -> &R { + &self.inner + } + + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + pub fn buffer(&self) -> &[u8] { + &self.buf[self.pos..] + } + + pub fn into_inner(self) -> R { + self.inner + } + + fn reset_buffer(&mut self) { + self.buf.clear(); + self.pos = 0; + } +} + +impl CharReader { + fn refresh_buffer(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.buf.len() { + debug_assert!(self.pos == self.buf.len()); + + self.buf.clear(); + + let mut word = [0u8;4]; + let nread = self.inner.read(&mut word)?; + + self.buf.extend_from_slice(&word[..nread]); + self.pos = 0; + } + + Ok(&self.buf[self.pos..]) + } +} + +impl CharRead for CharReader { + fn peek_char(&mut self) -> Option> { + match self.refresh_buffer() { + Ok(_buf) => {} + Err(e) => return Some(Err(e)), + } + + loop { + let buf = &self.buf[self.pos..]; + + if !buf.is_empty() { + let e = match str::from_utf8(buf) { + Ok(s) => { + let mut chars = s.chars(); + let c = chars.next().unwrap(); + + return Some(Ok(c)); + } + Err(e) => { + e + } + }; + + if buf.len() - e.valid_up_to() >= 4 { + // If we have 4 bytes that still don't make up + // a valid code point, then we have garbage. + + // We have bad data in the buffer. Remove + // leading bytes until either the buffer is + // empty, or we have a valid code point. + + let mut split_point = 1; + let mut badbytes = vec![]; + + loop { + let (bad, rest) = buf.split_at(split_point); + + if rest.is_empty() || str::from_utf8(rest).is_ok() { + badbytes.extend_from_slice(bad); + break; + } + + split_point += 1; + } + + // Raise the error. If we still have data in + // the buffer, it will be returned on the next + // loop. + + return Some(Err(io::Error::new(io::ErrorKind::InvalidData, + BadUtf8Error { bytes: badbytes }))); + } else { + if self.pos >= self.buf.len() { + return None; + } else if self.buf.len() - self.pos >= 4 { + return match str::from_utf8(&self.buf[..e.valid_up_to()]) { + Ok(s) => { + let mut chars = s.chars(); + let c = chars.next().unwrap(); + + Some(Ok(c)) + } + Err(e) => { + let badbytes = self.buf[..e.valid_up_to()].to_vec(); + + Some(Err(io::Error::new(io::ErrorKind::InvalidData, + BadUtf8Error { bytes: badbytes }))) + } + }; + } else { + let buf_len = self.buf.len(); + + for (c, idx) in (self.pos..buf_len).enumerate() { + self.buf[c] = self.buf[idx]; + } + + self.buf.truncate(buf_len - self.pos); + + let buf_len = self.buf.len(); + + let mut word = [0u8;4]; + let word_slice = &mut word[buf_len..4]; + + match self.inner.read(word_slice) { + Err(e) => return Some(Err(e)), + Ok(nread) => { + self.buf.extend_from_slice(&word_slice[0..nread]); + } + } + + self.pos = 0; + } + } + } else { + return None; + } + } + } + + #[inline(always)] + fn put_back_char(&mut self, c: char) { + let src_len = self.buf.len() - self.pos; + debug_assert!(src_len <= 4); + + let c_len = c.len_utf8(); + let mut shifted_slice = [0u8; 4]; + + shifted_slice[0..src_len].copy_from_slice(&self.buf[self.pos .. self.buf.len()]); + + self.buf.resize(c_len, 0); + self.buf.extend_from_slice(&shifted_slice[0..src_len]); + self.pos = 0; + + c.encode_utf8(&mut self.buf[0..c_len]); + } + + #[inline(always)] + fn consume(&mut self, nread: usize) { + self.pos += nread; + } +} + +/* +impl BufReader { + /// Seeks relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + #[stable(feature = "bufreader_seek_relative", since = "1.53.0")] + pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { + let pos = self.pos as u64; + if offset < 0 { + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + self.pos = new_pos as usize; + return Ok(()); + } + } else { + if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; + return Ok(()); + } + } + } + self.seek(SeekFrom::Current(offset)).map(drop) + } +} +*/ + +impl Read for CharReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // // If we don't have any buffered data and we're doing a massive read + // // (larger than our internal buffer), bypass our internal buffer + // // entirely. + // if self.pos == self.cap && buf.len() >= self.buf.len() { + // self.discard_buffer(); + // return self.inner.read(buf); + // } + + let mut inner_buf = self.refresh_buffer()?; + let nread = inner_buf.read(buf)?; + + // let nread = { + // let mut rem = self.fill_buf()?; + // rem.read(buf)? + // }; + + self.consume(nread); + Ok(nread) + } + + // Small read_exacts from a BufReader are extremely common when used with a deserializer. + // The default implementation calls read in a loop, which results in surprisingly poor code + // generation for the common path where the buffer has enough bytes to fill the passed-in + // buffer. + fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> { + if self.buffer().len() >= buf.len() { + buf.copy_from_slice(&self.buffer()[..buf.len()]); + self.consume(buf.len()); + return Ok(()); + } + + while !buf.is_empty() { + match self.read(buf) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + } + Err(e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + + if !buf.is_empty() { + Err(io::Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer")) + } else { + Ok(()) + } + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum::(); + + if self.pos == self.buf.len() && total_len >= self.buf.len() { + self.reset_buffer(); // self.discard_buffer(); + return self.inner.read_vectored(bufs); + } + + let nread = { + self.refresh_buffer()?; + (&self.buf[self.pos..]).read_vectored(bufs)? + }; + + self.consume(nread); + Ok(nread) + } +} + +/* +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for BufReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); + self.cap = self.inner.read(&mut self.buf)?; + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} +*/ + +impl fmt::Debug for CharReader +where + R: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("CharReader") + .field("reader", &self.inner) + .field("buf", &format_args!("{}/{}", self.buf.capacity() - self.pos, self.buf.len())) + .finish() + } +} + +/* +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for BufReader { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// position the underlying reader would be at if the `BufReader` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader + /// at the same position. + /// + /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. + /// + /// See [`std::io::Seek`] for more details. + /// + /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// where `n` minus the internal buffer length overflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// [`Err`], the underlying reader will be left at the same position it would + /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// + /// [`std::io::Seek`]: Seek + fn seek(&mut self, pos: SeekFrom) -> io::Result { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 exbibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::MIN so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = self.inner.seek(SeekFrom::Current(offset))?; + } else { + // seek backwards by our remainder, and then by the offset + self.inner.seek(SeekFrom::Current(-remainder))?; + self.discard_buffer(); + result = self.inner.seek(SeekFrom::Current(n))?; + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = self.inner.seek(pos)?; + } + self.discard_buffer(); + Ok(result) + } + + /// Returns the current seek position from the start of the stream. + /// + /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` + /// but does not flush the internal buffer. Due to this optimization the + /// function does not guarantee that calling `.into_inner()` immediately + /// afterwards will yield the underlying reader at the same position. Use + /// [`BufReader::seek`] instead if you require that guarantee. + /// + /// # Panics + /// + /// This function will panic if the position of the inner reader is smaller + /// than the amount of buffered data. That can happen if the inner reader + /// has an incorrect implementation of [`Seek::stream_position`], or if the + /// position has gone out of sync due to calling [`Seek::seek`] directly on + /// the underlying reader. + /// + /// # Example + /// + /// ```no_run + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + fn stream_position(&mut self) -> io::Result { + let remainder = (self.cap - self.pos) as u64; + self.inner.stream_position().map(|pos| { + pos.checked_sub(remainder).expect( + "overflow when subtracting remaining buffer size from inner stream position", + ) + }) + } +} +*/ +/* +impl SizeHint for CharReader { + fn lower_bound(&self) -> usize { + self.buffer().len() + } +} +*/ + +#[cfg(test)] +mod tests { + use crate::parser::char_reader::*; + use std::io::Cursor; + + #[test] + fn plain_string() { + let mut read_string = CharReader::new(Cursor::new("a string")); + + for c in "a string".chars() { + assert_eq!(read_string.peek_char().unwrap().ok(), Some(c)); + assert_eq!(read_string.read_char().unwrap().ok(), Some(c)); + } + + assert!(read_string.read_char().is_none()); + } + + #[test] + fn greek_string() { + let mut read_string = CharReader::new(Cursor::new("λέξη")); + + for c in "λέξη".chars() { + assert_eq!(read_string.peek_char().unwrap().ok(), Some(c)); + assert_eq!(read_string.read_char().unwrap().ok(), Some(c)); + } + + assert!(read_string.read_char().is_none()); + } + + #[test] + fn russian_string() { + let mut read_string = CharReader::new(Cursor::new("слово")); + + for c in "слово".chars() { + assert_eq!(read_string.peek_char().unwrap().ok(), Some(c)); + assert_eq!(read_string.read_char().unwrap().ok(), Some(c)); + } + + assert!(read_string.read_char().is_none()); + } + + #[test] + fn greek_lorem_ipsum() { + let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ + εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ + σιγνιφερθμqθε, σεδ ετ μθτατ jθστο, ει cθμ ελιγενδι σcριπτορεμ + ρεπρεηενδθντ. Εοσ ατ αμετ μαλισ ελειφενδ. Ιν cθμ εριπθιτ + νομινατι. Θσθ ιν cετεροσ μαιορθμ, μθνερε ατομορθμ ινcιδεριντ θτ + ηασ. Αν ηασ λιβρισ πραεσεντ πατριοqθε, ηινc θτιναμ πριμισ νε + cθμ. Cθ μοδο ερρεμ σcριβεντθρ cθμ. Ει vισ δεcορε μαλορθμ + σεντεντιαε, σεδ νο λιβερ εvερτι μεντιτθμ. Προ φαcερ vολθτπατ + σαπιεντεμ ιν. Cθ εροσ περσεqθερισ πρι, εα ποσσιτ cετεροσ δθο. Πρι + εα μαλισ μθνερε. + + Qθισ jθστο μαλορθμ cθ qθο. Νεc ατ οδιο σολετ μαιεστατισ, νε + φορενσιβθσ σαδιπσcινγ ιθσ, αν qθι ειθσ βρθτε σαπιεντεμ. Cομμθνε + περcιπιτθρ ιθσ αδ, μθνερε δολορθμ ιμπεδιτ ηισ νε. Νεc ετιαμ + προπριαε vιτθπερατα ιν. Σονετ νεμορε ιθσ cθ, ιν αφφερτ ινερμισ + cοτιδιεqθε vισ. + + Ηασ ιδ νονθμυ δοcτθσ cοτιδιεqθε. Σινγθλισ πηιλοσοπηια εξ δθο. Εστ + νο ιραcθνδια cονσεqθθντθρ. Τε διcτασ επιcθρει εφφιcιαντθρ δθο, εοσ + νε νθλλα νομιναvι. Εθμ cθ ελιτρ λιβεραvισσε, σιτ περσεqθερισ + cομπλεcτιτθρ εξ, πονδερθμ σιμιλιqθε ηασ νο. + + Σολθμ ποσσιμ λαβιτθρ εξ ηισ, ει δομινγ εξπετενδισ vελ, διαμ μινιμ + σcριπσεριτ ει περ. Αθδιαμ οcθρρερετ προ εξ, δομινγ vολθπταρια ετ + qθο. Cονσθλ σανcτθσ αccθμσαν νο ιθσ, αδ εαμ αλβθcιθσ + ηονεστατισ. Ετ vιξ φαcιλισ qθαλισqθε ερροριβθσ, ηισ εθ πθρτο + ασσεντιορ. Ιθσ βονορθμ ηονεστατισ σcριπσεριτ ατ, ιν ναμ εσσε μοvετ + γραεcο. Αθγθε cονσεcτετθερ εστ ατ. + + Αδ ταλε σθασ μθνερε σεδ, vισ φεθγαιτ αντιοπαμ ιδ. Προ εθ ινερμισ + σαλθτατθσ, σαεπε qθαεστιο θρβανιτασ cθ περ. Ιν μαλορθμ σαλθτατθσ + δετερρθισσετ περ, νε παρτεμ vολθτπατ ινστρθcτιορ vιξ. Νο vισ + δεμοcριτθμ εφφιcιαντθρ, επιcθρει αδολεσcενσ εστ cθ, ιδ vιξ + λθcιλιθσ αδιπισcινγ. Σεα τε cλιτα ιραcθνδια. Σεα αν σιμθλ + εσσεντ. Vοcιβθσ ελειφενδ cονσεqθθντθρ περ αδ, αν ναμ πονδερθμ + vολθπταρια. + + Λιβερ ερθδιτι αccθσαμθσ θτ ναμ. Σιτ αντιοπαμ γθβεργρεν νε. Αμετ + ανcιλλαε ετ qθι, μεα σολθμ λαθδεμ εα. Εθ μελ παρτεμ οβλιqθε + πηαεδρθμ. Εξ μελ jθστο αccομμοδαρε, νε νολθισσε σινγθλισ σενσιβθσ + cθμ, vισ εθ τιμεαμ αδιπισcινγ. + + Τε νολθισσε vολθπτατθμ εστ. Ασσθμ νομιναvι πρι νε, ει νοστρθμ + επιcθρει μεα. Σεδ cθ ελιτ δεσερθντ, γραεcε ερροριβθσ προ θτ, περ + νε εθισμοδ vολθπταρια. Νο εθμ διcατ ποσσιμ, νεc πρινcιπεσ + cονcεπταμ νε. Εθ αππαρεατ ιντελλεγατ σεα. Μελ θτ ελιτ λαθδεμ, θσθ + δολορεμ cομπλεcτιτθρ ετ, νε μεα δολορεσ μολεστιαε. + + Θσθ λεγενδοσ vολθπτατιβθσ cθ. Qθο νε αδηθc ρεφερρεντθρ, αλια + μεδιοcρεμ δθο νε, σεδ ερρεμ δολορθμ αccομμοδαρε νε. Ετιαμ εqθιδεμ + δετερρθισσετ cθ μει, ετ εροσ cετεροσ σεα, εξ vιξ ενιμ cασε + δετραξιτ. Σεδ σολθτα λιβρισ ειρμοδ τε, νοvθμ ποπθλο νε εθμ. Σθμμο + αδμοδθμ δεσερθντ εστ εξ, εστ διcαμ εqθιδεμ cθ. + + Ιλλθμ cορπορα ινvιδθντ εαμ ετ. Σεδ μαλισ ταcιματεσ εvερτιτθρ εα, + μαζιμ νθλλαμ vοcιβθσ μεα ει. Μεα ορνατθσ λθπτατθμ αδιπισcινγ + αδ. Μεα αφφερτ νοστερ ατ, ναμ αν σολεατ ερροριβθσ. Εξ σεα αεqθε + μθνερε cετερο, εοσ ηινc ελειφενδ δεμοcριτθμ."; + + let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum)); + + for c in lorem_ipsum.chars() { + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + } + + assert!(lorem_ipsum_reader.read_char().is_none()); + } + + #[test] + fn armenian_lorem_ipsum() { + let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո + սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում + եսթ, մեա թե ծոմմոդո ծոռպոռա. եթ ծոնսուլ ադիպիսծինգ ռեֆոռմիդանս + պեռ, ինեռմիս ֆեուգաիթ նո քուո, թալե սալե պռո եա. եթ նիբհ + աուգուե վոլումուս դուո, նե ծում եխեռծի սալութաթուս գլոռիաթուռ, + ծու թաթիոն պռաեսենթ մեդիոծռեմ վիս. + + վիխ եռոս ռեֆեռռենթուռ եու. պեռսիուս վիթուպեռաթոռիբուս ութ սեա, + վիդե ինվիդունթ պռոբաթուս նո քուո. մեի եռոս մելիուս նոմինավի + իդ, ութ պռո քուաս քուաեսթիո. եթ նաթում պեթենթիում սուավիթաթե + հիս. քուի ծոնսթիթութո մեդիոծռիթաթեմ թե. ծեթեռո դեթռածթո + ծոնծեպթամ սեա եթ. դիսսենթիեթ ելոքուենթիամ թհեոպհռասթուս նեծ + աթ, աթ ֆածեթե եռիպուիթ վիխ. + + ասսուեվեռիթ սծռիպսեռիթ եսթ եթ, վիդիթ դեբեթ եվեռթի եխ + եսթ. աութեմ լաուդեմ պոսիդոնիում մեի եի. ռեբում դիծամ ծեթեռոս + եում ծու. նիհիլ եխպեթենդա ասսուեվեռիթ ուսու ան. ւիսի թաթիոն + դելենիթ նո իուս, սեդ եխ իդքուե սիգնիֆեռումքուե, բռութե զռիլ + ալբուծիուս ան պռի. + + մովեթ իռիուռե սալութանդի պեռ նո, եի ոմնիս աֆֆեռթ պեռսեքուեռիս + իուս, եթ պռաեսենթ մալուիսսեթ եսթ. եսթ պռոբո գուբեռգռեն եթ, հաս + ին դիամ նումքուամ. ֆեուգաիթ ինվենիռե ռեպուդիանդաե աթ սեդ, + իուվառեթ ծոնսուլաթու եֆֆիծիանթուռ ուսու եի. ութ մեա ածծումսան + նոմինավի թինծիդունթ, մեի դիծթա ածծումսան ութ. վիմ ոմնիում + ելիգենդի սծռիպթոռեմ եու. + + իդ վիս եռռոռ ալիքուիպ ելոքուենթիամ, ադ դելենիթի պեռծիպիթ + դեֆինիթիոնես իուս. վիմ իուդիծո դեմոծռիթում ծոմպռեհենսամ թե, + ութ նիհիլ լոբոռթիս վոլուպթաթիբուս վել, դիծունթ մենթիթում + ֆածիլիսիս եի եում. եսսե սալե մինիմ եոս նե. ագամ ոմնեսքուե ծում + ին. + + իուվառեթ իուդիծաբիթ ծում աթ, ուսու նիբհ աթքուի դոմինգ եխ. եի + քուի սանծթուս սենսիբուս, նամ ուբիքուե ապպեթեռե պռոդեսսեթ + եու. ուսու եթ աուգուե ծոնվենիռե սծռիբենթուռ. ան ոմնիում վեռեառ + ութռոքուե դուո, եսթ եի լիբեռ մեդիոծռեմ եխպլիծառի, ոմնիս + աուդիռե թե պռի. վիմ մունեռե սոլեաթ ծու, եռոս ինվենիռե + դիսպութաթիոնի եի քուո, ան ալթեռա պութենթ լաբոռես պռո. անթիոպամ + դեմոծռիթում պեռ ին. + + նե քուի ծիբո ելիթռ. նեծ նե լիբեռ վոլուպթուա. նիսլ ծոմմունե + եխպեթենդիս նամ եխ, իուդիծո պլածեռաթ պեռծիպիթուռ մել նո, եթ + պառթեմ պութանթ քուի. վիմ թինծիդունթ ածծոմմոդառե աթ, նե նամ + վիդիթ իռիուռե, պռո եա ելիգենդի պոսթուլանթ ծոնսթիթութո. + + մել ութ ոդիո նուլլամ եխպլիծառի. պռոպռիաե թինծիդունթ + դելիծաթիսսիմի եամ ան, մոդո քուոդսի ապեռիռի եու եսթ, պեռ աթ + լաբոռես սենսեռիթ. վիմ ծոնգուե ռեպուդիանդաե եի, նեծ ագամ + դիծունթ դելիծաթիսսիմի աթ. պոսսիթ լիբեռավիսսե եոս եու. + + աթ ալիա դեբեթ ելաբոռառեթ քուո, ին ալիի ածծումսան ծոնսթիթուամ + հաս, մել թոթա ոմիթթանթուռ ինսթռուծթիոռ նո. պեռ նե ծաուսաե + սապիենթեմ, պաուլո ոմնեսքուե եի քուո, եխ ոռաթիո պհիլոսոպհիա + սիթ. իգնոթա ծաուսաե աթ ուսու, եխ քուո դիծթաս քուոդսի + ռեպուդիառե. ծոռպոռա պռոդեսսեթ ռեֆեռռենթուռ եոս եխ. + + եու եթիամ ելեիֆենդ մել, սալե սծռիպսեռիթ հիս եու. պոռռո + ադոլեսծենս մեի եա. ին մեա զռիլ պռոբաթուս սալութաթուս. եոս ադ + մինիմ թեմպոռիբուս. սեա նե եթիամ."; + + let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum)); + + for c in lorem_ipsum.chars() { + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + } + + assert!(lorem_ipsum_reader.read_char().is_none()); + } + + #[test] + fn russian_lorem_ipsum() { + let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи + сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи + саперет аппеллантур. Ех иус диам дицта волуптариа, еу пер + бруте омиттам аццусата. Хис сапиентем губергрен те, яуидам + луптатум персеяуерис ад ест. + + Ан алияуип перицулис нам, нец апериам цотидиеяуе волуптатибус + но. Солум тритани пер ех, меи не одио тритани рецусабо, цу при + веро мелиоре импердиет. Ин граеци индоцтум салутатус нец, диам + сцаевола пертинациа про те. Ут сеа дебитис лаборамус + диссентиас, еи цум яуот лобортис. + + Децоре сингулис вим не. Еос не риденс оффициис, еу нонумы + лабитур еррорибус хас, вел омнис цонституто посидониум но. Вел + персиус фастидии репрехендунт ид. Натум иллум ипсум сит ад, еа + еам новум латине. Еос нолуиссе патриояуе елояуентиам те. + + Стет малис яуаерендум хас ад, прима цотидиеяуе мел ан, + трацтатос десеруиссе нам ех. Ин малорум сусципиантур вим, ех + меа граецо тритани адолесценс. Промпта цонцлусионемяуе нам еи, + дуо ин лаборе алтерум цотидиеяуе. Но елитр промпта сплендиде + еум, аеяуе ассуеверит цонституам яуи ид. Ад тале еррор + интеллегебат хас, ерудити граецис хас не, пер ут лабитур + еуисмод. Те при суммо путант. Про утинам цоммуне урбанитас еа. + + Идяуе репрехендунт еи нам, алии толлит легере нам не, хис еа + виси адверсариум цонцлусионемяуе. Хас ассум омиттам луцилиус + ет, вих цонсул малорум фастидии не, сенсибус ассуеверит дуо + ут. Дуо алиа видит цетеро ат, еа аппареат пертинах вел. Пер + цонституто инцидеринт ин, убияуе риденс сенсерит цум цу. Про + ет цетерос темпорибус, те вел пурто суммо, дуо мунере вертерем + урбанитас ад. Сит оптион елецтрам форенсибус но. Еи татион + сапиентем ест, лаборе сцрипта сингулис но вим, усу еу елигенди + персецути. + + Иус ан елецтрам цонтентионес. Меи атяуи нонумес ут, вел амет + репрехендунт ан, вис еу яуаестио патриояуе. Про синт легере + детрацто ад. Постеа долорем евертитур при ет, вим номинави + принципес ирацундиа ех. Доцтус интеллегебат но нам. Фацете + оффициис нецесситатибус цу меа. + + Промпта симилияуе вис ин. Пер бонорум перицулис аргументум + ад. Еу дицат фацилис губергрен нам, еффициенди цомпрехенсам + хас еу. Инани нонумы усу но, ад цонцептам репудиандае + про. Тота нуллам делицата еа яуо, усу дуис дебет путент еи. + + Вис апериам доценди елояуентиам еа. Ех яуот детрацто + елояуентиам цум, ерос малис дицерет вис ин. Еа цум модус + еяуидем, дебет нуллам ан меи. Алтерум омиттам про ет. + + Яуи ех латине алияуам, ан меи одио нуллам. Ид хас омнис ребум + либрис. Ет убияуе путант дебитис про, ех хис медиоцрем + партиендо, но елит елецтрам дуо. Еу меа сонет номинави + цотидиеяуе. Нам фалли новум минимум еу, перфецто ратионибус + цонституто ад меа. + + Нобис детрацто еам ид, при еу ассум пертинах, те етиам + проприае салутанди яуо. Легимус сусципиантур ет хас, сед + поссит дефинитионес еа. Ест не патриояуе омиттантур + интеллегебат, еу яуо дебет цонцлудатуряуе. Еум ад мнесарчум + дефинитионем, елитр лаборамус перципитур про не, хас феугаит + фастидии луцилиус ид. Фастидии интеллегат ех."; + + let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum)); + + for c in lorem_ipsum.chars() { + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + + lorem_ipsum_reader.put_back_char(c); + + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + } + + assert!(lorem_ipsum_reader.read_char().is_none()); + } +} diff --git a/crates/prolog_parser/src/lexer.rs b/src/parser/lexer.rs similarity index 53% rename from crates/prolog_parser/src/lexer.rs rename to src/parser/lexer.rs index 8be50d36a..d24876665 100644 --- a/crates/prolog_parser/src/lexer.rs +++ b/src/parser/lexer.rs @@ -1,20 +1,24 @@ -use crate::rug::Integer; use lexical::parse_lossy; use ordered_float::*; -use crate::ast::*; -use crate::tabled_rc::*; +use crate::atom_table::*; +pub use crate::machine::machine_state::*; +use crate::parser::ast::*; +use crate::parser::char_reader::*; +use crate::parser::rug::Integer; use std::convert::TryFrom; use std::fmt; -use std::io::Read; -use std::rc::Rc; macro_rules! is_not_eof { - ($c:expr) => { + ($parser:expr, $c:expr) => { match $c { + Ok('\u{0}') => { + $parser.consume('\u{0}'.len_utf8()); + return Ok(true); + } Ok(c) => c, - Err($crate::ast::ParserError::UnexpectedEOF) => return Ok(true), + Err($crate::parser::ast::ParserError::UnexpectedEOF) => return Ok(true), Err(e) => return Err(e), } }; @@ -26,17 +30,17 @@ macro_rules! consume_chars_with { match $e { Ok(Some(c)) => $token.push(c), Ok(None) => continue, - Err($crate::ast::ParserError::UnexpectedChar(..)) => break, + Err($crate::parser::ast::ParserError::UnexpectedChar(..)) => break, Err(e) => return Err(e), } } }; } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, PartialEq)] pub enum Token { - Constant(Constant), - Var(Rc), + Literal(Literal), + Var(String), Open, // '(' OpenCT, // '(' Close, // ')' @@ -60,94 +64,93 @@ impl Token { } } -pub struct Lexer<'a, R: Read> { - pub(crate) atom_tbl: TabledData, - pub(crate) reader: &'a mut ParsingStream, - pub(crate) flags: MachineFlags, +pub struct Lexer<'a, R> { + pub(crate) reader: R, + pub(crate) machine_st: &'a mut MachineState, pub(crate) line_num: usize, pub(crate) col_num: usize, } -impl<'a, R: Read + fmt::Debug> fmt::Debug for Lexer<'a, R> { +impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Lexer") - .field("atom_tbl", &self.atom_tbl) - .field("reader", &"&'a mut ParsingStream") // Hacky solution. + .field("reader", &"&'a mut R") // Hacky solution. .field("line_num", &self.line_num) .field("col_num", &self.col_num) .finish() } } -impl<'a, R: Read> Lexer<'a, R> { - pub fn new( - atom_tbl: TabledData, - flags: MachineFlags, - src: &'a mut ParsingStream, - ) -> Self { +impl<'a, R: CharRead> Lexer<'a, R> { + pub fn new(src: R, machine_st: &'a mut MachineState) -> Self { Lexer { - atom_tbl, - flags, reader: src, + machine_st, line_num: 0, col_num: 0, } } - fn return_char(&mut self, c: char) { - if new_line_char!(c) { - self.line_num -= 1; - self.col_num = 0; + pub fn lookahead_char(&mut self) -> Result { + match self.reader.peek_char() { + Some(Ok(c)) => Ok(c), + _ => Err(ParserError::UnexpectedEOF) } + } - self.reader.put_back(Ok(c)); + pub fn read_char(&mut self) -> Result { + match self.reader.read_char() { + Some(Ok(c)) => Ok(c), + _ => Err(ParserError::UnexpectedEOF) + } } - fn skip_char(&mut self) -> Result { - if let Some(Ok(c)) = self.reader.next() { - self.col_num += 1; + #[inline(always)] + fn return_char(&mut self, c: char) { + self.reader.put_back_char(c); + } - if new_line_char!(c) { - self.line_num += 1; - self.col_num = 0; - } + fn skip_char(&mut self, c: char) { + self.reader.consume(c.len_utf8()); - Ok(c) + if new_line_char!(c) { + self.line_num += 1; + self.col_num = 0; } else { - Err(ParserError::UnexpectedEOF) + self.col_num += 1; } } pub fn eof(&mut self) -> Result { - if self.reader.peek().is_none() { + if self.reader.peek_char().is_none() { return Ok(true); } - let mut c = is_not_eof!(self.lookahead_char()); + let mut c = is_not_eof!(self.reader, self.lookahead_char()); while layout_char!(c) { - self.skip_char()?; + self.skip_char(c); - if self.reader.peek().is_none() { + if self.reader.peek_char().is_none() { return Ok(true); } - c = is_not_eof!(self.lookahead_char()); + c = is_not_eof!(self.reader, self.lookahead_char()); } Ok(false) } - pub fn lookahead_char(&mut self) -> Result { - match self.reader.peek() { - Some(&Ok(c)) => Ok(c), - _ => Err(ParserError::UnexpectedEOF), - } - } - fn single_line_comment(&mut self) -> Result<(), ParserError> { loop { - if self.reader.peek().is_none() || new_line_char!(self.skip_char()?) { + if self.reader.peek_char().is_none() { + break; + } + + let c = self.lookahead_char()?; + self.skip_char(c); + + if new_line_char!(c) { break; } } @@ -156,65 +159,80 @@ impl<'a, R: Read> Lexer<'a, R> { } fn bracketed_comment(&mut self) -> Result { - // we have already checked that the current lookahead_char is comment_1_char, just skip it - let c = self.skip_char()?; + // we have already checked that the current lookahead_char is + // comment_1_char, just skip it + self.skip_char('/'); - if comment_2_char!(self.lookahead_char()?) { - self.skip_char()?; + let c = self.lookahead_char()?; + + if comment_2_char!(c) { + self.skip_char(c); // Keep reading until we find characters '*' and '/' - // Deliberately skip checks for prolog_char to allow comments to contain any characters, - // including so-called "extended characters", without having to explicitly add them to a character class. + // Deliberately skip checks for prolog_char to allow + // comments to contain any characters, including so-called + // "extended characters", without having to explicitly add + // them to a character class. + let mut c = self.lookahead_char()?; + loop { while !comment_2_char!(c) { - self.skip_char()?; + self.skip_char(c); c = self.lookahead_char()?; } - self.skip_char()?; - + self.skip_char(c); c = self.lookahead_char()?; + if comment_1_char!(c) { break; } } if prolog_char!(c) { - self.skip_char()?; + self.skip_char(c); Ok(true) } else { Err(ParserError::NonPrologChar(self.line_num, self.col_num)) } } else { - self.return_char(c); + self.return_char('/'); Ok(false) } } fn get_back_quoted_char(&mut self) -> Result { - if back_quote_char!(self.lookahead_char()?) { - let c = self.skip_char()?; + let c = self.lookahead_char()?; - if !back_quote_char!(self.lookahead_char()?) { + if back_quote_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if !back_quote_char!(c2) { self.return_char(c); Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } else { - self.skip_char() + self.skip_char(c2); + Ok(c2) } - } else if single_quote_char!(self.lookahead_char()?) { - self.skip_char() + } else if single_quote_char!(c) { + self.skip_char(c); + self.read_char() } else { self.get_non_quote_char() } } fn get_back_quoted_item(&mut self) -> Result, ParserError> { - if backslash_char!(self.lookahead_char()?) { - let c = self.skip_char()?; + let c = self.lookahead_char()?; - if new_line_char!(self.lookahead_char()?) { - self.skip_char()?; + if backslash_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if new_line_char!(c2) { + self.skip_char(c2); Ok(None) } else { self.return_char(c); @@ -229,13 +247,15 @@ impl<'a, R: Read> Lexer<'a, R> { let c = self.lookahead_char()?; if back_quote_char!(c) { - self.skip_char()?; + self.skip_char(c); - let mut token = String::new(); + let mut token = String::with_capacity(16); consume_chars_with!(token, self.get_back_quoted_item()); - if back_quote_char!(self.lookahead_char()?) { - self.skip_char()?; + let c = self.lookahead_char()?; + + if back_quote_char!(c) { + self.skip_char(c); Ok(token) } else { Err(ParserError::MissingQuote(self.line_num, self.col_num)) @@ -246,11 +266,14 @@ impl<'a, R: Read> Lexer<'a, R> { } fn get_single_quoted_item(&mut self) -> Result, ParserError> { - if backslash_char!(self.lookahead_char()?) { - let c = self.skip_char()?; + let c = self.lookahead_char()?; + + if backslash_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; - if new_line_char!(self.lookahead_char()?) { - self.skip_char()?; + if new_line_char!(c2) { + self.skip_char(c2); return Ok(None); } else { self.return_char(c); @@ -264,27 +287,34 @@ impl<'a, R: Read> Lexer<'a, R> { let c = self.lookahead_char()?; if single_quote_char!(c) { - self.skip_char()?; + self.skip_char(c); + let c2 = self.lookahead_char()?; - if !single_quote_char!(self.lookahead_char()?) { + if !single_quote_char!(c2) { self.return_char(c); Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } else { - self.skip_char() + self.skip_char(c2); + Ok(c2) } } else if double_quote_char!(c) || back_quote_char!(c) { - self.skip_char() + self.skip_char(c); + Ok(c) } else { self.get_non_quote_char() } } fn get_double_quoted_item(&mut self) -> Result, ParserError> { - if backslash_char!(self.lookahead_char()?) { - let c = self.skip_char()?; + let c = self.lookahead_char()?; + + if backslash_char!(c) { + self.skip_char(c); - if new_line_char!(self.lookahead_char()?) { - self.skip_char()?; + let c2 = self.lookahead_char()?; + + if new_line_char!(c2) { + self.skip_char(c2); return Ok(None); } else { self.return_char(c); @@ -295,26 +325,31 @@ impl<'a, R: Read> Lexer<'a, R> { } fn get_double_quoted_char(&mut self) -> Result { - if double_quote_char!(self.lookahead_char()?) { - let c = self.skip_char()?; + let c = self.lookahead_char()?; - if !double_quote_char!(self.lookahead_char()?) { + if double_quote_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if !double_quote_char!(c2) { self.return_char(c); Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } else { - self.skip_char() + self.skip_char(c2); + Ok(c2) } - } else if single_quote_char!(self.lookahead_char()?) { - self.skip_char() - } else if back_quote_char!(self.lookahead_char()?) { - self.skip_char() + } else if single_quote_char!(c) || back_quote_char!(c) { + self.skip_char(c); + Ok(c) } else { self.get_non_quote_char() } } fn get_control_escape_sequence(&mut self) -> Result { - let escaped = match self.lookahead_char()? { + let c = self.lookahead_char()?; + + let escaped = match c { 'a' => '\u{07}', // UTF-8 alert 'b' => '\u{08}', // UTF-8 backspace 'v' => '\u{0b}', // UTF-8 vertical tab @@ -325,16 +360,16 @@ impl<'a, R: Read> Lexer<'a, R> { c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)), }; - self.skip_char()?; - return Ok(escaped); + self.skip_char(c); + Ok(escaped) } fn get_octal_escape_sequence(&mut self) -> Result { self.escape_sequence_to_char(|c| octal_digit_char!(c), 8) } - fn get_hexadecimal_escape_sequence(&mut self) -> Result { - self.skip_char()?; + fn get_hexadecimal_escape_sequence(&mut self, start: char) -> Result { + self.skip_char(start); let c = self.lookahead_char()?; if hexadecimal_digit_char!(c) { @@ -350,12 +385,12 @@ impl<'a, R: Read> Lexer<'a, R> { radix: u32, ) -> Result { let mut c = self.lookahead_char()?; - let mut token = String::new(); + let mut token = String::with_capacity(16); loop { token.push(c); - self.skip_char()?; + self.skip_char(c); c = self.lookahead_char()?; if !accept_char(c) { @@ -364,7 +399,7 @@ impl<'a, R: Read> Lexer<'a, R> { } if backslash_char!(c) { - self.skip_char()?; + self.skip_char(c); u32::from_str_radix(&token, radix).map_or_else( |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)), |n| { @@ -374,8 +409,8 @@ impl<'a, R: Read> Lexer<'a, R> { ) } else { // on failure, restore the token characters and backslash. - self.reader.put_back_all(token.chars().map(Ok)); - self.reader.put_back(Ok('\\')); + // self.reader.put_back_all(token.chars().map(Ok)); + // self.reader.put_back(Ok('\\')); Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } @@ -385,158 +420,212 @@ impl<'a, R: Read> Lexer<'a, R> { let c = self.lookahead_char()?; if graphic_char!(c) || alpha_numeric_char!(c) || solo_char!(c) || space_char!(c) { - self.skip_char() + self.skip_char(c); + Ok(c) } else { if !backslash_char!(c) { return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)); } - self.skip_char()?; - + self.skip_char(c); let c = self.lookahead_char()?; if meta_char!(c) { - self.skip_char() + self.skip_char(c); + Ok(c) } else if octal_digit_char!(c) { self.get_octal_escape_sequence() } else if symbolic_hexadecimal_char!(c) { - self.get_hexadecimal_escape_sequence() + self.get_hexadecimal_escape_sequence(c) } else { self.get_control_escape_sequence() } } } - fn char_code_list_token(&mut self) -> Result { - let mut token = String::new(); + fn char_code_list_token(&mut self, start: char) -> Result { + let mut token = String::with_capacity(16); - self.skip_char()?; + self.skip_char(start); consume_chars_with!(token, self.get_double_quoted_item()); - if double_quote_char!(self.lookahead_char()?) { - self.skip_char()?; + let c = self.lookahead_char()?; + + if double_quote_char!(c) { + self.skip_char(c); Ok(token) } else { Err(ParserError::MissingQuote(self.line_num, self.col_num)) } } - fn hexadecimal_constant(&mut self) -> Result { - self.skip_char()?; + fn hexadecimal_constant(&mut self, start: char) -> Result { + self.skip_char(start); + let mut c = self.lookahead_char()?; - if hexadecimal_digit_char!(self.lookahead_char()?) { - let mut token = String::new(); + if hexadecimal_digit_char!(c) { + let mut token = String::with_capacity(16); - while hexadecimal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + loop { + if hexadecimal_digit_char!(c) { + self.skip_char(c); + token.push(c); + c = self.lookahead_char()?; + } else { + break; + } } - isize::from_str_radix(&token, 16) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 16) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { Integer::from_str_radix(&token, 16) - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| Token::Literal(Literal::Integer( + arena_alloc!(n, &mut self.machine_st.arena) + ))) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) }) } else { - self.return_char('x'); + self.return_char(start); Err(ParserError::ParseBigInt(self.line_num, self.col_num)) } } - fn octal_constant(&mut self) -> Result { - self.skip_char()?; + fn octal_constant(&mut self, start: char) -> Result { + self.skip_char(start); + let mut c = self.lookahead_char()?; - if octal_digit_char!(self.lookahead_char()?) { - let mut token = String::new(); + if octal_digit_char!(c) { + let mut token = String::with_capacity(16); - while octal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + loop { + if octal_digit_char!(c) { + self.skip_char(c); + token.push(c); + c = self.lookahead_char()?; + } else { + break; + } } - isize::from_str_radix(&token, 8) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 8) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { Integer::from_str_radix(&token, 8) - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| Token::Literal(Literal::Integer( + arena_alloc!(n, &mut self.machine_st.arena) + ))) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) }) } else { - self.return_char('o'); + self.return_char(start); Err(ParserError::ParseBigInt(self.line_num, self.col_num)) } } - fn binary_constant(&mut self) -> Result { - self.skip_char()?; + fn binary_constant(&mut self, start: char) -> Result { + self.skip_char(start); + let mut c = self.lookahead_char()?; - if binary_digit_char!(self.lookahead_char()?) { - let mut token = String::new(); + if binary_digit_char!(c) { + let mut token = String::with_capacity(16); - while binary_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + loop { + if binary_digit_char!(c) { + self.skip_char(c); + token.push(c); + c = self.lookahead_char()?; + } else { + break; + } } - isize::from_str_radix(&token, 2) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 2) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { Integer::from_str_radix(&token, 2) - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| Token::Literal(Literal::Integer( + arena_alloc!(n, &mut self.machine_st.arena) + ))) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) }) } else { - self.return_char('b'); + self.return_char(start); Err(ParserError::ParseBigInt(self.line_num, self.col_num)) } } fn variable_token(&mut self) -> Result { - let mut s = String::new(); - s.push(self.skip_char()?); + let mut s = String::with_capacity(16); + s.push(self.read_char()?); - while alpha_numeric_char!(self.lookahead_char()?) { - s.push(self.skip_char()?); + loop { + let c = self.lookahead_char()?; + + if alpha_numeric_char!(c) { + self.skip_char(c); + s.push(c); + } else { + break; + } } - Ok(Token::Var(rc_atom!(s))) + Ok(Token::Var(s)) } fn name_token(&mut self, c: char) -> Result { - let mut token = String::new(); + let mut token = String::with_capacity(16); if small_letter_char!(c) { - token.push(self.skip_char()?); + self.skip_char(c); + token.push(c); + + loop { + let c = self.lookahead_char()?; - while alpha_numeric_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + if alpha_numeric_char!(c) { + self.skip_char(c); + token.push(c); + } else { + break; + } } } else if graphic_token_char!(c) { - token.push(self.skip_char()?); + self.skip_char(c); + token.push(c); + + loop { + let c = self.lookahead_char()?; - while graphic_token_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + if graphic_token_char!(c) { + self.skip_char(c); + token.push(c); + } else { + break; + } } } else if cut_char!(c) { - token.push(self.skip_char()?); + self.skip_char(c); + token.push(c); } else if semicolon_char!(c) { - token.push(self.skip_char()?); + self.skip_char(c); + token.push(c); } else if single_quote_char!(c) { - self.skip_char()?; - + self.skip_char(c); consume_chars_with!(token, self.get_single_quoted_item()); - if single_quote_char!(self.lookahead_char()?) { - self.skip_char()?; + let c = self.lookahead_char()?; + + if single_quote_char!(c) { + self.skip_char(c); if !token.is_empty() && token.chars().nth(1).is_none() { if let Some(c) = token.chars().next() { - return Ok(Token::Constant(Constant::Char(c))); + return Ok(Token::Literal(Literal::Char(c))); } } } else { - return Err(ParserError::InvalidSingleQuotedCharacter( - self.lookahead_char()?, - )); + return Err(ParserError::InvalidSingleQuotedCharacter(c)); } } else { match self.get_back_quoted_string() { @@ -546,24 +635,29 @@ impl<'a, R: Read> Lexer<'a, R> { } if token.as_str() == "[]" { - Ok(Token::Constant(Constant::EmptyList)) + Ok(Token::Literal(Literal::Atom(atom!("[]")))) } else { - Ok(Token::Constant(atom!(token, self.atom_tbl))) + Ok(Token::Literal(Literal::Atom( + self.machine_st.atom_tbl.build_with(&token), + ))) } } - fn vacate_with_float(&mut self, mut token: String) -> Token { + fn vacate_with_float(&mut self, mut token: String) -> Result { self.return_char(token.pop().unwrap()); - let result = OrderedFloat(parse_lossy::(token.as_bytes()).unwrap()); - Token::Constant(Constant::Float(result)) + let result = OrderedFloat(parse_lossy::(token.as_bytes())?); + Ok(Token::Literal(Literal::Float(arena_alloc!( + result, + &mut self.machine_st.arena + )))) } fn skip_underscore_in_number(&mut self) -> Result { let mut c = self.lookahead_char()?; if c == '_' { - self.skip_char()?; + self.skip_char(c); self.scan_for_layout()?; c = self.lookahead_char()?; @@ -577,112 +671,140 @@ impl<'a, R: Read> Lexer<'a, R> { } } - pub fn number_token(&mut self) -> Result { - let mut token = String::new(); + pub fn number_token(&mut self, leading_c: char) -> Result { + let mut token = String::with_capacity(16); - token.push(self.skip_char()?); + self.skip_char(leading_c); + token.push(leading_c); let mut c = self.skip_underscore_in_number()?; while decimal_digit_char!(c) { token.push(c); - self.skip_char()?; + self.skip_char(c); c = self.skip_underscore_in_number()?; } if decimal_point_char!(c) { - self.skip_char()?; + self.skip_char(c); - if self.reader.peek().is_none() { + if self.reader.peek_char().is_none() { self.return_char('.'); - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) + }) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) }) } else if decimal_digit_char!(self.lookahead_char()?) { token.push('.'); - token.push(self.skip_char()?); + token.push(self.read_char()?); let mut c = self.lookahead_char()?; while decimal_digit_char!(c) { token.push(c); - self.skip_char()?; + self.skip_char(c); c = self.lookahead_char()?; } - if exponent_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + if exponent_char!(c) { + self.skip_char(c); + token.push(c); let c = match self.lookahead_char() { - Err(_) => return Ok(self.vacate_with_float(token)), + Err(_) => return Ok(self.vacate_with_float(token)?), Ok(c) => c, }; if !sign_char!(c) && !decimal_digit_char!(c) { - return Ok(self.vacate_with_float(token)); + return Ok(self.vacate_with_float(token)?); } if sign_char!(c) { - token.push(self.skip_char()?); + self.skip_char(c); + token.push(c); let c = match self.lookahead_char() { Err(_) => { self.return_char(token.pop().unwrap()); - return Ok(self.vacate_with_float(token)); + return Ok(self.vacate_with_float(token)?); } Ok(c) => c, }; if !decimal_digit_char!(c) { self.return_char(token.pop().unwrap()); - return Ok(self.vacate_with_float(token)); + return Ok(self.vacate_with_float(token)?); } } - if decimal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + let mut c = self.lookahead_char()?; + + if decimal_digit_char!(c) { + self.skip_char(c); + token.push(c); - while decimal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); + loop { + c = self.lookahead_char()?; + + if decimal_digit_char!(c) { + self.skip_char(c); + token.push(c); + } else { + break; + } } - let n = OrderedFloat(parse_lossy::(token.as_bytes()).unwrap()); - Ok(Token::Constant(Constant::Float(n))) + let n = OrderedFloat(parse_lossy::(token.as_bytes())?); + Ok(Token::Literal(Literal::Float(arena_alloc!( + n, + &mut self.machine_st.arena + )))) } else { - return Ok(self.vacate_with_float(token)); + return Ok(self.vacate_with_float(token)?); } } else { - let n = OrderedFloat(parse_lossy::(token.as_bytes()).unwrap()); - Ok(Token::Constant(Constant::Float(n))) + let n = OrderedFloat(parse_lossy::(token.as_bytes())?); + Ok(Token::Literal(Literal::Float(arena_alloc!( + n, + &mut self.machine_st.arena + )))) } } else { self.return_char('.'); - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) + }) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) }) } } else { if token.starts_with('0') && token.len() == 1 { if c == 'x' { - self.hexadecimal_constant().or_else(|e| { + self.hexadecimal_constant(c).or_else(|e| { if let ParserError::ParseBigInt(..) = e { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) .map_err(|_| { ParserError::ParseBigInt(self.line_num, self.col_num) }) @@ -692,14 +814,19 @@ impl<'a, R: Read> Lexer<'a, R> { } }) } else if c == 'o' { - self.octal_constant().or_else(|e| { + self.octal_constant(c).or_else(|e| { if let ParserError::ParseBigInt(..) = e { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) .map_err(|_| { ParserError::ParseBigInt(self.line_num, self.col_num) }) @@ -709,14 +836,19 @@ impl<'a, R: Read> Lexer<'a, R> { } }) } else if c == 'b' { - self.binary_constant().or_else(|e| { + self.binary_constant(c).or_else(|e| { if let ParserError::ParseBigInt(..) = e { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) .map_err(|_| { ParserError::ParseBigInt(self.line_num, self.col_num) }) @@ -726,54 +858,68 @@ impl<'a, R: Read> Lexer<'a, R> { } }) } else if single_quote_char!(c) { - self.skip_char()?; + self.skip_char(c); + let c = self.lookahead_char()?; - if backslash_char!(self.lookahead_char()?) { - self.skip_char()?; + if backslash_char!(c) { + self.skip_char(c); + let c = self.lookahead_char()?; - if new_line_char!(self.lookahead_char()?) { - self.return_char('\\'); + if new_line_char!(c) { + self.skip_char(c); self.return_char('\''); - return Ok(Token::Constant(Constant::Fixnum(0))); + return Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(0)))); } else { self.return_char('\\'); } } self.get_single_quoted_char() - .map(|c| Token::Constant(Constant::Fixnum(c as isize))) + .map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64)))) .or_else(|_| { self.return_char(c); - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) .map_err(|_| { ParserError::ParseBigInt(self.line_num, self.col_num) }) }) }) } else { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) }) } } else { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) + }) .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) }) } @@ -789,7 +935,7 @@ impl<'a, R: Read> Lexer<'a, R> { match cr { Ok(c) if layout_char!(c) => { - self.skip_char()?; + self.skip_char(c); layout_inserted = true; } Ok(c) if end_line_comment_char!(c) => { @@ -825,17 +971,17 @@ impl<'a, R: Read> Lexer<'a, R> { } if c == ',' { - self.skip_char()?; + self.skip_char(c); return Ok(Token::Comma); } if c == ')' { - self.skip_char()?; + self.skip_char(c); return Ok(Token::Close); } if c == '(' { - self.skip_char()?; + self.skip_char(c); return Ok(if layout_inserted { Token::Open } else { @@ -844,12 +990,12 @@ impl<'a, R: Read> Lexer<'a, R> { } if c == '.' { - self.skip_char()?; + self.skip_char(c); match self.lookahead_char() { Ok(c) if layout_char!(c) || c == '%' => { if new_line_char!(c) { - self.skip_char()?; + self.skip_char(c); } return Ok(Token::End); @@ -861,47 +1007,48 @@ impl<'a, R: Read> Lexer<'a, R> { self.return_char('.'); } }; + + return self.name_token(c); } if decimal_digit_char!(c) { - return self.number_token(); + return self.number_token(c); } if c == ']' { - self.skip_char()?; + self.skip_char(c); return Ok(Token::CloseList); } if c == '[' { - self.skip_char()?; + self.skip_char(c); return Ok(Token::OpenList); } if c == '|' { - self.skip_char()?; + self.skip_char(c); return Ok(Token::HeadTailSeparator); } if c == '{' { - self.skip_char()?; + self.skip_char(c); return Ok(Token::OpenCurly); } if c == '}' { - self.skip_char()?; + self.skip_char(c); return Ok(Token::CloseCurly); } if c == '"' { - let s = self.char_code_list_token()?; + let s = self.char_code_list_token(c)?; + let atom = self.machine_st.atom_tbl.build_with(&s); - if let DoubleQuotes::Atom = self.flags.double_quotes { - let s = clause_name!(s, self.atom_tbl); - return Ok(Token::Constant(Constant::Atom(s, None))); + return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes { + Ok(Token::Literal(Literal::Atom(atom))) } else { - let s = Rc::new(s); - return Ok(Token::Constant(Constant::String(s))); - } + Ok(Token::Literal(Literal::String(atom))) + }; } self.name_token(c) diff --git a/crates/prolog_parser/src/macros.rs b/src/parser/macros.rs similarity index 100% rename from crates/prolog_parser/src/macros.rs rename to src/parser/macros.rs index f8ec9072d..6e37f3204 100644 --- a/crates/prolog_parser/src/macros.rs +++ b/src/parser/macros.rs @@ -54,9 +54,9 @@ macro_rules! back_quote_char { } #[macro_export] -macro_rules! binary_digit_char { +macro_rules! octet_char { ($c: expr) => { - $c >= '0' && $c <= '1' + ('\u{0000}'..='\u{00FF}').contains(&$c) }; } @@ -172,9 +172,9 @@ macro_rules! octal_digit_char { } #[macro_export] -macro_rules! octet_char { +macro_rules! binary_digit_char { ($c: expr) => { - ('\u{0000}'..='\u{00FF}').contains(&$c) + $c >= '0' && $c <= '1' }; } diff --git a/crates/prolog_parser/src/lib.rs b/src/parser/mod.rs similarity index 57% rename from crates/prolog_parser/src/lib.rs rename to src/parser/mod.rs index 2c37cea68..8835c9efc 100644 --- a/crates/prolog_parser/src/lib.rs +++ b/src/parser/mod.rs @@ -1,15 +1,17 @@ #[cfg(feature = "num-rug-adapter")] use num_rug_adapter as rug; #[cfg(feature = "rug")] -use rug; +pub use rug; -#[macro_use] -pub mod tabled_rc; +// #[macro_use] +// extern crate lazy_static; +// #[macro_use] +// extern crate static_assertions; + +pub mod char_reader; #[macro_use] pub mod ast; #[macro_use] pub mod macros; -pub mod parser; -pub mod put_back_n; - pub mod lexer; +pub mod parser; diff --git a/crates/prolog_parser/src/parser.rs b/src/parser/parser.rs similarity index 68% rename from crates/prolog_parser/src/parser.rs rename to src/parser/parser.rs index 43ee244cd..2d6334c00 100644 --- a/crates/prolog_parser/src/parser.rs +++ b/src/parser/parser.rs @@ -1,14 +1,15 @@ -use crate::ast::*; -use crate::lexer::*; -use crate::tabled_rc::*; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::char_reader::*; +use crate::parser::lexer::*; use ordered_float::OrderedFloat; -use crate::rug::ops::NegAssign; +use rug::ops::NegAssign; use std::cell::Cell; -use std::io::Read; -use std::mem::swap; +use std::mem; use std::rc::Rc; #[derive(Debug, Clone, Copy, PartialEq)] @@ -50,69 +51,114 @@ struct TokenDesc { spec: u32, } -pub fn get_clause_spec( - name: ClauseName, - arity: usize, - op_dir: &CompositeOpDir, -) -> Option { - match arity { - 1 => { - /* This is a clause with an operator principal functor. Prefix operators - are supposed over post. - */ - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { - return Some(cell.clone()); +fn is_partial_string( + head: Term, + mut tail: Term, + atom_tbl: &mut AtomTable, +) -> Result<(Atom, Option>), Term> { + let mut string = match &head { + Term::Literal(_, Literal::Atom(atom)) => { + if let Some(c) = atom.as_char() { + c.to_string() + } else { + return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); } + } + Term::Literal(_, Literal::Char(c)) => c.to_string(), + _ => { + return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + }; + + let mut orig_tail = Box::new(tail); + let mut tail_ref = &mut orig_tail; + + loop { + match &mut **tail_ref { + Term::Cons(_, prev, succ) => { + match prev.as_ref() { + Term::Literal(_, Literal::Atom(atom)) => { + if let Some(c) = atom.as_char() { + string.push(c); + } else { + return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail)); + } + } + Term::Literal(_, Literal::Char(c)) => { + string.push(*c); + } + _ => { + return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail)); + } + } - if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) { - return Some(cell.clone()); + tail_ref = succ; } - } - 2 => { - if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) { - return Some(cell.clone()); + tail_ref => { + tail = mem::replace(tail_ref, Term::AnonVar); + break; } } - _ => {} - }; + } - None + match &tail { + Term::AnonVar | Term::Var(..) => { + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, Some(Box::new(tail)))) + } + Term::Literal(_, Literal::Atom(atom!("[]"))) => { + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, None)) + } + Term::Literal(_, Literal::String(tail)) => { + string += tail.as_str(); + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, None)) + } + _ => { + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, Some(Box::new(tail)))) + } + } } -pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option { - let mut op_desc = OpDesc { +pub fn get_op_desc( + name: Atom, + op_dir: &CompositeOpDir, +) -> Option { + let mut op_desc = CompositeOpDesc { pre: 0, inf: 0, post: 0, spec: 0, }; - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { + if let Some(cell) = op_dir.get(name, Fixity::Pre) { let (pri, spec) = cell.get(); if pri > 0 { - op_desc.pre = pri; - op_desc.spec |= spec; - } else if name.as_str() == "-" { + op_desc.pre = pri as usize; + op_desc.spec |= spec as u32; + } else if name == atom!("-") { op_desc.spec |= NEGATIVE_SIGN; } } - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Post) { + if let Some(cell) = op_dir.get(name, Fixity::Post) { let (pri, spec) = cell.get(); if pri > 0 { - op_desc.post = pri; - op_desc.spec |= spec; + op_desc.post = pri as usize; + op_desc.spec |= spec as u32; } } - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::In) { + if let Some(cell) = op_dir.get(name, Fixity::In) { let (pri, spec) = cell.get(); if pri > 0 { - op_desc.inf = pri; - op_desc.spec |= spec; + op_desc.inf = pri as usize; + op_desc.spec |= spec as u32; } } @@ -123,6 +169,31 @@ pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option } } +pub fn get_clause_spec(name: Atom, arity: usize, op_dir: &CompositeOpDir) -> Option { + match arity { + 1 => { + /* This is a clause with an operator principal functor. Prefix operators + are supposed over post. + */ + if let Some(cell) = op_dir.get(name, Fixity::Pre) { + return Some(cell); + } + + if let Some(cell) = op_dir.get(name, Fixity::Post) { + return Some(cell); + } + } + 2 => { + if let Some(cell) = op_dir.get(name, Fixity::In) { + return Some(cell); + } + } + _ => {} + }; + + None +} + fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { d2.priority <= priority && is_term!(d3.spec) @@ -164,23 +235,8 @@ fn affirm_fx(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool { d2.priority <= priority && is_term!(d1.spec) && d1.priority < d2.priority } -fn sep_to_atom(tt: TokenType) -> Option { - match tt { - TokenType::Open | TokenType::OpenCT => Some(clause_name!("(")), - TokenType::Close => Some(clause_name!(")")), - TokenType::OpenList => Some(clause_name!("[")), - TokenType::CloseList => Some(clause_name!("]")), - TokenType::OpenCurly => Some(clause_name!("{")), - TokenType::CloseCurly => Some(clause_name!("}")), - TokenType::HeadTailSeparator => Some(clause_name!("|")), - TokenType::Comma => Some(clause_name!(",")), - TokenType::End => Some(clause_name!(".")), - _ => None, - } -} - #[derive(Debug, Clone, Copy)] -pub struct OpDesc { +pub struct CompositeOpDesc { pub pre: usize, pub inf: usize, pub post: usize, @@ -188,14 +244,14 @@ pub struct OpDesc { } #[derive(Debug)] -pub struct Parser<'a, R: Read> { - lexer: Lexer<'a, R>, +pub struct Parser<'a, R> { + pub lexer: Lexer<'a, R>, tokens: Vec, stack: Vec, terms: Vec, } -fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { +fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { let mut tokens = vec![]; loop { @@ -209,7 +265,10 @@ fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> } } Err(ParserError::UnexpectedEOF) if !tokens.is_empty() => { - return Err(ParserError::IncompleteReduction(lexer.line_num, lexer.col_num)); + return Err(ParserError::IncompleteReduction( + lexer.line_num, + lexer.col_num, + )); } Err(e) => { return Err(e); @@ -222,20 +281,46 @@ fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> Ok(tokens) } -impl<'a, R: Read> Parser<'a, R> { - pub fn new( - stream: &'a mut ParsingStream, - atom_tbl: TabledData, - flags: MachineFlags, - ) -> Self { +fn atomize_term(atom_tbl: &mut AtomTable, term: &Term) -> Option { + match term { + Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c), + _ => None, + } +} + +fn atomize_constant(atom_tbl: &mut AtomTable, c: Literal) -> Option { + match c { + Literal::Atom(ref name) => Some(*name), + Literal::Char(c) => Some(atom_tbl.build_with(&c.to_string())), + _ => None, + } +} + +impl<'a, R: CharRead> Parser<'a, R> { + pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self { Parser { - lexer: Lexer::new(atom_tbl, flags, stream), + lexer: Lexer::new(stream, machine_st), tokens: vec![], stack: Vec::new(), terms: Vec::new(), } } + fn sep_to_atom(&mut self, tt: TokenType) -> Option { + match tt { + TokenType::Open | TokenType::OpenCT => Some(atom!("(")), + TokenType::Close => Some(atom!(")")), + TokenType::OpenList => Some(atom!("[")), + TokenType::CloseList => Some(atom!("]")), + TokenType::OpenCurly => Some(atom!("{")), + TokenType::CloseCurly => Some(atom!("}")), + TokenType::HeadTailSeparator => Some(atom!("|")), + TokenType::Comma => Some(atom!(",")), + TokenType::End => Some(atom!(".")), + _ => None, + } + } + #[inline] pub fn line_num(&self) -> usize { self.lexer.line_num @@ -246,25 +331,12 @@ impl<'a, R: Read> Parser<'a, R> { self.lexer.col_num } - #[inline] - pub fn get_atom_tbl(&self) -> TabledData { - self.lexer.atom_tbl.clone() - } - - #[inline] - pub fn set_atom_tbl(&mut self, atom_tbl: TabledData) { - self.lexer.atom_tbl = atom_tbl; - } - - fn get_term_name(&mut self, td: TokenDesc) -> Option<(ClauseName, Option)> { + fn get_term_name(&mut self, td: TokenDesc) -> Option { match td.tt { - TokenType::HeadTailSeparator => Some(( - clause_name!("|"), - Some(SharedOpDesc::new(td.priority, td.spec)), - )), - TokenType::Comma => Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))), + TokenType::HeadTailSeparator => Some(atom!("|")), + TokenType::Comma => Some(atom!(",")), TokenType::Term => match self.terms.pop() { - Some(Term::Constant(_, Constant::Atom(atom, spec))) => Some((atom, spec)), + Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom), Some(term) => { self.terms.push(term); None @@ -277,14 +349,9 @@ impl<'a, R: Read> Parser<'a, R> { fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) { if let Some(arg2) = self.terms.pop() { - if let Some((name, shared_op_desc)) = self.get_term_name(td) { + if let Some(name) = self.get_term_name(td) { if let Some(arg1) = self.terms.pop() { - let term = Term::Clause( - Cell::default(), - name, - vec![Box::new(arg1), Box::new(arg2)], - shared_op_desc, - ); + let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]); self.terms.push(term); self.stack.push(TokenDesc { @@ -301,12 +368,11 @@ impl<'a, R: Read> Parser<'a, R> { if let Some(mut arg1) = self.terms.pop() { if let Some(mut name) = self.terms.pop() { if is_postfix!(assoc) { - swap(&mut arg1, &mut name); + mem::swap(&mut arg1, &mut name); } - if let Term::Constant(_, Constant::Atom(name, shared_op_desc)) = name { - let term = - Term::Clause(Cell::default(), name, vec![Box::new(arg1)], shared_op_desc); + if let Term::Literal(_, Literal::Atom(name)) = name { + let term = Term::Clause(Cell::default(), name, vec![arg1]); self.terms.push(term); self.stack.push(TokenDesc { @@ -319,17 +385,8 @@ impl<'a, R: Read> Parser<'a, R> { } } - fn promote_atom_op( - &mut self, - atom: ClauseName, - priority: usize, - assoc: u32, - op_dir_val: Option<&OpDirValue>, - ) { - let spec = op_dir_val.map(|op_dir_val| op_dir_val.shared_op_desc()); - - self.terms - .push(Term::Constant(Cell::default(), Constant::Atom(atom, spec))); + fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { + self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom))); self.stack.push(TokenDesc { tt: TokenType::Term, priority, @@ -339,15 +396,15 @@ impl<'a, R: Read> Parser<'a, R> { fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { let tt = match token { - Token::Constant(Constant::String(s)) if self.lexer.flags.double_quotes.is_codes() => { - let mut list = Term::Constant(Cell::default(), Constant::EmptyList); + Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_codes() => { + let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); - for c in s.chars().rev() { + for c in s.as_str().chars().rev() { list = Term::Cons( Cell::default(), - Box::new(Term::Constant( + Box::new(Term::Literal( Cell::default(), - Constant::Fixnum(c as isize), + Literal::Fixnum(Fixnum::build_with(c as i64)), )), Box::new(list), ); @@ -356,15 +413,19 @@ impl<'a, R: Read> Parser<'a, R> { self.terms.push(list); TokenType::Term } - Token::Constant(c) => { - self.terms.push(Term::Constant(Cell::default(), c)); + Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => { + self.terms.push(Term::PartialString(Cell::default(), s, None)); + TokenType::Term + } + Token::Literal(c) => { + self.terms.push(Term::Literal(Cell::default(), c)); TokenType::Term } Token::Var(v) => { if v.trim() == "_" { self.terms.push(Term::AnonVar); } else { - self.terms.push(Term::Var(Cell::default(), v)); + self.terms.push(Term::Var(Cell::default(), Rc::new(v))); } TokenType::Term @@ -457,7 +518,7 @@ impl<'a, R: Read> Parser<'a, R> { None } - fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool { + fn reduce_term(&mut self) -> bool { if self.stack.is_empty() { return false; } @@ -489,22 +550,40 @@ impl<'a, R: Read> Parser<'a, R> { let idx = self.terms.len() - arity; if TokenType::Term == self.stack[stack_len].tt { - if self.atomize_term(&self.terms[idx - 1]).is_some() { + if atomize_term(&mut self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some() { self.stack.truncate(stack_len + 1); - let mut subterms: Vec<_> = self.terms.drain(idx..).map(Box::new).collect(); + let mut subterms: Vec<_> = self.terms.drain(idx..).collect(); - if let Some(name) = self.terms.pop().and_then(|t| self.atomize_term(&t)) { + if let Some(name) = self + .terms + .pop() + .and_then(|t| atomize_term(&mut self.lexer.machine_st.atom_tbl, &t)) + { // reduce the '.' functor to a cons cell if it applies. - if name.as_str() == "." && subterms.len() == 2 { + if name == atom!(".") && subterms.len() == 2 { let tail = subterms.pop().unwrap(); let head = subterms.pop().unwrap(); - self.terms.push(Term::Cons(Cell::default(), head, tail)); + self.terms.push( + match is_partial_string(head, tail, &mut self.lexer.machine_st.atom_tbl) { + Ok((string_buf, tail_opt)) => { + Term::PartialString(Cell::default(), string_buf, tail_opt) + } + Err(term) => term, + }, + ); + + /* + self.terms.push(Term::Cons( + Cell::default(), + Box::new(head), + Box::new(tail), + )); + */ } else { - let spec = get_clause_spec(name.clone(), subterms.len(), op_dir); self.terms - .push(Term::Clause(Cell::default(), name, subterms, spec)); + .push(Term::Clause(Cell::default(), name, subterms)); } if let Some(&mut TokenDesc { @@ -544,8 +623,8 @@ impl<'a, R: Read> Parser<'a, R> { * an operator, so expand the * terms it compacted out again. */ match (term.name(), term.arity()) { - (Some(name), 2) if name.as_str() == "," => { - let terms = unfold_by_str(term, ","); + (Some(name), 2) if name == atom!(",") => { + let terms = unfold_by_str(term, name); // notice: name == "," here. let arity = terms.len() - 1; self.terms.extend(terms.into_iter()); @@ -603,8 +682,7 @@ impl<'a, R: Read> Parser<'a, R> { td.tt = TokenType::Term; td.priority = 0; - self.terms - .push(Term::Constant(Cell::default(), Constant::EmptyList)); + self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))); return Ok(true); } } @@ -621,7 +699,7 @@ impl<'a, R: Read> Parser<'a, R> { let list_len = self.stack.len() - 2 * arity; let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { - Term::Constant(Cell::default(), Constant::EmptyList) + Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))) } else { let term = match self.terms.pop() { Some(term) => term, @@ -662,7 +740,18 @@ impl<'a, R: Read> Parser<'a, R> { priority: 0, spec: TERM, }); - self.terms.push(list); + + self.terms.push(match list { + Term::Cons(_, head, tail) => { + match is_partial_string(*head, *tail, &mut self.lexer.machine_st.atom_tbl) { + Ok((string_buf, tail_opt)) => { + Term::PartialString(Cell::default(), string_buf, tail_opt) + } + Err(term) => term, + } + } + term => term, + }); Ok(true) } @@ -678,7 +767,11 @@ impl<'a, R: Read> Parser<'a, R> { td.priority = 0; td.spec = TERM; - let term = Term::Constant(Cell::default(), atom!("{}", self.lexer.atom_tbl)); + let term = Term::Literal( + Cell::default(), + Literal::Atom(atom!("{}")), + ); + self.terms.push(term); return Ok(true); } @@ -710,9 +803,8 @@ impl<'a, R: Read> Parser<'a, R> { self.terms.push(Term::Clause( Cell::default(), - clause_name!("{}"), - vec![Box::new(term)], - None, + atom!("{}"), + vec![term], )); return Ok(true); @@ -744,27 +836,28 @@ impl<'a, R: Read> Parser<'a, R> { return false; } - if let Some(atom) = sep_to_atom(self.stack[idx].tt) { + if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) { self.terms - .push(Term::Constant(Cell::default(), Constant::Atom(atom, None))); + .push(Term::Literal(Cell::default(), Literal::Atom(atom))); } self.stack[idx].spec = TERM; self.stack[idx].tt = TokenType::Term; self.stack[idx].priority = 0; + true } _ => false, } } - fn shift_op(&mut self, name: ClauseName, op_dir: &CompositeOpDir) -> Result { - if let Some(OpDesc { + fn shift_op(&mut self, name: Atom, op_dir: &CompositeOpDir) -> Result { + if let Some(CompositeOpDesc { pre, inf, post, spec, - }) = get_op_desc(name.clone(), op_dir) + }) = get_op_desc(name, op_dir) { if (pre > 0 && inf + post > 0) || is_negate!(spec) { match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? { @@ -775,15 +868,9 @@ impl<'a, R: Read> Parser<'a, R> { // or post == 0. self.reduce_op(inf + post); - let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; - let op_dir_val = op_dir.get(name.clone(), fixity); + // let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; - self.promote_atom_op( - name, - inf + post, - spec & (XFX | XFY | YFX | YF | XF), - op_dir_val, - ); + self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF)); } _ => { self.reduce_op(inf + post); @@ -791,49 +878,22 @@ impl<'a, R: Read> Parser<'a, R> { if let Some(TokenDesc { spec: pspec, .. }) = self.stack.last().cloned() { // rterm.c: 412 if is_term!(pspec) { - let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; - let op_dir_val = op_dir.get(name.clone(), fixity); - self.promote_atom_op( name, inf + post, spec & (XFX | XFY | YFX | XF | YF), - op_dir_val, ); } else { - let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); - self.promote_atom_op( - name, - pre, - spec & (FX | FY | NEGATIVE_SIGN), - op_dir_val, - ); + self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN)); } } else { - let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); - self.promote_atom_op( - name, - pre, - spec & (FX | FY | NEGATIVE_SIGN), - op_dir_val, - ); + self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN)); } } } } else { - let op_dir_val = op_dir.get( - name.clone(), - if pre + inf == 0 { - Fixity::Post - } else if post + pre == 0 { - Fixity::In - } else { - Fixity::Pre - }, - ); - self.reduce_op(pre + inf + post); // only one non-zero priority among these. - self.promote_atom_op(name, pre + inf + post, spec, op_dir_val); + self.promote_atom_op(name, pre + inf + post, spec); } Ok(true) @@ -843,38 +903,23 @@ impl<'a, R: Read> Parser<'a, R> { } } - fn atomize_term(&self, term: &Term) -> Option { - match term { - Term::Constant(_, ref c) => self.atomize_constant(c), - _ => None, - } - } - - fn atomize_constant(&self, c: &Constant) -> Option { - match c { - Constant::Atom(ref name, _) => Some(name.clone()), - Constant::Char(c) => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), - Constant::EmptyList => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), - _ => None, - } - } - - fn negate_number(&mut self, n: N, negator: Negator, constr: ToConstant) + fn negate_number(&mut self, n: N, negator: Negator, constr: ToLiteral) where Negator: Fn(N) -> N, - ToConstant: Fn(N) -> Constant, + ToLiteral: Fn(N, &mut Arena) -> Literal, { if let Some(desc) = self.stack.last().cloned() { if let Some(term) = self.terms.last().cloned() { match term { - Term::Constant(_, Constant::Atom(ref name, _)) - if name.as_str() == "-" - && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => + Term::Literal(_, Literal::Atom(name)) + if name == atom!("-") && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => { self.stack.pop(); self.terms.pop(); - self.shift(Token::Constant(constr(negator(n))), 0, TERM); + let literal = constr(negator(n), &mut self.lexer.machine_st.arena); + self.shift(Token::Literal(literal), 0, TERM); + return; } _ => {} @@ -882,43 +927,45 @@ impl<'a, R: Read> Parser<'a, R> { } } - self.shift(Token::Constant(constr(n)), 0, TERM); + let literal = constr(n, &mut self.lexer.machine_st.arena); + self.shift(Token::Literal(literal), 0, TERM); } fn shift_token(&mut self, token: Token, op_dir: &CompositeOpDir) -> Result<(), ParserError> { - fn negate_rc(mut t: Rc) -> Rc { - if let Some(t) = Rc::get_mut(&mut t) { - t.neg_assign(); - }; - + fn negate_rc(mut t: TypedArenaPtr) -> TypedArenaPtr { + (&mut t).neg_assign(); t } match token { - Token::Constant(Constant::Fixnum(n)) => self.negate_number(n, |n| -n, Constant::Fixnum), - Token::Constant(Constant::Integer(n)) => { - self.negate_number(n, negate_rc, Constant::Integer) + Token::Literal(Literal::Fixnum(n)) => { + self.negate_number(n, |n| -n, |n, _| Literal::Fixnum(n)) } - Token::Constant(Constant::Rational(n)) => { - self.negate_number(n, negate_rc, Constant::Rational) + Token::Literal(Literal::Integer(n)) => { + self.negate_number(n, negate_rc, |n, _| Literal::Integer(n)) } - Token::Constant(Constant::Float(n)) => { - self.negate_number(n, |n| OrderedFloat(-n.into_inner()), Constant::Float) + Token::Literal(Literal::Rational(n)) => { + self.negate_number(n, negate_rc, |r, _| Literal::Rational(r)) } - Token::Constant(c) => { - if let Some(name) = self.atomize_constant(&c) { + Token::Literal(Literal::Float(n)) => self.negate_number( + **n, + |n| OrderedFloat(-n.into_inner()), + |n, arena| Literal::Float(arena_alloc!(n, arena)), + ), + Token::Literal(c) => { + if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, c) { if !self.shift_op(name, op_dir)? { - self.shift(Token::Constant(c), 0, TERM); + self.shift(Token::Literal(c), 0, TERM); } } else { - self.shift(Token::Constant(c), 0, TERM); + self.shift(Token::Literal(c), 0, TERM); } } Token::Var(v) => self.shift(Token::Var(v), 0, TERM), Token::Open => self.shift(Token::Open, 1300, DELIMITER), Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER), Token::Close => { - if !self.reduce_term(op_dir) { + if !self.reduce_term() { if !self.reduce_brackets() { return Err(ParserError::IncompleteReduction( self.lexer.line_num, @@ -949,8 +996,10 @@ impl<'a, R: Read> Parser<'a, R> { /* '|' as an operator must have priority > 1000 and can only be infix. * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78 */ - let (priority, spec) = get_op_desc(clause_name!("|"), op_dir) - .map(|OpDesc { inf, spec, .. }| (inf, spec)) + let bar_atom = atom!("|"); + + let (priority, spec) = get_op_desc(bar_atom, op_dir) + .map(|CompositeOpDesc { inf, spec, .. }| (inf, spec)) .unwrap_or((1000, DELIMITER)); self.reduce_op(priority); @@ -990,7 +1039,7 @@ impl<'a, R: Read> Parser<'a, R> { } #[inline] - pub fn num_lines_read(&self) -> usize { + pub fn lines_read(&self) -> usize { self.lexer.line_num } diff --git a/src/raw_block.rs b/src/raw_block.rs new file mode 100644 index 000000000..d39c65ca1 --- /dev/null +++ b/src/raw_block.rs @@ -0,0 +1,105 @@ +use core::marker::PhantomData; + +use std::alloc; +use std::ptr; + +pub trait RawBlockTraits { + fn init_size() -> usize; + fn align() -> usize; +} + +#[derive(Debug)] +pub struct RawBlock { + pub base: *const u8, + pub top: *const u8, + pub ptr: *mut u8, + _marker: PhantomData, +} + +impl RawBlock { + #[inline] + fn empty_block() -> Self { + RawBlock { + base: ptr::null(), + top: ptr::null(), + ptr: ptr::null_mut(), + _marker: PhantomData, + } + } + + pub fn new() -> Self { + let mut block = Self::empty_block(); + + unsafe { + block.grow(); + } + + block + } + + unsafe fn init_at_size(&mut self, cap: usize) { + let layout = alloc::Layout::from_size_align_unchecked(cap, T::align()); + + self.base = alloc::alloc(layout) as *const _; + self.top = (self.base as usize + cap) as *const _; + self.ptr = self.base as *mut _; + } + + pub unsafe fn grow(&mut self) { + if self.base.is_null() { + self.init_at_size(T::init_size()); + } else { + let size = self.size(); + let layout = alloc::Layout::from_size_align_unchecked(size, T::align()); + + self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _; + self.top = (self.base as usize + size * 2) as *const _; + self.ptr = (self.base as usize + size) as *mut _; + } + } + + /* + #[inline] + pub fn take(&mut self) -> Self { + mem::replace(self, Self::empty_block()) + } + */ + + #[inline] + pub fn size(&self) -> usize { + self.top as usize - self.base as usize + } + + #[inline(always)] + fn free_space(&self) -> usize { + debug_assert!( + self.ptr as *const _ >= self.base, + "self.ptr = {:?} < {:?} = self.base", + self.ptr, + self.base + ); + + self.top as usize - self.ptr as usize + } + + pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 { + if self.free_space() >= size { + let ptr = self.ptr; + self.ptr = (self.ptr as usize + size) as *mut _; + ptr + } else { + ptr::null_mut() + } + } + + pub fn deallocate(&mut self) { + unsafe { + let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align()); + alloc::dealloc(self.base as *mut _, layout); + + self.top = ptr::null(); + self.base = ptr::null(); + self.ptr = ptr::null_mut(); + } + } +} diff --git a/src/read.rs b/src/read.rs index 366962cb0..b4c4dbcc8 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,254 +1,261 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::*; -use prolog_parser::tabled_rc::TabledData; +use crate::parser::ast::*; +use crate::parser::parser::*; +use crate::arena::*; +use crate::atom_table::*; use crate::forms::*; use crate::iterators::*; +use crate::machine::heap::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::MachineState; -use crate::machine::streams::Stream; +use crate::machine::streams::*; +use crate::parser::char_reader::*; +use crate::types::*; + +use rustyline::error::ReadlineError; +use rustyline::{Cmd, Config, Editor, KeyEvent}; use std::collections::VecDeque; +use std::io::{Cursor, Error, ErrorKind, Read}; type SubtermDeque = VecDeque<(usize, usize)>; -pub(crate) type PrologStream = ParsingStream; +// pub(crate) type PrologStream = ParsingStream; -pub mod readline { - use crate::machine::streams::Stream; - use rustyline::error::ReadlineError; - use rustyline::{Cmd, Config, Editor, KeyEvent}; - use std::io::{Cursor, Error, ErrorKind, Read}; +impl MachineState { + pub(crate) fn devour_whitespace( + &mut self, + mut inner: Stream, + ) -> Result { + let mut parser = Parser::new(inner, self); - static mut PROMPT: bool = false; + parser.devour_whitespace()?; + inner.add_lines_read(parser.lines_read()); - const HISTORY_FILE: &'static str = ".scryer_history"; + parser.eof() + } - pub(crate) fn set_prompt(value: bool) { - unsafe { - PROMPT = value; - } + pub(crate) fn read( + &mut self, + mut inner: Stream, + op_dir: &OpDir, + ) -> Result { + let (term, num_lines_read) = { + let prior_num_lines_read = inner.lines_read(); + let mut parser = Parser::new(inner, self); + + parser.add_lines_read(prior_num_lines_read); + + let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?; + (term, parser.lines_read() - prior_num_lines_read) + }; + + inner.add_lines_read(num_lines_read); + Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl)) } +} - #[inline] - fn get_prompt() -> &'static str { - unsafe { - if PROMPT { - "?- " - } else { - "" - } - } +static mut PROMPT: bool = false; + +const HISTORY_FILE: &'static str = ".scryer_history"; + +pub(crate) fn set_prompt(value: bool) { + unsafe { + PROMPT = value; } +} - #[derive(Debug)] - pub struct ReadlineStream { - rl: Editor<()>, - pending_input: Cursor, +#[inline] +fn get_prompt() -> &'static str { + unsafe { + if PROMPT { + "?- " + } else { + "" + } } +} - impl ReadlineStream { - #[inline] - pub(crate) fn new(pending_input: String) -> Self { - let config = Config::builder().check_cursor_position(true).build(); - - let mut rl = Editor::<()>::with_config(config); //Editor::<()>::new(); - if let Some(mut path) = dirs_next::home_dir() { - path.push(HISTORY_FILE); - if path.exists() { - if rl.load_history(&path).is_err() { - println!("Warning: loading history failed"); - } - } - } +#[inline] +pub fn input_stream(arena: &mut Arena) -> Stream { + let input_stream = ReadlineStream::new(""); + Stream::from_readline_stream(input_stream, arena) +} + +#[derive(Debug)] +pub struct ReadlineStream { + rl: Editor<()>, + pending_input: Cursor, +} - rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string())); - ReadlineStream { - rl, - pending_input: Cursor::new(pending_input), +impl ReadlineStream { + #[inline] + pub fn new(pending_input: &str) -> Self { + let config = Config::builder().check_cursor_position(true).build(); + let mut rl = Editor::<()>::with_config(config); + + if let Some(mut path) = dirs_next::home_dir() { + path.push(HISTORY_FILE); + if path.exists() && rl.load_history(&path).is_err() { + println!("Warning: loading history failed"); } } - #[inline] - pub(crate) fn input_stream(pending_input: String) -> Stream { - Stream::from(Self::new(pending_input)) + rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string())); + + ReadlineStream { + rl, + pending_input: Cursor::new(pending_input.to_owned()), } + } - fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result { - match self.rl.readline(get_prompt()) { - Ok(text) => { - *self.pending_input.get_mut() = text; - self.pending_input.set_position(0); - - unsafe { - if PROMPT { - self.rl.history_mut().add(self.pending_input.get_ref()); - self.save_history(); - PROMPT = false; - } + fn call_readline(&mut self) -> std::io::Result { + match self.rl.readline(get_prompt()) { + Ok(text) => { + *self.pending_input.get_mut() = text; + self.pending_input.set_position(0); + + unsafe { + if PROMPT { + self.rl.history_mut().add(self.pending_input.get_ref()); + self.save_history(); + PROMPT = false; } + } - if self.pending_input.get_ref().chars().last() != Some('\n') { - *self.pending_input.get_mut() += "\n"; - } + if self.pending_input.get_ref().chars().last() != Some('\n') { + *self.pending_input.get_mut() += "\n"; + } + + Ok(self.pending_input.get_ref().len()) + } + Err(ReadlineError::Eof) => Ok(0), + Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)), + } + } - self.pending_input.read(buf) + fn save_history(&mut self) { + if let Some(mut path) = dirs_next::home_dir() { + path.push(HISTORY_FILE); + if path.exists() { + if self.rl.append_history(&path).is_err() { + println!("Warning: couldn't append history (existing file)"); } - Err(ReadlineError::Eof) => Ok(0), - Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)), + } else if self.rl.save_history(&path).is_err() { + println!("Warning: couldn't save history (new file)"); } } + } - fn save_history(&mut self) { - if let Some(mut path) = dirs_next::home_dir() { - path.push(HISTORY_FILE); - if path.exists() { - if self.rl.append_history(&path).is_err() { - println!("Warning: couldn't append history (existing file)"); + pub(crate) fn peek_byte(&mut self) -> std::io::Result { + loop { + match self.pending_input.get_ref().bytes().next() { + Some(0) => { + return Ok(0); + } + Some(b) => { + return Ok(b); + } + None => match self.call_readline() { + Err(e) => { + return Err(e); } - } else { - if self.rl.save_history(&path).is_err() { - println!("Warning: couldn't save history (new file)"); + Ok(0) => { + self.pending_input.get_mut().push('\u{0}'); + return Ok(0); } - } + _ => { + set_prompt(false); + } + }, } } + } +} - pub(crate) fn peek_byte(&mut self) -> std::io::Result { - set_prompt(false); - - loop { - match self.pending_input.get_ref().bytes().next() { - Some(b) => { - return Ok(b); - } - None => match self.call_readline(&mut []) { - Err(e) => { - return Err(e); - } - Ok(0) => { - return Err(Error::new(ErrorKind::UnexpectedEof, "end of file")); - } - _ => {} - }, - } +impl Read for ReadlineStream { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + match self.pending_input.read(buf) { + Ok(0) => { + self.call_readline()?; + self.pending_input.read(buf) } + result => result } + } +} - pub(crate) fn peek_char(&mut self) -> std::io::Result { - set_prompt(false); +impl CharRead for ReadlineStream { + fn peek_char(&mut self) -> Option> { + loop { + let pos = self.pending_input.position() as usize; - loop { - match self.pending_input.get_ref().chars().next() { - Some(c) => { - return Ok(c); - } - None => match self.call_readline(&mut []) { + match self.pending_input.get_ref()[pos ..].chars().next() { + Some('\u{0}') => { + return Some(Ok('\u{0}')); + } + Some(c) => { + return Some(Ok(c)); + } + None => { + match self.call_readline() { Err(e) => { - return Err(e); + return Some(Err(e)); } Ok(0) => { - return Err(Error::new(ErrorKind::UnexpectedEof, "end of file")); + self.pending_input.get_mut().push('\u{0}'); + return Some(Ok('\u{0}')); } - _ => {} - }, + _ => { + set_prompt(false); + } + } } } } } - impl Read for ReadlineStream { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - match self.pending_input.read(buf) { - Ok(0) => self.call_readline(buf), - result => result, - } - } + fn consume(&mut self, nread: usize) { + let offset = self.pending_input.position() as usize; + self.pending_input.set_position((offset + nread) as u64); } - #[inline] - pub fn input_stream() -> Stream { - let input_stream = ReadlineStream::input_stream(String::from("")); - Stream::from(input_stream) - } -} - -impl MachineState { - pub(crate) fn devour_whitespace( - &mut self, - mut inner: Stream, - atom_tbl: TabledData, - ) -> Result { - let mut stream = parsing_stream(inner.clone())?; - let mut parser = Parser::new(&mut stream, atom_tbl, self.flags); - - parser.devour_whitespace()?; - - inner.add_lines_read(parser.num_lines_read()); - - let result = parser.eof(); - let buf = stream.take_buf(); - - inner.pause_stream(buf)?; - - result - } - - pub(crate) fn read( - &mut self, - mut inner: Stream, - atom_tbl: TabledData, - op_dir: &OpDir, - ) -> Result { - let mut stream = parsing_stream(inner.clone())?; - - let (term, num_lines_read) = { - let prior_num_lines_read = inner.lines_read(); - let mut parser = Parser::new(&mut stream, atom_tbl, self.flags); - - parser.add_lines_read(prior_num_lines_read); - - let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?; - (term, parser.num_lines_read() - prior_num_lines_read) - }; - - inner.add_lines_read(num_lines_read); - - // 'pausing' the stream saves the pending top buffer - // created by the parsing stream, which was created in this - // scope and is about to be destroyed in it. - - let buf = stream.take_buf(); - inner.pause_stream(buf)?; - - Ok(write_term_to_heap(&term, self)) + fn put_back_char(&mut self, c: char) { + let offset = self.pending_input.position() as usize; + self.pending_input.set_position((offset - c.len_utf8()) as u64); } } #[inline] -pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult { - let term_writer = TermWriter::new(machine_st); +pub(crate) fn write_term_to_heap( + term: &Term, + heap: &mut Heap, + atom_tbl: &mut AtomTable, +) -> TermWriteResult { + let term_writer = TermWriter::new(heap, atom_tbl); term_writer.write_term_to_heap(term) } #[derive(Debug)] -struct TermWriter<'a> { - machine_st: &'a mut MachineState, +struct TermWriter<'a, 'b> { + heap: &'a mut Heap, + atom_tbl: &'b mut AtomTable, queue: SubtermDeque, var_dict: HeapVarDict, } #[derive(Debug)] -pub(crate) struct TermWriteResult { - pub(crate) heap_loc: usize, - pub(crate) var_dict: HeapVarDict, +pub struct TermWriteResult { + pub heap_loc: usize, + pub var_dict: HeapVarDict, } -impl<'a> TermWriter<'a> { +impl<'a, 'b> TermWriter<'a, 'b> { #[inline] - fn new(machine_st: &'a mut MachineState) -> Self { + fn new(heap: &'a mut Heap, atom_tbl: &'b mut AtomTable) -> Self { TermWriter { - machine_st, + heap, + atom_tbl, queue: SubtermDeque::new(), var_dict: HeapVarDict::new(), } @@ -257,7 +264,7 @@ impl<'a> TermWriter<'a> { #[inline] fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) { if let Some((arity, site_h)) = self.queue.pop_front() { - self.machine_st.heap[site_h] = HeapCellValue::Addr(self.term_as_addr(term, h)); + self.heap[site_h] = self.term_as_addr(term, h); if arity > 1 { self.queue.push_front((arity - 1, site_h + 1)); @@ -267,64 +274,82 @@ impl<'a> TermWriter<'a> { #[inline] fn push_stub_addr(&mut self) { - let h = self.machine_st.heap.h(); - self.machine_st - .heap - .push(HeapCellValue::Addr(Addr::HeapCell(h))); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); } - fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr { + fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> HeapCellValue { match term { - &TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h), - &TermRef::Cons(..) => Addr::HeapCell(h), - &TermRef::Constant(_, _, c) => self.machine_st.heap.put_constant(c.clone()), - &TermRef::Clause(..) => Addr::Str(h), - &TermRef::PartialString(..) => Addr::PStrLocation(h, 0), + &TermRef::Cons(..) => list_loc_as_cell!(h), + &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h), + &TermRef::PartialString(_, _, ref src, None) => + if src.as_str().is_empty() { + empty_list_as_cell!() + } else if self.heap[h].get_tag() == HeapCellValueTag::CStr { + heap_loc_as_cell!(h) + } else { + pstr_loc_as_cell!(h) + }, + &TermRef::PartialString(..) => pstr_loc_as_cell!(h), + &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal), + &TermRef::Clause(..) => str_loc_as_cell!(h), } } fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult { - let heap_loc = self.machine_st.heap.h(); + let heap_loc = self.heap.len(); for term in breadth_first_iter(term, true) { - let h = self.machine_st.heap.h(); + let h = self.heap.len(); match &term { - &TermRef::Cons(lvl, ..) => { + &TermRef::Cons(Level::Root, ..) => { self.queue.push_back((2, h + 1)); - self.machine_st - .heap - .push(HeapCellValue::Addr(Addr::Lis(h + 1))); + self.heap.push(list_loc_as_cell!(h + 1)); self.push_stub_addr(); self.push_stub_addr(); - if let Level::Root = lvl { - continue; - } + continue; } - &TermRef::Clause(lvl, _, ref ct, subterms) => { - self.queue.push_back((subterms.len(), h + 1)); - let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec()); + &TermRef::Cons(..) => { + self.queue.push_back((2, h)); + + self.push_stub_addr(); + self.push_stub_addr(); + } + &TermRef::Clause(Level::Root, _, ref ct, subterms) => { + self.heap.push(str_loc_as_cell!(heap_loc + 1)); + + self.queue.push_back((subterms.len(), h + 2)); + let named = atom_as_cell!(ct.name(), subterms.len()); - self.machine_st.heap.push(named); + self.heap.push(named); for _ in 0..subterms.len() { self.push_stub_addr(); } - if let Level::Root = lvl { - continue; + continue; + } + &TermRef::Clause(_, _, ref ct, subterms) => { + self.queue.push_back((subterms.len(), h + 1)); + let named = atom_as_cell!(ct.name(), subterms.len()); + + self.heap.push(named); + + for _ in 0..subterms.len() { + self.push_stub_addr(); } } - &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => { + &TermRef::AnonVar(Level::Root) | &TermRef::Literal(Level::Root, ..) => { let addr = self.term_as_addr(&term, h); - self.machine_st.heap.push(HeapCellValue::Addr(addr)); + self.heap.push(addr); } &TermRef::Var(Level::Root, _, ref var) => { let addr = self.term_as_addr(&term, h); - self.var_dict.insert(var.clone(), Addr::HeapCell(h)); - self.machine_st.heap.push(HeapCellValue::Addr(addr)); + self.var_dict.insert(var.clone(), heap_loc_as_cell!(h)); + self.heap.push(addr); } &TermRef::AnonVar(_) => { if let Some((arity, site_h)) = self.queue.pop_front() { @@ -335,25 +360,28 @@ impl<'a> TermWriter<'a> { continue; } - &TermRef::PartialString(lvl, _, ref pstr, tail) => { + &TermRef::PartialString(lvl, _, ref src, tail) => { if tail.is_some() { - self.machine_st.heap.allocate_pstr(&pstr); + allocate_pstr(self.heap, src.as_str(), self.atom_tbl); } else { - self.machine_st.heap.put_complete_string(&pstr); + put_complete_string(self.heap, src.as_str(), self.atom_tbl); } - if let Level::Root = lvl { - } else if tail.is_some() { - let h = self.machine_st.heap.h(); + if tail.is_some() { + let h = self.heap.len(); self.queue.push_back((1, h - 1)); + + if let Level::Root = lvl { + continue; + } } } &TermRef::Var(_, _, ref var) => { if let Some((arity, site_h)) = self.queue.pop_front() { if let Some(addr) = self.var_dict.get(var).cloned() { - self.machine_st.heap[site_h] = HeapCellValue::Addr(addr); + self.heap[site_h] = addr; } else { - self.var_dict.insert(var.clone(), Addr::HeapCell(site_h)); + self.var_dict.insert(var.clone(), heap_loc_as_cell!(site_h)); } if arity > 1 { diff --git a/src/targets.rs b/src/targets.rs index 78e988e5d..0d4ac6d6e 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -1,37 +1,39 @@ -use prolog_parser::ast::*; +use crate::parser::ast::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; +use crate::types::*; pub(crate) trait CompilationTarget<'a> { type Iterator: Iterator>; - fn iter(_: &'a Term) -> Self::Iterator; + fn iter(term: &'a Term) -> Self::Iterator; - fn to_constant(_: Level, _: Constant, _: RegType) -> Self; - fn to_list(_: Level, _: RegType) -> Self; - fn to_structure(_: ClauseType, _: usize, _: RegType) -> Self; + fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Self; + fn to_list(lvl: Level, r: RegType) -> Self; + fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self; - fn to_void(_: usize) -> Self; + fn to_void(num_subterms: usize) -> Self; fn is_void_instr(&self) -> bool; - fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self; + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self; fn incr_void_instr(&mut self); - fn constant_subterm(_: Constant) -> Self; + fn constant_subterm(literal: Literal) -> Self; - fn argument_to_variable(_: RegType, _: usize) -> Self; - fn argument_to_value(_: RegType, _: usize) -> Self; + fn argument_to_variable(r: RegType, r: usize) -> Self; + fn argument_to_value(r: RegType, val: usize) -> Self; - fn move_to_register(_: RegType, _: usize) -> Self; + fn move_to_register(r: RegType, val: usize) -> Self; - fn subterm_to_variable(_: RegType) -> Self; - fn subterm_to_value(_: RegType) -> Self; + fn subterm_to_variable(r: RegType) -> Self; + fn subterm_to_value(r: RegType) -> Self; - fn clause_arg_to_instr(_: RegType) -> Self; + fn clause_arg_to_instr(r: RegType) -> Self; } impl<'a> CompilationTarget<'a> for FactInstruction { @@ -41,8 +43,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { breadth_first_iter(term, false) // do not iterate over the root clause if one exists. } - fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { - FactInstruction::GetConstant(lvl, constant, reg) + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self { + FactInstruction::GetConstant(lvl, HeapCellValue::from(constant), reg) } fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self { @@ -53,8 +55,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { FactInstruction::GetList(lvl, reg) } - fn to_void(subterms: usize) -> Self { - FactInstruction::UnifyVoid(subterms) + fn to_void(num_subterms: usize) -> Self { + FactInstruction::UnifyVoid(num_subterms) } fn is_void_instr(&self) -> bool { @@ -64,7 +66,7 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } } - fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self { + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self { FactInstruction::GetPartialString(lvl, string, r, has_tail) } @@ -75,8 +77,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } } - fn constant_subterm(constant: Constant) -> Self { - FactInstruction::UnifyConstant(constant) + fn constant_subterm(constant: Literal) -> Self { + FactInstruction::UnifyConstant(HeapCellValue::from(constant)) } fn argument_to_variable(arg: RegType, val: usize) -> Self { @@ -115,15 +117,15 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { QueryInstruction::PutStructure(ct, arity, r) } - fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { - QueryInstruction::PutConstant(lvl, constant, reg) + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self { + QueryInstruction::PutConstant(lvl, HeapCellValue::from(constant), reg) } fn to_list(lvl: Level, reg: RegType) -> Self { QueryInstruction::PutList(lvl, reg) } - fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self { + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self { QueryInstruction::PutPartialString(lvl, string, r, has_tail) } @@ -145,8 +147,8 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { } } - fn constant_subterm(constant: Constant) -> Self { - QueryInstruction::SetConstant(constant) + fn constant_subterm(constant: Literal) -> Self { + QueryInstruction::SetConstant(HeapCellValue::from(constant)) } fn argument_to_variable(arg: RegType, val: usize) -> Self { diff --git a/src/toplevel.pl b/src/toplevel.pl index fdc5c18fc..441d470a0 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -4,6 +4,7 @@ :- use_module(library(charsio)). :- use_module(library(files)). :- use_module(library(iso_ext)). +:- use_module(library(lambda)). :- use_module(library(lists)). :- use_module(library(si)). @@ -17,7 +18,7 @@ append(HomeDir, "/.scryerrc", ScryerrcFile), ( file_exists(ScryerrcFile) -> atom_chars(ScryerrcFileAtom, ScryerrcFile), - catch(consult(ScryerrcFileAtom), E, print_exception(E)) + catch(use_module(ScryerrcFileAtom), E, print_exception(E)) ; true ) ; true @@ -166,7 +167,7 @@ ; Term = end_of_file -> halt ; - submit_query_and_print_results(Term, VarList) + submit_query_and_print_results(Term, VarList) ). @@ -193,10 +194,10 @@ needs_bracketing(Value, Op) :- catch((functor(Value, F, _), - current_op(EqPrec, EqSpec, Op), - current_op(FPrec, _, F)), - _, - false), + current_op(EqPrec, EqSpec, Op), + current_op(FPrec, _, F)), + _, + false), ( EqPrec < FPrec -> true ; FPrec > 0, F == Value, graphic_token_char(F) -> @@ -210,15 +211,15 @@ write_goal(G, VarList, MaxDepth) :- ( G = (Var = Value) -> ( var(Value) -> - select((Var = _), VarList, NewVarList) + select((Var = _), VarList, NewVarList) ; VarList = NewVarList ), write(Var), write(' = '), ( needs_bracketing(Value, (=)) -> - write('('), - write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - write(')') + write('('), + write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), + write(')') ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]) ) ; G == [] -> @@ -229,20 +230,20 @@ write_last_goal(G, VarList, MaxDepth) :- ( G = (Var = Value) -> ( var(Value) -> - select((Var = _), VarList, NewVarList) + select((Var = _), VarList, NewVarList) ; VarList = NewVarList ), write(Var), write(' = '), ( needs_bracketing(Value, (=)) -> - write('('), - write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - write(')') + write('('), + write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), + write(')') ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - ( trailing_period_is_ambiguous(Value) -> - write(' ') - ; true - ) + ( trailing_period_is_ambiguous(Value) -> + write(' ') + ; true + ) ) ; G == [] -> write('true') @@ -272,8 +273,13 @@ ValueChars \== ['.'], graphic_token_char(Char). +term_variables_under_max_depth(Term, MaxDepth, Vars) :- + '$term_variables_under_max_depth'(Term, MaxDepth, Vars). + write_eqs_and_read_input(B, VarList) :- - term_variables(VarList, Vars0), + gather_query_vars(VarList, OrigVars), + % one layer of depth added for (=/2) functor + '$term_variables_under_max_depth'(OrigVars, 22, Vars0), '$term_attributed_variables'(VarList, AttrVars), '$project_atts':project_attributes(Vars0, AttrVars), copy_term(AttrVars, AttrVars, AttrGoals), @@ -281,12 +287,13 @@ append([Vars0, AttrGoalVars, AttrVars], Vars), charsio:extend_var_list(Vars, VarList, NewVarList, fabricated), '$get_b_value'(B0), - gather_query_vars(VarList, OrigVars), gather_equations(NewVarList, OrigVars, Equations), append(Equations, AttrGoals, Goals), - term_variables(Equations, EquationVars), - append([AttrGoalVars, EquationVars], Vars1), - charsio:extend_var_list(Vars1, VarList, NewVarList0, fabricated), + % one layer of depth added for (=/2) functor + maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars), + append([AttrGoalVars | EquationVars], Vars1), + sort(Vars1, Vars2), + charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated), ( bb_get('$first_answer', true) -> write(' '), bb_put('$first_answer', false) @@ -294,11 +301,11 @@ ), ( B0 == B -> ( Goals == [] -> - write('true.'), nl + write('true.'), nl ; loader:thread_goals(Goals, ThreadedGoals, (',')), - write_eq(ThreadedGoals, NewVarList0, 20), - write('.'), - nl + write_eq(ThreadedGoals, NewVarList0, 20), + write('.'), + nl ) ; loader:thread_goals(Goals, ThreadedGoals, (',')), write_eq(ThreadedGoals, NewVarList0, 20), @@ -340,7 +347,7 @@ QueryVars = [Var | QueryVars0], gather_query_vars(Vars, QueryVars0) ; - gather_query_vars(Vars, QueryVars) + gather_query_vars(Vars, QueryVars) ). gather_query_vars([], []). @@ -358,8 +365,8 @@ Vars = [OtherVar = OtherValue | Vars0], select_all(Pairs, Var, Value, Vars0, NewPairs) ; - NewPairs = [OtherVar = OtherValue | NewPairs0], - select_all(Pairs, Var, Value, Vars, NewPairs0) + NewPairs = [OtherVar = OtherValue | NewPairs0], + select_all(Pairs, Var, Value, Vars, NewPairs0) ). gather_equations([], _, []). @@ -370,11 +377,11 @@ append([Var = Value | VarEqs], Goals0, Goals), gather_equations(NewPairs, OrigVarList, Goals0) ; - gather_equations(Pairs, OrigVarList, Goals) + gather_equations(Pairs, OrigVarList, Goals) ) ; - Goals = [Var = Value | Goals0], - gather_equations(Pairs, OrigVarList, Goals0) + Goals = [Var = Value | Goals0], + gather_equations(Pairs, OrigVarList, Goals0) ). print_exception(E) :- diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 000000000..57c999ebd --- /dev/null +++ b/src/types.rs @@ -0,0 +1,739 @@ +use crate::arena::*; +use crate::atom_table::*; +use crate::forms::*; +use crate::machine::machine_indices::*; +use crate::machine::partial_string::PartialString; +use crate::parser::ast::Fixnum; + +use modular_bitfield::prelude::*; + +use std::cmp::Ordering; +use std::convert::TryFrom; +use std::fmt; +use std::mem; +use std::ops::{Add, Sub, SubAssign}; + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 6] +pub enum HeapCellValueTag { + // non-constants / tags with adjoining forwarding bits. + Cons = 0b00, + F64 = 0b01, + Str = 0b000010, + Lis = 0b000011, + Var = 0b000110, + StackVar = 0b000111, + AttrVar = 0b010011, + PStrLoc = 0b111111, + PStrOffset = 0b001110, + // constants. + Fixnum = 0b010010, + Char = 0b011011, + Atom = 0b001010, + PStr = 0b001011, + CStr = 0b010110, // a complete string. +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 6] +pub enum HeapCellValueView { + // non-constants / tags with adjoining forwarding bits. + Cons = 0b00, + F64 = 0b01, + Str = 0b000010, + Lis = 0b000011, + Var = 0b000110, + StackVar = 0b000111, + AttrVar = 0b010011, + PStrLoc = 0b111111, + PStrOffset = 0b001110, + // constants. + Fixnum = 0b010010, + Char = 0b011011, + Atom = 0b001010, + PStr = 0b001011, + CStr = 0b010110, + // trail elements. + TrailedHeapVar = 0b011110, + TrailedStackVar = 0b011111, + TrailedAttrVarHeapLink = 0b101110, + TrailedAttrVarListLink = 0b100010, + TrailedAttachedValue = 0b101010, + TrailedBlackboardEntry = 0b100110, + TrailedBlackboardOffset = 0b100111, +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 2] +pub enum ConsPtrMaskTag { + Cons = 0b00, + F64 = 0b01, +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub struct ConsPtr { + ptr: B61, + m: bool, + tag: ConsPtrMaskTag, +} + +impl ConsPtr { + #[inline(always)] + pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self { + ConsPtr::new() + .with_ptr(ptr as *const u8 as u64) + .with_m(false) + .with_tag(tag) + } + + #[inline] + pub fn as_ptr(self) -> *mut u8 { + self.ptr() as *mut _ + } +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug)] +#[bits = 6] +pub(crate) enum RefTag { + HeapCell = 0b0110, + StackCell = 0b111, + AttrVar = 0b10011, +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Ref { + val: B56, + #[allow(unused)] m: bool, + #[allow(unused)] f: bool, + tag: RefTag, +} + +impl Ord for Ref { + fn cmp(&self, rhs: &Ref) -> Ordering { + match self.get_tag() { + RefTag::HeapCell | RefTag::AttrVar => { + match rhs.get_tag() { + RefTag::StackCell => Ordering::Less, + _ => self.get_value().cmp(&rhs.get_value()), + } + } + RefTag::StackCell => { + match rhs.get_tag() { + RefTag::StackCell => + self.get_value().cmp(&rhs.get_value()), + _ => + Ordering::Greater, + } + } + } + } +} + +impl PartialOrd for Ref { + fn partial_cmp(&self, rhs: &Self) -> Option { + Some(self.cmp(rhs)) + } +} + +impl Ref { + #[inline(always)] + pub(crate) fn build_with(tag: RefTag, value: u64) -> Self { + Ref::new().with_tag(tag).with_val(value) + } + + #[inline(always)] + pub(crate) fn get_tag(self) -> RefTag { + self.tag() + } + + #[inline(always)] + pub(crate) fn get_value(self) -> u64 { + self.val() + } + + #[inline(always)] + pub(crate) fn as_heap_cell_value(self) -> HeapCellValue { + HeapCellValue::from_bytes(self.into_bytes()) + } + + #[inline(always)] + pub(crate) fn heap_cell(h: usize) -> Self { + Ref::build_with(RefTag::HeapCell, h as u64) + } + + #[inline(always)] + pub(crate) fn stack_cell(h: usize) -> Self { + Ref::build_with(RefTag::StackCell, h as u64) + } + + #[inline(always)] + pub(crate) fn attr_var(h: usize) -> Self { + Ref::build_with(RefTag::AttrVar, h as u64) + } +} + +#[derive(Debug, Clone, Copy)] +pub enum TrailRef { + Ref(Ref), + AttrVarHeapLink(usize), + AttrVarListLink(usize, usize), + BlackboardEntry(Atom), + BlackboardOffset(Atom, HeapCellValue), // key atom, key value +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 6] +pub(crate) enum TrailEntryTag { + TrailedHeapVar = 0b011110, + TrailedStackVar = 0b011111, + TrailedAttrVar = 0b101110, + TrailedAttrVarHeapLink = 0b100010, + TrailedAttrVarListLink = 0b100011, + TrailedAttachedValue = 0b101010, + TrailedBlackboardEntry = 0b100110, + TrailedBlackboardOffset = 0b100111, +} + +#[bitfield] +#[derive(Copy, Clone, Debug)] +#[repr(u64)] +pub(crate) struct TrailEntry { + val: B56, + #[allow(unused)] f: bool, + #[allow(unused)] m: bool, + #[allow(unused)] tag: TrailEntryTag, +} + +impl TrailEntry { + #[inline(always)] + pub(crate) fn build_with(tag: TrailEntryTag, value: u64) -> Self { + TrailEntry::new() + .with_tag(tag) + .with_m(false) + .with_f(false) + .with_val(value) + } + + #[inline(always)] + pub(crate) fn get_tag(self) -> TrailEntryTag { + match self.tag_or_err() { + Ok(tag) => tag, + Err(_) => TrailEntryTag::TrailedAttachedValue, + } + } + + #[inline] + pub(crate) fn get_value(self) -> u64 { + self.val() + } +} + +#[repr(u64)] +#[bitfield] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct HeapCellValue { + val: B56, + f: bool, + m: bool, + tag: HeapCellValueTag, +} + +impl fmt::Debug for HeapCellValue { + fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result { + match self.get_tag() { + tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => { + let cons_ptr = ConsPtr::from_bytes(self.into_bytes()); + + f.debug_struct("HeapCellValue") + .field("tag", &tag) + .field("ptr", &cons_ptr.ptr()) + .field("m", &cons_ptr.m()) + .finish() + } + HeapCellValueTag::Atom => { + let (name, arity) = cell_as_atom_cell!(self) + .get_name_and_arity(); + + f.debug_struct("HeapCellValue") + .field("tag", &HeapCellValueTag::Atom) + .field("name", &name.as_str()) + .field("arity", &arity) + .field("m", &self.m()) + .field("f", &self.f()) + .finish() + } + HeapCellValueTag::PStr => { + let (name, _) = cell_as_atom_cell!(self) + .get_name_and_arity(); + + f.debug_struct("HeapCellValue") + .field("tag", &HeapCellValueTag::PStr) + .field("contents", &name.as_str()) + .field("m", &self.m()) + .field("f", &self.f()) + .finish() + } + tag => { + f.debug_struct("HeapCellValue") + .field("tag", &tag) + .field("value", &self.get_value()) + .field("m", &self.get_mark_bit()) + .field("f", &self.get_forwarding_bit()) + .finish() + } + } + } +} + +impl From> for HeapCellValue { + #[inline] + fn from(arena_ptr: TypedArenaPtr) -> HeapCellValue { + HeapCellValue::from(arena_ptr.header_ptr() as u64) + } +} + +impl From for HeapCellValue { + #[inline] + fn from(f64_ptr: F64Ptr) -> HeapCellValue { + HeapCellValue::from_bytes( + ConsPtr::from(f64_ptr.as_ptr() as u64) + .with_tag(ConsPtrMaskTag::F64) + .with_m(false) + .into_bytes(), + ) + } +} + +impl From for HeapCellValue { + #[inline(always)] + fn from(cons_ptr: ConsPtr) -> HeapCellValue { + HeapCellValue::from_bytes( + ConsPtr::from(cons_ptr.as_ptr() as u64) + .with_tag(ConsPtrMaskTag::Cons) + .with_m(false) + .into_bytes(), + ) + } +} + +impl<'a> From<(Number, &mut Arena)> for HeapCellValue { + #[inline(always)] + fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue { + match n { + Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)), + Number::Integer(n) => HeapCellValue::from(n), + Number::Rational(n) => HeapCellValue::from(n), + Number::Fixnum(n) => fixnum_as_cell!(n), + } + } +} + +impl HeapCellValue { + #[inline(always)] + pub fn build_with(tag: HeapCellValueTag, value: u64) -> Self { + HeapCellValue::new() + .with_tag(tag) + .with_val(value) + .with_m(false) + .with_f(false) + } + + #[inline] + pub fn is_string_terminator(self, heap: &[HeapCellValue]) -> bool { + read_heap_cell!(self, + (HeapCellValueTag::Atom, (name, arity)) => { + name == atom!("[]") && arity == 0 + } + (HeapCellValueTag::CStr) => { + true + } + (HeapCellValueTag::PStrOffset, pstr_offset) => { + heap[pstr_offset].get_tag() == HeapCellValueTag::CStr + } + _ => { + false + } + ) + } + + #[inline(always)] + pub fn is_forwarded(self) -> bool { + self.get_forwarding_bit().unwrap_or(false) + } + + #[inline] + pub fn is_ref(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::Var | + HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | + HeapCellValueTag::PStrOffset => true, + _ => false, + } + } + + #[inline] + pub fn as_char(self) -> Option { + read_heap_cell!(self, + (HeapCellValueTag::Char, c) => { + Some(c) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity > 0 { + return None; + } + + name.as_char() + } + _ => { + None + } + ) + } + + #[inline] + pub fn is_constant(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | HeapCellValueTag::CStr => { + true + } + HeapCellValueTag::Atom => { + cell_as_atom_cell!(self).get_arity() == 0 + } + _ => { + false + } + } + } + + #[inline(always)] + pub fn is_stack_var(self) -> bool { + self.get_tag() == HeapCellValueTag::StackVar + } + + #[inline] + pub fn is_compound(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Str + | HeapCellValueTag::Lis + | HeapCellValueTag::CStr + | HeapCellValueTag::PStr + | HeapCellValueTag::PStrLoc + | HeapCellValueTag::PStrOffset => { + true + } + HeapCellValueTag::Atom => { + cell_as_atom_cell!(self).get_arity() > 0 + } + _ => { false } + } + } + + #[inline] + pub fn is_var(self) -> bool { + read_heap_cell!(self, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + true + } + _ => { + false + } + ) + } + + #[inline] + pub(crate) fn as_var(self) -> Option { + read_heap_cell!(self, + (HeapCellValueTag::Var, h) => { + Some(Ref::heap_cell(h)) + } + (HeapCellValueTag::AttrVar, h) => { + Some(Ref::attr_var(h)) + } + (HeapCellValueTag::StackVar, s) => { + Some(Ref::stack_cell(s)) + } + _ => { + None + } + ) + } + + #[inline] + pub fn get_value(self) -> usize { + self.val() as usize + } + + #[inline] + pub fn set_value(&mut self, val: usize) { + self.set_val(val as u64); + } + + #[inline] + pub fn get_tag(self) -> HeapCellValueTag { + match self.tag_or_err() { + Ok(tag) => tag, + Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() { + ConsPtrMaskTag::Cons => HeapCellValueTag::Cons, + ConsPtrMaskTag::F64 => HeapCellValueTag::F64, + }, + } + } + + #[inline] + pub fn to_atom(self) -> Option { + match self.tag() { + HeapCellValueTag::Atom => Some(Atom::from((self.val() << 3) as usize)), + _ => None, + } + } + + #[inline] + pub fn to_pstr(self) -> Option { + match self.tag() { + HeapCellValueTag::PStr => { + Some(PartialString::from(Atom::from((self.val() as usize) << 3))) + } + _ => None, + } + } + + #[inline] + pub fn to_fixnum(self) -> Option { + match self.get_tag() { + HeapCellValueTag::Fixnum => Some(Fixnum::from_bytes(self.into_bytes())), + _ => None, + } + } + + #[inline] + pub fn to_untyped_arena_ptr(self) -> Option { + match self.tag() { + HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(self.into_bytes())), + _ => None, + } + } + + #[inline] + pub fn get_forwarding_bit(self) -> Option { + match self.get_tag() { + HeapCellValueTag::Cons // the list of non-forwardable cell tags. + | HeapCellValueTag::F64 + // | HeapCellValueTag::Atom + // | HeapCellValueTag::PStr + | HeapCellValueTag::Fixnum + | HeapCellValueTag::Char => None, + _ => Some(self.f()), + } + } + + #[inline] + pub fn set_forwarding_bit(&mut self, f: bool) { + match self.get_tag() { + HeapCellValueTag::Cons // the list of non-forwardable cell tags. + | HeapCellValueTag::F64 + // | HeapCellValueTag::Atom + // | HeapCellValueTag::PStr + | HeapCellValueTag::Fixnum + | HeapCellValueTag::Char => {} + _ => self.set_f(f), + } + } + + #[inline] + pub fn get_mark_bit(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Cons | HeapCellValueTag::F64 => { + ConsPtr::from_bytes(self.into_bytes()).m() + } + _ => self.m(), + } + } + + #[inline] + pub fn set_mark_bit(&mut self, m: bool) { + match self.get_tag() { + HeapCellValueTag::Cons | HeapCellValueTag::F64 => { + let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m); + *self = HeapCellValue::from_bytes(value.into_bytes()); + } + _ => self.set_m(m), + } + } + + pub fn order_category(self) -> Option { + match Number::try_from(self).ok() { + Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { + Some(TermOrderCategory::Integer) + } + Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), + None => match self.get_tag() { + HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => { + Some(TermOrderCategory::Variable) + } + HeapCellValueTag::Char => Some(TermOrderCategory::Atom), + HeapCellValueTag::Atom => { + Some(if cell_as_atom_cell!(self).get_arity() > 0 { + TermOrderCategory::Compound + } else { + TermOrderCategory::Atom + }) + } + HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | + HeapCellValueTag::CStr | HeapCellValueTag::Str => { + Some(TermOrderCategory::Compound) + } + _ => { + None + } + }, + } + } + + #[inline(always)] + pub fn is_protected(self, e: usize) -> bool { + read_heap_cell!(self, + (HeapCellValueTag::StackVar, s) => { + s < e + } + _ => { + true + } + ) + } +} + +const_assert!(mem::size_of::() == 8); + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub struct UntypedArenaPtr { + ptr: B61, + m: bool, + #[allow(unused)] padding: B2, +} + +const_assert!(mem::size_of::() == 8); + +impl From<*const ArenaHeader> for UntypedArenaPtr { + #[inline] + fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr { + unsafe { mem::transmute(ptr) } + } +} + +impl From for *const ArenaHeader { + #[inline] + fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader { + unsafe { mem::transmute(ptr) } + } +} + +impl UntypedArenaPtr { + #[inline] + pub fn set_mark_bit(&mut self, m: bool) { + self.set_m(m); + } + + #[inline] + pub fn get_ptr(self) -> *const u8 { + self.ptr() as *const u8 + } + + #[inline] + pub fn get_tag(self) -> ArenaHeaderTag { + unsafe { + let header = *(self.ptr() as *const ArenaHeader); + header.get_tag() + } + } + + #[inline] + pub fn payload_offset(self) -> *const u8 { + unsafe { + self.get_ptr() + .offset(mem::size_of::() as isize) + } + } + + #[inline] + pub fn get_mark_bit(self) -> bool { + self.m() + } +} + +impl Add for HeapCellValue { + type Output = HeapCellValue; + + fn add(self, rhs: usize) -> Self::Output { + match self.get_tag() { + tag @ HeapCellValueTag::Str | + tag @ HeapCellValueTag::Lis | + tag @ HeapCellValueTag::PStrOffset | + tag @ HeapCellValueTag::PStrLoc | + tag @ HeapCellValueTag::Var | + tag @ HeapCellValueTag::AttrVar => { + HeapCellValue::build_with(tag, (self.get_value() + rhs) as u64) + } + _ => { + self + } + } + } +} + +impl Sub for HeapCellValue { + type Output = HeapCellValue; + + fn sub(self, rhs: usize) -> Self::Output { + match self.get_tag() { + tag @ HeapCellValueTag::Str | + tag @ HeapCellValueTag::Lis | + tag @ HeapCellValueTag::PStrOffset | + tag @ HeapCellValueTag::PStrLoc | + tag @ HeapCellValueTag::Var | + tag @ HeapCellValueTag::AttrVar => { + HeapCellValue::build_with(tag, (self.get_value() - rhs) as u64) + } + _ => { + self + } + } + } +} + +impl SubAssign for HeapCellValue { + #[inline(always)] + fn sub_assign(&mut self, rhs: usize) { + *self = *self - rhs; + } +} + +impl Sub for HeapCellValue { + type Output = HeapCellValue; + + fn sub(self, rhs: i64) -> Self::Output { + if rhs < 0 { + match self.get_tag() { + tag @ HeapCellValueTag::Str | + tag @ HeapCellValueTag::Lis | + tag @ HeapCellValueTag::PStrOffset | + tag @ HeapCellValueTag::Var | + tag @ HeapCellValueTag::AttrVar => { + HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64) + } + _ => { + self + } + } + } else { + self.sub(rhs as usize) + } + } +} + diff --git a/src/write.rs b/src/write.rs index 1c1fc3dcf..49e8c10bf 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1,10 +1,17 @@ +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; -use crate::indexing::IndexingCodePtr; use crate::instructions::*; use crate::machine::loader::CompilationTarget; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; +use crate::machine::partial_string::*; +use crate::machine::streams::*; +use crate::parser::rug::{Integer, Rational}; +use crate::types::*; + +use ordered_float::OrderedFloat; use std::fmt; @@ -13,7 +20,9 @@ impl fmt::Display for LocalCodePtr { match self { LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p), LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"), - LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i), + LocalCodePtr::IndexingBuf(p, o, i) => { + write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i) + } } } } @@ -21,74 +30,50 @@ impl fmt::Display for LocalCodePtr { impl fmt::Display for REPLCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - REPLCodePtr::AddDiscontiguousPredicate => - write!(f, "REPLCodePtr::AddDiscontiguousPredicate"), - REPLCodePtr::AddDynamicPredicate => - write!(f, "REPLCodePtr::AddDynamicPredicate"), - REPLCodePtr::AddMultifilePredicate => - write!(f, "REPLCodePtr::AddMultifilePredicate"), - REPLCodePtr::AddGoalExpansionClause => - write!(f, "REPLCodePtr::AddGoalExpansionClause"), - REPLCodePtr::AddTermExpansionClause => - write!(f, "REPLCodePtr::AddTermExpansionClause"), - REPLCodePtr::AddInSituFilenameModule => - write!(f, "REPLCodePtr::AddInSituFilenameModule"), - REPLCodePtr::AbolishClause => - write!(f, "REPLCodePtr::AbolishClause"), - REPLCodePtr::Assertz => - write!(f, "REPLCodePtr::Assertz"), - REPLCodePtr::Asserta => - write!(f, "REPLCodePtr::Asserta"), - REPLCodePtr::Retract => - write!(f, "REPLCodePtr::Retract"), - REPLCodePtr::ClauseToEvacuable => - write!(f, "REPLCodePtr::ClauseToEvacuable"), - REPLCodePtr::ScopedClauseToEvacuable => - write!(f, "REPLCodePtr::ScopedClauseToEvacuable"), - REPLCodePtr::ConcludeLoad => - write!(f, "REPLCodePtr::ConcludeLoad"), - REPLCodePtr::DeclareModule => - write!(f, "REPLCodePtr::DeclareModule"), - REPLCodePtr::LoadCompiledLibrary => - write!(f, "REPLCodePtr::LoadCompiledLibrary"), - REPLCodePtr::LoadContextSource => - write!(f, "REPLCodePtr::LoadContextSource"), - REPLCodePtr::LoadContextFile => - write!(f, "REPLCodePtr::LoadContextFile"), - REPLCodePtr::LoadContextDirectory => - write!(f, "REPLCodePtr::LoadContextDirectory"), - REPLCodePtr::LoadContextModule => - write!(f, "REPLCodePtr::LoadContextModule"), - REPLCodePtr::LoadContextStream => - write!(f, "REPLCodePtr::LoadContextStream"), - REPLCodePtr::PopLoadContext => - write!(f, "REPLCodePtr::PopLoadContext"), - REPLCodePtr::PopLoadStatePayload => - write!(f, "REPLCodePtr::PopLoadStatePayload"), - REPLCodePtr::PushLoadContext => - write!(f, "REPLCodePtr::PushLoadContext"), - REPLCodePtr::PushLoadStatePayload => - write!(f, "REPLCodePtr::PushLoadStatePayload"), - REPLCodePtr::UseModule => - write!(f, "REPLCodePtr::UseModule"), - REPLCodePtr::MetaPredicateProperty => - write!(f, "REPLCodePtr::MetaPredicateProperty"), - REPLCodePtr::BuiltInProperty => - write!(f, "REPLCodePtr::BuiltInProperty"), - REPLCodePtr::DynamicProperty => - write!(f, "REPLCodePtr::DynamicProperty"), - REPLCodePtr::MultifileProperty => - write!(f, "REPLCodePtr::MultifileProperty"), - REPLCodePtr::DiscontiguousProperty => - write!(f, "REPLCodePtr::DiscontiguousProperty"), - REPLCodePtr::IsConsistentWithTermQueue => - write!(f, "REPLCodePtr::IsConsistentWithTermQueue"), - REPLCodePtr::FlushTermQueue => - write!(f, "REPLCodePtr::FlushTermQueue"), - REPLCodePtr::RemoveModuleExports => - write!(f, "REPLCodePtr::RemoveModuleExports"), - REPLCodePtr::AddNonCountedBacktracking => - write!(f, "REPLCodePtr::AddNonCountedBacktracking"), + REPLCodePtr::AddDiscontiguousPredicate => { + write!(f, "REPLCodePtr::AddDiscontiguousPredicate") + } + REPLCodePtr::AddDynamicPredicate => write!(f, "REPLCodePtr::AddDynamicPredicate"), + REPLCodePtr::AddMultifilePredicate => write!(f, "REPLCodePtr::AddMultifilePredicate"), + REPLCodePtr::AddGoalExpansionClause => write!(f, "REPLCodePtr::AddGoalExpansionClause"), + REPLCodePtr::AddTermExpansionClause => write!(f, "REPLCodePtr::AddTermExpansionClause"), + REPLCodePtr::AddInSituFilenameModule => { + write!(f, "REPLCodePtr::AddInSituFilenameModule") + } + REPLCodePtr::AbolishClause => write!(f, "REPLCodePtr::AbolishClause"), + REPLCodePtr::Assertz => write!(f, "REPLCodePtr::Assertz"), + REPLCodePtr::Asserta => write!(f, "REPLCodePtr::Asserta"), + REPLCodePtr::Retract => write!(f, "REPLCodePtr::Retract"), + REPLCodePtr::ClauseToEvacuable => write!(f, "REPLCodePtr::ClauseToEvacuable"), + REPLCodePtr::ScopedClauseToEvacuable => { + write!(f, "REPLCodePtr::ScopedClauseToEvacuable") + } + REPLCodePtr::ConcludeLoad => write!(f, "REPLCodePtr::ConcludeLoad"), + REPLCodePtr::DeclareModule => write!(f, "REPLCodePtr::DeclareModule"), + REPLCodePtr::LoadCompiledLibrary => write!(f, "REPLCodePtr::LoadCompiledLibrary"), + REPLCodePtr::LoadContextSource => write!(f, "REPLCodePtr::LoadContextSource"), + REPLCodePtr::LoadContextFile => write!(f, "REPLCodePtr::LoadContextFile"), + REPLCodePtr::LoadContextDirectory => write!(f, "REPLCodePtr::LoadContextDirectory"), + REPLCodePtr::LoadContextModule => write!(f, "REPLCodePtr::LoadContextModule"), + REPLCodePtr::LoadContextStream => write!(f, "REPLCodePtr::LoadContextStream"), + REPLCodePtr::PopLoadContext => write!(f, "REPLCodePtr::PopLoadContext"), + REPLCodePtr::PopLoadStatePayload => write!(f, "REPLCodePtr::PopLoadStatePayload"), + REPLCodePtr::PushLoadContext => write!(f, "REPLCodePtr::PushLoadContext"), + REPLCodePtr::PushLoadStatePayload => write!(f, "REPLCodePtr::PushLoadStatePayload"), + REPLCodePtr::UseModule => write!(f, "REPLCodePtr::UseModule"), + REPLCodePtr::MetaPredicateProperty => write!(f, "REPLCodePtr::MetaPredicateProperty"), + REPLCodePtr::BuiltInProperty => write!(f, "REPLCodePtr::BuiltInProperty"), + REPLCodePtr::DynamicProperty => write!(f, "REPLCodePtr::DynamicProperty"), + REPLCodePtr::MultifileProperty => write!(f, "REPLCodePtr::MultifileProperty"), + REPLCodePtr::DiscontiguousProperty => write!(f, "REPLCodePtr::DiscontiguousProperty"), + REPLCodePtr::IsConsistentWithTermQueue => { + write!(f, "REPLCodePtr::IsConsistentWithTermQueue") + } + REPLCodePtr::FlushTermQueue => write!(f, "REPLCodePtr::FlushTermQueue"), + REPLCodePtr::RemoveModuleExports => write!(f, "REPLCodePtr::RemoveModuleExports"), + REPLCodePtr::AddNonCountedBacktracking => { + write!(f, "REPLCodePtr::AddNonCountedBacktracking") + } } } } @@ -107,7 +92,7 @@ impl fmt::Display for CompilationTarget { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { CompilationTarget::User => write!(f, "user"), - CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name), + CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name.as_str()), } } } @@ -122,11 +107,17 @@ impl fmt::Display for FactInstruction { write!(f, "get_list {}{}", lvl, r.reg_num()) } &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => { - write!(f, "get_partial_string({}, {}, {}, {})", - lvl, s, r, has_tail) + write!( + f, + "get_partial_string({}, {}, {}, {})", + lvl, + s.as_str(), + r, + has_tail + ) } &FactInstruction::GetStructure(ref ct, ref arity, ref r) => { - write!(f, "get_structure {}/{}, {}", ct.name(), arity, r) + write!(f, "get_structure {}/{}, {}", ct.name().as_str(), arity, r) } &FactInstruction::GetValue(ref x, ref a) => { write!(f, "get_value {}, A{}", x, a) @@ -166,11 +157,17 @@ impl fmt::Display for QueryInstruction { write!(f, "put_list {}{}", lvl, r.reg_num()) } &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => { - write!(f, "put_partial_string({}, {}, {}, {})", - lvl, s, r, has_tail) + write!( + f, + "put_partial_string({}, {}, {}, {})", + lvl, + s.as_str(), + r, + has_tail + ) } &QueryInstruction::PutStructure(ref ct, ref arity, ref r) => { - write!(f, "put_structure {}/{}, {}", ct.name(), arity, r) + write!(f, "put_structure {}/{}, {}", ct.name().as_str(), arity, r) } &QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a), &QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a), @@ -214,12 +211,12 @@ impl fmt::Display for ClauseType { &ClauseType::System(SystemClauseType::SetCutPoint(r)) => { write!(f, "$set_cp({})", r) } - &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { + &ClauseType::Named(ref name, _, ref idx) => { let idx = idx.0.get(); - write!(f, "{}/{}", name, idx) + write!(f, "{}/{}", name.as_str(), idx) } ref ct => { - write!(f, "{}", ct.name()) + write!(f, "{}", ct.name().as_str()) } } } @@ -227,6 +224,52 @@ impl fmt::Display for ClauseType { impl fmt::Display for HeapCellValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + read_heap_cell!(*self, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + write!(f, "{}", name.as_str()) + } else { + write!( + f, + "{}/{}", + name.as_str(), + arity + ) + } + } + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + write!( + f, + "pstr ( \"{}\", )", + pstr.as_str_from(0) + ) + } + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::Integer, n) => { + write!(f, "{}", n) + } + (ArenaHeaderTag::Rational, r) => { + write!(f, "{}", r) + } + (ArenaHeaderTag::F64, fl) => { + write!(f, "{}", fl) + } + (ArenaHeaderTag::Stream, stream) => { + write!(f, "$stream({})", stream.as_ptr() as usize) + } + _ => { + write!(f, "") + } + ) + } + _ => { + unreachable!() + } + ) + /* match self { &HeapCellValue::Addr(ref addr) => write!(f, "{}", addr), &HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()), @@ -260,9 +303,11 @@ impl fmt::Display for HeapCellValue { write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap()) } } + */ } } +/* impl fmt::Display for DBRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -273,7 +318,9 @@ impl fmt::Display for DBRef { } } } +*/ +/* impl fmt::Display for Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -296,6 +343,7 @@ impl fmt::Display for Addr { } } } +*/ impl fmt::Display for ControlInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -353,29 +401,45 @@ impl fmt::Display for ChoiceInstruction { &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => { write!(f, "dynamic_else {}, {}, fail({})", offset, d, i) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => { + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Infinity, + NextOrFail::Next(i), + ) => { write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => { - write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i) + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Infinity, + NextOrFail::Fail(i), + ) => { + write!( + f, + "dynamic_internal_else {}, {}, fail({})", + offset, "inf", i + ) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => { + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Finite(d), + NextOrFail::Next(i), + ) => { write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => { + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Finite(d), + NextOrFail::Fail(i), + ) => { write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i) } - &ChoiceInstruction::TryMeElse(offset) => - write!(f, "try_me_else {}", offset), + &ChoiceInstruction::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"), } } } @@ -434,8 +498,8 @@ impl fmt::Display for SessionError { write!( f, "module {} does not contain claimed export {}/{}", - module, - key.0, + module.as_str(), + key.0.as_str(), key.1, ) } @@ -452,12 +516,23 @@ impl fmt::Display for SessionError { write!(f, "queries cannot be defined as facts.") } &SessionError::ModuleCannotImportSelf(ref module_name) => { - write!(f, "modules ({}, in this case) cannot import themselves.", - module_name) + write!( + f, + "modules ({}, in this case) cannot import themselves.", + module_name.as_str() + ) } - &SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => { - write!(f, "module {} does not define {}/{} as multifile or discontiguous.", - compilation_target.module_name(), key.0, key.1) + &SessionError::PredicateNotMultifileOrDiscontiguous( + ref compilation_target, + ref key, + ) => { + write!( + f, + "module {} does not define {}/{} as multifile or discontiguous.", + compilation_target.module_name().as_str(), + key.0.as_str(), + key.1 + ) } } } @@ -466,14 +541,19 @@ impl fmt::Display for SessionError { impl fmt::Display for ExistenceError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &ExistenceError::Module(ref module_name) => { - write!(f, "the module {} does not exist", module_name) + &ExistenceError::Module(module_name) => { + write!(f, "the module {} does not exist", module_name.as_str()) } &ExistenceError::ModuleSource(ref module_source) => { write!(f, "the source/sink {} does not exist", module_source) } - &ExistenceError::Procedure(ref name, arity) => { - write!(f, "the procedure {}/{} does not exist", name, arity) + &ExistenceError::Procedure(name, arity) => { + write!( + f, + "the procedure {}/{} does not exist", + name.as_str(), + arity + ) } &ExistenceError::SourceSink(ref addr) => { write!(f, "the source/sink {} does not exist", addr) @@ -489,10 +569,10 @@ impl fmt::Display for ModuleSource { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &ModuleSource::File(ref file) => { - write!(f, "at the file {}", file) + write!(f, "at the file {}", file.as_str()) } &ModuleSource::Library(ref library) => { - write!(f, "at library({})", library) + write!(f, "at library({})", library.as_str()) } } } @@ -538,7 +618,9 @@ impl fmt::Display for Line { Ok(()) } &Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), - &Line::DynamicIndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), + &Line::DynamicIndexedChoice(ref indexed_choice_instr) => { + write!(f, "{}", indexed_choice_instr) + } &Line::Query(ref query_instr) => write!(f, "{}", query_instr), } } @@ -547,10 +629,10 @@ impl fmt::Display for Line { impl fmt::Display for Number { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &Number::Fixnum(n) => write!(f, "{}", n), - &Number::Float(fl) => write!(f, "{}", fl), - &Number::Integer(ref bi) => write!(f, "{}", bi), - &Number::Rational(ref r) => write!(f, "{}", r), + Number::Float(fl) => write!(f, "{}", fl), + Number::Integer(n) => write!(f, "{}", n), + Number::Rational(r) => write!(f, "{}", r), + Number::Fixnum(n) => write!(f, "{}", n.get_num()), } } } diff --git a/tests/scryer/helper.rs b/tests/scryer/helper.rs index baa057d07..93e7b7ca3 100644 --- a/tests/scryer/helper.rs +++ b/tests/scryer/helper.rs @@ -31,21 +31,23 @@ impl Expectable for &[u8] { pub(crate) fn load_module_test(file: &str, expected: T) { use scryer_prolog::*; - let input = machine::Stream::from(""); - let output = machine::Stream::from(String::new()); - let error = machine::Stream::from(String::new()); + // let input = machine::Stream::from(""); + // let output = machine::Stream::from(String::new()); + // let error = machine::Stream::from(String::new()); - let mut wam = machine::Machine::new(input, output.clone(), error); + let mut wam = machine::Machine::new(); // input, output.clone(), error); + expected.assert_eq(wam.test_load_file(file).as_slice()); - wam.load_file( - file.into(), - machine::Stream::from( - std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), - ), - ); - - let output = output.bytes().unwrap(); - expected.assert_eq(output.as_slice()); + // wam.load_file( + // file.into(), + // machine::Stream::from_owned_string( + // std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), + // &mut wam.machine_st.arena, + // ), + // ); + // + // let output = output.bytes().unwrap(); + // expected.assert_eq(output.as_slice()); } pub const SCRYER_PROLOG: &str = "scryer-prolog";