diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9fa463a4..e35ce825 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,10 +63,11 @@ jobs: # Build and test. - name: Build library - run: cargo rustc --lib --target ${{ matrix.target }} ${{ matrix.args }} --verbose + continue-on-error: ${{ contains(matrix.target,'wasm32') }} # allow wasm builds to fail tests for now + run: cargo build --all-targets --target ${{ matrix.target }} ${{ matrix.args }} --verbose - name: Test continue-on-error: ${{ contains(matrix.target,'wasm32') }} # allow wasm builds to fail tests for now - run: cargo test --target ${{ matrix.target }} ${{ matrix.args }} --all --verbose + run: cargo test --target ${{ matrix.target }} ${{ matrix.args }} --all # On stable rust builds, build a binary and publish as a github actions # artifact. These binaries could be useful for testing the pipeline but diff --git a/Cargo.lock b/Cargo.lock index 122966be..dd6b1d84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,9 +32,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -60,12 +60,54 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "arrayvec" version = "0.5.2" @@ -127,9 +169,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bincode" @@ -163,9 +205,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bitvec" @@ -261,9 +303,9 @@ checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -303,7 +345,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -335,18 +377,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.7" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.7" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstyle", "clap_lex", @@ -369,6 +411,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -380,10 +428,19 @@ dependencies = [ ] [[package]] -name = "core-foundation" -version = "0.9.3" +name = "content_inspector" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -391,9 +448,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpp_demangle" @@ -416,9 +473,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -461,9 +518,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -472,22 +529,20 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" dependencies = [ "cfg-if", ] @@ -551,12 +606,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" dependencies = [ "nix 0.27.1", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -566,10 +621,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "lock_api", "once_cell", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.9", ] [[package]] @@ -593,9 +648,9 @@ checksum = "e183fc153511989674ede304b5592c74683393ca09cf20391898c28d6ba04264" [[package]] name = "dashu-float" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7696675af30ae057b1629d27b153bbafb06461826b7d0ef1858d06b801f355f" +checksum = "a672ddc5e64033c8279692d973a89831eb3c3f0ebb1def47435aee0401b6269d" dependencies = [ "dashu-base", "dashu-int", @@ -723,6 +778,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "either" version = "1.9.0" @@ -752,23 +813,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -783,9 +833,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fd-lock" @@ -795,7 +845,19 @@ checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", "rustix", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] @@ -833,9 +895,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -858,9 +920,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -873,9 +935,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -883,15 +945,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -900,38 +962,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -975,9 +1037,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "js-sys", @@ -988,37 +1050,41 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git-version" -version = "0.3.5" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b0decc02f4636b9ccad390dcbe77b722a77efedfa393caf8379a51d5c61899" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" dependencies = [ "git-version-macro", - "proc-macro-hack", ] [[package]] name = "git-version-macro" -version = "0.3.5" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe69f1cbdb6e28af2bac214e943b99ce8a0a06b447d15d3e61161b0423139f3f" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ - "proc-macro-hack", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.43", ] [[package]] -name = "h2" -version = "0.3.21" +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -1026,7 +1092,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -1047,9 +1113,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "headers" @@ -1057,7 +1123,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "headers-core", "http", @@ -1092,11 +1158,11 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1126,9 +1192,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1137,9 +1203,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1159,10 +1225,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "hyper" -version = "0.14.27" +name = "humantime" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "humantime-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" +dependencies = [ + "humantime", + "serde", +] + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1175,7 +1257,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", @@ -1213,7 +1295,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] @@ -1226,16 +1308,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -1249,9 +1331,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1269,22 +1351,22 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", ] [[package]] name = "inferno" -version = "0.11.17" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50453ec3a6555fad17b1cd1a80d16af5bc7cb35094f64e429fd46549018c6a3" +checksum = "321f0f839cd44a4686e9504b0a62b4d69a50b62072144c71c68f5873c167b8d9" dependencies = [ "ahash", - "indexmap 2.0.1", + "indexmap 2.1.0", "is-terminal", "itoa", "log", @@ -1306,9 +1388,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" @@ -1318,7 +1400,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1332,15 +1414,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -1385,9 +1467,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libffi" @@ -1419,16 +1501,27 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.4.11" +name = "libredox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1486,28 +1579,19 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memmap2" -version = "0.8.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -1548,13 +1632,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1653,11 +1737,17 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "libc", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "ntapi" version = "0.3.7" @@ -1713,18 +1803,18 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -1740,11 +1830,11 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "openssl" -version = "0.10.60" +version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -1761,7 +1851,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] @@ -1772,9 +1862,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.96" +version = "0.9.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" dependencies = [ "cc", "libc", @@ -1784,13 +1874,23 @@ dependencies = [ [[package]] name = "ordered-float" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ "num-traits", ] +[[package]] +name = "os_pipe" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -1809,7 +1909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.9", ] [[package]] @@ -1828,22 +1928,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" @@ -1944,7 +2044,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] @@ -1961,9 +2061,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "plotters" @@ -2086,9 +2186,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -2188,21 +2288,21 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -2214,13 +2314,13 @@ checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6" [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", + "regex-automata 0.4.3", "regex-syntax", ] @@ -2232,9 +2332,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -2243,17 +2343,17 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -2274,6 +2374,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -2303,25 +2404,23 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] [[package]] -name = "ring-wasi" -version = "0.16.25" +name = "ring" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db1418b2535ed5e71a9fc73d3fede8596792fd7cb4b4a0f8ecf412cfddaaedd4" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", "libc", - "once_cell", - "spin 0.5.2", - "untrusted", - "web-sys", - "winapi", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", ] [[package]] @@ -2352,15 +2451,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2370,18 +2469,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", - "ring", + "ring 0.16.20", "sct", "webpki", ] [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] @@ -2396,7 +2495,7 @@ version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "994eca4bca05c87e86e15d90fc7a91d1be64b4482b38cb2d27474568fe7c9db9" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "clipboard-win", "fd-lock", @@ -2415,9 +2514,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -2430,11 +2529,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2497,8 +2596,7 @@ dependencies = [ "ref_thread_local", "regex", "reqwest", - "ring", - "ring-wasi", + "ring 0.17.7", "ripemd160", "roxmltree", "rustyline", @@ -2513,10 +2611,11 @@ dependencies = [ "static_assertions", "strum", "strum_macros", - "syn 2.0.37", + "syn 2.0.43", "to-syn-value", "to-syn-value_derive", "tokio", + "trycmd", "walkdir", "warp", "wasm-bindgen", @@ -2526,12 +2625,12 @@ dependencies = [ [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.7", + "untrusted 0.9.0", ] [[package]] @@ -2570,9 +2669,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -2590,26 +2689,35 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2644,7 +2752,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] @@ -2660,9 +2768,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -2692,6 +2800,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -2722,6 +2836,12 @@ dependencies = [ "libc", ] +[[package]] +name = "similar" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597" + [[package]] name = "siphasher" version = "0.3.11" @@ -2739,28 +2859,49 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] -name = "socket2" -version = "0.4.9" +name = "snapbox" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "c4f1976ee8fd1be27d5f72c98be0aac4397a882a4736935d47418a5fbbd12042" dependencies = [ + "anstream", + "anstyle", + "content_inspector", + "dunce", + "filetime", "libc", - "winapi", + "normalize-line-endings", + "os_pipe", + "similar", + "snapbox-macros", + "tempfile", + "wait-timeout", + "walkdir", + "windows-sys 0.52.0", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1559baff8a696add3322b9be3e940d433e7bb4e38d79017205fd37ff28b28e" +dependencies = [ + "anstream", ] [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2858,9 +2999,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "symbolic-common" -version = "12.6.0" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "405af7bd5edd866cef462e22ef73f11cf9bf506c9d62824fef8364eb69d4d4ad" +checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" dependencies = [ "debugid", "memmap2", @@ -2870,9 +3011,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.6.0" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bcd041ccfb77d9c70639efcd5b804b508ac7a273e9224d227379e225625daf9" +checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -2892,15 +3033,36 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -2909,15 +3071,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2939,22 +3101,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] @@ -2988,7 +3150,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfcc684f2ceaec3b4e8689657c9e0944b07bf5e34563e0bd758c4d42c05c82ed" dependencies = [ - "syn 2.0.37", + "syn 2.0.43", "to-syn-value_derive", ] @@ -3000,37 +3162,37 @@ checksum = "3dfffda778de8443144ff3b042ddf14e8bc5445f0fd9fe937c3d252535dc9212" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] name = "tokio" -version = "1.32.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", "libc", - "mio 0.8.8", + "mio 0.8.10", "num_cpus", "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] [[package]] @@ -3079,9 +3241,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -3091,6 +3253,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -3099,11 +3283,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-core", @@ -3111,18 +3294,34 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "trycmd" +version = "0.14.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed009372a42fb103e6f8767b9222925485e03cca032b700d203e2c5b67bee4fb" +dependencies = [ + "glob", + "humantime", + "humantime-serde", + "rayon", + "serde", + "shlex", + "snapbox", + "toml_edit", +] [[package]] name = "tungstenite" @@ -3160,9 +3359,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -3198,10 +3397,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] -name = "url" -version = "2.4.1" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -3222,9 +3427,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" [[package]] name = "vcpkg" @@ -3306,9 +3511,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3316,24 +3521,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -3343,9 +3548,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3353,28 +3558,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -3382,12 +3587,12 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.1" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring", - "untrusted", + "ring 0.17.7", + "untrusted 0.9.0", ] [[package]] @@ -3422,12 +3627,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3436,7 +3641,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -3445,13 +3659,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -3460,42 +3689,93 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -3503,7 +3783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3528,26 +3808,26 @@ dependencies = [ [[package]] name = "xmlparser" -version = "0.13.5" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" [[package]] name = "zerocopy" -version = "0.7.25" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.25" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.43", ] diff --git a/Cargo.toml b/Cargo.toml index 2b4f103b..62fab35f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ bytes = "1" dashu = "0.4.0" num-order = { version = "1.2.0" } rand = "0.8.5" +ring = { version = "0.17.5", features = ["wasm32_unknown_unknown_js"] } serde_json = "1.0.95" serde = "1.0.159" @@ -83,7 +84,7 @@ ctrlc = { version = "3.2.2", optional = true } rustyline = { version = "12.0.0", optional = true } native-tls = { version = "0.2.4", optional = true } warp = { version = "=0.3.5", features = ["tls"], optional = true } -reqwest = { version = "0.11.18", features = ["blocking"], optional = true } +reqwest = { version = "0.11.18", optional = true } tokio = { version = "1.28.2", features = ["full"] } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -104,12 +105,6 @@ serde-wasm-bindgen = "0.5" web-sys = { version = "0.3", features = ["Document", "Window", "Element", "Performance"] } js-sys = "0.3" -[target.'cfg(target_os = "wasi")'.dependencies] -ring-wasi = { version = "0.16.25" } - -[target.'cfg(not(target_os = "wasi"))'.dependencies] -ring = { version = "0.16.13" } - [dev-dependencies] assert_cmd = "1.0.3" predicates-core = "1.0.2" @@ -117,6 +112,7 @@ maplit = "1.0.2" serial_test = "2.0.0" iai-callgrind = { git = "https://github.com/iai-callgrind/iai-callgrind.git", rev = "c77bc3c83d7f4e976cc42d4597236a8db259e772" } criterion = "0.5.1" +trycmd = "0.14.19" [target.'cfg(not(target_os = "windows"))'.dev-dependencies] pprof = { version = "0.13.0", features = ["criterion", "flamegraph"] } diff --git a/README.md b/README.md index ce8f16bb..10358f21 100644 --- a/README.md +++ b/README.md @@ -316,6 +316,35 @@ To quit Scryer Prolog, use the standard predicate `halt/0`: ?- halt. ``` +### Starting Scryer Prolog + +Scryer Prolog can be started from the command line by specifying +options, files and additional arguments. All components are optional: + +
+scryer-prolog [OPTIONS] [FILES] [-- ARGUMENTS]
+
+ +The supported options are: + +``` + -h, --help Display help message + -v, --version Print version information and exit + -g, --goal GOAL Run the query GOAL after consulting files + -f Fast startup. Do not load initialization file (~/.scryerrc) + --no-add-history Prevent adding input to history file (~/.scryer_history) +``` + +All specified Prolog files are consulted. + +After Prolog files, application-specific arguments can be specified on +the command line. These arguments can be accessed from within Prolog +applications with the predicate `argv/1`, which yields the list +of arguments represented as strings. + +Prolog files can also be turned into *shell scripts* as explained in +https://github.com/mthom/scryer-prolog/issues/2170#issuecomment-1821713993. + ### Dynamic operators Scryer supports dynamic operators. Using the built-in diff --git a/build/instructions_template.rs b/build/instructions_template.rs index db0baae3..1840341b 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -511,18 +511,12 @@ enum SystemClauseType { #[cfg(feature = "crypto-full")] #[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))] CryptoDataDecrypt, - #[cfg(feature = "crypto-full")] - #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))] - Ed25519Sign, - #[cfg(feature = "crypto-full")] - #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))] - Ed25519Verify, - #[cfg(feature = "crypto-full")] - #[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))] - Ed25519NewKeyPair, - #[cfg(feature = "crypto-full")] - #[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))] - Ed25519KeyPairPublicKey, + #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign_raw")))] + Ed25519SignRaw, + #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify_raw")))] + Ed25519VerifyRaw, + #[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_seed_to_public_key")))] + Ed25519SeedToPublicKey, #[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))] FirstNonOctet, #[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))] @@ -610,6 +604,8 @@ enum SystemClauseType { KeySortWithConstantVarOrdering, #[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))] InferenceLimitExceeded, + #[strum_discriminants(strum(props(Arity = "1", Name = "$argv")))] + Argv, REPL(REPLCodePtr), } @@ -796,8 +792,8 @@ enum InstructionTemplate { #[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))] InstallVerifyAttr, // call verify_attrs. - #[strum_discriminants(strum(props(Arity = "0", Name = "verify_attr_interrupt")))] - VerifyAttrInterrupt, + #[strum_discriminants(strum(props(Arity = "1", Name = "verify_attr_interrupt")))] + VerifyAttrInterrupt(usize), // procedures CallClause(ClauseType, usize, usize, bool, bool), // ClauseType, // arity, @@ -1157,6 +1153,33 @@ fn generate_instruction_preface() -> TokenStream { pub type CodeDeque = VecDeque; impl Instruction { + #[inline] + pub fn registers(&self) -> Vec { + match self { + &Instruction::GetConstant(_, _, r) => vec![r], + &Instruction::GetList(_, r) => vec![r], + &Instruction::GetPartialString(_, _, r, _) => vec![r], + &Instruction::GetStructure(_, _, _, r) => vec![r], + &Instruction::GetVariable(r, t) => vec![r, temp_v!(t)], + &Instruction::GetValue(r, t) => vec![r, temp_v!(t)], + &Instruction::UnifyLocalValue(r) => vec![r], + &Instruction::UnifyVariable(r) => vec![r], + &Instruction::PutConstant(_, _, r) => vec![r], + &Instruction::PutList(_, r) => vec![r], + &Instruction::PutPartialString(_, _, r, _) => vec![r], + &Instruction::PutStructure(_, _, r) => vec![r], + &Instruction::PutValue(r, t) => vec![r, temp_v!(t)], + &Instruction::PutVariable(r, t) => vec![r, temp_v!(t)], + &Instruction::SetLocalValue(r) => vec![r], + &Instruction::SetVariable(r) => vec![r], + &Instruction::SetValue(r) => vec![r], + &Instruction::GetLevel(r) => vec![r], + &Instruction::GetPrevLevel(r) => vec![r], + &Instruction::GetCutPoint(r) => vec![r], + _ => vec![], + } + } + #[inline] pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec> { match self { @@ -1199,7 +1222,10 @@ fn generate_instruction_preface() -> TokenStream { Instruction::SetLocalValue(..) | Instruction::SetVariable(..) | Instruction::SetValue(..) | - Instruction::SetVoid(..)) + Instruction::SetVoid(..) | + Instruction::GetLevel(..) | + Instruction::GetPrevLevel(..) | + Instruction::GetCutPoint(..)) } pub fn enqueue_functors( @@ -1244,8 +1270,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::InstallVerifyAttr => { functor!(atom!("install_verify_attr")) } - &Instruction::VerifyAttrInterrupt => { - functor!(atom!("verify_attr_interrupt")) + &Instruction::VerifyAttrInterrupt(arity) => { + functor!(atom!("verify_attr_interrupt"), [fixnum(arity)]) } &Instruction::DynamicElse(birth, death, next_or_fail) => { match (death, next_or_fail) { @@ -1874,18 +1900,18 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallFlushTermQueue | &Instruction::CallRemoveModuleExports | &Instruction::CallAddNonCountedBacktracking | - &Instruction::CallPopCount => { + &Instruction::CallPopCount | + &Instruction::CallArgv | + &Instruction::CallEd25519SignRaw | + &Instruction::CallEd25519VerifyRaw | + &Instruction::CallEd25519SeedToPublicKey => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("call"), [atom(name), fixnum(arity)]) } // #[cfg(feature = "crypto-full")] &Instruction::CallCryptoDataEncrypt | - &Instruction::CallCryptoDataDecrypt | - &Instruction::CallEd25519Sign | - &Instruction::CallEd25519Verify | - &Instruction::CallEd25519NewKeyPair | - &Instruction::CallEd25519KeyPairPublicKey => { + &Instruction::CallCryptoDataDecrypt => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("call"), [atom(name), fixnum(arity)]) } @@ -2110,18 +2136,18 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteFlushTermQueue | &Instruction::ExecuteRemoveModuleExports | &Instruction::ExecuteAddNonCountedBacktracking | - &Instruction::ExecutePopCount => { + &Instruction::ExecutePopCount | + &Instruction::ExecuteArgv | + &Instruction::ExecuteEd25519SignRaw | + &Instruction::ExecuteEd25519VerifyRaw | + &Instruction::ExecuteEd25519SeedToPublicKey => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("execute"), [atom(name), fixnum(arity)]) } // #[cfg(feature = "crypto-full")] &Instruction::ExecuteCryptoDataEncrypt | - &Instruction::ExecuteCryptoDataDecrypt | - &Instruction::ExecuteEd25519Sign | - &Instruction::ExecuteEd25519Verify | - &Instruction::ExecuteEd25519NewKeyPair | - &Instruction::ExecuteEd25519KeyPairPublicKey => { + &Instruction::ExecuteCryptoDataDecrypt => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("execute"), [atom(name), fixnum(arity)]) } diff --git a/src/allocator.rs b/src/allocator.rs index e20bf2cf..e961b975 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -53,40 +53,5 @@ pub(crate) trait Allocator { fn reset_contents(&mut self); fn advance_arg(&mut self); - - /* - fn bindings(&self) -> &AllocVarDict; - fn bindings_mut(&mut self) -> &mut AllocVarDict; - fn take_bindings(self) -> AllocVarDict; - */ - fn max_reg_allocated(&self) -> usize; - - // TODO: wha.. why?? grrr. it drains the VarStatus data from vs (which it owns!) - // into self.bindings and perm_vs after all is computed (i.e. vs.populate_restricting_sets() - // and vs.set_perm_vals(has_deep_cut) have both been called). - /* - fn drain_var_data<'a>( - &mut self, - vs: VariableFixtures, - num_of_chunks: usize, - ) -> VariableFixtures { - let mut perm_vs = VariableFixtures::new(); - - for (var, var_status) in vs.into_iter() { - match var_status { - VarStatus::Temp(chunk_num, tvd) => { - self.bindings_mut() - .insert(var.clone(), VarAlloc::Temp(chunk_num, 0, tvd)); - } - VarStatus::Perm(_) => { - self.bindings_mut().insert(var.clone(), VarAlloc::Perm(0)); - perm_vs.insert(var, var_status); - } - }; - } - - perm_vs - } - */ } diff --git a/src/arena.rs b/src/arena.rs index 40c1b029..172e6e9d 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -821,9 +821,9 @@ impl AllocSlab { } fn payload_offset(&self) -> *mut T { - let mut ptr = (self as *const AllocSlab) as usize; - ptr += mem::size_of::(); - ptr as *mut T + // This looks really scary, should this method be marked as unsafe? + // Also, this seems to cause UB. + unsafe { (self as *const AllocSlab).add(1) as *mut T } } } @@ -864,6 +864,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn heap_cell_value_const_cast() { let mut wam = MockWAM::new(); #[cfg(target_pointer_width = "32")] @@ -907,6 +908,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on arena.rs UB")] fn heap_put_literal_tests() { let mut wam = MockWAM::new(); diff --git a/src/atom_table.rs b/src/atom_table.rs index e62ca927..3f60eca6 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -239,6 +239,7 @@ impl Atom { } else if let Some(ptr) = self.as_ptr() { AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| { let header = + // Miri seems to hit this line a lot unsafe { ptr::read::(ptr as *const u8 as *const AtomHeader) }; let len = header.len() as usize; let buf = unsafe { (ptr as *const u8).add(mem::size_of::()) }; @@ -265,7 +266,7 @@ impl Atom { 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; + let str_ptr = ptr.add(mem::size_of::()); ptr::copy_nonoverlapping(string.as_ptr(), str_ptr, string.len()); } diff --git a/src/bin/scryer-prolog.rs b/src/bin/scryer-prolog.rs index 572eb2fa..9ae80773 100644 --- a/src/bin/scryer-prolog.rs +++ b/src/bin/scryer-prolog.rs @@ -23,6 +23,6 @@ fn main() -> std::process::ExitCode { runtime.block_on(async move { let mut wam = machine::Machine::new(Default::default()); - wam.run_top_level(atom!("$toplevel"), (atom!("$repl"), 1)) + wam.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 0)) }) } diff --git a/src/codegen.rs b/src/codegen.rs index fd0d21f9..23c59238 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -860,6 +860,9 @@ impl<'b> CodeGenerator<'b> { self.marker.mark_safe_var_unconditionally(var_num); compile_expr!(self, &terms[1], term_loc, code) } else { + self.marker + .mark_anon_var::(Level::Shallow, term_loc, code); + if let Term::Var(ref vr, ref var) = &terms[1] { let var_num = var.to_var_num().unwrap(); diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index ed905ec0..d44c36cb 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -604,16 +604,9 @@ impl DebrayAllocator { Target::unsafe_argument_to_value(r, arg_c) } } - VarAlloc::Temp { ref mut safety, .. } => { - if self - .branch_stack - .safety_unneeded_in_branch(safety, &branch_designator) - { - Target::argument_to_value(r, arg_c) - } else { - *safety = VarSafetyStatus::GloballyUnneeded; - Target::unsafe_argument_to_value(r, arg_c) - } + VarAlloc::Temp { .. } => { + debug_assert!(matches!(r, RegType::Temp(_))); + Target::argument_to_value(r, arg_c) } _ => { unreachable!() diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 4713aa63..cada66cf 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -108,7 +108,7 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> { let var_value = self.heap[h]; self.heap[h].set_mark_bit(self.mark_phase); - if !(self.heap[h].is_var() && self.heap[h].get_value() as usize == h) { + if var_value.get_mark_bit() || !(self.heap[h].is_var() && self.heap[h].get_value() as usize == h) { self.iter_stack.push(var_value); continue; } @@ -125,12 +125,13 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> { continue; } - let value = self.heap[h+1]; - self.heap[h].set_mark_bit(self.mark_phase); - self.heap[h+1].set_mark_bit(self.mark_phase); - self.iter_stack.push(value); + if self.heap[h].get_tag() == HeapCellValueTag::PStr { + let value = self.heap[h+1]; + self.heap[h+1].set_mark_bit(self.mark_phase); + self.iter_stack.push(value); + } } _ => { } @@ -685,6 +686,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "it takes too long to run")] fn heap_stackless_iter_tests() { let mut wam = MockWAM::new(); @@ -1756,6 +1758,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")] fn heap_stackful_iter_tests() { let mut wam = MockWAM::new(); @@ -2348,6 +2351,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")] fn heap_stackful_post_order_iter() { let mut wam = MockWAM::new(); @@ -2831,6 +2835,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")] fn heap_stackless_post_order_iter() { let mut wam = MockWAM::new(); diff --git a/src/heap_print.rs b/src/heap_print.rs index 14ee274d..515ebef6 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1444,7 +1444,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - #[allow(dead_code)] fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) { let (ip, port) = if let Ok(addr) = tcp_listener.local_addr() { (addr.ip(), addr.port()) @@ -1727,6 +1726,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (ArenaHeaderTag::Stream, stream) => { self.print_stream(stream, max_depth); } + (ArenaHeaderTag::TcpListener, listener) => { + self.print_tcp_listener(&*listener, max_depth); + } (ArenaHeaderTag::Dropped, _value) => { self.print_impromptu_atom(atom!("$dropped_value")); } @@ -1833,6 +1835,7 @@ mod tests { use crate::machine::mock_wam::*; #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn term_printing_tests() { let mut wam = MockWAM::new(); diff --git a/src/lib/atts.pl b/src/lib/atts.pl index d6ee47a3..f251b57d 100644 --- a/src/lib/atts.pl +++ b/src/lib/atts.pl @@ -1,8 +1,8 @@ :- module(atts, [op(1199, fx, attribute), - call_residue_vars/2, term_attributed_variables/2]). :- use_module(library(dcgs)). +:- use_module(library(error)). :- use_module(library(terms)). /* represent the list of attributes belonging to a variable, @@ -110,12 +110,5 @@ user:goal_expansion(Term, M:get_atts(Var, Attr)) :- nonvar(Term), Term = get_atts(Var, M, Attr). -:- meta_predicate call_residue_vars(0, ?). - -call_residue_vars(Goal, Vars) :- - '$get_attr_var_queue_delim'(B), - call(Goal), - '$get_attr_var_queue_beyond'(B, Vars). - term_attributed_variables(Term, Vars) :- '$term_attributed_variables'(Term, Vars). diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 9cb533d1..b24244d6 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1239,7 +1239,10 @@ call_retract_helper(Head, Body, P, Module) :- ; ClauseQualifier = Module ), ClauseQualifier:'$clause'(Head, Body), - '$get_clause_p'(Head, P, Module). + % ensure '$get_clause_p'/3 is not the last clause so it can + % recover the choice point of '$clause' if necessary. + '$get_clause_p'(Head, P, Module), + true. call_retract(Head, Body, Name, Arity, Module) :- findall(P, builtins:call_retract_helper(Head, Body, P, Module), Ps), diff --git a/src/lib/clpb.pl b/src/lib/clpb.pl index 4dde600b..a20694d0 100644 --- a/src/lib/clpb.pl +++ b/src/lib/clpb.pl @@ -189,18 +189,18 @@ A _Boolean expression_ is one of: | `1` | true | | _variable_ | unknown truth value | | _atom_ | universally quantified variable | -| ~ _Expr_ | logical NOT | -| _Expr_ + _Expr_ | logical OR | -| _Expr_ * _Expr_ | logical AND | -| _Expr_ # _Expr_ | exclusive OR | -| _Var_ ^ _Expr_ | existential quantification | -| _Expr_ =:= _Expr_ | equality | -| _Expr_ =\= _Expr_ | disequality (same as #) | -| _Expr_ =< _Expr_ | less or equal (implication) | -| _Expr_ >= _Expr_ | greater or equal | -| _Expr_ < _Expr_ | less than | -| _Expr_ > _Expr_ | greater than | -| card(Is,Exprs) | cardinality constraint (_see below_) | +| `~` _Expr_ | logical NOT | +| _Expr_ `+` _Expr_ | logical OR | +| _Expr_ `*` _Expr_ | logical AND | +| _Expr_ `#` _Expr_ | exclusive OR | +| _Var_ `^` _Expr_ | existential quantification | +| _Expr_ `=:=` _Expr_ | equality | +| _Expr_ `=\=` _Expr_ | disequality (same as #) | +| _Expr_ `=<` _Expr_ | less or equal (implication) | +| _Expr_ `>=` _Expr_ | greater or equal | +| _Expr_ `<` _Expr_ | less than | +| _Expr_ `>` _Expr_ | greater than | +| `card(Is,Exprs)` | cardinality constraint (_see below_) | | `+(Exprs)` | n-fold disjunction (_see below_) | | `*(Exprs)` | n-fold conjunction (_see below_) | @@ -1251,7 +1251,7 @@ bdd_restriction_(Node, VI, Value, Res) --> node_id(Node, ID) }, ( { I0 =:= VI } -> ( { Value =:= 0 } -> { Res = Low } - ; { Value =:= 1 } -> { Res = High } + ; { Res = High } ) ; { I0 > VI } -> { Res = Node } ; state(G0), { get_assoc(ID, G0, Res) } -> [] diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index 23c909e9..07768da5 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -3,7 +3,7 @@ Author: Markus Triska E-mail: triska@metalevel.at WWW: https://www.metalevel.at - Copyright (C): 2016-2023 Markus Triska + Copyright (C): 2016-2024 Markus Triska This library provides CLP(ℤ): @@ -1015,6 +1015,9 @@ X in inf..sup. needed to schedule the propagators! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +:- meta_predicate(duophrase(4, ?, ?)). +:- meta_predicate(duophrase(4, ?, ?, ?, ?)). + duophrase(NT, As, Bs) :- duophrase(NT, As, [], Bs, []). @@ -1735,7 +1738,7 @@ intervals_to_domain(Is, D) :- % _Lower_ must be an integer or the atom *inf*, which % denotes negative infinity. _Upper_ must be an integer or % the atom *sup*, which denotes positive infinity. -% * Domain1 \/ Domain2 +% * Domain1 `\/` Domain2 % The union of Domain1 and Domain2. Var in Dom :- clpz_in(Var, Dom). @@ -2409,22 +2412,22 @@ sum_finite_domains([C|Cs], [V|Vs], Inf0, Sup0, Inf, Sup) ++> ), sum_finite_domains(Cs, Vs, Inf2, Sup2, Inf, Sup). -remove_dist_upper_lower([], _, _, _). -remove_dist_upper_lower([C|Cs], [V|Vs], D1, D2) :- - ( fd_get(V, VD, VPs) -> +remove_dist_upper_lower([], _, _, _) --> []. +remove_dist_upper_lower([C|Cs], [V|Vs], D1, D2) --> + ( { fd_get(V, VD, VPs) } -> ( C < 0 -> - domain_supremum(VD, n(Sup)), - L is Sup + D1//C, - domain_remove_smaller_than(VD, L, VD1), - domain_infimum(VD1, n(Inf)), - G is Inf - D2//C, - domain_remove_greater_than(VD1, G, VD2) - ; domain_infimum(VD, n(Inf)), - G is Inf + D1//C, - domain_remove_greater_than(VD, G, VD1), - domain_supremum(VD1, n(Sup)), - L is Sup - D2//C, - domain_remove_smaller_than(VD1, L, VD2) + { domain_supremum(VD, n(Sup)), + L is Sup + D1//C, + domain_remove_smaller_than(VD, L, VD1), + domain_infimum(VD1, n(Inf)), + G is Inf - D2//C, + domain_remove_greater_than(VD1, G, VD2) } + ; { domain_infimum(VD, n(Inf)), + G is Inf + D1//C, + domain_remove_greater_than(VD, G, VD1), + domain_supremum(VD1, n(Sup)), + L is Sup - D2//C, + domain_remove_smaller_than(VD1, L, VD2) } ), fd_put(V, VD2, VPs) ; true @@ -2432,16 +2435,16 @@ remove_dist_upper_lower([C|Cs], [V|Vs], D1, D2) :- remove_dist_upper_lower(Cs, Vs, D1, D2). -remove_dist_upper_leq([], _, _). -remove_dist_upper_leq([C|Cs], [V|Vs], D1) :- - ( fd_get(V, VD, VPs) -> +remove_dist_upper_leq([], _, _) --> []. +remove_dist_upper_leq([C|Cs], [V|Vs], D1) --> + ( { fd_get(V, VD, VPs) } -> ( C < 0 -> - domain_supremum(VD, n(Sup)), - L is Sup + D1//C, - domain_remove_smaller_than(VD, L, VD1) - ; domain_infimum(VD, n(Inf)), - G is Inf + D1//C, - domain_remove_greater_than(VD, G, VD1) + { domain_supremum(VD, n(Sup)), + L is Sup + D1//C, + domain_remove_smaller_than(VD, L, VD1) } + ; { domain_infimum(VD, n(Inf)), + G is Inf + D1//C, + domain_remove_greater_than(VD, G, VD1) } ), fd_put(V, VD1, VPs) ; true @@ -2449,18 +2452,18 @@ remove_dist_upper_leq([C|Cs], [V|Vs], D1) :- remove_dist_upper_leq(Cs, Vs, D1). -remove_dist_upper([], _). -remove_dist_upper([C*V|CVs], D) :- - ( fd_get(V, VD, VPs) -> +remove_dist_upper([], _) --> []. +remove_dist_upper([C*V|CVs], D) --> + ( { fd_get(V, VD, VPs) } -> ( C < 0 -> - ( domain_supremum(VD, n(Sup)) -> - L is Sup + D//C, - domain_remove_smaller_than(VD, L, VD1) + ( { domain_supremum(VD, n(Sup)) } -> + { L is Sup + D//C, + domain_remove_smaller_than(VD, L, VD1) } ; VD1 = VD ) - ; ( domain_infimum(VD, n(Inf)) -> - G is Inf + D//C, - domain_remove_greater_than(VD, G, VD1) + ; ( { domain_infimum(VD, n(Inf)) } -> + { G is Inf + D//C, + domain_remove_greater_than(VD, G, VD1) } ; VD1 = VD ) ), @@ -2469,18 +2472,18 @@ remove_dist_upper([C*V|CVs], D) :- ), remove_dist_upper(CVs, D). -remove_dist_lower([], _). -remove_dist_lower([C*V|CVs], D) :- - ( fd_get(V, VD, VPs) -> +remove_dist_lower([], _) --> []. +remove_dist_lower([C*V|CVs], D) --> + ( { fd_get(V, VD, VPs) } -> ( C < 0 -> - ( domain_infimum(VD, n(Inf)) -> - G is Inf - D//C, - domain_remove_greater_than(VD, G, VD1) + ( { domain_infimum(VD, n(Inf)) } -> + { G is Inf - D//C, + domain_remove_greater_than(VD, G, VD1) } ; VD1 = VD ) - ; ( domain_supremum(VD, n(Sup)) -> - L is Sup - D//C, - domain_remove_smaller_than(VD, L, VD1) + ; ( { domain_supremum(VD, n(Sup)) } -> + { L is Sup - D//C, + domain_remove_smaller_than(VD, L, VD1) } ; VD1 = VD ) ), @@ -2489,26 +2492,26 @@ remove_dist_lower([C*V|CVs], D) :- ), remove_dist_lower(CVs, D). -remove_upper([], _). -remove_upper([C*X|CXs], Max) :- - ( fd_get(X, XD, XPs) -> +remove_upper([], _) --> []. +remove_upper([C*X|CXs], Max) --> + ( { fd_get(X, XD, XPs) } -> D is Max//C, ( C < 0 -> - domain_remove_smaller_than(XD, D, XD1) - ; domain_remove_greater_than(XD, D, XD1) + { domain_remove_smaller_than(XD, D, XD1) } + ; { domain_remove_greater_than(XD, D, XD1) } ), fd_put(X, XD1, XPs) ; true ), remove_upper(CXs, Max). -remove_lower([], _). -remove_lower([C*X|CXs], Min) :- - ( fd_get(X, XD, XPs) -> +remove_lower([], _) --> []. +remove_lower([C*X|CXs], Min) --> + ( { fd_get(X, XD, XPs) } -> D is -Min//C, ( C < 0 -> - domain_remove_greater_than(XD, D, XD1) - ; domain_remove_smaller_than(XD, D, XD1) + { domain_remove_greater_than(XD, D, XD1) } + ; { domain_remove_smaller_than(XD, D, XD1) } ), fd_put(X, XD1, XPs) ; true @@ -2747,20 +2750,24 @@ propagator_init_trigger(Vs, P) :- prop_init(Prop, V) :- init_propagator(V, Prop). geq(A, B) :- - ( fd_get(A, AD, APs) -> - domain_infimum(AD, AI), - ( fd_get(B, BD, _) -> - domain_supremum(BD, BS), - ( AI cis_geq BS -> true - ; propagator_init_trigger(pgeq(A,B)) + new_queue(Q), + phrase((geq(A, B),do_queue), [Q], _). + +geq(A, B) --> + ( { fd_get(A, AD, APs) } -> + { domain_infimum(AD, AI) }, + ( { fd_get(B, BD, _) } -> + { domain_supremum(BD, BS) }, + ( { AI cis_geq BS } -> true + ; { propagator_init_trigger(pgeq(A,B)) } ) - ; ( AI cis_geq n(B) -> true - ; domain_remove_smaller_than(AD, B, AD1), + ; ( { AI cis_geq n(B) } -> true + ; { domain_remove_smaller_than(AD, B, AD1) }, fd_put(A, AD1, APs) ) ) - ; fd_get(B, BD, BPs) -> - domain_remove_greater_than(BD, A, BD1), + ; { fd_get(B, BD, BPs) } -> + { domain_remove_greater_than(BD, A, BD1) }, fd_put(B, BD1, BPs) ; A >= B ). @@ -4164,6 +4171,7 @@ var(V) --> { var(V) }. ground(T) --> { ground(T) }. true --> []. +false --> { false }. X >= Y --> { X >= Y }. X =< Y --> { X =< Y }. @@ -4221,10 +4229,7 @@ activate_propagator(propagator(P,State)) --> ) ). -enable_queue :- true. % NOP -disable_queue :- true. % NOP - -%do_queue --> print_queue, { false }. +%do_queue --> print_queue, false. do_queue --> ( queue_enabled -> ( queue_get_goal(Goal) -> { call(Goal) }, do_queue @@ -4507,13 +4512,13 @@ run_propagator(pelement(N, Is, V), MState) --> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -run_propagator(pgcc_single(Vs, Pairs), _) --> { gcc_global(Vs, Pairs) }. +run_propagator(pgcc_single(Vs, Pairs), _) --> gcc_global(Vs, Pairs). -run_propagator(pgcc_check_single(Pairs), _) --> { gcc_check(Pairs) }. +run_propagator(pgcc_check_single(Pairs), _) --> gcc_check(Pairs). -run_propagator(pgcc_check(Pairs), _) --> { gcc_check(Pairs) }. +run_propagator(pgcc_check(Pairs), _) --> gcc_check(Pairs). -run_propagator(pgcc(Vs, _, Pairs), _) --> { gcc_global(Vs, Pairs) }. +run_propagator(pgcc(Vs, _, Pairs), _) --> gcc_global(Vs, Pairs). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -4588,7 +4593,7 @@ run_propagator(pserialized(S_I, D_I, S_J, D_J, _), MState) --> kill(MState), ( S_I + D_I =< S_J -> [] ; S_J + D_J =< S_I -> [] - ; { false } + ; false ) ; serialize_lower_upper(S_I, D_I, S_J, D_J, MState), serialize_lower_upper(S_J, D_J, S_I, D_I, MState) @@ -4661,7 +4666,7 @@ run_propagator(x_eq_abs_plus_v(X,V), MState) --> ( nonvar(V) -> ( V =:= 0 -> kill(MState), { X in 0..sup } ; V < 0 -> kill(MState), { X #= V / 2 } - ; V > 0 -> { false } + ; false % V > 0 ) ; nonvar(X) -> kill(MState), @@ -4753,55 +4758,55 @@ run_propagator(scalar_product_neq(Cs0,Vs0,P0), MState) --> ) }. run_propagator(scalar_product_leq(Cs0,Vs0,P0), MState) --> - { coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I), - P is P0 - I, - ( Vs = [] -> kill(MState), P >= 0 - ; duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups), - D1 is P - Inf, - disable_queue, - ( Infs == [], Sups == [] -> - Inf =< P, - ( Sup =< P -> kill(MState) - ; remove_dist_upper_leq(Cs, Vs, D1) - ) - ; Infs == [] -> Inf =< P, remove_dist_upper(Sups, D1) - ; Infs = [_] -> remove_upper(Infs, D1) - ; true - ), - enable_queue - ) }. + { coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I) }, + P is P0 - I, + ( Vs = [] -> kill(MState), P >= 0 + ; { duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups) }, + D1 is P - Inf, + disable_queue, + ( Infs == [], Sups == [] -> + Inf =< P, + ( Sup =< P -> kill(MState) + ; remove_dist_upper_leq(Cs, Vs, D1) + ) + ; Infs == [] -> Inf =< P, remove_dist_upper(Sups, D1) + ; Infs = [_] -> remove_upper(Infs, D1) + ; true + ), + enable_queue + ). run_propagator(scalar_product_eq(Cs0,Vs0,P0), MState) --> - { coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I), - P is P0 - I, - ( Vs = [] -> kill(MState), P =:= 0 - ; Vs = [V], Cs = [C] -> kill(MState), P mod C =:= 0, V is P // C - ; Cs == [1,1] -> kill(MState), Vs = [A,B], A + B #= P - ; Cs == [1,-1] -> kill(MState), Vs = [A,B], A #= P + B - ; Cs == [-1,1] -> kill(MState), Vs = [A,B], B #= P + A - ; Cs == [-1,-1] -> kill(MState), Vs = [A,B], P1 is -P, A + B #= P1 - ; P =:= 0, Cs == [1,1,-1] -> kill(MState), Vs = [A,B,C], A + B #= C - ; P =:= 0, Cs == [1,-1,1] -> kill(MState), Vs = [A,B,C], A + C #= B - ; P =:= 0, Cs == [-1,1,1] -> kill(MState), Vs = [A,B,C], B + C #= A - ; duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups), - % nl, writeln(Infs-Sups-Inf-Sup), - D1 is P - Inf, - D2 is Sup - P, - disable_queue, - ( Infs == [], Sups == [] -> - between(Inf, Sup, P), - remove_dist_upper_lower(Cs, Vs, D1, D2) - ; Sups = [] -> P =< Sup, remove_dist_lower(Infs, D2) - ; Infs = [] -> Inf =< P, remove_dist_upper(Sups, D1) - ; Sups = [_], Infs = [_] -> - remove_lower(Sups, D2), - remove_upper(Infs, D1) - ; Infs = [_] -> remove_upper(Infs, D1) - ; Sups = [_] -> remove_lower(Sups, D2) - ; true - ), - enable_queue - ) }. + { coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I) }, + P is P0 - I, + ( Vs = [] -> kill(MState), P =:= 0 + ; Vs = [V], Cs = [C] -> kill(MState), P mod C =:= 0, V is P // C + ; Cs == [1,1] -> kill(MState), Vs = [A,B], { A + B #= P } + ; Cs == [1,-1] -> kill(MState), Vs = [A,B], { A #= P + B } + ; Cs == [-1,1] -> kill(MState), Vs = [A,B], { B #= P + A } + ; Cs == [-1,-1] -> kill(MState), Vs = [A,B], P1 is -P, { A + B #= P1 } + ; P =:= 0, Cs == [1,1,-1] -> kill(MState), Vs = [A,B,C], { A + B #= C } + ; P =:= 0, Cs == [1,-1,1] -> kill(MState), Vs = [A,B,C], { A + C #= B } + ; P =:= 0, Cs == [-1,1,1] -> kill(MState), Vs = [A,B,C], { B + C #= A } + ; { duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups) }, + % { nl, writeln(Infs-Sups-Inf-Sup) }, + D1 is P - Inf, + D2 is Sup - P, + disable_queue, + ( Infs == [], Sups == [] -> + { between(Inf, Sup, P) }, + remove_dist_upper_lower(Cs, Vs, D1, D2) + ; Sups = [] -> P =< Sup, remove_dist_lower(Infs, D2) + ; Infs = [] -> Inf =< P, remove_dist_upper(Sups, D1) + ; Sups = [_], Infs = [_] -> + remove_lower(Sups, D2), + remove_upper(Infs, D1) + ; Infs = [_] -> remove_upper(Infs, D1) + ; Sups = [_] -> remove_lower(Sups, D2) + ; true + ), + enable_queue + ). % X + Y = Z run_propagator(pplus(X,Y,Z,Morph), MState) --> @@ -5048,8 +5053,8 @@ run_propagator(ptzdiv(X,Y,Z,Morph), MState) --> %% % Z = X mod Y run_propagator(pmod(X,Y,Z), MState) --> - ( Y == 0 -> { false } - ; Y == Z -> { false } + ( Y == 0 -> false + ; Y == Z -> false ; X == Y -> kill(MState), queue_goal(Z = 0) ; true ), @@ -5058,7 +5063,7 @@ run_propagator(pmod(X,Y,Z), MState) --> Z is X mod Y ; nonvar(Y), nonvar(Z) -> ( Y > 0 -> Z >= 0, Z < Y - ; Y < 0 -> Z =< 0, Z > Y + ; Z =< 0, Z > Y % Y < 0 ), ( { fd_get(X, _, n(XL), _, _) } -> ( (XL - Z) mod Y =\= 0 -> @@ -5127,7 +5132,7 @@ run_propagator(pmodz(X,Y,Z), MState) --> fd_put(Z, ZD2, ZPs) % queue_goal(Z #=< X) ) - ; X < 0 -> + ; X < 0, ( { fd_get(Y, _, _, n(YU), _), YU < X } -> kill(MState), queue_goal(Z = X) @@ -5167,7 +5172,7 @@ run_propagator(pmodz(X,Y,Z), MState) --> fd_put(Z, ZD5, ZPs) % queue_goal(Z in ZMin..0) ) - ; Y > 0 -> + ; Y > 0, ( { fd_get(X, _, n(XL), n(XU), _), XL >= 0, Y > XU } -> kill(MState), queue_goal(Z = X) @@ -5378,8 +5383,9 @@ run_propagator(pmax(X,Y,Z), MState) --> ; nonvar(Z) -> ( Z =:= X -> kill(MState), queue_goal(X #>= Y) ; Z > X -> queue_goal(Z = Y) - ; { false } % Z < X + ; false % Z < X ) + ; Y == Z -> kill(MState), queue_goal(Y #>= X) ; { fd_get(Y, _, YInf, YSup, _) }, ( { YInf cis_gt n(X) } -> queue_goal(Z = Y) ; { YSup cis_lt n(X) } -> queue_goal(Z = X) @@ -5394,7 +5400,7 @@ run_propagator(pmax(X,Y,Z), MState) --> ; { fd_get(Z, ZD, ZPs) } -> { fd_get(X, _, XInf, XSup, _), fd_get(Y, _, YInf, YSup, _) }, - ( { YInf cis_gt YSup } -> kill(MState), queue_goal(Z = Y) + ( { YInf cis_gt XSup } -> kill(MState), queue_goal(Z = Y) ; { YSup cis_lt XInf } -> kill(MState), queue_goal(Z = X) ; { n(M) cis max(XSup, YSup) } -> { domain_remove_greater_than(ZD, M, ZD1) }, @@ -5413,8 +5419,9 @@ run_propagator(pmin(X,Y,Z), MState) --> ; nonvar(Z) -> ( Z =:= X -> kill(MState), { X #=< Y } ; Z < X -> Z = Y - ; { false } % Z > X + ; false % Z > X ) + ; Y == Z -> kill(MState), queue_goal(Y #=< X) ; { fd_get(Y, _, YInf, YSup, _) }, ( { YSup cis_lt n(X) } -> Z = Y ; { YInf cis_gt n(X) } -> Z = X @@ -5429,7 +5436,7 @@ run_propagator(pmin(X,Y,Z), MState) --> ; { fd_get(Z, ZD, ZPs) } -> { fd_get(X, _, XInf, XSup, _), fd_get(Y, _, YInf, YSup, _) }, - ( { YSup cis_lt YInf } -> kill(MState), Z = Y + ( { YSup cis_lt XInf } -> kill(MState), Z = Y ; { YInf cis_gt XSup } -> kill(MState), Z = X ; { n(M) cis min(XInf, YInf) } -> { domain_remove_smaller_than(ZD, M, ZD1) }, @@ -5448,6 +5455,7 @@ run_propagator(pexp(X,Y,Z,Morph), MState) --> morph_into_propagator(MState, [Y,Z], reified_eq(1,Y,1,0,[],Z), Morph) ; Y == 0 -> kill(MState), Z = 1 ; Y == 1 -> kill(MState), Z = X + ; Y == Z -> kill(MState), X = Y, queue_goal(X in -1\/1) ; nonvar(X) -> ( nonvar(Y) -> ( Y >= 0 -> true ; X =:= -1 ), @@ -5536,7 +5544,7 @@ run_propagator(pexp(X,Y,Z,Morph), MState) --> fd_put(Z, ZD2, ZPs), { ( even(Y), ZU = n(Num) -> integer_kth_root_leq(Num, Y, RU), - ( XL cis_geq n(0), ZL = n(Num1) -> + ( XL cis_geq n(0), ZL = n(Num1), Num1 >= 0 -> integer_kth_root_leq(Num1, Y, RL0), ( RL0^Y < Num1 -> RL is RL0 + 1 ; RL = RL0 @@ -5726,8 +5734,7 @@ run_propagator(reified_fd(V,B), MState) --> B = 1 ; { B == 0 } -> ( { fd_inf(V, inf) } -> [] - ; { fd_sup(V, sup) } -> [] - ; { false } + ; { fd_sup(V, sup) } ) ; [] ). @@ -6788,13 +6795,20 @@ gcc_pairs([Key-Num0|KNs], Vs, [Key-Num|Rest]) :- Constraint", AAAI-96 Portland, OR, USA, pp 209--215, 1996 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -gcc_global(Vs, KNs) :- - gcc_check(KNs), - % previously: call do_queue/0 (now a NOP) here to reach a - % fix-point: all elements of clpz_gcc_vs must be variables. We - % must ensure this holds if gcc_check/1 is later rewritten to - % actually disable the queue. - with_local_attributes(Vs, +gcc_global(Vs, KNs) --> + % at this point, all elements of clpz_gcc_vs must be + % variables, which a previously scheduled and called + % gcc_check//1 ensures. Note that gcc_check//1 disables the + % queue and accumulates constraints in the queue. Do we need + % to insert a call of do_queue//0 here to reach a fixpoint? I + % think not, because verify_attributes/3 gives each variable + % that is involved in a unification an opportunity to schedule + % its propagators, even if the unifications happen + % simultaneously (such as [A,B] = [0,1], which can happen in + % the propagator of tuples_in/2). Hence: We need this only if + % an example shows it, ideally found by a systematic search + % that can be used to test the implementation. + { with_local_attributes(Vs, (gcc_arcs(KNs, S, Vals), variables_with_num_occurrences(Vs, VNs), maplist(target_to_v(T), VNs), @@ -6805,9 +6819,9 @@ gcc_global(Vs, KNs) :- gcc_consistent(T), scc(Vals, gcc_successors), phrase(gcc_goals(Vals), Gs) - ; Gs = [] )), Gs), + ; Gs = [] )), Gs) }, disable_queue, - maplist(call, Gs), + neq_nums(Gs), enable_queue. gcc_consistent(T) :- @@ -6834,7 +6848,7 @@ gcc_edge_goal(arc_to(_,_,V,F), Val) --> get_attr(Val, lowlink, L2), L1 =\= L2, get_attr(Val, value, Value) } -> - [clpz:neq_num(V, Value)] + [neq_num(V, Value)] ; [] ). @@ -7004,7 +7018,7 @@ gcc_succ_edge(arc_from(_,_,V,F)) --> consistency. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -gcc_check(Pairs) :- +gcc_check(Pairs) --> disable_queue, gcc_check_(Pairs), enable_queue. @@ -7014,36 +7028,36 @@ gcc_done(Num) :- del_attr(Num, clpz_gcc_num), del_attr(Num, clpz_gcc_occurred). -gcc_check_([]). -gcc_check_([Key-Num0|KNs]) :- - ( get_attr(Num0, clpz_gcc_vs, Vs) -> - get_attr(Num0, clpz_gcc_num, Num), - get_attr(Num0, clpz_gcc_occurred, Occ0), - vs_key_min_others(Vs, Key, 0, Min, Os), - put_attr(Num0, clpz_gcc_vs, Os), - put_attr(Num0, clpz_gcc_occurred, Occ1), - Occ1 is Occ0 + Min, +gcc_check_([]) --> []. +gcc_check_([Key-Num0|KNs]) --> + ( { get_attr(Num0, clpz_gcc_vs, Vs) } -> + { get_attr(Num0, clpz_gcc_num, Num), + get_attr(Num0, clpz_gcc_occurred, Occ0), + vs_key_min_others(Vs, Key, 0, Min, Os), + put_attr(Num0, clpz_gcc_vs, Os), + put_attr(Num0, clpz_gcc_occurred, Occ1), + Occ1 is Occ0 + Min }, geq(Num, Occ1), % The queue is disabled for efficiency here in any case. % If it were enabled, make sure to retain the invariant % that gcc_global is never triggered during an % inconsistent state (after gcc_done/1 but before all % relevant constraints are posted). - ( Occ1 == Num -> all_neq(Os, Key), gcc_done(Num0) - ; Os == [] -> gcc_done(Num0), Num = Occ1 - ; length(Os, L), - Max is Occ1 + L, + ( Occ1 == Num -> all_neq(Os, Key), { gcc_done(Num0) } + ; Os == [] -> { gcc_done(Num0) }, Num = Occ1 + ; { length(Os, L), + Max is Occ1 + L }, geq(Max, Num), - ( nonvar(Num) -> Diff is Num - Occ1 - ; fd_get(Num, ND, _), - domain_infimum(ND, n(NInf)), + ( { nonvar(Num) } -> Diff is Num - Occ1 + ; { fd_get(Num, ND, _), + domain_infimum(ND, n(NInf)) }, Diff is NInf - Occ1 ), L >= Diff, ( L =:= Diff -> Num is Occ1 + Diff, - maplist(=(Key), Os), - gcc_done(Num0) + { maplist(=(Key), Os), + gcc_done(Num0) } ; true ) ) diff --git a/src/lib/crypto.pl b/src/lib/crypto.pl index bec12d51..bcd2bb9d 100644 --- a/src/lib/crypto.pl +++ b/src/lib/crypto.pl @@ -25,6 +25,7 @@ crypto_password_hash/3, % +Password, -Hash, +Options crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options + ed25519_seed_keypair/2, % +Seed, -KeyPair ed25519_new_keypair/1, % -KeyPair ed25519_keypair_public_key/2, % +KeyPair, +PublicKey ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options @@ -612,6 +613,50 @@ encoding_chars(utf8, Cs, Cs) :- =============================== - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +%% ed25519_seed_keypair(+Seed, -Pair) +% +% Use Seed to deterministically generate an Ed25519 key pair Pair, a +% list of characters. Seed must be a list of 32 bytes. It can be +% chosen at random (using for example `crypto_n_random_bytes/2`) or +% derived from input keying material (IKM) using for example +% `crypto_data_hkdf/4`. The pair contains the private key and must be +% kept absolutely secret. Pair can be used for signing. Its public +% key can be obtained with `ed25519_keypair_public_key/2`. + +ed25519_seed_keypair(Seed, Pair) :- + must_be_bytes(Seed, ed25519_keypair_from_seed/2), + length(Seed, 32), + '$ed25519_seed_to_public_key'(Seed, Public), + maplist(char_code, Public, PublicBytes), + phrase(ed25519_PKCS8v2(Seed,PublicBytes), DERs), + maplist(char_code, Pair, DERs). + +% DER (and hence BER) encoding of an Ed25519 private key and +% corresponding public key in PKCS#8v2 format (RFC 5958) as specified +% in RFC 8410. + +ed25519_PKCS8v2(Seed, PublicBytes) --> + [0x30,81], % a SEQUENCE of 81 bytes follows + + % the publicKey is present, hence we set version to v2 + [2,1,1], % the integer 1 denoting version 2 (awesome design!) + + % privateKeyAlgorithm: SEQUENCE + [0x30,5], % a SEQUENCE of 5 bytes follows + [6,3], % an OBJECT IDENTIFIER of 3 bytes follows + [43,101,112], % OID of Ed25519 + + % privateKey: OCTET STRING + [4,34], % an OCTET STRING of 34 bytes follows + [4,32], % an OCTET STRING of 32 bytes follows + seq(Seed), % the seed is the private key + + % publicKey: [1] IMPLICIT BIT STRING; context-specific, hence bit 7 set + [0b10000001], % the public key follows + [33], % a BIT STRING of length 33 follows + [0], % 32 bytes is divisible by 8, hence 0 unused bits + seq(PublicBytes). + %% ed25519_new_keypair(-Pair) % % Yields a new Ed25519 key pair Pair, a list of characters. The @@ -620,7 +665,8 @@ encoding_chars(utf8, Cs, Cs) :- % with `ed25519_keypair_public_key/2`. ed25519_new_keypair(Pair) :- - '$ed25519_new_keypair'(Pair). + crypto_n_random_bytes(32, Bytes), + ed25519_seed_keypair(Bytes, Pair). %% ed25519_keypair_public_key(+Pair, -PublicKey) % @@ -629,8 +675,11 @@ ed25519_new_keypair(Pair) :- % The public key is represented as a list of characters. ed25519_keypair_public_key(Pair, PublicKey) :- - must_be_octet_chars(Pair, ed25519_keypair_public_key), - '$ed25519_keypair_public_key'(Pair, PublicKey). + must_be_octet_chars(Pair, ed25519_keypair_public_key/2), + reverse(Pair, RPs), + length(RPublicKey, 32), + phrase((seq(RPublicKey),...), RPs), + reverse(RPublicKey, PublicKey). %% ed25519_sign(+Key, +Data, -Signature, +Options) % @@ -638,10 +687,14 @@ ed25519_keypair_public_key(Pair, PublicKey) :- % PKCS#8 v2 format as generated by `ed25519_new_keypair/1`. Sign Data % with Key, yielding Signature as a list of hexadecimal characters. -ed25519_sign(Key, Data0, Signature, Options) :- - must_be_octet_chars(Key, ed25519_sign), +ed25519_sign(KeyPair, Data0, Signature, Options) :- + must_be_octet_chars(KeyPair, ed25519_sign/4), + length(Prefix, 16), + length(PrivateKeyChars, 32), + phrase((seq(Prefix),seq(PrivateKeyChars),...), KeyPair), + maplist(char_code, PrivateKeyChars, PrivateKey), options_data_chars(Options, Data0, Data, Encoding), - '$ed25519_sign'(Key, Data, Encoding, Signature0), + '$ed25519_sign_raw'(PrivateKey, Data, Encoding, Signature0), hex_bytes(Signature, Signature0). %% ed25519_verify(+Key, +Data, +Signature, +Options) @@ -658,10 +711,10 @@ ed25519_sign(Key, Data0, Signature, Options) :- % which treats Data as a list of raw bytes. ed25519_verify(Key, Data0, Signature0, Options) :- - must_be_octet_chars(Key, ed25519_verify), + must_be_octet_chars(Key, ed25519_verify/4), options_data_chars(Options, Data0, Data, Encoding), hex_bytes(Signature0, Signature), - '$ed25519_verify'(Key, Data, Encoding, Signature). + '$ed25519_verify_raw'(Key, Data, Encoding, Signature). /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - X25519: ECDH key exchange over Curve25519 diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 1767d2bb..4ee763f0 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -12,9 +12,12 @@ to learn more about them. [op(1105, xfy, '|'), phrase/2, phrase/3, + phrase/4, + phrase/5, seq//1, seqq//1, - ... //0 + ... //0, + (-->)/2 ]). :- use_module(library(error)). @@ -26,6 +29,10 @@ to learn more about them. :- meta_predicate phrase(2, ?, ?). +:- meta_predicate phrase(2, ?, ?, ?). + +:- meta_predicate phrase(2, ?, ?, ?, ?). + %% phrase(+Body, ?Ls). % % True iff Body describes the list Ls. Body must be a DCG body. @@ -75,6 +82,34 @@ phrase(GRBody, S0, S) :- ; call(M:GRBody1, S0, S) ). +phrase(GRBody, Arg, S0, S) :- + strip_module(GRBody, M, GRBody1), + ( var(GRBody) -> + instantiation_error(phrase/4) + ; nonvar(GRBody1), + GRBody1 =.. GRBodys1, + append(GRBodys1, [Arg], GRBodys2), + GRBody2 =.. GRBodys2, + dcg_constr(GRBody2), + dcg_body(GRBody2, S0, S, GRBody3) -> + call(M:GRBody3) + ; call(M:GRBody1, Arg, S0, S) + ). + +phrase(GRBody, Arg1, Arg2, S0, S) :- + strip_module(GRBody, M, GRBody1), + ( var(GRBody) -> + instantiation_error(phrase/5) + ; nonvar(GRBody1), + GRBody1 =.. GRBodys1, + append(GRBodys1, [Arg1,Arg2], GRBodys2), + GRBody2 =.. GRBodys2, + dcg_constr(GRBody2), + dcg_body(GRBody2, S0, S, GRBody3) -> + call(M:GRBody3) + ; call(M:GRBody1, Arg1, Arg2, S0, S) + ). + % The same version of the below two dcg_rule clauses, but with module scoping. dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :- dcg_non_terminal(NonTerminal, S0, S, Head), @@ -101,7 +136,10 @@ dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :- dcg_non_terminal(NonTerminal, S0, S, Goal) :- NonTerminal =.. NonTerminalUniv, append(NonTerminalUniv, [S0, S], GoalUniv), - Goal =.. GoalUniv. + ( callable(NonTerminal) -> + Goal =.. GoalUniv + ; Goal = NonTerminal % let call/N throw an error instead of throwing one here. + ). dcg_terminals(Terminals, S0, S, S0 = List) :- append(Terminals, S, List). @@ -116,8 +154,6 @@ dcg_body(GRBody, S0, S, Body) :- dcg_body(NonTerminal, S0, S, Goal1) :- nonvar(NonTerminal), \+ dcg_constr(NonTerminal), - NonTerminal \= ( _ -> _ ), - NonTerminal \= ( \+ _ ), loader:strip_module(NonTerminal, M, NonTerminal0), dcg_non_terminal(NonTerminal0, S0, S, Goal0), ( functor(NonTerminal, (:), 2) -> @@ -135,9 +171,13 @@ dcg_constr(( _'|'_ )). % 7.14.6 - alternative dcg_constr({_}). % 7.14.7 dcg_constr(call(_)). % 7.14.8 dcg_constr(phrase(_)). % 7.14.9 +dcg_constr(phrase(_,_)). % extension of 7.14.9 +dcg_constr(phrase(_,_,_)). % extension of 7.14.9 dcg_constr(!). % 7.14.10 -%% dcg_constr(\+ _). % 7.14.11 - not (existence implementation dep.) -dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.) +dcg_constr(\+ G_0) :- % 7.14.11 - not (existence implementation def.) + throw(error(representation_error(dcg_body), [culprit- (\+ G_0)])). +dcg_constr((If->Then)) :- % 7.14.12 - if-then (existence implementation def.) + throw(error(representation_error(dcg_body), [culprit- (If->Then)])). % The principal functor of the first argument indicates % the construct to be expanded. @@ -162,8 +202,10 @@ dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :- dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )). dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)). dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)). +dcg_cbody(phrase(Body, Arg), S0, S, phrase(Body, Arg, S0, S)). +dcg_cbody(phrase(Body, Arg1, Arg2), S0, S, phrase(Body, Arg1, Arg2, S0, S)). dcg_cbody(!, S0, S, ( !, S0 = S )). -dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )). +% dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )). dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :- dcg_body(GRIf, S0, S1, If), dcg_body(GRThen, S1, S, Then). @@ -202,6 +244,8 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess). error_goal(error(E, must_be/2), error(E, must_be/2)). error_goal(error(E, (=..)/2), error(E, (=..)/2)). +error_goal(error(representation_error(dcg_body), Context), + error(representation_error(dcg_body), Context)). error_goal(E, _) :- throw(E). user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :- @@ -217,3 +261,10 @@ user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :- ). user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])). + + +% (-->)/2 behaves as if it didn't exist. We export (and define) it +% only so that clauses for (-->)/2 cannot be asserted when +% library(dcgs) is loaded. + +(_-->_) :- throw(error(existence_error(procedure,(-->)/2),(-->)/2)). diff --git a/src/lib/files.pl b/src/lib/files.pl index 6d89eaad..6c50aeeb 100644 --- a/src/lib/files.pl +++ b/src/lib/files.pl @@ -178,7 +178,7 @@ directory_must_exist(Directory, Context) :- ; throw(error(existence_error(directory, Directory), Context)) ). -%% workind_directory(Dir0, Dir). +%% working_directory(Dir0, Dir). % % Dir0 is the current working directory, and the working directory % is changed to Dir. diff --git a/src/lib/format.pl b/src/lib/format.pl index 9280156f..3b3d1dc4 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -1,5 +1,5 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written 2020-2023 by Markus Triska (triska@metalevel.at) + Written 2020-2024 by Markus Triska (triska@metalevel.at) Part of Scryer Prolog. I place this code in the public domain. Use it in any way you want. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -302,14 +302,14 @@ format_number_chars(N0, Chars) :- N is N0, % evaluate compound expression number_chars(N, Chars). -n_newlines(0) --> !. n_newlines(N0) --> { N0 > 0, N is N0 - 1 }, [newline], n_newlines(N). +n_newlines(0) --> []. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -?- phrase(upto_what(Cs, ~), "abc~test", Rest). -Cs = [a,b,c], Rest = [~,t,e,s,t]. -?- phrase(upto_what(Cs, ~), "abc", Rest). -Cs = [a,b,c], Rest = []. +?- phrase(format:upto_what(Cs, ~), "abc~test", Rest). + Cs = "abc", Rest = "~test". +?- phrase(format:upto_what(Cs, ~), "abc", Rest). + Cs = "abc", Rest = []. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ separate_digits_fractional(Arg, Sep, Num, Cs) :- @@ -444,9 +444,9 @@ format(Stream, Fs, Args) :- ?- phrase(format:cells("~`at~50|", [], 0, [], []), Cs), phrase(format:format_cells(Cs), Ls). ?- phrase(format:cells("~ta~t~tb~tc~21|", [], 0, [], []), Cs). -Cs = [cell(0,21,[glue(' ',_A),chars("a"),glue(' ',_B),glue(' ',_C),chars("b"),glue(' ',_D),chars("c ...")])] + Cs = [cell(0,21,[glue(' ',_A),chars("a"),glue(' ',_B),glue(' ',_C),chars("b"),glue(' ',_D),chars("c")])]. ?- phrase(format:cells("~ta~t~4|", [], 0, [], []), Cs). -Cs = [cell(0,4,[glue(' ',_A),chars("a"),glue(' ',_B)])] + Cs = [cell(0,4,[glue(' ',_A),chars("a"),glue(' ',_B)])]. ?- phrase(format:format_cell(cell(0,1,[glue(a,_94)])), Ls). diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index 15c05fd2..3eb00a3e 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -9,6 +9,7 @@ but they're not part of the ISO Prolog standard at the moment. bb_put/2, call_cleanup/2, call_with_inference_limit/3, + call_residue_vars/2, forall/2, partial_string/1, partial_string/3, @@ -17,7 +18,8 @@ but they're not part of the ISO Prolog standard at the moment. succ/2, call_nth/2, countall/2, - copy_term_nat/2]). + copy_term_nat/2, + copy_term/3]). :- use_module(library(error), [can_be/2, domain_error/3, @@ -26,6 +28,8 @@ but they're not part of the ISO Prolog standard at the moment. :- use_module(library(lists), [maplist/3]). +:- use_module(library('$project_atts')). + :- meta_predicate(forall(0, 0)). %% forall(Generate, Test). @@ -382,3 +386,23 @@ countall(Goal, N) :- copy_term_nat(Source, Dest) :- '$copy_term_without_attr_vars'(Source, Dest). +%% copy_term(+Term, -Copy, -Gs). +% +% Produce a deep copy of Term and unify it to Copy, without attributes. +% Unify Gs with a list of goals that represent the attributes of Term. +% Similar to `copy_term/2` but splitting the attributes. +copy_term(Term, Copy, Gs) :- + can_be(list, Gs), + findall(Term-Rs, '$project_atts':term_residual_goals(Term,Rs), [Copy-Gs]), + ( var(Gs) -> + Gs = [] + ; true + ). + +:- meta_predicate call_residue_vars(0, ?). + +call_residue_vars(Goal, Vars) :- + can_be(list, Vars), + '$get_attr_var_queue_delim'(B), + call(Goal), + '$get_attr_var_queue_beyond'(B, Vars). diff --git a/src/lib/os.pl b/src/lib/os.pl index 5d31b5ce..aa955e9b 100644 --- a/src/lib/os.pl +++ b/src/lib/os.pl @@ -23,7 +23,9 @@ finding out the PID of the running system. unsetenv/1, shell/1, shell/2, - pid/1]). + pid/1, + raw_argv/1, + argv/1]). :- use_module(library(error)). :- use_module(library(charsio)). @@ -110,3 +112,34 @@ permitted('_'). must_be_chars(Cs) :- must_be(list, Cs), maplist(must_be(character), Cs). + +%% raw_argv(-Argv) +% +% True iff Argv is the list of arguments that this program was started with (usually passed via command line). +% In contrast to `argv/1`, this version includes every argument, without any postprocessing, just as the operating +% system reports it to the system. This includes-flags of Scryer itself, which are not needed in general. +raw_argv(Argv) :- + can_be(list, Argv), + '$argv'(Argv). + +%% argv(-Argv) +% +% True if Argv is the list of arguments that this program was started with (usually passed via command line). +% In this version, only arguments specific to the program are passed. To differentiate between the system +% arguments and the program arguments, we use `--` as a separator. +% +% Example: +% +% ``` +% % Call with scryer-prolog -f -- -t hello +% ?- argv(X). +% X = ["-t", "hello"]. +% ``` +argv(Argv) :- + can_be(list, Argv), + '$argv'(Argv0), + ( append(_, ["--"|Argv1], Argv0) -> + Argv = Argv1 + ; + Argv = [] + ). diff --git a/src/lib/si.pl b/src/lib/si.pl index ac28b43c..0e29c190 100644 --- a/src/lib/si.pl +++ b/src/lib/si.pl @@ -39,7 +39,8 @@ character_si/1, term_si/1, chars_si/1, - dif_si/2]). + dif_si/2, + when_si/2]). :- use_module(library(lists)). @@ -98,3 +99,31 @@ dif_si(X, Y) :- ( X \= Y -> true ; throw(error(instantiation_error,dif_si/2)) ). + +:- meta_predicate(when_si(+, 0)). + +%% when_si(Condition, Goal). +% +% Executes Goal when Condition becomes true. Throws an instantiation error if +% it can't decide. +when_si(Condition, Goal) :- + % Taken from https://stackoverflow.com/a/40449516 + ( when_condition_si(Condition) -> + ( Condition -> + Goal + ; throw(error(instantiation_error,when_si/2)) + ) + ; throw(error(domain_error(when_condition_si, Condition),_)) + ). + +when_condition_si(Cond) :- + var(Cond), !, throw(error(instantiation_error,when_condition_si/2)). +when_condition_si(ground(_)). +when_condition_si(nonvar(_)). +when_condition_si((A, B)) :- + when_condition_si(A), + when_condition_si(B). +when_condition_si((A ; B)) :- + when_condition_si(A), + when_condition_si(B). + diff --git a/src/lib/when.pl b/src/lib/when.pl new file mode 100644 index 00000000..56734057 --- /dev/null +++ b/src/lib/when.pl @@ -0,0 +1,106 @@ +/** +Provides the predicate `when/2`. +*/ + +:- module(when, [when/2]). + +:- use_module(library(atts)). +:- use_module(library(dcgs)). +:- use_module(library(lists)). +:- use_module(library(lambda)). + +:- use_module(library(format)). +:- use_module(library(debug)). + +:- attribute when_list/1. + +:- meta_predicate(when(+, 0)). + +%% when(Condition, Goal). +% +% Executes Goal when Condition becomes true. +when(Condition, Goal) :- + ( when_condition(Condition) -> + ( Condition -> + Goal + ; term_variables(Condition, Vars), + maplist( + [Goal, Condition]+\Var^( + get_atts(Var, when_list(Whens0)) -> + Whens = [when(Condition, Goal) | Whens0], + put_atts(Var, when_list(Whens)) + ; put_atts(Var, when_list([when(Condition, Goal)])) + ), + Vars + ) + ) + ; throw(error(domain_error(when_condition, Condition),_)) + ). + +when_condition(Cond) :- + % Should this be delayed? + var(Cond), !, throw(error(instantiation_error,when_condition/1)). +when_condition(ground(_)). +when_condition(nonvar(_)). +when_condition((A, B)) :- + when_condition(A), + when_condition(B). +when_condition((A ; B)) :- + when_condition(A), + when_condition(B). + +remove_goal([], _, []). +remove_goal([G0|G0s], Goal, Goals) :- + ( G0 == Goal -> + remove_goal(G0s, Goal, Goals) + ; Goals = [G0|Goals1], + remove_goal(G0s, Goal, Goals1) + ). + +vars_remove_goal(Vars, Goal) :- + maplist( + Goal+\Var^( + get_atts(Var, when_list(Whens0)) -> + remove_goal(Whens0, Goal, Whens), + ( Whens = [] -> + put_atts(Var, -when_list(_)) + ; put_atts(Var, when_list(Whens)) + ) + ; true + ), + Vars + ). + +reinforce_goal(Goal0, Goal) :- + Goal = ( + term_variables(Goal0, Vars), + when:vars_remove_goal(Vars, Goal0), + Goal0 + ). + +verify_attributes(Var, Value, Goals) :- + ( get_atts(Var, when_list(Whens)) -> + ( var(Value) -> + ( get_atts(Value, when_list(WhensValue)) -> + append(Whens, WhensValue, WhensNew), + put_atts(Value, when_list(WhensNew)) + ; put_atts(Value, when_list(Whens)) + ), + Goals = [] + ; maplist(reinforce_goal, Whens, Goals) + ) + ; Goals = [] + ). + +gather_when_goals([], _) --> []. +gather_when_goals([When|Whens], Var) --> + ( { term_variables(When, [V0|_]), Var == V0 } -> + [when:When] + ; [] + ), + gather_when_goals(Whens, Var). + +attribute_goals(Var) --> + { get_atts(Var, when_list(Whens)) }, + gather_when_goals(Whens, Var), + { put_atts(Var, -when_list(_)) }. diff --git a/src/loader.pl b/src/loader.pl index d1b718b0..c282301c 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -112,7 +112,7 @@ success_or_warning(Goal) :- ( call(Goal) -> true ; %% initialization goals can fail without thwarting the load. - write('Warning: initialization/1 failed for: '), + write('% Warning: initialization/1 failed for: '), writeq(Goal), nl ). @@ -138,7 +138,7 @@ file_load_cleanup(Evacuable, Error) :- load_context(Module), abolish(Module:'$initialization_goals'/1), unload_evacuable(Evacuable), - ( clause('$toplevel':argv(_), _) -> + ( clause('$toplevel':started, _) -> % let the toplevel call loader:write_error/1 throw(Error) ; '$print_message_and_fail'(Error) @@ -188,7 +188,7 @@ warn_about_singletons([], _). warn_about_singletons([Singleton|Singletons], LinesRead) :- ( filter_anonymous_vars([Singleton|Singletons], VarEqs), VarEqs \== [] -> - write('Warning: singleton variables '), + write('% Warning: singleton variables '), print_comma_separated_list(VarEqs), write(' at line '), write(LinesRead), @@ -231,14 +231,17 @@ complete_partial_goal(N, HeadArg, InnerHeadArgs, SuppArgs, CompleteHeadArg) :- integer(N), N >= 0, HeadArg =.. [Functor | InnerHeadArgs], - % the next two lines are equivalent to length(SuppArgs, N) but - % avoid length/2 so that copy_term/3 (which is invoked by - % length/2) can be bootstrapped without self-reference. - functor(SuppArgsFunctor, '.', N), - SuppArgsFunctor =.. [_ | SuppArgs], - % length(SuppArgs, N), - append(InnerHeadArgs, SuppArgs, InnerHeadArgs0), - CompleteHeadArg =.. [Functor | InnerHeadArgs0]. + ( callable(Functor) -> + % the next two lines are equivalent to length(SuppArgs, N) but + % avoid length/2 so that copy_term/3 (which is invoked by + % length/2) can be bootstrapped without self-reference. + functor(SuppArgsFunctor, '.', N), + SuppArgsFunctor =.. [_ | SuppArgs], + % length(SuppArgs, N), + append(InnerHeadArgs, SuppArgs, InnerHeadArgs0), + CompleteHeadArg =.. [Functor | InnerHeadArgs0] + ; type_error(callable, Functor, _) + ). inner_meta_specs(0, HeadArg, InnerHeadArgs, InnerMetaSpecs) :- !, @@ -283,7 +286,7 @@ module_expanded_head_variables(Head, HeadVars) :- print_goal_expansion_warning(Pred) :- nl, - write('Warning: clause body goal expansion failed because '), + write('% Warning: clause body goal expansion failed because '), writeq(Pred), write(' is not callable.'), nl. @@ -296,7 +299,7 @@ expand_term_goals(Terms0, Terms) :- ( atom(Module) -> prolog_load_context(module, Target), module_expanded_head_variables(Head2, HeadVars), - catch(expand_goal(Body0, Target, Body1, HeadVars), + catch(expand_goal(Body0, Target, Body1, HeadVars, []), error(type_error(callable, Pred), _), ( loader:print_goal_expansion_warning(Pred), builtins:(Body1 = Body0) @@ -306,7 +309,7 @@ expand_term_goals(Terms0, Terms) :- ) ; module_expanded_head_variables(Head1, HeadVars), prolog_load_context(module, Target), - catch(expand_goal(Body0, Target, Body1, HeadVars), + catch(expand_goal(Body0, Target, Body1, HeadVars, []), error(type_error(callable, Pred), _), ( loader:print_goal_expansion_warning(Pred), builtins:(Body1 = Body0) @@ -726,9 +729,9 @@ subgoal_expansion(Goal, Module, ExpandedGoal) :- ). -:- non_counted_backtracking expand_subgoal/5. +:- non_counted_backtracking expand_subgoal/6. -expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars) :- +expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars, TGs) :- strip_subst_module(UnexpandedGoals, M, Module, UnexpandedGoals0), nonvar(UnexpandedGoals0), complete_partial_goal(MS, UnexpandedGoals0, _, SuppArgs, UnexpandedGoals1), @@ -740,7 +743,7 @@ expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars) :- ), strip_subst_module(UnexpandedGoals3, Module, Module1, UnexpandedGoals4), ( inner_meta_specs(0, UnexpandedGoals4, _, MetaSpecs) -> - expand_module_names(UnexpandedGoals4, MetaSpecs, Module1, ExpandedGoals0, HeadVars) + expand_module_names(UnexpandedGoals4, MetaSpecs, Module1, ExpandedGoals0, HeadVars, TGs) ; ExpandedGoals0 = UnexpandedGoals4 ), '$compile_inline_or_expanded_goal'(ExpandedGoals0, SuppArgs, ExpandedGoals1, Module1, UnexpandedGoals0), @@ -769,10 +772,10 @@ expand_module_name(ESG0, MS, M, ESG) :- :- non_counted_backtracking eq_member/2. -eq_member(V, [L-_|Ls]) :- +eq_member(V-M, [L-M|Ls]) :- V == L. -eq_member(V, [_|Ls]) :- - eq_member(V, Ls). +eq_member(V-M, [_|Ls]) :- + eq_member(V-M, Ls). :- non_counted_backtracking qualified_spec/1. @@ -782,11 +785,19 @@ qualified_spec(MS) :- integer(MS), MS >= 0. :- non_counted_backtracking expand_meta_predicate_subgoals/5. -expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars) :- +expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars, TGs) :- ( var(SG) -> ( qualified_spec(MS) -> - ( eq_member(SG, HeadVars) -> + ( eq_member(SG-_, HeadVars) -> ESG = SG + ; eq_member(SG-TG, TGs), + % transitive goals come about from previous equalities: + % if SG was bound by (=)/2 to a potential goal TG earlier + % in the goal sequence, expand TG and substitute SG with it + % in this subgoal context. the binding to SG must not be + % changed. + expand_subgoal(TG, MS, M, ESG, HeadVars, TGs) -> + true ; expand_module_name(SG, MS, M, ESG) ) ; ESG = SG @@ -795,26 +806,26 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars expand_module_name(SG, MS, M, ESG) ; '$is_expanded_or_inlined'(SG) -> ESG = SG - ; expand_subgoal(SG, MS, M, ESG, HeadVars) -> + ; expand_subgoal(SG, MS, M, ESG, HeadVars, TGs) -> true ; integer(MS), MS >= 0 -> expand_module_name(SG, MS, M, ESG) ; SG = ESG ), - expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars). + expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars, TGs). -expand_meta_predicate_subgoals([], _, _, [], _). +expand_meta_predicate_subgoals([], _, _, [], _, _). -:- non_counted_backtracking expand_module_names/5. +:- non_counted_backtracking expand_module_names/6. -expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :- +expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars, TGs) :- Goals =.. [GoalFunctor | SubGoals], ( GoalFunctor == (:), SubGoals = [M, SubGoal] -> - expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars), + expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars, TGs), expand_module_name(ExpandedSubGoal, 0, M, ExpandedGoals) - ; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars), + ; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars, TGs), ExpandedGoals =.. [GoalFunctor | ExpandedGoalList] ). @@ -822,26 +833,26 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :- :- non_counted_backtracking expand_goal/3. expand_goal(UnexpandedGoals, Module, ExpandedGoals) :- - catch(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, []), + catch(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, [], []), error(type_error(callable, _), _), UnexpandedGoals = ExpandedGoals), !. -:- non_counted_backtracking expand_goal/4. +:- non_counted_backtracking expand_goal/5. -expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :- +expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars, TGs) :- ( var(UnexpandedGoals) -> - expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars) + expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars, TGs) ; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1), ( Module \== user -> goal_expansion(UnexpandedGoals1, user, Goals) ; Goals = UnexpandedGoals1 ), - ( expand_goal_cases(Goals, Module, ExpandedGoals, HeadVars) -> + ( expand_goal_cases(Goals, Module, ExpandedGoals, HeadVars, TGs) -> true ; predicate_property(Module:Goals, meta_predicate(MetaSpecs0)), MetaSpecs0 =.. [_ | MetaSpecs] -> - expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) + expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars, TGs) ; thread_goals(Goals, ExpandedGoals, (',')) ; Goals = ExpandedGoals ) @@ -874,28 +885,40 @@ expand_call_goal_(UnexpandedGoals, Module, ExpandedGoals) :- ) ). -:- non_counted_backtracking expand_goal_cases/4. +:- non_counted_backtracking transitive_goal/3. -expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars) :- - ( expand_goal(Goal0, Module, Goal1, HeadVars) -> - expand_goal(Goals0, Module, Goals1, HeadVars), +transitive_goal(G, TGs0, TGs1) :- + ( G = (G1 = PotentialGoal), + callable(PotentialGoal), + subsumes_term(G1, PotentialGoal) -> + TGs1 = [G1-PotentialGoal|TGs0] + ; TGs1 = TGs0 + ). + +:- non_counted_backtracking expand_goal_cases/5. + +expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars, TGs) :- + ( expand_goal(Goal0, Module, Goal1, HeadVars, TGs) -> + transitive_goal(Goal0, TGs, TGs1), + expand_goal(Goals0, Module, Goals1, HeadVars, TGs1), thread_goals(Goal1, ExpandedGoals, Goals1, (',')) - ; expand_goal(Goals0, Module, Goals1, HeadVars), + ; expand_goal(Goals0, Module, Goals1, HeadVars, TGs), ExpandedGoals = (Goal0, Goals1) ). -expand_goal_cases((Goals0 -> Goals1), Module, ExpandedGoals, HeadVars) :- - expand_goal(Goals0, Module, ExpandedGoals0, HeadVars), - expand_goal(Goals1, Module, ExpandedGoals1, HeadVars), +expand_goal_cases((Goals0 -> Goals1), Module, ExpandedGoals, HeadVars, TGs) :- + expand_goal(Goals0, Module, ExpandedGoals0, HeadVars, TGs), + transitive_goal(ExpandedGoals0, TGs, TGs1), + expand_goal(Goals1, Module, ExpandedGoals1, HeadVars, TGs1), ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1). -expand_goal_cases((Goals0 ; Goals1), Module, ExpandedGoals, HeadVars) :- - expand_goal(Goals0, Module, ExpandedGoals0, HeadVars), - expand_goal(Goals1, Module, ExpandedGoals1, HeadVars), +expand_goal_cases((Goals0 ; Goals1), Module, ExpandedGoals, HeadVars, TGs) :- + expand_goal(Goals0, Module, ExpandedGoals0, HeadVars, TGs), + expand_goal(Goals1, Module, ExpandedGoals1, HeadVars, TGs), ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1). -expand_goal_cases((\+ Goals0), Module, ExpandedGoals, HeadVars) :- - expand_goal(Goals0, Module, Goals1, HeadVars), +expand_goal_cases((\+ Goals0), Module, ExpandedGoals, HeadVars, TGs) :- + expand_goal(Goals0, Module, Goals1, HeadVars, TGs), ExpandedGoals = (\+ Goals1). -expand_goal_cases((Module:Goals0), _, ExpandedGoals, HeadVars) :- - expand_goal(Goals0, Module, Goals1, HeadVars), +expand_goal_cases((Module:Goals0), _, ExpandedGoals, HeadVars, TGs) :- + expand_goal(Goals0, Module, Goals1, HeadVars, TGs), ExpandedGoals = (Module:Goals1). :- non_counted_backtracking thread_goals/3. diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 8380c130..3de47a60 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1423,6 +1423,7 @@ mod tests { use crate::machine::mock_wam::*; #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn arith_eval_by_metacall_tests() { let mut wam = MachineState::new(); let mut op_dir = default_op_dir(); diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 296d076f..7f967e8b 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -42,42 +42,35 @@ pub(super) fn bootstrapping_compile( Ok(()) } -fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize { +fn lower_bound_of_target_clause(skeleton: &mut PredicateSkeleton, target_pos: usize) -> usize { if target_pos == 0 { return 0; } - let arg_num = skeleton.clauses[target_pos - 1].opt_arg_index_key.arg_num(); + debug_assert!(skeleton.clauses.len() >= 2); - if arg_num == 0 { - return target_pos - 1; - } + let index = target_pos - 1; - let mut index_loc_opt = None; + let index = if let Some(index_loc) = skeleton.clauses[index] + .opt_arg_index_key + .switch_on_term_loc() + { + let search_result = skeleton.clauses.make_contiguous() + [0..skeleton.core.clause_assert_margin] + .partition_point(|clause_index_info| clause_index_info.clause_start > index_loc); - for index in (0..target_pos).rev() { - let current_arg_num = skeleton.clauses[index].opt_arg_index_key.arg_num(); - - if current_arg_num == 0 || current_arg_num != arg_num { - return index + 1; - } - - if let Some(index_loc) = index_loc_opt { - let current_index_loc = skeleton.clauses[index] - .opt_arg_index_key - .switch_on_term_loc(); - - if Some(index_loc) != current_index_loc { - return index + 1; - } + if search_result < skeleton.core.clause_assert_margin { + search_result } else { - index_loc_opt = skeleton.clauses[index] - .opt_arg_index_key - .switch_on_term_loc(); + skeleton.clauses.make_contiguous()[skeleton.core.clause_assert_margin..] + .partition_point(|clause_index_info| clause_index_info.clause_start < index_loc) + + skeleton.core.clause_assert_margin } - } + } else { + index + }; - 0 + index.clamp(0, skeleton.clauses.len() - 2) } fn derelictize_try_me_else( @@ -1215,7 +1208,7 @@ fn print_overwrite_warning( } println!( - "Warning: overwriting {}/{} because the clauses are discontiguous", + "% Warning: overwriting {}/{} because the clauses are discontiguous", key.0.as_str(), key.1 ); @@ -1327,7 +1320,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .clause_clause_locs .extend(&clause_clause_locs.make_contiguous()[0..]); - let skeleton = cg.skeleton; + let mut skeleton = cg.skeleton; + skeleton.core.is_dynamic = settings.is_dynamic(); self.add_extensible_predicate(key, skeleton, predicates.compilation_target); } @@ -1527,6 +1521,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let code_len = self.wam_prelude.code.len(); + standalone_skeleton.clauses[0].clause_start += code_len; + let skeleton = match self .wam_prelude .indices @@ -1539,8 +1535,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { match append_or_prepend { AppendOrPrepend::Append => { let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap(); - skeleton.clauses.push_back(clause_index_info); + skeleton.clauses.push_back(clause_index_info); skeleton.core.clause_clause_locs.push_back(code_len); self.payload @@ -2148,7 +2144,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .map(|skeleton| skeleton.predicate_info()) .unwrap_or_default(); - let mut predicate_info = self + let predicate_info = self .wam_prelude .indices .get_predicate_skeleton(&self.payload.predicates.compilation_target, &key) @@ -2183,7 +2179,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { if is_cross_module_clause && !local_predicate_info.is_extensible { if predicate_info.is_multifile { println!( - "Warning: overwriting multifile predicate {}:{}/{} because \ + "% Warning: overwriting multifile predicate {}:{}/{} because \ it was not locally declared multifile.", self.payload.predicates.compilation_target, key.0.as_str(), @@ -2210,8 +2206,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { (0..skeleton.clauses.len()).map(Some).collect(), false, // the builtin M:'$clause'/2 is never dynamic. ); - - predicate_info.is_dynamic = false; } self.payload diff --git a/src/machine/copier.rs b/src/machine/copier.rs index c02854ff..b64be4a0 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -398,6 +398,7 @@ mod tests { use crate::machine::mock_wam::*; #[test] + #[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")] fn copier_tests() { let mut wam = MockWAM::new(); diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index ff7d0188..f3a73e6c 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -557,20 +557,29 @@ impl Machine { } let mut p = self.machine_st.p; + let mut arity = 0; while self.code[p].is_head_instr() { + for r in self.code[p].registers() { + if let RegType::Temp(t) = r { + arity = std::cmp::max(arity, t); + } + } + p += 1; } - let instr = - std::mem::replace(&mut self.code[p], Instruction::VerifyAttrInterrupt); + let instr = std::mem::replace( + &mut self.code[p], + Instruction::VerifyAttrInterrupt(arity), + ); self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr; self.machine_st.attr_var_init.cp = p; } - &Instruction::VerifyAttrInterrupt => { - let (_, arity) = self.code[VERIFY_ATTR_INTERRUPT_LOC].to_name_and_arity(); - let arity = std::cmp::max(arity, self.machine_st.num_of_args); + &Instruction::VerifyAttrInterrupt(arity) => { + // let (_, arity) = self.code[VERIFY_ATTR_INTERRUPT_LOC].to_name_and_arity(); + // let arity = std::cmp::max(arity, self.machine_st.num_of_args); self.run_verify_attr_interrupt(arity); } &Instruction::Add(ref a1, ref a2, t) => { @@ -4147,6 +4156,14 @@ impl Machine { try_or_throw!(self.machine_st, self.js_eval()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + &Instruction::CallArgv => { + try_or_throw!(self.machine_st, self.argv()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteArgv => { + try_or_throw!(self.machine_st, self.argv()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } &Instruction::CallCurrentTime => { self.current_time(); step_or_fail!(self, self.machine_st.p += 1); @@ -4491,44 +4508,28 @@ impl Machine { self.crypto_curve_scalar_mult(); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } - #[cfg(feature = "crypto-full")] - &Instruction::CallEd25519Sign => { - self.ed25519_sign(); + &Instruction::CallEd25519SignRaw => { + self.ed25519_sign_raw(); step_or_fail!(self, self.machine_st.p += 1); } - #[cfg(feature = "crypto-full")] - &Instruction::ExecuteEd25519Sign => { - self.ed25519_sign(); + &Instruction::ExecuteEd25519SignRaw => { + self.ed25519_sign_raw(); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } - #[cfg(feature = "crypto-full")] - &Instruction::CallEd25519Verify => { - self.ed25519_verify(); + &Instruction::CallEd25519VerifyRaw => { + self.ed25519_verify_raw(); step_or_fail!(self, self.machine_st.p += 1); } - #[cfg(feature = "crypto-full")] - &Instruction::ExecuteEd25519Verify => { - self.ed25519_verify(); + &Instruction::ExecuteEd25519VerifyRaw => { + self.ed25519_verify_raw(); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } - #[cfg(feature = "crypto-full")] - &Instruction::CallEd25519NewKeyPair => { - self.ed25519_new_key_pair(); + &Instruction::CallEd25519SeedToPublicKey => { + self.ed25519_seed_to_public_key(); step_or_fail!(self, self.machine_st.p += 1); } - #[cfg(feature = "crypto-full")] - &Instruction::ExecuteEd25519NewKeyPair => { - self.ed25519_new_key_pair(); - step_or_fail!(self, self.machine_st.p = self.machine_st.cp); - } - #[cfg(feature = "crypto-full")] - &Instruction::CallEd25519KeyPairPublicKey => { - self.ed25519_key_pair_public_key(); - step_or_fail!(self, self.machine_st.p += 1); - } - #[cfg(feature = "crypto-full")] - &Instruction::ExecuteEd25519KeyPairPublicKey => { - self.ed25519_key_pair_public_key(); + &Instruction::ExecuteEd25519SeedToPublicKey => { + self.ed25519_seed_to_public_key(); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCurve25519ScalarMult => { diff --git a/src/machine/gc.rs b/src/machine/gc.rs index 32142e1d..f62231ea 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -369,6 +369,7 @@ mod tests { use crate::machine::mock_wam::*; #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn heap_marking_tests() { let mut wam = MockWAM::new(); diff --git a/src/machine/lib_machine.rs b/src/machine/lib_machine.rs index 44c5d727..d355ee7e 100644 --- a/src/machine/lib_machine.rs +++ b/src/machine/lib_machine.rs @@ -236,6 +236,7 @@ mod tests { use crate::machine::{QueryMatch, QueryResolution, Value}; #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn programatic_query() { let mut machine = Machine::new_lib(); @@ -275,6 +276,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn failing_query() { let mut machine = Machine::new_lib(); let query = String::from(r#"triple("a",P,"b")."#); @@ -288,6 +290,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore)] fn complex_results() { let mut machine = Machine::new_lib(); machine.load_module_string( @@ -344,6 +347,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn empty_predicate() { let mut machine = Machine::new_lib(); machine.load_module_string( @@ -359,6 +363,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn list_results() { let mut machine = Machine::new_lib(); machine.load_module_string( @@ -387,6 +392,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn consult() { let mut machine = Machine::new_lib(); @@ -445,6 +451,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn integration_test() { let mut machine = Machine::new_lib(); @@ -495,6 +502,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn findall() { let mut machine = Machine::new_lib(); diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 3cdc10aa..f340ad03 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -466,24 +466,48 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { None => return, }; - for (key, code_index) in removed_module.code_dir.iter_mut() { - match removed_module - .local_extensible_predicates - .get(&(CompilationTarget::User, *key)) - { - Some(skeleton) if skeleton.is_multifile => continue, - _ => {} + let mut skipped_local_predicates = IndexSet::with_hasher(FxBuildHasher::default()); + + for ((local_compilation_target, key), skeleton) in + removed_module.local_extensible_predicates.iter() + { + skipped_local_predicates.insert(key); + + if skeleton.is_multifile { + continue; } - let old_index_ptr = code_index.replace(IndexPtr::undefined()); + if let Some(code_index) = removed_module.code_dir.get_mut(key) { + if let Some(global_skeleton) = self + .wam_prelude + .indices + .get_predicate_skeleton(local_compilation_target, key) + { + let old_index_ptr = code_index.replace(if global_skeleton.core.is_dynamic { + IndexPtr::dynamic_undefined() + } else { + IndexPtr::undefined() + }); - self.payload - .retraction_info - .push_record(RetractionRecord::ReplacedModulePredicate( - module_name, - *key, - old_index_ptr, - )); + self.payload.retraction_info.push_record( + RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr), + ); + } + } + } + + for (key, code_index) in removed_module.code_dir.iter_mut() { + if skipped_local_predicates.contains(key) { + continue; + } + + if !code_index.is_undefined() && !code_index.is_dynamic_undefined() { + let old_index_ptr = code_index.replace(IndexPtr::undefined()); + + self.payload.retraction_info.push_record( + RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr), + ); + } } for (key, skeleton) in removed_module.extensible_predicates.drain(..) { diff --git a/src/machine/loader.rs b/src/machine/loader.rs index fb200f03..cd4f419a 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1833,9 +1833,33 @@ impl Machine { } pub(crate) fn scoped_clause_to_evacuable(&mut self) -> CallResult { - let module_name = cell_as_atom!(self - .machine_st - .store(self.machine_st.deref(self.machine_st.registers[1]))); + let target = self.deref_register(1); + + let mut permission_error = || { + let err = self.machine_st.permission_error( + Permission::Modify, + atom!("static_procedure"), + functor_stub(atom!(":"), 2) + .into_iter() + .collect::(), + ); + + self.machine_st + .error_form(err, functor_stub(atom!("load"), 1)) + }; + + let module_name = read_heap_cell!(target, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + name + } else { + return Err(permission_error()); + } + } + _ => { + return Err(permission_error()); + } + ); let loader = self.loader_from_heap_evacuable(temp_v!(3)); @@ -1948,11 +1972,13 @@ impl Machine { _ => CompilationTarget::Module(module_name), }; - let stub_gen = || match append_or_prepend { - AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1), - AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1), + let key = match append_or_prepend { + AppendOrPrepend::Append => (atom!("assertz"), 1), + AppendOrPrepend::Prepend => (atom!("asserta"), 1), }; + let stub_gen = || functor_stub(key.0, key.1); + let head = self.deref_register(2); if head.is_var() { @@ -1991,7 +2017,11 @@ impl Machine { .map(|code_idx| code_idx.get_tag()) .unwrap_or(IndexPtrTag::DynamicUndefined); - idx_tag == IndexPtrTag::DynamicUndefined || idx_tag == IndexPtrTag::Undefined + if idx_tag == IndexPtrTag::Index { + return Err(SessionError::CannotOverwriteStaticProcedure((name, arity))); + } else { + idx_tag == IndexPtrTag::Undefined || idx_tag == IndexPtrTag::DynamicUndefined + } } else if is_builtin { return Err(SessionError::CannotOverwriteBuiltIn((name, arity))); } else { diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 49d56510..c2cbb405 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -488,6 +488,13 @@ impl MachineState { .into_iter() .collect::(), ), + SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error( + Permission::Modify, + atom!("static_procedure"), + functor_stub(key.0, key.1) + .into_iter() + .collect::(), + ), SessionError::CannotOverwriteBuiltInModule(module) => { self.permission_error(Permission::Modify, atom!("static_module"), module) } @@ -1005,6 +1012,7 @@ pub enum SessionError { CompilationError(CompilationError), CannotOverwriteBuiltIn(PredicateKey), CannotOverwriteBuiltInModule(Atom), + CannotOverwriteStaticProcedure(PredicateKey), ExistenceError(ExistenceError), ModuleDoesNotContainExport(Atom, PredicateKey), ModuleCannotImportSelf(Atom), diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index edd6b673..459db1d7 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1450,10 +1450,15 @@ impl MachineState { a1.as_var().unwrap(), ); } + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | + HeapCellValueTag::F64) if arity != 0 => { + let err = self.type_error(ValidType::Atom, store_name); + return Err(self.error_form(err, stub_gen())); // 8.5.1.3 e) + } _ => { let err = self.type_error(ValidType::Atomic, store_name); - return Err(self.error_form(err, stub_gen())); - } // 8.5.1.3 c) + return Err(self.error_form(err, stub_gen())); // 8.5.1.3 c) + } ); } _ => { diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 0da42e08..2679be43 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -260,6 +260,7 @@ mod tests { use super::*; #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn unify_tests() { let mut wam = MachineState::new(); let mut op_dir = default_op_dir(); @@ -481,6 +482,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn test_unify_with_occurs_check() { let mut wam = MachineState::new(); let mut op_dir = default_op_dir(); diff --git a/src/machine/mod.rs b/src/machine/mod.rs index b25627db..5326c83c 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -228,7 +228,7 @@ impl Machine { self.machine_st.throw_exception(err); } - fn run_module_predicate( + pub fn run_module_predicate( &mut self, module_name: Atom, key: PredicateKey, @@ -307,29 +307,6 @@ impl Machine { } } - pub fn run_top_level( - &mut self, - module_name: Atom, - key: PredicateKey, - ) -> std::process::ExitCode { - let mut arg_pstrs = vec![]; - - for arg in env::args() { - arg_pstrs.push(put_complete_string( - &mut self.machine_st.heap, - &arg, - &self.machine_st.atom_tbl, - )); - } - - 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(module_name, key) - } - pub fn set_user_input(&mut self, input: String) { self.user_input = Stream::from_owned_string(input, &mut self.machine_st.arena); } @@ -414,7 +391,7 @@ impl Machine { self.code.extend(vec![ Instruction::BreakFromDispatchLoop, Instruction::InstallVerifyAttr, - Instruction::VerifyAttrInterrupt, + Instruction::VerifyAttrInterrupt(0), Instruction::BreakFromDispatchLoop, // the location of LIB_QUERY_SUCCESS Instruction::ExecuteTermGreaterThan, Instruction::ExecuteTermLessThan, @@ -925,8 +902,8 @@ impl Machine { self.machine_st.hb = self.machine_st.heap.len(); - self.machine_st.oip = 0; - self.machine_st.iip = 0; + // self.machine_st.oip = 0; + // self.machine_st.iip = 0; } self.machine_st.p += offset; @@ -1010,8 +987,22 @@ impl Machine { self.machine_st.heap.truncate(target_h); - self.machine_st.oip = 0; - self.machine_st.iip = 0; + // these registers don't need to be reset here and MUST + // NOT be (nor in indexed_try! trust_epilogue is an + // exception, see next paragraph)! oip could be reset + // without any adverse effects but iip is needed by + // get_clause_p to find the last executed clause/2 clause. + + // trust_epilogue must reset these for the sake of + // subsequent predicates beginning with + // switch_to_term. get_clause_p copes by checking + // self.machine_st.b > self.machine.e: if true, it is safe + // to use self.machine_st.iip; if false, use the choice + // point left at the top of the stack by '$clause' + // (specifically its biip value). + + // self.machine_st.oip = 0; + // self.machine_st.iip = 0; } else { self.trust_epilogue(offset); } @@ -1116,7 +1107,7 @@ impl Machine { } Unknown::Warn => { println!( - "warning: predicate {}/{} is undefined", + "% Warning: predicate {}/{} is undefined", name.as_str(), arity ); diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index cfbd4d8b..80d86e69 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -351,9 +351,9 @@ impl<'a> HeapPStrIter<'a> { ); value.as_char().map(|c| PStrIterStep { - iteratee: PStrIteratee::Char(curr_hare, c), - next_hare: s+2, - }) + iteratee: PStrIteratee::Char(curr_hare, c), + next_hare: s+2, + }) } else { None }; @@ -764,13 +764,29 @@ pub fn compare_pstr_prefixes<'a>( if i1.focus == empty_list_as_cell!() { PStrCmpResult::Ordered(Ordering::Less) } else { - PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) + let r2_step = r2.unwrap(); + + // advance i2 to the next character so the same character + // isn't repeated + if matches!(r2_step.iteratee, PStrIteratee::Char(..)) { + cycle_detection_step(i2, i1, &r2_step); + } + + PStrCmpResult::SecondIterContinuable(r2_step.iteratee) } } else if r2_at_end { if i2.focus == empty_list_as_cell!() { PStrCmpResult::Ordered(Ordering::Greater) } else { - PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) + let r1_step = r1.unwrap(); + + // advance i1 to the next character so the same character + // isn't repeated + if matches!(r1_step.iteratee, PStrIteratee::Char(..)) { + cycle_detection_step(i1, i2, &r1_step); + } + + PStrCmpResult::FirstIterContinuable(r1_step.iteratee) } } else if i1.is_continuable() && i2.is_continuable() { PStrCmpResult::Ordered(Ordering::Equal) @@ -785,6 +801,7 @@ mod test { use crate::machine::mock_wam::*; #[test] + #[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn pstr_iter_tests() { let mut wam = MockWAM::new(); @@ -1089,9 +1106,119 @@ mod test { Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1)) ); - // assert!(iter.next().is_none()); - for _ in iter {} } + + // #2293, test1. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a "))); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(char_as_cell!(' ')); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + + assert!(!wam.machine_st.fail); + + // #2293, test2. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a"))); + wam.machine_st.heap.push(char_as_cell!(' ')); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + + assert!(!wam.machine_st.fail); + + // #2293, test3. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a b"))); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(char_as_cell!(' ')); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(heap_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + + assert!(!wam.machine_st.fail); + + // #2293, test4. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a "))); + wam.machine_st.heap.push(char_as_cell!(' ')); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(char_as_cell!(' ')); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + + assert!(!wam.machine_st.fail); + + // #2293, test5. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a bc"))); + wam.machine_st.heap.push(char_as_cell!(' ')); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(char_as_cell!(' ')); + wam.machine_st.heap.push(heap_loc_as_cell!(6)); + + unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + + assert!(!wam.machine_st.fail); + + // #2293, test6. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abc"))); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(char_as_cell!('b')); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(heap_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + + assert!(!wam.machine_st.fail); + + // #2293, test7. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abcde"))); + wam.machine_st.heap.push(char_as_cell!('a')); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(char_as_cell!('c')); + wam.machine_st.heap.push(list_loc_as_cell!(7)); + wam.machine_st.heap.push(heap_loc_as_cell!(7)); + wam.machine_st.heap.push(list_loc_as_cell!(9)); + wam.machine_st.heap.push(char_as_cell!('e')); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + + assert!(!wam.machine_st.fail); } } diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 2681e8c0..b6e82ab7 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -565,21 +565,6 @@ impl Preprocessor { } } - /* - fn try_term_to_query<'a, LS: LoadState<'a>>( - &mut self, - loader: &mut Loader<'a, LS>, - terms: Vec, - cut_context: CutContext, - ) -> Result { - Ok(TopLevel::Query(self.setup_query( - loader, - terms, - cut_context, - )?)) - } - */ - pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, @@ -607,20 +592,4 @@ impl Preprocessor { } } } - - /* - fn try_terms_to_tls<'a, I: IntoIterator, LS: LoadState<'a>>( - &mut self, - loader: &mut Loader<'a, LS>, - terms: I, - ) -> Result, CompilationError> { - let mut results = VecDeque::new(); - - for term in terms.into_iter() { - results.push_back(self.try_term_to_tl(loader, term)?); - } - - Ok(results) - } - */ } diff --git a/src/machine/project_attributes.pl b/src/machine/project_attributes.pl index f54797c8..1ad0c47f 100644 --- a/src/machine/project_attributes.pl +++ b/src/machine/project_attributes.pl @@ -1,4 +1,4 @@ -:- module('$project_atts', [copy_term/3]). +:- module('$project_atts', []). :- use_module(library(dcgs)). :- use_module(library(error), [can_be/2]). @@ -100,14 +100,6 @@ gather_residual_goals([V|Vs]) --> delete_all_attributes_from_var(V) :- '$delete_all_attributes_from_var'(V). -copy_term(Term, Copy, Gs) :- - can_be(list, Gs), - findall(Term-Rs, term_residual_goals(Term,Rs), [Copy-Gs]), - ( var(Gs) -> - Gs = [] - ; true - ). - term_residual_goals(Term,Rs) :- '$term_attributed_variables'(Term, Vs), phrase(gather_residual_goals(Vs), Rs), diff --git a/src/machine/stack.rs b/src/machine/stack.rs index 46638bee..12aba456 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -189,7 +189,7 @@ impl Stack { for idx in 0..num_cells { ptr::write( - (new_ptr as usize + offset) as *mut HeapCellValue, + new_ptr.add(offset) as *mut HeapCellValue, stack_loc_as_cell!(AndFrame, e, idx + 1), ); @@ -203,6 +203,10 @@ impl Stack { } } + pub(crate) fn top(&self) -> usize { + unsafe { (*self.buf.ptr.get()) as usize - self.buf.base as usize } + } + pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize { let frame_size = OrFrame::size_of(num_cells); @@ -238,7 +242,8 @@ impl Stack { #[inline(always)] pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame { unsafe { - let ptr = self.buf.base as usize + e; + // This is doing alignment wrong + let ptr = self.buf.base.add(e); &mut *(ptr as *mut AndFrame) } } @@ -276,6 +281,7 @@ mod tests { use crate::machine::mock_wam::*; #[test] + #[cfg_attr(miri, ignore)] fn stack_tests() { let mut wam = MockWAM::new(); diff --git a/src/machine/streams.rs b/src/machine/streams.rs index fc957ade..53269bf4 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -469,6 +469,7 @@ macro_rules! arena_allocated_impl_for_stream { #[inline] fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { unsafe { + // Miri seems to hit this a lot ptr::write(dst, self); TypedArenaPtr::new(dst as *mut Self) } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 758bbc9d..5a10358d 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -81,14 +81,11 @@ use ring::rand::{SecureRandom, SystemRandom}; use ring::{digest, hkdf, pbkdf2}; #[cfg(feature = "crypto-full")] -use ring::{ - aead, - signature::{self, KeyPair}, -}; +use ring::aead; use ripemd160::{Digest, Ripemd160}; use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512}; -use crrl::{secp256k1, x25519}; +use crrl::{ed25519, secp256k1, x25519}; #[cfg(feature = "tls")] use native_tls::{Identity, TlsAcceptor, TlsConnector}; @@ -1171,63 +1168,33 @@ impl Machine { .get_predicate_skeleton(&compilation_target, &key) .unwrap(); - if self.machine_st.b > self.machine_st.e { - let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b); - let bp = or_frame.prelude.bp; + let module_name = match compilation_target { + CompilationTarget::User => atom!("builtins"), + CompilationTarget::Module(target) => target, + }; - match &self.code[bp] { - Instruction::IndexingCode(ref indexing_code) => { - match &indexing_code[or_frame.prelude.boip as usize] { - IndexingLine::IndexedChoice(ref indexed_choice) => { - let p = or_frame.prelude.biip as usize - 1; + let mut bp = self + .indices + .get_predicate_code_index(atom!("$clause"), 2, module_name) + .and_then(|idx| idx.local()) + .unwrap(); - match &indexed_choice[p] { - &IndexedChoiceInstruction::Try(offset) - | &IndexedChoiceInstruction::Retry(offset) - | &IndexedChoiceInstruction::DefaultRetry(offset) => { - let clause_clause_loc = skeleton.core.clause_clause_locs[p]; - (clause_clause_loc, bp + offset) - } - &IndexedChoiceInstruction::Trust(_) - | &IndexedChoiceInstruction::DefaultTrust(_) => { - unreachable!() - } - } - } - _ => { - unreachable!() - } + macro_rules! extract_ptr { + ($ptr: expr) => { + match $ptr { + IndexingCodePtr::External(p) => { + return ( + skeleton.core.clause_clause_locs.back().cloned().unwrap(), + bp + p, + ) } + IndexingCodePtr::Internal(boip) => boip, + _ => unreachable!(), } - _ => unreachable!(), - } - } else { - let module_name = match compilation_target { - CompilationTarget::User => atom!("builtins"), - CompilationTarget::Module(target) => target, }; + } - let bp = self - .indices - .get_predicate_code_index(atom!("$clause"), 2, module_name) - .and_then(|idx| idx.local()) - .unwrap(); - - macro_rules! extract_ptr { - ($ptr: expr) => { - match $ptr { - IndexingCodePtr::External(p) => { - return ( - skeleton.core.clause_clause_locs.back().cloned().unwrap(), - bp + p, - ) - } - IndexingCodePtr::Internal(boip) => boip, - _ => unreachable!(), - } - }; - } - + loop { match &self.code[bp] { Instruction::IndexingCode(ref indexing_code) => { let indexing_code_ptr = match &indexing_code[0] { @@ -1263,14 +1230,38 @@ impl Machine { match &indexing_code[boip] { IndexingLine::IndexedChoice(indexed_choice) => { + let p = if self.machine_st.b > self.machine_st.e { + // this means the last + // self.machine_st.iip value has yet + // to be overwritten by the Trust + // instruction. In this case, return + // it. + self.machine_st.iip as usize + } else { + // otherwise, read the '$clause' + // choicepoint from the top of the + // stack. this is very volatile in + // that it depends on '$clause' + // immediately preceding + // '$get_clause_p', which cannot be + // the last clause of the retract + // helper to delay deallocation of its + // environment frame. + let clause_b = self.machine_st.stack.top(); + self.machine_st.stack.index_or_frame(clause_b).prelude.biip as usize + }; + return ( - skeleton.core.clause_clause_locs.back().cloned().unwrap(), - bp + indexed_choice.back().unwrap().offset(), + skeleton.core.clause_clause_locs[p], + bp + indexed_choice[p].offset(), ); } _ => unreachable!(), } } + &Instruction::RevJmpBy(offset) => { + bp -= offset; + } _ => { return ( skeleton.core.clause_clause_locs.back().cloned().unwrap(), @@ -3501,6 +3492,12 @@ impl Machine { Some(Ok(c)) => { string.push(c); } + Some(Err(e)) => { + let stub = functor_stub(atom!("$get_n_chars"), 3); + let err = self.machine_st.session_error(SessionError::from(e)); + + return Err(self.machine_st.error_form(err, stub)); + } _ => { break; } @@ -4291,18 +4288,18 @@ impl Machine { let address_string = address_sink.as_str(); //to_string(); let address: Url = address_string.parse().unwrap(); - let client = reqwest::blocking::Client::builder().build().unwrap(); + let client = reqwest::Client::builder().build().unwrap(); // request - let mut req = reqwest::blocking::Request::new(method, address); + let mut req = reqwest::Request::new(method, address); *req.headers_mut() = headers; if !bytes.is_empty() { - *req.body_mut() = Some(reqwest::blocking::Body::from(bytes)); + *req.body_mut() = Some(reqwest::Body::from(bytes)); } // do it! - match client.execute(req) { + match futures::executor::block_on(client.execute(req)) { Ok(resp) => { // status code let status = resp.status().as_u16(); @@ -4339,7 +4336,7 @@ impl Machine { self.machine_st.registers[6] ); // body - let reader = resp.bytes().unwrap().reader(); + let reader = futures::executor::block_on(resp.bytes()).unwrap().reader(); let mut stream = Stream::from_http_stream( AtomTable::build_with(&self.machine_st.atom_tbl, &address_string), @@ -4953,6 +4950,27 @@ impl Machine { } } + #[inline(always)] + pub(crate) fn argv(&mut self) -> CallResult { + let args = self.deref_register(1); + + let mut args_pstrs = vec![]; + for arg in env::args() { + args_pstrs.push(put_complete_string( + &mut self.machine_st.heap, + &arg, + &self.machine_st.atom_tbl, + )); + } + let cell = heap_loc_as_cell!(iter_to_heap_list( + &mut self.machine_st.heap, + args_pstrs.into_iter() + )); + + unify!(self.machine_st, args, cell); + Ok(()) + } + #[inline(always)] pub(crate) fn current_time(&mut self) { let timestamp = self.systemtime_to_timestamp(SystemTime::now()); @@ -5721,11 +5739,11 @@ impl Machine { #[inline(always)] pub(super) fn restore_instr_at_verify_attr_interrupt(&mut self) { match &self.code[VERIFY_ATTR_INTERRUPT_LOC] { - &Instruction::VerifyAttrInterrupt => {} + &Instruction::VerifyAttrInterrupt(_) => {} _ => { let instr = mem::replace( &mut self.code[VERIFY_ATTR_INTERRUPT_LOC], - Instruction::VerifyAttrInterrupt, + Instruction::VerifyAttrInterrupt(0), ); self.code[self.machine_st.attr_var_init.cp] = instr; @@ -6520,10 +6538,8 @@ impl Machine { ); if had_zero_port { - self.machine_st.unify_fixnum( - Fixnum::build_with(port as i64), - self.machine_st.registers[2], - ); + self.machine_st + .unify_fixnum(Fixnum::build_with(port as i64), self.deref_register(2)); } Ok(()) @@ -7625,33 +7641,16 @@ impl Machine { unify!(self.machine_st, self.machine_st.registers[4], uncompressed); } - #[cfg(feature = "crypto-full")] #[inline(always)] - pub(crate) fn ed25519_new_key_pair(&mut self) { - let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); - let complete_string = self.u8s_to_string(pkcs8_bytes.as_ref()); + pub(crate) fn ed25519_seed_to_public_key(&mut self) { + let stub_gen = || functor_stub(atom!("ed25519_seed_keypair"), 2); + let seed_bytes = self + .machine_st + .integers_to_bytevec(self.machine_st.registers[1], stub_gen); - unify!( - self.machine_st, - self.machine_st.registers[1], - complete_string - ) - } + let skey = ed25519::PrivateKey::from_seed(&seed_bytes); - #[cfg(feature = "crypto-full")] - #[inline(always)] - pub(crate) fn ed25519_key_pair_public_key(&mut self) { - let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - - let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) { - Ok(kp) => kp, - _ => { - self.machine_st.fail = true; - return; - } - }; - - let complete_string = self.u8s_to_string(key_pair.public_key().as_ref()); + let complete_string = self.u8s_to_string(skey.public_key.encoded.as_ref()); unify!( self.machine_st, @@ -7660,22 +7659,19 @@ impl Machine { ); } - #[cfg(feature = "crypto-full")] #[inline(always)] - pub(crate) fn ed25519_sign(&mut self) { - let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + pub(crate) fn ed25519_sign_raw(&mut self) { + let stub_gen = || functor_stub(atom!("ed25519_sign"), 4); + let seed_bytes = self + .machine_st + .integers_to_bytevec(self.machine_st.registers[1], stub_gen); + + let skey = ed25519::PrivateKey::from_seed(&seed_bytes); + let encoding = cell_as_atom!(self.deref_register(3)); let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); - let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) { - Ok(kp) => kp, - _ => { - self.machine_st.fail = true; - return; - } - }; - - let sig = key_pair.sign(&data); + let sig = skey.sign_raw(&data); let sig_list = heap_loc_as_cell!(iter_to_heap_list( &mut self.machine_st.heap, @@ -7687,25 +7683,21 @@ impl Machine { unify!(self.machine_st, self.machine_st.registers[4], sig_list); } - #[cfg(feature = "crypto-full")] #[inline(always)] - pub(crate) fn ed25519_verify(&mut self) { - let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + pub(crate) fn ed25519_verify_raw(&mut self) { + let key_bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + let pkey = ed25519::PublicKey::decode(&key_bytes).unwrap(); + let encoding = cell_as_atom!(self.deref_register(3)); let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); - let stub_gen = || functor_stub(atom!("ed25519_verify"), 5); + + let stub_gen = || functor_stub(atom!("ed25519_verify"), 4); + let signature = self .machine_st .integers_to_bytevec(self.machine_st.registers[4], stub_gen); - let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key); - - match peer_public_key.verify(&data, &signature) { - Ok(_) => {} - _ => { - self.machine_st.fail = true; - } - } + self.machine_st.fail = !pkey.verify_raw(&signature, &data); } #[inline(always)] diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 3c100ce4..b045552b 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -173,6 +173,98 @@ pub(crate) trait Unifier: DerefMut { let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1); let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1); + fn unify_sequence( + machine_st: &mut MachineState, + iter: PStrIteratee, + source_cell: HeapCellValue, + ) -> bool { + match iter { + PStrIteratee::Char(focus, _) => { + machine_st.pdl.push(machine_st.heap[focus]); + machine_st.pdl.push(source_cell); + } + PStrIteratee::PStrSegment(focus, _, n) => { + read_heap_cell!(machine_st.heap[focus], + (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { + if focus < machine_st.heap.len() - 2 { + machine_st.heap.pop(); + machine_st.heap.pop(); + } + + if n == 0 { + let target_cell = match machine_st.heap[focus].get_tag() { + HeapCellValueTag::CStr => { + atom_as_cstr_cell!(pstr_atom) + } + HeapCellValueTag::PStr => { + pstr_loc_as_cell!(focus) + } + _ => { + unreachable!() + } + }; + + machine_st.pdl.push(target_cell); + machine_st.pdl.push(source_cell); + } else { + let h_len = machine_st.heap.len(); + + machine_st.heap.push(pstr_offset_as_cell!(focus)); + machine_st.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + machine_st.pdl.push(pstr_loc_as_cell!(h_len)); + machine_st.pdl.push(source_cell); + } + + return true; + } + (HeapCellValueTag::PStrOffset, pstr_loc) => { + let n0 = cell_as_fixnum!(machine_st.heap[focus+1]) + .get_num() as usize; + + if pstr_loc < machine_st.heap.len() - 2 { + machine_st.heap.pop(); + machine_st.heap.pop(); + } + + if n == n0 { + machine_st.pdl.push(pstr_loc_as_cell!(focus)); + machine_st.pdl.push(source_cell); + } else { + let h_len = machine_st.heap.len(); + + machine_st.heap.push(pstr_offset_as_cell!(pstr_loc)); + machine_st.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + machine_st.pdl.push(pstr_loc_as_cell!(h_len)); + machine_st.pdl.push(source_cell); + } + + return true; + } + _ => { + } + ); + + if focus < machine_st.heap.len() - 2 { + machine_st.heap.pop(); + machine_st.heap.pop(); + } + + machine_st.pdl.push(machine_st.heap[focus]); + machine_st.pdl.push(source_cell); + + return true; + } + } + + false + } + match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { PStrCmpResult::Ordered(Ordering::Equal) => {} PStrCmpResult::Ordered(Ordering::Less) => { @@ -229,89 +321,13 @@ pub(crate) trait Unifier: DerefMut { break 'outer; } } + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + unify_sequence(machine_st, chars_iter.item.unwrap(), focus); + return; + } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - match chars_iter.item.unwrap() { - PStrIteratee::Char(focus, _) => { - machine_st.pdl.push(machine_st.heap[focus]); - machine_st.pdl.push(heap_loc_as_cell!(h)); - } - PStrIteratee::PStrSegment(focus, _, n) => { - read_heap_cell!(machine_st.heap[focus], - (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { - if focus < machine_st.heap.len() - 2 { - machine_st.heap.pop(); - machine_st.heap.pop(); - } - - if n == 0 { - let target_cell = match machine_st.heap[focus].get_tag() { - HeapCellValueTag::CStr => { - atom_as_cstr_cell!(pstr_atom) - } - HeapCellValueTag::PStr => { - pstr_loc_as_cell!(focus) - } - _ => { - unreachable!() - } - }; - - machine_st.pdl.push(target_cell); - machine_st.pdl.push(heap_loc_as_cell!(h)); - } else { - let h_len = machine_st.heap.len(); - - machine_st.heap.push(pstr_offset_as_cell!(focus)); - machine_st.heap.push(fixnum_as_cell!( - Fixnum::build_with(n as i64) - )); - - machine_st.pdl.push(pstr_loc_as_cell!(h_len)); - machine_st.pdl.push(heap_loc_as_cell!(h)); - } - - return; - } - (HeapCellValueTag::PStrOffset, pstr_loc) => { - let n0 = cell_as_fixnum!(machine_st.heap[focus+1]) - .get_num() as usize; - - if pstr_loc < machine_st.heap.len() - 2 { - machine_st.heap.pop(); - machine_st.heap.pop(); - } - - if n == n0 { - machine_st.pdl.push(pstr_loc_as_cell!(focus)); - machine_st.pdl.push(heap_loc_as_cell!(h)); - } else { - let h_len = machine_st.heap.len(); - - machine_st.heap.push(pstr_offset_as_cell!(pstr_loc)); - machine_st.heap.push(fixnum_as_cell!( - Fixnum::build_with(n as i64) - )); - - machine_st.pdl.push(pstr_loc_as_cell!(h_len)); - machine_st.pdl.push(heap_loc_as_cell!(h)); - } - - return; - } - _ => { - } - ); - - if focus < machine_st.heap.len() - 2 { - machine_st.heap.pop(); - machine_st.heap.pop(); - } - - machine_st.pdl.push(machine_st.heap[focus]); - machine_st.pdl.push(heap_loc_as_cell!(h)); - - return; - } + if unify_sequence(machine_st, chars_iter.item.unwrap(), heap_loc_as_cell!(h)) { + return; } break 'outer; diff --git a/src/parser/ast.rs b/src/parser/ast.rs index ec46a74f..04d6fc99 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -417,6 +417,9 @@ impl ParserError { ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => { atom!("unexpected_end_of_file") } + ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => { + atom!("invalid_data") + } ParserError::IO(_) => atom!("input_output_error"), ParserError::LexicalError(_) => atom!("lexical_error"), ParserError::MissingQuote(..) => atom!("missing_quote"), diff --git a/src/parser/char_reader.rs b/src/parser/char_reader.rs index bf3b8f8e..aa1813a9 100644 --- a/src/parser/char_reader.rs +++ b/src/parser/char_reader.rs @@ -144,6 +144,35 @@ impl CharRead for CharReader { Err(e) => return Some(Err(e)), } + let bad_bytes_error = |buf: &[u8]| { + // 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. + + io::Error::new(io::ErrorKind::InvalidData, BadUtf8Error { bytes: badbytes }) + }; + loop { let buf = &self.buf[self.pos..]; @@ -159,38 +188,10 @@ impl CharRead for CharReader { }; 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 }, - ))); + return Some(Err(bad_bytes_error(buf))); } else if self.pos >= self.buf.len() { return None; - } else if self.buf.len() - self.pos >= 4 { + } else if self.buf.len() - self.pos >= 4 && self.pos < e.valid_up_to() { return match str::from_utf8(&self.buf[self.pos..e.valid_up_to()]) { Ok(s) => { let mut chars = s.chars(); @@ -217,18 +218,22 @@ impl CharRead for CharReader { self.buf.truncate(buf_len - self.pos); let buf_len = self.buf.len(); + self.pos = 0; + + if buf_len >= 4 { + continue; + } 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) if nread == 0 => return Some(Err(bad_bytes_error(&self.buf))), Ok(nread) => { self.buf.extend_from_slice(&word_slice[0..nread]); } } - - self.pos = 0; } } else { return None; @@ -375,6 +380,7 @@ mod tests { use std::io::Cursor; #[test] + #[cfg_attr(miri, ignore = "slow and not very relevant")] fn plain_string() { let mut read_string = CharReader::new(Cursor::new("a string")); @@ -387,6 +393,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "slow and not very relevant")] fn greek_string() { let mut read_string = CharReader::new(Cursor::new("λέξη")); @@ -399,6 +406,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "slow and not very relevant")] fn russian_string() { let mut read_string = CharReader::new(Cursor::new("слово")); @@ -411,6 +419,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "slow and not very relevant")] fn greek_lorem_ipsum() { let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ @@ -482,6 +491,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "slow and not very relevant")] fn armenian_lorem_ipsum() { let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում @@ -555,6 +565,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore = "slow and not very relevant")] fn russian_lorem_ipsum() { let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи diff --git a/src/parser/parser.rs b/src/parser/parser.rs index de2b04a0..3637df24 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -97,7 +97,12 @@ pub(crate) fn as_partial_string( string.push(*c); } _ => { - return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail)); + tail = Term::Cons( + Cell::default(), + Box::new((**prev).clone()), + Box::new((**succ).clone()), + ); + break; } } @@ -880,11 +885,7 @@ impl<'a, R: CharRead> Parser<'a, R> { .push(Term::Literal(Cell::default(), Literal::Atom(atom))); } - self.stack[idx].spec = if self.stack[idx].priority > 0 { - TERM - } else { - BTERM - }; + self.stack[idx].spec = BTERM; self.stack[idx].tt = TokenType::Term; self.stack[idx].priority = 0; diff --git a/src/raw_block.rs b/src/raw_block.rs index 41be0706..2c10f494 100644 --- a/src/raw_block.rs +++ b/src/raw_block.rs @@ -43,7 +43,7 @@ impl RawBlock { 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.top = self.base.add(cap); *self.ptr.get_mut() = self.base as *mut _; } @@ -98,7 +98,7 @@ impl RawBlock { pub unsafe fn alloc(&self, size: usize) -> *mut u8 { if self.free_space() >= size { let ptr = *self.ptr.get(); - *self.ptr.get() = (ptr as usize + size) as *mut _; + *self.ptr.get() = ptr.add(size) as *mut _; ptr } else { ptr::null_mut() diff --git a/src/read.rs b/src/read.rs index 1115bf1a..c13c0250 100644 --- a/src/read.rs +++ b/src/read.rs @@ -130,7 +130,7 @@ impl ReadlineStream { 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"); + println!("% Warning: loading history failed"); } } @@ -213,10 +213,10 @@ impl ReadlineStream { path.push(HISTORY_FILE); if path.exists() { if self.rl.append_history(&path).is_err() { - println!("Warning: couldn't append history (existing file)"); + println!("% Warning: couldn't append history (existing file)"); } } else if self.rl.save_history(&path).is_err() { - println!("Warning: couldn't save history (new file)"); + println!("% Warning: couldn't save history (new file)"); } } } diff --git a/src/tests/dif.pl b/src/tests/dif.pl index f0836007..c7dfbdd7 100644 --- a/src/tests/dif.pl +++ b/src/tests/dif.pl @@ -1,10 +1,10 @@ /**/ -:- use_module(library(format)). :- use_module(library(dcgs)). +:- use_module(library(format)). :- use_module(library(lists)). :- use_module(library(debug)). -:- use_module(library(atts)). +:- use_module(library(iso_ext)). :- use_module(library(dif)). % Tests from https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif diff --git a/src/tests/when.pl b/src/tests/when.pl new file mode 100644 index 00000000..7356e42e --- /dev/null +++ b/src/tests/when.pl @@ -0,0 +1,145 @@ +/**/ + +:- use_module(library(iso_ext)). +:- use_module(library(format)). +:- use_module(library(dcgs)). +:- use_module(library(lists)). +:- use_module(library(debug)). + +:- use_module(library(when)). + +test("condition true before ground/1",( + A = 1, + when(ground(A), Run = true), + Run == true +)). + +test("condition true before nonvar/1",( + A = a(_), + when(nonvar(A), Run = true), + Run == true +)). + +test("condition true before ','/2",( + A = 1, + B = a(_), + when((ground(A), nonvar(B)), Run = true), + Run == true +)). + +test("condition true before (;)/2",( + A = 1, + when((ground(A) ; nonvar(_)), Run1 = true), + Run1 == true, + + B = a(_), + when((ground(_) ; nonvar(B)), Run2 = true), + Run2 == true +)). + +test("condition true after ground/1",( + when(ground(A), Run = true), + var(Run), + A = 1, + Run == true +)). + +test("condition true after nonvar/1",( + when(nonvar(A), Run = true), + var(Run), + A = a(_), + Run == true +)). + +test("condition true after ','/2",( + when((ground(A), nonvar(B)), Run = true), + var(Run), + A = 1, + var(Run), + B = a(_), + Run == true +)). + +test("condition true after (;)/2",( + when((ground(A) ; nonvar(_)), Run1 = true), + var(Run1), + A = 1, + Run1 == true, + + when((ground(_) ; nonvar(B)), Run2 = true), + var(Run2), + B = a(_), + Run2 == true +)). + +test("multiple when/2 on same variable",( + when(nonvar(A), Run1 = true), + when(ground(A), Run2 = true), + var(Run1), var(Run2), + A = a(B), + Run1 == true, var(Run2), + B = 1, + Run2 == true +)). + +main :- + findall(test(Name, Goal), test(Name, Goal), Tests), + run_tests(Tests, Failed), + show_failed(Failed), + halt. + +main_quiet :- + findall(test(Name, Goal), test(Name, Goal), Tests), + run_tests_quiet(Tests, Failed), + ( Failed = [] -> + format("All tests passed", []) + ; format("Some tests failed", []) + ), + halt. + +portray_failed_([]) --> []. +portray_failed_([F|Fs]) --> + "\"", F, "\"", "\n", portray_failed_(Fs). + +portray_failed([]) --> []. +portray_failed([F|Fs]) --> + "\n", "Failed tests:", "\n", portray_failed_([F|Fs]). + +show_failed(Failed) :- + phrase(portray_failed(Failed), F), + format("~s", [F]). + +run_tests([], []). +run_tests([test(Name, Goal)|Tests], Failed) :- + format("Running test \"~s\"~n", [Name]), + ( call(Goal) -> + Failed = Failed1 + ; format("Failed test \"~s\"~n", [Name]), + Failed = [Name|Failed1] + ), + run_tests(Tests, Failed1). + +run_tests_quiet([], []). +run_tests_quiet([test(Name, Goal)|Tests], Failed) :- + ( call(Goal) -> + Failed = Failed1 + ; Failed = [Name|Failed1] + ), + run_tests_quiet(Tests, Failed1). + +assert_p(A, B) :- + phrase(portray_clause_(A), Portrayed), + phrase((B, ".\n"), Portrayed). + +call_residual_goals(Goal, ResidualGoals) :- + call_residue_vars(Goal, Vars), + variables_residual_goals(Vars, ResidualGoals). + +variables_residual_goals(Vars, Goals) :- + phrase(variables_residual_goals(Vars), Goals). + +variables_residual_goals([]) --> []. +variables_residual_goals([Var|Vars]) --> + dif_:attribute_goals(Var), + variables_residual_goals(Vars). + diff --git a/src/toplevel.pl b/src/toplevel.pl index a9a423c4..820d91d0 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -1,7 +1,5 @@ -:- module('$toplevel', [argv/1, - copy_term/3]). +:- module('$toplevel', []). -:- use_module(library(atts), [call_residue_vars/2]). :- use_module(library(charsio)). :- use_module(library(error)). :- use_module(library(files)). @@ -9,11 +7,13 @@ :- use_module(library(lambda)). :- use_module(library(lists)). :- use_module(library(si)). +:- use_module(library(os)). :- use_module(library('$project_atts')). :- use_module(library('$atts')). :- dynamic(disabled_init_file/0). +:- dynamic(started/0). load_scryerrc :- ( '$home_directory'(HomeDir) -> @@ -26,24 +26,18 @@ load_scryerrc :- ; true ). -:- dynamic(argv/1). - -'$repl'([_|Args0]) :- - \+ argv(_), - ( append(Args1, ["--"|Args2], Args0) -> - asserta('$toplevel':argv(Args2)), +'$repl' :- + asserta('$toplevel':started), + raw_argv(Args0), + ( append(Args1, ["--"|_], Args0) -> Args = Args1 - ; asserta('$toplevel':argv([])), - Args = Args0 + ; Args = Args0 ), - delegate_task(Args, []), - (\+ disabled_init_file -> load_scryerrc ; true), - repl. -'$repl'(_) :- - ( \+ argv(_) -> asserta('$toplevel':argv([])) + ( Args = [_|TaskArgs] -> + delegate_task(TaskArgs, []) ; true ), - load_scryerrc, + (\+ disabled_init_file -> load_scryerrc ; true), repl. delegate_task([], []). @@ -134,7 +128,7 @@ run_goals([g(Gs0)|Goals]) :- !, write_term(Exception, [double_quotes(DQ)]), nl % halt? ) ) -> true - ; write('Warning: initialization failed for: '), + ; write('% Warning: initialization failed for: '), write_term(Goal, [variable_names(VNs),double_quotes(DQ)]), nl ), run_goals(Goals). @@ -191,7 +185,7 @@ submit_query_and_print_results_(Term, VarList) :- bb_put('$report_all', false), bb_put('$report_n_more', 0), expand_goal(Term, user, Term0), - atts:call_residue_vars(user:Term0, AttrVars), + call_residue_vars(user:Term0, AttrVars), write_eqs_and_read_input(B, VarList, AttrVars), !. submit_query_and_print_results_(_, _) :- @@ -314,7 +308,11 @@ write_eqs_and_read_input(B, VarList, AttrVars) :- % one layer of depth added for (=/2) functor '$term_variables_under_max_depth'(OrigVars, 22, Vars0), '$project_atts':project_attributes(Vars0, AttrVars), - copy_term(AttrVars, AttrVars, AttrGoals), + % Need to copy all the visible Vars here so that they appear + % properly in AttrGoals, even the non-attributed. Need to also + % copy all the attributed variables here so that anonymous + % attributed variables also appear properly in AttrGoals. + copy_term([Vars0, AttrVars], [Vars0, AttrVars], AttrGoals), term_variables(AttrGoals, AttrGoalVars), append([Vars0, AttrGoalVars, AttrVars], Vars), charsio:extend_var_list(Vars, VarList, NewVarList, fabricated), @@ -452,4 +450,3 @@ print_exception_with_check(E) :- % is expected to be printed instead. ; print_exception(E) ). - diff --git a/tests-pl/iso-conformity-tests.pl b/tests-pl/iso-conformity-tests.pl index bfd74c61..dc08ce2d 100644 --- a/tests-pl/iso-conformity-tests.pl +++ b/tests-pl/iso-conformity-tests.pl @@ -1005,6 +1005,18 @@ test_311 :- test_syntax_error("Finis ().", syntax_error(incomplete_reduction)). test_318 :- writeq_term_to_chars(+((1*2)^3), C), C == "+ (1*2)^3". +test_320 :- writeq_term_to_chars([a|\+2], C), + C == "[a|\\+2]". + +test_321 :- test_syntax_error("writeq((a)(b)).", syntax_error(incomplete_reduction)). + +test_324 :- writeq_term_to_chars('%', C), + C == "'%'". + +test_325 :- test_syntax_error("writeq({[y}]).", syntax_error(incomplete_reduction)). + +test_326 :- test_syntax_error("(>)(1,2).", syntax_error(incomplete_reduction)). + run_tests([Test|Tests]) --> ( { call(Test) } -> [] diff --git a/tests/scryer/cli/issues/display_constraints.stderr b/tests/scryer/cli/issues/display_constraints.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/display_constraints.stdin b/tests/scryer/cli/issues/display_constraints.stdin new file mode 100644 index 00000000..5a3e1dfc --- /dev/null +++ b/tests/scryer/cli/issues/display_constraints.stdin @@ -0,0 +1,5 @@ +X = 1. +use_module(library(dif)). +X = 1. +dif(X,1). +halt. diff --git a/tests/scryer/cli/issues/display_constraints.stdout b/tests/scryer/cli/issues/display_constraints.stdout new file mode 100644 index 00000000..c96fa9ec --- /dev/null +++ b/tests/scryer/cli/issues/display_constraints.stdout @@ -0,0 +1,4 @@ + X = 1. + true. + X = 1. + dif:dif(X,1). diff --git a/tests/scryer/cli/issues/display_constraints.toml b/tests/scryer/cli/issues/display_constraints.toml new file mode 100644 index 00000000..266266c4 --- /dev/null +++ b/tests/scryer/cli/issues/display_constraints.toml @@ -0,0 +1,2 @@ +# issue 857 +args = ["-f", "--no-add-history"] diff --git a/tests-pl/issue852-throw_e.pl b/tests/scryer/cli/issues/do_not_duplicate_path_components.in/throw_e.pl similarity index 100% rename from tests-pl/issue852-throw_e.pl rename to tests/scryer/cli/issues/do_not_duplicate_path_components.in/throw_e.pl diff --git a/tests/scryer/cli/issues/do_not_duplicate_path_components.stderr b/tests/scryer/cli/issues/do_not_duplicate_path_components.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/do_not_duplicate_path_components.stdin b/tests/scryer/cli/issues/do_not_duplicate_path_components.stdin new file mode 100644 index 00000000..cf9a3782 --- /dev/null +++ b/tests/scryer/cli/issues/do_not_duplicate_path_components.stdin @@ -0,0 +1,3 @@ +['throw_e.pl']. +['throw_e.pl']. +halt. diff --git a/tests/scryer/cli/issues/do_not_duplicate_path_components.stdout b/tests/scryer/cli/issues/do_not_duplicate_path_components.stdout new file mode 100644 index 00000000..02d7a2d2 --- /dev/null +++ b/tests/scryer/cli/issues/do_not_duplicate_path_components.stdout @@ -0,0 +1,2 @@ + throw(e). + throw(e). diff --git a/tests/scryer/cli/issues/do_not_duplicate_path_components.toml b/tests/scryer/cli/issues/do_not_duplicate_path_components.toml new file mode 100644 index 00000000..f49e807c --- /dev/null +++ b/tests/scryer/cli/issues/do_not_duplicate_path_components.toml @@ -0,0 +1,2 @@ +# issue 852 +args = ["-f", "--no-add-history"] diff --git a/tests-pl/issue820-goals.pl b/tests/scryer/cli/issues/goals_compound_goal.in/goals.pl similarity index 100% rename from tests-pl/issue820-goals.pl rename to tests/scryer/cli/issues/goals_compound_goal.in/goals.pl diff --git a/tests/scryer/cli/issues/goals_compound_goal.stderr b/tests/scryer/cli/issues/goals_compound_goal.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/goals_compound_goal.stdout b/tests/scryer/cli/issues/goals_compound_goal.stdout new file mode 100644 index 00000000..31e0fce5 --- /dev/null +++ b/tests/scryer/cli/issues/goals_compound_goal.stdout @@ -0,0 +1 @@ +helloworld diff --git a/tests/scryer/cli/issues/goals_compound_goal.toml b/tests/scryer/cli/issues/goals_compound_goal.toml new file mode 100644 index 00000000..4fd7d5ba --- /dev/null +++ b/tests/scryer/cli/issues/goals_compound_goal.toml @@ -0,0 +1,2 @@ +# issue 820 +args = ["-f", "--no-add-history", "-g", "test,halt", "goals.pl"] diff --git a/tests/scryer/cli/issues/goals_multiple_goals.in/goals.pl b/tests/scryer/cli/issues/goals_multiple_goals.in/goals.pl new file mode 100644 index 00000000..fc94b92e --- /dev/null +++ b/tests/scryer/cli/issues/goals_multiple_goals.in/goals.pl @@ -0,0 +1,3 @@ +test :- write(world), nl. + +:- initialization(write(hello)). \ No newline at end of file diff --git a/tests/scryer/cli/issues/goals_multiple_goals.stderr b/tests/scryer/cli/issues/goals_multiple_goals.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/goals_multiple_goals.stdout b/tests/scryer/cli/issues/goals_multiple_goals.stdout new file mode 100644 index 00000000..31e0fce5 --- /dev/null +++ b/tests/scryer/cli/issues/goals_multiple_goals.stdout @@ -0,0 +1 @@ +helloworld diff --git a/tests/scryer/cli/issues/goals_multiple_goals.toml b/tests/scryer/cli/issues/goals_multiple_goals.toml new file mode 100644 index 00000000..25e739dd --- /dev/null +++ b/tests/scryer/cli/issues/goals_multiple_goals.toml @@ -0,0 +1,2 @@ +# issue 820 +args = ["-f", "--no-add-history", "-g", "test", "-g", "halt", "goals.pl"] diff --git a/tests/scryer/cli/issues/handle_residual_goal.stderr b/tests/scryer/cli/issues/handle_residual_goal.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/handle_residual_goal.stdin b/tests/scryer/cli/issues/handle_residual_goal.stdin new file mode 100644 index 00000000..1d7849f3 --- /dev/null +++ b/tests/scryer/cli/issues/handle_residual_goal.stdin @@ -0,0 +1,11 @@ +use_module(library(dif)). +use_module(library(iso_ext)). +-X\=X. +-X=X. +dif(-X,X). +dif(-X,X), -X=X. +call_residue_vars(dif(-X,X), Vars). +set_prolog_flag(occurs_check, true). +-X\=X. +dif(-X,X). +halt. diff --git a/tests/scryer/cli/issues/handle_residual_goal.stdout b/tests/scryer/cli/issues/handle_residual_goal.stdout new file mode 100644 index 00000000..288981d9 --- /dev/null +++ b/tests/scryer/cli/issues/handle_residual_goal.stdout @@ -0,0 +1,10 @@ + true. + true. + false. + X = -X. + dif:dif(-X,X). + false. + Vars = [X], dif:dif(-X,X). + true. + true. + true. diff --git a/tests/scryer/cli/issues/handle_residual_goal.toml b/tests/scryer/cli/issues/handle_residual_goal.toml new file mode 100644 index 00000000..6f3cb49f --- /dev/null +++ b/tests/scryer/cli/issues/handle_residual_goal.toml @@ -0,0 +1,2 @@ +# issue 844 +args = ["-f", "--no-add-history"] diff --git a/tests/scryer/cli/issues/ignored_constraint.stderr b/tests/scryer/cli/issues/ignored_constraint.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/ignored_constraint.stdin b/tests/scryer/cli/issues/ignored_constraint.stdin new file mode 100644 index 00000000..d6123a48 --- /dev/null +++ b/tests/scryer/cli/issues/ignored_constraint.stdin @@ -0,0 +1,2 @@ +use_module(library(freeze)), freeze(X,false), X \=a. +halt. diff --git a/tests/scryer/cli/issues/ignored_constraint.stdout b/tests/scryer/cli/issues/ignored_constraint.stdout new file mode 100644 index 00000000..051058c9 --- /dev/null +++ b/tests/scryer/cli/issues/ignored_constraint.stdout @@ -0,0 +1 @@ + freeze:freeze(X,false). diff --git a/tests/scryer/cli/issues/ignored_constraint.toml b/tests/scryer/cli/issues/ignored_constraint.toml new file mode 100644 index 00000000..9b1ed769 --- /dev/null +++ b/tests/scryer/cli/issues/ignored_constraint.toml @@ -0,0 +1,2 @@ +# issue 807 +args = ["-f", "--no-add-history"] diff --git a/tests/scryer/cli/issues/no_stutter.stderr b/tests/scryer/cli/issues/no_stutter.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/no_stutter.stdin b/tests/scryer/cli/issues/no_stutter.stdin new file mode 100644 index 00000000..f7ff0e90 --- /dev/null +++ b/tests/scryer/cli/issues/no_stutter.stdin @@ -0,0 +1,2 @@ +write(a), write(b), false. +halt. diff --git a/tests/scryer/cli/issues/no_stutter.stdout b/tests/scryer/cli/issues/no_stutter.stdout new file mode 100644 index 00000000..1e8d7051 --- /dev/null +++ b/tests/scryer/cli/issues/no_stutter.stdout @@ -0,0 +1 @@ +ab false. diff --git a/tests/scryer/cli/issues/no_stutter.toml b/tests/scryer/cli/issues/no_stutter.toml new file mode 100644 index 00000000..bf523922 --- /dev/null +++ b/tests/scryer/cli/issues/no_stutter.toml @@ -0,0 +1,2 @@ +# issue 815 +args = ["-f", "--no-add-history"] diff --git a/tests-pl/issue841-occurs-check.pl b/tests/scryer/cli/issues/occurs_check_flag.in/occurs_check_example.pl similarity index 100% rename from tests-pl/issue841-occurs-check.pl rename to tests/scryer/cli/issues/occurs_check_flag.in/occurs_check_example.pl diff --git a/tests/scryer/cli/issues/occurs_check_flag.stderr b/tests/scryer/cli/issues/occurs_check_flag.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/occurs_check_flag.stdin b/tests/scryer/cli/issues/occurs_check_flag.stdin new file mode 100644 index 00000000..8f652a7f --- /dev/null +++ b/tests/scryer/cli/issues/occurs_check_flag.stdin @@ -0,0 +1,2 @@ +f(X, X). +halt. diff --git a/tests/scryer/cli/issues/occurs_check_flag.stdout b/tests/scryer/cli/issues/occurs_check_flag.stdout new file mode 100644 index 00000000..53fd87fa --- /dev/null +++ b/tests/scryer/cli/issues/occurs_check_flag.stdout @@ -0,0 +1 @@ + false. diff --git a/tests/scryer/cli/issues/occurs_check_flag.toml b/tests/scryer/cli/issues/occurs_check_flag.toml new file mode 100644 index 00000000..b5013924 --- /dev/null +++ b/tests/scryer/cli/issues/occurs_check_flag.toml @@ -0,0 +1,2 @@ +# issue 841 +args = ["-f", "--no-add-history", "occurs_check_example.pl"] diff --git a/tests/scryer/cli/issues/occurs_check_flag2.stderr b/tests/scryer/cli/issues/occurs_check_flag2.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/occurs_check_flag2.stdin b/tests/scryer/cli/issues/occurs_check_flag2.stdin new file mode 100644 index 00000000..19cf9481 --- /dev/null +++ b/tests/scryer/cli/issues/occurs_check_flag2.stdin @@ -0,0 +1,6 @@ +set_prolog_flag(occurs_check, true). +X = -X. +asserta(f(X,g(X))). +f(X,X). +X-X = X-g(X). +halt. diff --git a/tests/scryer/cli/issues/occurs_check_flag2.stdout b/tests/scryer/cli/issues/occurs_check_flag2.stdout new file mode 100644 index 00000000..2203b5e0 --- /dev/null +++ b/tests/scryer/cli/issues/occurs_check_flag2.stdout @@ -0,0 +1,5 @@ + true. + false. + true. + false. + false. diff --git a/tests/scryer/cli/issues/occurs_check_flag2.toml b/tests/scryer/cli/issues/occurs_check_flag2.toml new file mode 100644 index 00000000..8d1da0ed --- /dev/null +++ b/tests/scryer/cli/issues/occurs_check_flag2.toml @@ -0,0 +1,2 @@ +# issue 841 +args = ["-f", "--no-add-history"] diff --git a/tests-pl/issue839-op3.pl b/tests/scryer/cli/issues/op3.in/op3.pl similarity index 100% rename from tests-pl/issue839-op3.pl rename to tests/scryer/cli/issues/op3.in/op3.pl diff --git a/tests/scryer/cli/issues/op3.stderr b/tests/scryer/cli/issues/op3.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/op3.stdout b/tests/scryer/cli/issues/op3.stdout new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/op3.toml b/tests/scryer/cli/issues/op3.toml new file mode 100644 index 00000000..864081c2 --- /dev/null +++ b/tests/scryer/cli/issues/op3.toml @@ -0,0 +1,2 @@ +# issue 839 +args = ["-f", "--no-add-history", "op3.pl", "-g", "halt"] diff --git a/tests/scryer/cli/issues/os_argv-no-final--.stderr b/tests/scryer/cli/issues/os_argv-no-final--.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/os_argv-no-final--.stdin b/tests/scryer/cli/issues/os_argv-no-final--.stdin new file mode 100644 index 00000000..59ba556c --- /dev/null +++ b/tests/scryer/cli/issues/os_argv-no-final--.stdin @@ -0,0 +1,6 @@ +os:argv(V). +os:argv(["test1"|_]). +os:argv(["--"|_]). +os:argv([V, "--"|_]). +os:argv(["test2"|_]). +os:argv([]). diff --git a/tests/scryer/cli/issues/os_argv-no-final--.stdout b/tests/scryer/cli/issues/os_argv-no-final--.stdout new file mode 100644 index 00000000..9558ca7f --- /dev/null +++ b/tests/scryer/cli/issues/os_argv-no-final--.stdout @@ -0,0 +1,6 @@ + V = ["test1","--","test2"]. + true. + false. + V = "test1". + false. + false. diff --git a/tests/scryer/cli/issues/os_argv-no-final--.toml b/tests/scryer/cli/issues/os_argv-no-final--.toml new file mode 100644 index 00000000..831d0fdd --- /dev/null +++ b/tests/scryer/cli/issues/os_argv-no-final--.toml @@ -0,0 +1,2 @@ +# https://github.com/mthom/scryer-prolog/pull/2263#issuecomment-1874400820 +args = ["-f", "--no-add-history", "--", "test1", "--", "test2"] diff --git a/tests/scryer/cli/issues/os_argv.stderr b/tests/scryer/cli/issues/os_argv.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/os_argv.stdin b/tests/scryer/cli/issues/os_argv.stdin new file mode 100644 index 00000000..59ba556c --- /dev/null +++ b/tests/scryer/cli/issues/os_argv.stdin @@ -0,0 +1,6 @@ +os:argv(V). +os:argv(["test1"|_]). +os:argv(["--"|_]). +os:argv([V, "--"|_]). +os:argv(["test2"|_]). +os:argv([]). diff --git a/tests/scryer/cli/issues/os_argv.stdout b/tests/scryer/cli/issues/os_argv.stdout new file mode 100644 index 00000000..2916310c --- /dev/null +++ b/tests/scryer/cli/issues/os_argv.stdout @@ -0,0 +1,6 @@ + V = ["test1","--","test2","--"]. + true. + false. + V = "test1". + false. + false. diff --git a/tests/scryer/cli/issues/os_argv.toml b/tests/scryer/cli/issues/os_argv.toml new file mode 100644 index 00000000..62b83a7a --- /dev/null +++ b/tests/scryer/cli/issues/os_argv.toml @@ -0,0 +1,2 @@ +# https://github.com/mthom/scryer-prolog/pull/2263#issuecomment-1874400820 +args = ["-f", "--no-add-history", "--", "test1", "--", "test2", "--"] diff --git a/tests-pl/issue812-singleton-warning.pl b/tests/scryer/cli/issues/singleton_warning.in/singleton_example.pl similarity index 60% rename from tests-pl/issue812-singleton-warning.pl rename to tests/scryer/cli/issues/singleton_warning.in/singleton_example.pl index 9c8673b9..f8207fa7 100644 --- a/tests-pl/issue812-singleton-warning.pl +++ b/tests/scryer/cli/issues/singleton_warning.in/singleton_example.pl @@ -1,4 +1,4 @@ % hello % line! -a :- b(X). \ No newline at end of file +a :- b(X). diff --git a/tests/scryer/cli/issues/singleton_warning.stderr b/tests/scryer/cli/issues/singleton_warning.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/issues/singleton_warning.stdin b/tests/scryer/cli/issues/singleton_warning.stdin new file mode 100644 index 00000000..9e58bda5 --- /dev/null +++ b/tests/scryer/cli/issues/singleton_warning.stdin @@ -0,0 +1,2 @@ +['singleton_example.pl']. +halt. diff --git a/tests/scryer/cli/issues/singleton_warning.stdout b/tests/scryer/cli/issues/singleton_warning.stdout new file mode 100644 index 00000000..4c8b7182 --- /dev/null +++ b/tests/scryer/cli/issues/singleton_warning.stdout @@ -0,0 +1,2 @@ +% Warning: singleton variables X at line 4 of singleton_example.pl + true. diff --git a/tests/scryer/cli/issues/singleton_warning.toml b/tests/scryer/cli/issues/singleton_warning.toml new file mode 100644 index 00000000..1d30dde6 --- /dev/null +++ b/tests/scryer/cli/issues/singleton_warning.toml @@ -0,0 +1,2 @@ +# issue 812 +args = ["-f", "--no-add-history"] diff --git a/tests/scryer/cli/src_tests/acyclic_term_tests.stderr b/tests/scryer/cli/src_tests/acyclic_term_tests.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/src_tests/acyclic_term_tests.stdout b/tests/scryer/cli/src_tests/acyclic_term_tests.stdout new file mode 100644 index 00000000..4952cede --- /dev/null +++ b/tests/scryer/cli/src_tests/acyclic_term_tests.stdout @@ -0,0 +1 @@ +All tests passed \ No newline at end of file diff --git a/tests/scryer/cli/src_tests/acyclic_term_tests.toml b/tests/scryer/cli/src_tests/acyclic_term_tests.toml new file mode 100644 index 00000000..042039ef --- /dev/null +++ b/tests/scryer/cli/src_tests/acyclic_term_tests.toml @@ -0,0 +1 @@ +args = ["-f", "--no-add-history", "src/tests/acyclic_term.pl", "-f", "-g", "main_quiet"] diff --git a/tests/scryer/cli/src_tests/dif_tests.stderr b/tests/scryer/cli/src_tests/dif_tests.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/src_tests/dif_tests.stdout b/tests/scryer/cli/src_tests/dif_tests.stdout new file mode 100644 index 00000000..4952cede --- /dev/null +++ b/tests/scryer/cli/src_tests/dif_tests.stdout @@ -0,0 +1 @@ +All tests passed \ No newline at end of file diff --git a/tests/scryer/cli/src_tests/dif_tests.toml b/tests/scryer/cli/src_tests/dif_tests.toml new file mode 100644 index 00000000..62665be2 --- /dev/null +++ b/tests/scryer/cli/src_tests/dif_tests.toml @@ -0,0 +1 @@ +args = ["-f", "--no-add-history", "src/tests/dif.pl", "-f", "-g", "main_quiet"] diff --git a/tests/scryer/cli/src_tests/ground_tests.stderr b/tests/scryer/cli/src_tests/ground_tests.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/src_tests/ground_tests.stdout b/tests/scryer/cli/src_tests/ground_tests.stdout new file mode 100644 index 00000000..4952cede --- /dev/null +++ b/tests/scryer/cli/src_tests/ground_tests.stdout @@ -0,0 +1 @@ +All tests passed \ No newline at end of file diff --git a/tests/scryer/cli/src_tests/ground_tests.toml b/tests/scryer/cli/src_tests/ground_tests.toml new file mode 100644 index 00000000..d7925bb7 --- /dev/null +++ b/tests/scryer/cli/src_tests/ground_tests.toml @@ -0,0 +1 @@ +args = ["-f", "--no-add-history", "src/tests/ground.pl", "-f", "-g", "main_quiet"] diff --git a/tests/scryer/cli/src_tests/setup_call_cleanup_process.stderr b/tests/scryer/cli/src_tests/setup_call_cleanup_process.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/src_tests/setup_call_cleanup_process.stdout b/tests/scryer/cli/src_tests/setup_call_cleanup_process.stdout new file mode 100644 index 00000000..380c3a78 --- /dev/null +++ b/tests/scryer/cli/src_tests/setup_call_cleanup_process.stdout @@ -0,0 +1 @@ +1+21+31+2>A+B1+G1+2>41+2>B1+2>31+2>31+2>4ba \ No newline at end of file diff --git a/tests/scryer/cli/src_tests/setup_call_cleanup_process.toml b/tests/scryer/cli/src_tests/setup_call_cleanup_process.toml new file mode 100644 index 00000000..40a47e98 --- /dev/null +++ b/tests/scryer/cli/src_tests/setup_call_cleanup_process.toml @@ -0,0 +1 @@ +args = ["-f", "--no-add-history", "src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"] diff --git a/tests/scryer/cli/src_tests/term_variables_tests.stderr b/tests/scryer/cli/src_tests/term_variables_tests.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/src_tests/term_variables_tests.stdout b/tests/scryer/cli/src_tests/term_variables_tests.stdout new file mode 100644 index 00000000..4952cede --- /dev/null +++ b/tests/scryer/cli/src_tests/term_variables_tests.stdout @@ -0,0 +1 @@ +All tests passed \ No newline at end of file diff --git a/tests/scryer/cli/src_tests/term_variables_tests.toml b/tests/scryer/cli/src_tests/term_variables_tests.toml new file mode 100644 index 00000000..6d75921e --- /dev/null +++ b/tests/scryer/cli/src_tests/term_variables_tests.toml @@ -0,0 +1 @@ +args = ["-f", "--no-add-history", "src/tests/term_variables.pl", "-f", "-g", "main_quiet"] diff --git a/tests/scryer/cli/src_tests/when_tests.stderr b/tests/scryer/cli/src_tests/when_tests.stderr new file mode 100644 index 00000000..e69de29b diff --git a/tests/scryer/cli/src_tests/when_tests.stdout b/tests/scryer/cli/src_tests/when_tests.stdout new file mode 100644 index 00000000..4952cede --- /dev/null +++ b/tests/scryer/cli/src_tests/when_tests.stdout @@ -0,0 +1 @@ +All tests passed \ No newline at end of file diff --git a/tests/scryer/cli/src_tests/when_tests.toml b/tests/scryer/cli/src_tests/when_tests.toml new file mode 100644 index 00000000..ff0a5330 --- /dev/null +++ b/tests/scryer/cli/src_tests/when_tests.toml @@ -0,0 +1 @@ +args = ["-f", "--no-add-history", "src/tests/when.pl", "-f", "-g", "main_quiet"] diff --git a/tests/scryer/helper.rs b/tests/scryer/helper.rs index 243952f2..f4d54fb8 100644 --- a/tests/scryer/helper.rs +++ b/tests/scryer/helper.rs @@ -1,6 +1,3 @@ -use assert_cmd::Command; -use std::ffi::OsStr; - pub(crate) trait Expectable { #[track_caller] fn assert_eq(self, other: &[u8]); @@ -34,41 +31,3 @@ pub(crate) fn load_module_test(file: &str, expected: T) { let mut wam = Machine::with_test_streams(); expected.assert_eq(wam.test_load_file(file).as_slice()); } - -pub const SCRYER_PROLOG: &str = "scryer-prolog"; - -pub fn run_top_level_test_no_args< - S: Into>, - O: assert_cmd::assert::IntoOutputPredicate

, - P: predicates_core::Predicate<[u8]>, ->( - stdin: S, - expected_stdout: O, -) { - run_top_level_test_with_args::<&[&str], _, _, _, _>(&[], stdin, expected_stdout) -} - -/// Test whether scryer-prolog -/// produces the expected output when called with the supplied -/// arguments and fed the supplied input -pub fn run_top_level_test_with_args< - A: IntoIterator, - S: Into>, - O: assert_cmd::assert::IntoOutputPredicate

, - AS: AsRef, - P: predicates_core::Predicate<[u8]>, ->( - args: A, - stdin: S, - expected_stdout: O, -) { - Command::cargo_bin(SCRYER_PROLOG) - .unwrap() - .arg("-f") - .arg("--no-add-history") - .args(args) - .write_stdin(stdin) - .assert() - .stdout(expected_stdout.into_output()) - .success(); -} diff --git a/tests/scryer/issues.rs b/tests/scryer/issues.rs index f7a71007..39e30378 100644 --- a/tests/scryer/issues.rs +++ b/tests/scryer/issues.rs @@ -1,169 +1,10 @@ -use crate::helper::{load_module_test, run_top_level_test_no_args, run_top_level_test_with_args}; +use crate::helper::load_module_test; use serial_test::serial; -// issue #857 -#[test] -fn display_constraints() { - run_top_level_test_no_args( - "\ - X = 1.\n\ - use_module(library(dif)).\n\ - X = 1.\n\ - dif(X,1).\n - halt.\n", - " \ - X = 1.\n \ - true.\n \ - X = 1.\n \ - dif:dif(X,1).\n\ - ", - ); -} - -// issue #852 -#[test] -fn do_not_duplicate_path_components() { - run_top_level_test_no_args( - "\ - ['tests-pl/issue852-throw_e.pl'].\n\ - ['tests-pl/issue852-throw_e.pl'].\n\ - halt.\n\ - ", - " throw(e).\n throw(e).\n", - ); -} - -// issue #844 -#[test] -fn handle_residual_goal() { - run_top_level_test_no_args( - "\ - use_module(library(dif)).\n\ - use_module(library(atts)).\n\ - -X\\=X.\n\ - -X=X.\n\ - dif(-X,X).\n\ - dif(-X,X), -X=X.\n\ - call_residue_vars(dif(-X,X), Vars).\n\ - set_prolog_flag(occurs_check, true).\n\ - -X\\=X.\n\ - dif(-X,X).\n\ - halt.\n\ - ", - " \ - true.\n \ - true.\n \ - false.\n \ - X = -X.\n \ - dif:dif(-X,X).\n \ - false.\n \ - Vars = [X], dif:dif(-X,X).\n \ - true.\n \ - true.\n \ - true.\n\ - ", - ) -} - -// issue #841 -#[test] -fn occurs_check_flag() { - run_top_level_test_with_args( - ["tests-pl/issue841-occurs-check.pl"], - "\ - f(X, X).\n\ - halt.\n\ - ", - " false.\n", - ) -} - -#[test] -fn occurs_check_flag2() { - run_top_level_test_no_args( - "\ - set_prolog_flag(occurs_check, true).\n\ - X = -X.\n\ - asserta(f(X,g(X))).\n\ - f(X,X).\n\ - X-X = X-g(X).\n\ - halt.\n\ - ", - " \ - true.\n \ - false.\n \ - true.\n \ - false.\n \ - false.\n\ - ", - ) -} - -// issue #839 -#[test] -fn op3() { - run_top_level_test_with_args(["tests-pl/issue839-op3.pl", "-g", "halt"], "", "") -} - -// issue #820 -#[test] -fn multiple_goals() { - run_top_level_test_with_args( - ["-g", "test", "-g", "halt", "tests-pl/issue820-goals.pl"], - "", - "helloworld\n", - ); -} - -// issue #820 -#[test] -fn compound_goal() { - run_top_level_test_with_args( - ["-g", "test,halt", "tests-pl/issue820-goals.pl"], - "", - "helloworld\n", - ) -} - -// issue #815 -#[test] -fn no_stutter() { - run_top_level_test_no_args( - "write(a), write(b), false.\n\ - halt.\n\ - ", - "ab false.\n", - ) -} - -/* -// issue #812 -#[test] // FIXME: the line number is of by one (should be 4), empty line not accounted for or starting to count at line 0? -fn singleton_warning() { - run_top_level_test_no_args( - "['tests-pl/issue812-singleton-warning.pl'].\n\ - halt.\n", - "\ - Warning: singleton variables X at line 3 of issue812-singleton-warning.pl\n \ - true.\n\ - ", - ); -} -*/ - -// issue #807 -#[test] -fn ignored_constraint() { - run_top_level_test_no_args( - "use_module(library(freeze)), freeze(X,false), X \\=a.\n\ - halt.", - " freeze:freeze(X,false).\n", - ); -} - // issue #831 #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn call_0() { load_module_test( "tests-pl/issue831-call0.pl", diff --git a/tests/scryer/main.rs b/tests/scryer/main.rs index 7865c0b3..d1e826f0 100644 --- a/tests/scryer/main.rs +++ b/tests/scryer/main.rs @@ -1,3 +1,23 @@ mod helper; mod issues; mod src_tests; + +/// To add new cli test copy an existing .toml file in `tests/scryer/cli/issues/` or `tests/scryer/cli/issues/src_tests/`, +/// adjust as necessary the `-f` and `--no-add-history` args should be kept but additional args may be added. +/// For input on stdin add a .stdin file with the same filename. +/// Then to generate new reference output files into dump/ run `TRYCMD=dump cargo test -- cli_test` +/// check that the output in the .stdout and .stderr file is as expected, then move them next to the .toml file. +/// +/// If a test does not have a .stderr or .stdout the corresponding output is ignored i.e. any and no output is accepted +/// +/// to re-generate all reference output files run `TRYCMD=overwrite cargo test -- cli_test` +/// then check that the changes are as expected e.g. by looking at the `git diff` +#[test] +#[cfg_attr(miri, ignore = "blocked on crossbeam UB")] +fn cli_tests() { + trycmd::TestCases::new() + .default_bin_name("scryer-prolog") + .case("tests/scryer/cli/issues/*.toml") + .skip("tests/scryer/cli/issues/singleton_warning.toml") // wrong line number + .case("tests/scryer/cli/src_tests/*.toml"); +} diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index ba68e5dd..a3d6ddbf 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -1,32 +1,37 @@ -use crate::helper::{load_module_test, run_top_level_test_with_args}; +use crate::helper::load_module_test; use serial_test::serial; #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn builtins() { load_module_test("src/tests/builtins.pl", ""); } #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn call_with_inference_limit() { load_module_test("src/tests/call_with_inference_limit.pl", ""); } #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn facts() { load_module_test("src/tests/facts.pl", ""); } #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn hello_world() { load_module_test("src/tests/hello_world.pl", "Hello World!\n"); } #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn syntax_error() { load_module_test( "tests-pl/syntax_error.pl", @@ -36,18 +41,21 @@ fn syntax_error() { #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn predicates() { load_module_test("src/tests/predicates.pl", ""); } #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn rules() { load_module_test("src/tests/rules.pl", ""); } #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", @@ -55,59 +63,16 @@ fn setup_call_cleanup_load() { ); } -#[test] -fn setup_call_cleanup_process() { - run_top_level_test_with_args( - ["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], - "", - "1+21+31+2>A+B1+G1+2>41+2>B1+2>31+2>31+2>4ba", - ); -} - #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn clpz_load() { load_module_test("src/tests/clpz/test_clpz.pl", ""); } #[serial] #[test] +#[cfg_attr(miri, ignore = "blocked on streams.rs UB")] fn iso_conformity_tests() { load_module_test("tests-pl/iso-conformity-tests.pl", "All tests passed"); } - -#[test] -fn dif_tests() { - run_top_level_test_with_args( - ["src/tests/dif.pl", "-f", "-g", "main_quiet"], - "", - "All tests passed", - ); -} - -#[test] -fn ground_tests() { - run_top_level_test_with_args( - ["src/tests/ground.pl", "-f", "-g", "main_quiet"], - "", - "All tests passed", - ); -} - -#[test] -fn term_variables_tests() { - run_top_level_test_with_args( - ["src/tests/term_variables.pl", "-f", "-g", "main_quiet"], - "", - "All tests passed", - ); -} - -#[test] -fn acyclic_term_tests() { - run_top_level_test_with_args( - ["src/tests/acyclic_term.pl", "-f", "-g", "main_quiet"], - "", - "All tests passed", - ); -}